一 compute_subpel_params函数说明
compute_subpel_params 函数在SVT-AV1源码中扮演着关键角色,用于计算呀像素精度运动补偿所需的参数。以下是该函数的详细作用说明。
函数参数说明
SequenceControlSet scs;指向序列控制集的指针,包含视频序列的编码参数和配置信息。
int16_t pre_y,int16_t pre_x 表示预测块在参考帧中的位置坐标。
MV mv 运动矢量,表示当前块相对于参考块的位移
const struct ScaleFactors const sf;//缩放因子结构体指针,用于处理不同分辨率下的缩放
uint16_t frame_width, uint16_t frame_height 当前帧的宽度和高度。
uint8_t blk_width, uint8_t blk_height;//当前处理块的宽度和高度。
MacroBlock av1xd 指向宏块解码结构体的指针,包含宏块相关的解码信息。
constu int32_t ss_y, const uint32_t ss_x; 垂直和水平方向的子采样因子。
SubpelParams subpel_params;输出参数,用于存储计算得到的亚像素参数
int32_t pos_y, int32_t pos_x;输出参数,用于存储计算得到的呀像素位置坐标。
函数作用
1 亚像素精度运动补偿,在视频编码中,运动估计通常在整像素级别进行,但是为了获得更高的编码效率,需要进行呀像素精度的运动补偿,该函数通过计算亚像素参数,使得运动补偿能够在亚像素级别进行,从而提高编码质量。
2 计算亚像素位置 根据输入的运动矢量和块的位置,计算出亚像素级别的位置坐标。这些坐标将用于后续的运动补偿过程。
3 确定插值滤波参数 亚像素运动补偿需要使用插值滤波器来生成亚像素位置的像素值。该函数计算出插值滤波器所需的参数,如滤波器系数和偏移量。
4 处理块边界条件 考虑块边界可能超出参数帧边界的情况,函数需要处理这些边界条件,确保运动补偿的正确性。
函数流程
1 初始化参数:根据输入的运动矢量和块位置,初始化相关的计算参数
2 计算亚像素位置:根据运动矢量和块位置,计算出亚像素几倍的位置坐标
3 确定插值滤波器参数 根据亚像素位置,确定插值滤波器的系数和偏移量。
4 处理边界条件 检查块边界是否超出参考帧边界,并进行相应的处理
5 输出结果 将计算得到的亚像素参数和位置坐标存储到输出参数中。
总结 compute_subpel_params 函数在视频变啊吗中扮演着重要角色,通过计算呀像素精度的运动补偿参数,提高了编码效率和视频质量。该函数的实现涉及到运动矢量处理,插值滤波器参数计算以及边界条件处理等多方面。
二 函数注释
static void computer_subpel_params(SequenceControlSet *scs, int16_t pre_y, int16_t pre_x, Mv mv, const struct ScaleFactors *const sf, uint16_t frame_width, uint16_t frame_height, uint8_t blk_width, uint8_t blk_height, MacroBlockD *av1xd, const uint32_t ss_y, const uint32_t ss_x, SubpelParams *subpel_params, int32_t *pos_y, int32_t *pos_x)
{//检查是否需要进行缩放处理
const int32_t is_scaled = av1_is_scaled(sf);
//如果需要缩放处理
if (is_scaled) {
// 计算原始位置的y坐标,考虑运动矢量的影响
int orig_pos_y = (pre_y + 0) << SUBPEL_BITS;
orig_pos_y += mv.row * (1 << (1 - ss_y));
//计算原始位置的x坐标,考虑运动矢量的影响
int orig_pos_x = (pre_x + 0) << SUBPEL_BITS;
orig_pos_x += mv.col * (1<<(1 - ss_x));//参考缩放因子ss_x对运动矢量的影响
//使用缩放因子将原始坐标转换为缩放后的坐标(垂直方向)
*pos_y = sf->scale_value_y(orig_pos_y, sf);
//使用缩放因子将原石坐标转换为缩放后的坐标(水平方向)
*pos_x = sf->scale_value_x(orig_pos_x, sf);
//添加额外的偏移量(用于缩放过程中的误差)
*pos_x += SCALE_EXTRA_OFF;
*pos_y += SCALE_EXTRA_OFF;
//计算边界限制(用于防止内存访问越界
//border_in_pixels 是边界的像素大小,基于超块大小和额外的边距
const int border_in_pixels = scs->super_blokc_size * 2 + 32;
//计算顶部边界(考虑缩放因子 ss_y 和插值扩展)
const int top = - (((border_in_pixels >> ss_y) - INTERPOLATION_OFFSET) << SCALE_SUBPEL_BITS);
//计算左侧边界(考虑缩放因子ss_x 和插值扩展)
const int left =- ((border_in_pixels >. s_x) - INTERPOLATION_OFFSET) << SCALE_SUBPEL_BITS;
//计算地步边界(基于帧高度和插值扩展
const int bottom = ((frame_height >> s_y) + AOM_INTERP_EXTEND) << SCALE_SUBPEL_BITS;
//计算右侧边界(基于帧宽度和插值扩展)
const int right = ((frame_width >> ss_x) + AOM_INTERP_EXTEND) << SCALE_SUBPEL_BITS;
//将缩放后的坐标限制在允许范围内(垂直方向)
*pos_y = clamp(*pos_y, top, bottom);
//将缩放后的坐标限制在允许的范围内(水平方向)
*pos_x = clamp(*pos_x, left, right);
//提取呀像素偏移(水平方向)
subpel_params->subpel_x = *pos_x & SCALE_SUBPEL_MASK;
//提取亚像素偏移(垂直方向)
subpel_params->subpel_y = *pos_y & SCALE_SUBPEL_MASK;
//设置水平方向的缩放步长
subpel_params->xs = sf->x_step_q4;
//设置垂直方向的缩放步长
subpel_params->ys = sf->y_step_q4;
//将缩放后的坐标转换为整数精度(垂直方向)
*pos_y = *pos_y >> SCALE_SUBPEL_BITS;
//将缩放后的坐标转换为整数精度(水平方向)
*pos_x = *pos_x >> SCALE_SUBPEL_BITS;
)else {
//如果不需要缩放,直接裁剪运动矢量
MV mv_q4;
//裁剪运动矢量,确保其在允许范围内
mv_q4 = clamp_mv_to_umv_border_sb(av1xd, &mv, blk_width, blk_height,ss_x, ss_y);
//提取亚像素偏移(水平方向)
subpel_params->subpel_x = (m4_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS;
//设置呀像素偏移 (垂直方向)
subpel_params->subpel_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS;
//设置水平方向的补偿(默认值)
subpel_params->xs = SCALE_SUBPEL_SHIFTS;
//设置垂直方向的步长(默认值)
subpel_params->ys = SCALE_SUBPEL_SHIFT;
//计算整数精度的坐标(垂直方向)
*pos_y = pre_y = (mv_q4.row >> SUBPEL_BITS);
//计算整数精度的坐标(水平方向)
*pos_x = pre_x = (mv_q4.col >> SUBPEL_BITS);
}
}
}
1 缩放相关逻辑
当is_scaled为真时,代码计算缩放后的坐标,并确保这些坐标在允许范围内
使用scale_value_y和scale_value_x函数将原石坐标转换为缩放后的坐标
添加SCALE_EXTRA_OFF偏移量时为了补偿缩放过程中的误差
2 边界限制
clamp 函数用于确保坐标不会超出允许范围,避免内存访问越界
border_in_pixels 是边界的像素大小,基于超级快大小和额外的边距
3 非缩放逻辑
当is_scaled为false时,直接裁剪运动矢量,并提取亚像素偏移
使用默认的步长值(SCALE_SUBPEL_SHIFTS)
4 亚像素偏移
subpel_x和subpel_y存储亚像素偏移,用于后续的插值操作。