x264 环路滤波模块介绍

时间:2024-12-13 07:12:46

H264 环路滤波

H.264 环路滤波是视频编码中用于减少块效应和提高视频质量的关键技术。它主要在编码侧进行,并且解码部分也必须执行,是视频编码方案不可或缺的一部分。环路滤波包括多种情况,具体如下:

  1. 环路滤波的四种情形:在Baseline配置下,环路滤波可能包括以下四种情况 :

    • Bs = 4:宏块边界上的任一侧是帧内预测。
    • Bs = 3:宏块边界上的任一侧是帧内预测,或者块边界上存在帧内预测。
    • Bs = 2:两侧都是帧间预测,并且任一侧的宏块是编码的。
    • Bs = 1:两侧都是帧间预测,没有宏块被编码,且使用不同的参考图片,或者任一侧的MV分量不小于4。
    • Bs = 0:其他情况,不需要进行滤波。
  2. 滤波过程:滤波过程包括水平和垂直宏块滤波。每个宏块的四条边界都被等分为四部分,每部分对应一个最小块大小的边界,以此为单元进行滤波。每条边界的长度为16个像素 。

  3. 块效应的原因:块效应主要由两方面因素引起 :

    • 基于块的帧内和帧间预测残差经过整数变换和量化,量化操作的离散性导致反量化恢复变换系数时产生误差,尤其在图像边界上形成视觉上的不连续。
    • 运动补偿过程中,由于从不同帧的不同位置内插样点,即使最匹配的块也可能存在微小的不一致,导致复制块的边界数据不连续性。
  4. 环路滤波的目的:环路滤波的目的是消除由于编码过程引入的块效应,通过平滑图像边界,提高视频的平滑度和视觉质量 。

  5. 真假边界的区分:在进行环路滤波之前,需要区分真假边界。真边界是图像本身的特征,而假边界是由编码过程中的量化和运动补偿引起的。H.264 标准定义了两个变量 α 和 β 来判决边界是否需要进行环路滤波 。

  6. 滤波运算:根据边界强度 Bs 的不同,H.264 使用不同强度的滤波器。Bs = 1, 2, 3 时使用较弱的滤波器,而 Bs = 4 时可以选择强滤波器或弱滤波器,具体取决于是否存在大量细节信息 。

  7. 自适应滤波强度:滤波强度可以根据量化参数 QP 调整。QP 越大,α 和 β 的值也越大,意味着量化误差越大,块效应越明显,因此阈值也应该取较大值来增大滤波效果 。

  8. 滤波器的复杂度:在实际实现中,去块滤波器的计算复杂度非常高,可能占用解码过程中相当比例的时间 。

通过这些措施,H.264 环路滤波能够有效地减少编码后视频的块效应,改善视频质量。

x264 环路滤波

相关编码参数

  • b_deblocking_filter
  • i_deblocking_filter_alphac0
  • i_deblocking_filter_beta

编码参数设置

  1. 默认:
param->b_deblocking_filter = 1;
param->i_deblocking_filter_alphac0 = 0;
param->i_deblocking_filter_beta = 0;
  • 1
  • 2
  • 3
  1. preset= ultrafast
param->b_deblocking_filter = 0;
  • 1
  1. tune= film
param->i_deblocking_filter_alphac0 = -1;
param->i_deblocking_filter_beta = -1;
  • 1
  • 2
  1. tune=animation
param->i_deblocking_filter_alphac0 = 1;
param->i_deblocking_filter_beta = 1;
  • 1
  • 2
  1. tune = grain
param->i_deblocking_filter_alphac0 = -2;
param->i_deblocking_filter_beta = -2;
  • 1
  • 2
  1. tune = stillimage
param->i_deblocking_filter_alphac0 = -3;
param->i_deblocking_filter_beta = -3;
  • 1
  • 2
  1. tune = fastdecode
param->b_deblocking_filter = 0;
  • 1
  1. tune= touhou
param->i_deblocking_filter_alphac0 = -1;
param->i_deblocking_filter_beta = -1;
  • 1
  • 2

环路去块相关设置

  1. validate_parameters函数会将编码参数限制在合理范围内:
h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 );
h->param.i_deblocking_filter_beta    = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 );
  • 1
  • 2
  1. slice_header_init函数中会将编码参数转换到x264_slice_header_t结构体中:
    int deblock_thresh = i_qp + 2 * X264_MIN(param->i_deblocking_filter_alphac0, param->i_deblocking_filter_beta);
    /* If effective qp <= 15, deblocking would have no effect anyway */
    if( param->b_deblocking_filter && (h->mb.b_variable_qp || 15 < deblock_thresh ) )
        sh->i_disable_deblocking_filter_idc = param->b_sliced_threads ? 2 : 0;
    else
        sh->i_disable_deblocking_filter_idc = 1;
    sh->i_alpha_c0_offset = param->i_deblocking_filter_alphac0 * 2;
    sh->i_beta_offset = param->i_deblocking_filter_beta * 2;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. slice_header_write函数将相关信息写入码流头中
    if( sh->pps->b_deblocking_filter_control )
    {
        bs_write_ue( s, sh->i_disable_deblocking_filter_idc );
        if( sh->i_disable_deblocking_filter_idc != 1 )
        {
            bs_write_se( s, sh->i_alpha_c0_offset >> 1 );
            bs_write_se( s, sh->i_beta_offset >> 1 );
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. 关于b_deblocking_filter_control
    • x264_pps_init函数中赋值 1:pps->b_deblocking_filter_control = 1;【这个变量直接赋值 1,中间也没有变化,意义何在?????】
    • x264_pps_write函数中将其写入码流中:bs_write1( s, pps->b_deblocking_filter_control );

环路滤波函数关系图

在这里插入图片描述

环路滤波核心函数介绍

  1. fdec_filter_row·:在 x264 编码器中负责对一行宏块进行滤波处理。这个函数主要完成以下三个步骤:
    • 环路滤波(去块效应滤波):通过调用 x264_frame_deblock_row() 函数实现,用于平滑宏块边界,减少视觉不连续。
    • 半像素内插:通过调用 x264_frame_filter() 函数实现,用于生成半像素精度的参考帧,以提高编码效率。
    • 视频质量 SSIM 和 PSNR 的计算:PSNR 通过调用 x264_pixel_ssd_wxh() 函数实现,SSIM 的计算则是通过 x264_pixel_ssim_wxh() 函数实现 。
  2. x264_macroblock_deblock_strength·:该函数的作用是计算去块滤波器的强度。在 H.264/AVC 视频编码标准中,去块滤波器用于减少宏块之间的不连续性,即所谓的块效应。这种效应通常在编码过程中由于块的独立编码和量化引入。x264_macroblock_deblock_strength 函数通过分析宏块的特性来确定滤波器的强度参数,这些参数随后用于去块滤波过程。
  3. x264_macroblock_deblock 函数:开启 RDO 时,会在各个宏块分析中计算 rd 代价时调用。