当前位置: 首页 > news >正文

SVT-AV1源码分析-函数svt_aom_motion_estimation_kernel

svt_aom_motion_estimation_kernel函数作用

这段代码EBSDK 一个运动估计 内核函数用于处理视频编码运动估计任务运动估计任务运动估计视频编码一个关键步骤目的时间找到当前参考帧最佳匹配从而减少视频数据冗余

函数主要功能

函数svt_aom_motion_estimation_kernel 无限循环输入队列获取任务并且处理然后结果输出结果队列主要处理以下几种任务类型

1 PAME 运动估计用于PB运动估计

2 TFME 时间滤波运动估计用于实践滤波器运动估计

3 DG_DETECTOR_HME 动态GOP检测器HME部分

代码结构解析

1 获取输入对象

EB_GET_FULL_OBJECT(me_context_ptr->picture_decision_results_input_fifo_ptr, &in_results_wrapper_ptr)

输入队列picture_decision_results_input_fifo_ptr获取一个完整对象这个任务包含当前需要处理运动估计相关信息

2 获取任务类型

if (in_results_ptr->task_type == TASK_TFME)

m_context_ptr->me_ctx->me_type = ME_MCTF;

else if (in_results_ptr->task_type == TASK_PAME || in_results_ptr->task_type == TASK_SUPPERRES_RE_ME)

me_context_ptr->me_ctx->me_type = ME_OPEN_LOOP;

else if (in_results_ptr->task_type == TASK_DG_DETECTOR_HME)

me_context_ptr->me_ctx->me_type = ME_DG_DETECTOR;

根据任务类型设置运动估计类型me_type

3 ME核心信号推导

if (in_results_ptr->task_type == TASK_PAME) ||

(in_results_ptr->task_type == TASK_SUPPERRES_RE_ME)

svt_aom_sig_deriv_me(scs, pcs, me_context_ptr->me_ctx);

else if (in_result_ctx->task_type == TASK_TFME)

svt_aom_sig_deriv_me_tf(pcs, me_context_ptr->me_ctx);

4 处理PAME或者SUPERRES_RE_ME任务

if (in_results_ptr->task_type == TASK_PAME)

if (in_results_ptr->task_type == TASK_SUPPERRES_RE_ME)

这部分代码主要处理PAMESUPPERRES_RE_ME任务包括以下步骤

1 获取图片缓冲区指针

EbPictureBufferDesc *sixteenth_picture_ptr;

EbPictureBufferDesc *quarter_picture_ptr;

EbPictureBufferDesc *input_padded_pic;

EbPictureBufferDesc *input_pic;

这些指针分别指向1/16下采样1/4采样输入填充图片原始输入图片缓冲区

2 获取索引图片尺寸

uint32_t segment_index = in_results_ptr->segment_index;

uint32_t pic_width_in_b64 = (pcs->aligned_width + scs->b64_size - 1) / scs->b64_size;

uint32_t picture_height_in_b64 = (pcs->aligned_height + scs->b64_size - 1) / scs->b64_size;

计算图片64x64尺寸下宽度高度获取当前索引

3 转换索引XY坐标

SEGMENT_CONVERT_IDX_TO_XY(segment_index, x_segment_index, y_segment_index, pcs->me_segments_column_count);

一维索引转换二维XY坐标

4 计算64x64起始结束索引

uint32_t x_b64_start_index = SEGMENT_START_IDX(x_segment_index, pic_width_in_b64, pcs->me_segments_column_count);

uint32_t x_b64_end_index = SEGMENT_END_IDX(x_segment_index, pic_width_in_b64, pcs->me_segments_column_count);

uint32_t y_b64_start_index = SEGMENT_START_IDX(y_segment_index, picture_height_in_b64, pcs->me_segments_row_count);

uint32_t y_b64_end_index = SEGMENT_END_IDX(y_segment_index, picture_height_in_b64, pcs->me_segments_row_count);

计算当前段中64x64起始结束索引

5 运动估计处理

if (!skip_me) {

if (pcs->slice_type != I_SLICE) {

// 使用缩放源参考帧(如果需要)

svt_aom_use_scaled_source_refs_if_needed(pcs, input_pic, pa_ref_obj_, &input_padded_pic, &quarter_picture_ptr, &sixteenth_picture_ptr);

// 64x64 块循环

for (uint32_t y_b64_index = y_b64_start_index; y_b64_index < y_b64_end_index; ++y_b64_index) {

for (uint32_t x_b64_index = x_b64_start_index; x_b64_index < x_b64_end_index; ++x_b64_index) {

// 获取 64x64 块的索引和起始位置

uint32_t b64_index = (uint16_t)(x_b64_index + y_b64_index * pic_width_in_b64);

uint32_t b64_origin_x = x_b64_index * scs->b64_size;

uint32_t b64_origin_y = y_b64_index * scs->b64_size;

// 加载 64x64 块数据到中间缓冲区

uint32_t buffer_index = (input_pic->org_y + b64_origin_y) * input_pic->stride_y +

input_pic->org_x + b64_origin_x;

me_context_ptr->me_ctx->b64_src_ptr = &input_padded_pic->buffer_y[buffer_index];

me_context_ptr->me_ctx->b64_src_stride = input_padded_pic->stride_y;

// 加载 1/4 和 1/16 下采样块数据

if (me_context_ptr->me_ctx->enable_hme_level1_flag) {

buffer_index = (quarter_picture_ptr->org_y + (b64_origin_y >> 1)) * quarter_picture_ptr->stride_y +

quarter_picture_ptr->org_x + (b64_origin_x >> 1);

me_context_ptr->me_ctx->quarter_b64_buffer = &quarter_picture_ptr->buffer_y[buffer_index];

me_context_ptr->me_ctx->quarter_b64_buffer_stride = quarter_picture_ptr->stride_y;

}

if (me_context_ptr->me_ctx->enable_hme_level0_flag) {

buffer_index = (sixteenth_picture_ptr->org_y + (b64_origin_y >> 2)) * sixteenth_picture_ptr->stride_y +

sixteenth_picture_ptr->org_x + (b64_origin_x >> 2);

me_context_ptr->me_ctx->sixteenth_b64_buffer = &sixteenth_picture_ptr->buffer_y[buffer_index];

me_context_ptr->me_ctx->sixteenth_b64_buffer_stride = sixteenth_picture_ptr->stride_y;

}

// 设置运动估计参数

me_context_ptr->me_ctx->me_type = ME_OPEN_LOOP;

// 设置参考帧信息

if ((in_results_ptr->task_type == TASK_PAME) || (in_results_ptr->task_type == TASK_SUPERRES_RE_ME)) {

me_context_ptr->me_ctx->num_of_list_to_search = (pcs->slice_type == P_SLICE) ? 1 : 2;

me_context_ptr->me_ctx->num_of_ref_pic_to_search[0] = pcs->ref_list0_count_try;

if (pcs->slice_type == B_SLICE)

me_context_ptr->me_ctx->num_of_ref_pic_to_search[1] = pcs->ref_list1_count_try;

me_context_ptr->me_ctx->temporal_layer_index = pcs->temporal_layer_index;

me_context_ptr->me_ctx->is_ref = pcs->is_ref;

// 处理超分辨率或帧调整

if (pcs->frame_superres_enabled || pcs->frame_resize_enabled) {

for (int i = 0; i < me_context_ptr->me_ctx->num_of_list_to_search; i++) {

for (int j = 0; j < me_context_ptr->me_ctx->num_of_ref_pic_to_search[i]; j++) {

uint8_t sr_denom_idx = svt_aom_get_denom_idx(pcs->superres_denom);

uint8_t resize_denom_idx = svt_aom_get_denom_idx(pcs->resize_denom);

EbPaReferenceObject *ref_object = (EbPaReferenceObject *)pcs->ref_pa_pic_ptr_array[i][j]->object_ptr;

me_context_ptr->me_ctx->me_ds_ref_array[i][j].picture_ptr = ref_object->downscaled_input_padded_picture_ptr[sr_denom_idx][resize_denom_idx];

me_context_ptr->me_ctx->me_ds_ref_array[i][j].quarter_picture_ptr = ref_object->downscaled_quarter_downsampled_picture_ptr[sr_denom_idx][resize_denom_idx];

me_context_ptr->me_ctx->me_ds_ref_array[i][j].sixteenth_picture_ptr = ref_object->downscaled_sixteenth_downsampled_picture_ptr[sr_denom_idx][resize_denom_idx];

me_context_ptr->me_ctx->me_ds_ref_array[i][j].picture_number = ref_object->picture_number;

}

}

} else {

for (int i = 0; i < me_context_ptr->me_ctx->num_of_list_to_search; i++) {

for (int j = 0; j < me_context_ptr->me_ctx->num_of_ref_pic_to_search[i]; j++) {

EbPaReferenceObject *ref_object = (EbPaReferenceObject *)pcs->ref_pa_pic_ptr_array[i][j]->object_ptr;

me_context_ptr->me_ctx->me_ds_ref_array[i][j].picture_ptr = ref_object->input_padded_pic;

me_context_ptr->me_ctx->me_ds_ref_array[i][j].quarter_picture_ptr = ref_object->quarter_downsampled_picture_ptr;

me_context_ptr->me_ctx->me_ds_ref_array[i][j].sixteenth_picture_ptr = ref_object->sixteenth_downsampled_picture_ptr;

me_context_ptr->me_ctx->me_ds_ref_array[i][j].picture_number = ref_object->picture_number;

}

}

}

}

// 执行运动估计

svt_aom_motion_estimation_b64(pcs, b64_index, b64_origin_x, b64_origin_y, me_context_ptr->me_ctx, input_pic);

// 处理全局运动估计

if ((in_results_ptr->task_type == TASK_PAME) || (in_results_ptr->task_type == TASK_SUPERRES_RE_ME)) {

svt_block_on_mutex(pcs->me_processed_b64_mutex);

pcs->me_processed_b64_count++;

if (pcs->me_processed_b64_count == pcs->b64_total_count) {

if (pcs->gm_ctrls.enabled && (!pcs->gm_ctrls.pp_enabled || pcs->gm_pp_detected)) {

svt_aom_global_motion_estimation(pcs, input_pic);

} else {

memset(pcs->is_global_motion, FALSE, MAX_NUM_OF_REF_PIC_LIST * REF_LIST_MAX_DEPTH);

}

}

svt_release_mutex(pcs->me_processed_b64_mutex);

}

}

}

}

// 处理开放环路内块估计

if (scs->in_loop_ois == 0 && pcs->tpl_ctrls.enable)

for (uint32_t y_b64_index = y_b64_start_index; y_b64_index < y_b64_end_index; ++y_b64_index)

for (uint32_t x_b64_index = x_b64_start_index; x_b64_index < x_b64_end_index; ++x_b64_index) {

uint32_t b64_index = (uint16_t)(x_b64_index + y_b64_index * pic_width_in_b64);

svt_aom_open_loop_intra_search_mb(pcs, b64_index, input_pic);

}

}

这部分代码主要处理 PAME 和 SUPERRES_RE_ME 任务的运动估计,包括:

  • 加载 64x64 块数据:从输入图片中加载当前 64x64 块的数据到中间缓冲区。
  • 加载下采样块数据:如果启用了 HME(Hierarchical Motion Estimation),加载 1/4 和 1/16 下采样块数据。
  • 设置参考帧信息:根据切片类型(P 或 B)设置参考帧列表和数量。
  • 执行运动估计:调用 `svt_aom_motion_estimation_b64` 函数进行运动估计。
  • 处理全局运动估计:在所有 64x64 块处理完成后,执行全局运动估计。
  • 开放环路内块估计:如果启用了开放环路内块估计,处理每个 64x64 块的内块估计。

5. 处理 TFME 任务


else if (in_results


>task_type == TASK_TFME) {

// gm pre-processing for only base B

if (pcs->gm_ctrls.pp_enabled && pcs->gm_pp_enabled && in_results_ptr->segment_index == 0)

svt_aom_gm_pre_processor(pcs, pcs->temp_filt_pcs_list);

// temporal filtering start

me_context_ptr->me_ctx->me_type = ME_MCTF;

svt_av1_init_temporal_filtering(pcs->temp_filt_pcs_list, pcs, me_context_ptr, in_results_ptr->segment_index);

// Release the Input Results

svt_release_object(in_results_wrapper_ptr);

}

这部分代码处理TAME任务主要是时间滤波器运动估计包括

全局运动处理如果启用全局运动预处理当前索引0调用svt_aom_gm_pre_processor 进行与处理

初始化时间滤波调用svt_av1_init_temporal_filtering 初始化时与滤波

6 处理DG_DETECTOR_HME任务

else if (in_results_ptr->task_type == TASK_DG_DETECTOR_HME) {

// dynamic gop detector

dg_detector_hme_level0(pcs, in_results_ptr->segment_index);

// Release the Input Results

svt_release_object(in_results_wrapper_ptr);

}

这部分代码处理DG_DETECTOR_HME任务主要是动态GOP检测器HME部分调用dg_detector_hme_level0 函数进行处理

7 发布结果

// Get Empty Results Object

svt_get_empty_object(me_context_ptr->motion_estimation_results_output_fifo_ptr,

&out_results_wrapper);

MotionEstimationResults out_results = (MotionEstimationResults )out_results_wrapper->object_ptr;

out_results->pcs_wrapper = in_results_ptr->pcs_wrapper;

out_results->segment_index = segment_index;

out_results->task_type = in_results_ptr->task_type;

// Release the Input Results

svt_release_object(in_results_wrapper_ptr);

// Post the Full Results Object

svt_post_full_object(out_results_wrapper);

获取一个结果对象填充结果数据(如 pcs_wrapper, segment_index 和task_type) 然后发布结果输出队列

总结

这个函数EBSDK汇总运动估计模块核心部分负责处理不同类型运动估计任务通过输入队列获取任务根据任务类型进行相应处理然后结果发布输出队列

主要功能

1 任务类型处理根据不同任务类型PAME,TFME,DG_DETECTOR_HME执行相应运动估计逻辑

2 运动估计内核 64x64进行运动估计包括加载数据设置参考帧信息执行运动估计算法

3 全局运动估计 在所有处理完执行全局运动估计

4 结果发布 处理结果发布输出队列后续模块使用

相关文章:

  • linux:进程的替换
  • 深入解读:2025 数字化转型管理 参考架构
  • 【算法】回溯法
  • 杭电oj(1010、1015、1241)题解
  • 【沉浸式求职学习day27】
  • 【视频生成模型】通义万相Wan2.1模型本地部署和LoRA微调
  • Python----深度学习(基于DNN的吃鸡预测)
  • 动手学深度学习11.11. 学习率调度器-笔记练习(PyTorch)
  • arcpy列表函数的应用(4)
  • MySQL的锁(InnoDB)【学习笔记】
  • win11报错 ‘wmic‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件 的解决方案
  • NestJS + Kafka 秒杀系统完整实践总结
  • 在 Ubuntu 24.04 系统上安装和管理 Nginx
  • SDRAM介绍和时序
  • 列出es查询match、term、wildcard、prefix、fuzzy、range、query_string、text、missing的区别及用法
  • 数据可视化 —— 饼图
  • 人工智能时代的网络安全威胁
  • EN18031测试,EN18031认证,EN18031报告解读
  • [Jupyter Notebook]:Jupyter Notebook 安装教程(代码编辑器)
  • C# 高级编程:Linq
  • 国家发改委答澎湃:力争6月底前下达2025年两重建设和中央预算内投资全部项目清单
  • 我的科学观|张峥:AI快速迭代,我们更需学会如何与科技共处
  • 王一博赛车故障退赛冲上热搜,工作室回应:下次再战
  • 南阳市委原书记朱是西被“双开”:搞劳民伤财的“政绩工程”
  • 俄罗斯准备在没有先决条件的情况下与乌克兰进行谈判
  • 商务部:汽车流通消费改革试点正在加快推进