HM 复现论文《An Effective CU Size Decision Method for HEVC Encoder》

论文作者、摘要、关键词

在这里插入图片描述

论文解读

这篇文章提出了两种用于帧间编码加速的算法:自适应 CU 深度区间(Adaptive CU Depth Range ACUDR)和提前终止 CU 划分(Early Terminate ET)。

1. ACUDR

传统的 CU 划分算法是通过对所有的深度进行编码并计算代价,选择其中代价最小的策略作为最优策略,因此从深度为 0 (CU大小为 64x64,HEVC 中允许的最大 CU 大小)到深度为3(CU大小为 8x8, HEVC 中允许的最小 CU 大小)的情况都需要进行编码并计算代价,计算量非常大。

该算法考虑到相邻的 CU 具有很高的相关性,因此可以通过时域上(参考帧对应位置的 CU)和空域上(周围已编码的 CU)相关的 CU 来得到一个需要进行测试的深度区间,从而不必将所有的深度都尝试一遍,可以免去一些不必要的计算。

空域上的相关 CU 为当前 CU 的左侧 (L) 、上方 (U) 和左上方 (L-U) 的 CU;时域上的相关 CU 为前一个已编码帧的同位 CU (Col)。如下图(该文献的 Fig2):
在这里插入图片描述
通过利用这些已编码的相关 CU 的最优深度来计算得到预测深度 D e p t h p r e d Depth_{pred} Depthpred 。其计算公式如下:
D e p t h p r e d = ∑ i = 0 N − 1 ω i ⋅ δ i Depth_{pred}=\sum_{i=0}^{N-1}\omega_i \cdot \delta_i Depthpred=i=0N1ωiδi
其中 N 是相关 CU 的数量,恒等于 4; δ i \delta_i δi 表示第 i 个相关 CU 的最优深度; ω i \omega_i ωi 表示权重:对于 L、Col、U 三个相关 CU,其权重取 0.3;对于 L-U, 其权重取 0.1。

之后根据 D e p t h p r e d Depth_{pred} Depthpred 的值判断深度区间:

  • 若等于0,则深度范围为 [0,0](即只对 LCU 进行测试,不划分子 CU)
  • 若大于0且小于 0.5 ,则深度范围为 [0,1]
  • 若大于0.5且小于1.5,则深度范围为 [0,2]
  • 若大于1.5且小于2.5,则深度范围为 [1,3]
  • 若大于2.5,则深度范围为 [2,3]

该算法可能会错过实际上最优的深度,但在大多数情况下是能够选择到最优的 CU 的。如下表(该文献中的 Table 3):
在这里插入图片描述

2. ET

该文献的 ET 算法中提供了三个判断条件。只要满足其中任意一个条件,都可以提前终止更深的 CU 划分。

方法1:运动一致性检测

该方法是利用空间上相关的 CU(上文提到的L, U, L-U 三个 CU)来判断当前的 CU 是否与周围 CU 属于一致性运动。如果是,则执行 ET 操作。

该算法根据运动矢量(Motion Vector MV)来判断运动一致性,需要用到与当前 CU 深度相同的周围块的运动矢量。如下示意图(蓝色线条表示 LCU 的边界,C 表示当前 CU,红色线条框起来的区域内的 MV 会被用来评估运动一致性,其中的 16x16 或 8x8 表示当前 LCU 在红色区域内的 CU 的大小):

在这里插入图片描述
在这里插入图片描述
请添加图片描述
请添加图片描述

评估运动一致性的方法如下:首先获得红色区域内的所有 4x4 块的 MV,通过下面两个公式计算 MVHx 和 MVHy。计算公式如下:

M V H x = 1 m ∑ ( i , j ) ∈ O ∣ m v x ( i , j ) − 1 m ∑ ( i , j ) ∈ O m v x i , j ∣ {MVH}_{x}=\frac{1}{m}\sum_{(i,j)\in O}|mvx_{(i,j)}-\frac{1}{m}\sum_{(i,j)\in O}mvx_{i,j}| MVHx=m1(i,j)Omvx(i,j)m1(i,j)Omvxi,j

M V H y = 1 m ∑ ( i , j ) ∈ O ∣ m v y ( i , j ) − 1 m ∑ ( i , j ) ∈ O m v y i , j ∣ {MVH}_{y}=\frac{1}{m}\sum_{(i,j)\in O}|mvy_{(i,j)}-\frac{1}{m}\sum_{(i,j)\in O}mvy_{i,j}| MVHy=m1(i,j)Omvy(i,j)m1(i,j)Omvyi,j

其中 O O O 表示红色区域内, m m m 表示块的数量, m v x mvx mvx 表示 MV 的 x 分量, m v y mvy mvy 同理。得到 M V H MVH MVH 后,若 M V H x MVH_x MVHx M V H y MVH_y MVHy 均小于 0.1,则认为这片区域具有运动一致性,执行 ET 操作。

方法2:RDCost 相似性检测

该方法是基于一个已有研究提出的。该研究认为相关 CU 的 RDCost 通常具有相似的分布。因此如果当前得到的 RDCost 小于一个与周围 CU 的RdCost 相关的阈值,则可以认为当前的划分深度有很大概率是最优的,从而执行 ET 操作。该阈值计算公式如下:

T h r = β ⋅ ∑ i = 0 N − 1 ω i ⋅ R D c o s t i Thr=\beta \cdot\sum_{i=0}^{N-1}\omega_i\cdot RDcost_i Thr=βi=0N1ωiRDcosti

其中 N 是相关 CU 的数量,恒等于 4; R D C o s t i RDCost_i RDCosti 表示第 i 个相关 CU 的RDCost 的值; ω i \omega_i ωi 表示权重:对于 L、Col、U 三个相关 CU,其权重取 0.3;对于 L-U, 其权重取 0.1; β \beta β 为一个阈值,设置为 0.5。

方法3:SKIP 模式检测

该方法比较简单:如果当前 CU 的最优模式是 SKIP 且它的父 CU 的最优模式也是 SKIP,则进行 ET 操作。

HM 编码器修改

我使用的 HM 版本是 16.22。本次复现修改了 TEncCU.cpp、TComDataCU.h、TComPic.h 中的代码。下面将分别说明对数据结构和算法逻辑的修改。

注:以下代码会出现两个自定义的宏:

  • PAPER_INTER_SHENLIQUAN:代表 ACUDR 算法
  • PAPER_INTER_SHENLIQUAN_2:代表ET算法
数据结构的修改
  1. 在 TComDataCU.h 中的 TComDataCU 类的声明中加入以下语句:
#if PAPER_INTER_SHENLIQUAN
public:
  Int uiBestDepth;    //当前 LCU 的最优深度(只有 LCU 有)
  Int iInterDepthMin; //当前 LCU 的最小搜索深度 
  Int iInterDepthMax; //当前 LCU 的最大搜索深度
  Bool bInterEarlyStopFlag; // 标志位,代表当前 LCU 是否适用 ACUDR 算法
#endif

#if PAPER_INTER_SHENLIQUAN_2
public:
  TComDataCU *parentCU; //当前 CU 的父 CU

#endif

其中的 bInterEarlyStopFlag 表示是否适用当前的算法。在执行的过程中,只有其为 true 时才会进行 ACUDR 算法,否则按照常规步骤进行。不适用的情况包括但不限于:当前帧为 I 帧、当前 LCU 的相邻 LCU 不存在等。

  1. TComPic.h 中,在 TComPic 类的声明中加入以下代码:
//public
#if PAPER_INTER_SHENLIQUAN
  UInt auiBestDepthInCtu[2048]; //用于保存 LCU 的最优深度
#endif
#if PAPER_INTER_SHENLIQUAN_2
  Double audRDCostInCtu[2048]; //用于保存 LCU 的 RDCost
#endif

由于一帧图像编码完成后,其对应的编码单元都会被释放,使得在后续的编码中无法得到 Col-CU。为了方便起见,我将后续编码会使用到的信息保存在 Pic 中,之后便可以通过参考 Pic 获得对应的信息。

这些信息以 LCU 为单位保存,偏移量设置为 2048 可以保证最高在编码 8K 的视频时不会发生溢出。

对于这些信息的更新放在 TEncSlice.cpp 文件中,在 compressSlice 函数中调用完 compressCtu 后将处理完的 CTU 信息写入 Pic 中。(注:在 HM 中,Ctu 通常指的就是 LCU)。这部分的代码如下:

#if PAPER_INTER_SHENLIQUAN
    pCtu->bInterEarlyStopFlag = false; //初始化标志
#endif
    m_pcCuEncoder->compressCtu( pCtu );//处理 CTU,源码中已有的代码
#if PAPER_INTER_SHENLIQUAN
		//将当前 LCU 最优深度写入 Pic
    pcPic->auiBestDepthInCtu[ctuRsAddr] = pCtu->uiBestDepth; 
#endif
#if PAPER_INTER_SHENLIQUAN_2
		//将当前 LCU 的 RdCost 写入 Pic
    pcPic->audRDCostInCtu[ctuRsAddr] = pCtu->getTotalCost();
#endif
算法的修改

算法部分在 TEncCu.cpp 中的 xCompress 函数中实现。这个函数是比较重要的一个函数,可以参考这篇博客中关于 xCompress 函数的讲解。

  1. 声明我们要使用到的变量,这个放在函数的最前面。代码如下:
#if (PAPER_INTER_SHENLIQUAN_2) || (PAPER_INTER_SHENLIQUAN)
  TComDataCU *pcLCU = pcPic->getCtu(rpcTempCU->getCtuRsAddr()); //当前的 LCU
  TComDataCU *aboveLCU = pcLCU->getCtuAbove(); //上方的 LCU
  TComDataCU *leftLCU  = pcLCU->getCtuLeft(); //左侧的 LCU
  TComDataCU *aboveleftLCU = pcLCU->getCtuAboveLeft(); //左上的 LCU
  TComPic * pcColPic = pcLCU->getSlice()->getRefPic(RefPicList(pcLCU->getSlice()->isInterB() ? 1-pcLCU->getSlice()->getColFromL0Flag() : 0), 
                                        pcLCU->getSlice()->getColRefIdx());
                                        //参考图片
#endif
#if PAPER_INTER_SHENLIQUAN_2
  
  Bool ETFlag = false; 
  
#endif
  1. 紧接着开始 ACUDR 算法,根据周围 LCU 的信息确定搜索深度范围。代码如下:
#if PAPER_INTER_SHENLIQUAN
  Bool bInterEarlyStopFlag = false;
  
  //如果参考图片不存在,则 ColBestDepth = -1
  Int ColBestDepth = pcColPic?pcColPic->auiBestDepthInCtu[rpcTempCU->getCtuRsAddr()]:-1;

	//判断是否适用 ACUDR
  if(rpcTempCU->getSlice()->getSliceType()!=I_SLICE && uiDepth== 0 && aboveLCU && leftLCU && aboveleftLCU && ColBestDepth != -1){
    bInterEarlyStopFlag = true;
  }

	//如果适用,则计算 Depth_pred 并更新 pcLCU 的搜索深度范围
  if(bInterEarlyStopFlag){
    pcLCU->bInterEarlyStopFlag = true;
    Double value = 0.3*double(aboveLCU->uiBestDepth)+0.3*double(leftLCU->uiBestDepth)+0.3*double(ColBestDepth)+0.1*double(aboveleftLCU->uiBestDepth);
    if(value==0){
      pcLCU->iInterDepthMax = 0;
      pcLCU->iInterDepthMin = 0;
    }
    else if(value<=0.5){
      pcLCU->iInterDepthMax = 1;
      pcLCU->iInterDepthMin = 0;
    }
    else if(value<1.5){
      pcLCU->iInterDepthMax = 2;
      pcLCU->iInterDepthMin = 0;
    }
    else if(value<2.5){
      pcLCU->iInterDepthMax = 3;
      pcLCU->iInterDepthMin = 1;
    }
    else{
      pcLCU->iInterDepthMax = 3;
      pcLCU->iInterDepthMin = 2;
    }
  }
#endif
  1. 由于 xCompressCU 先检测当前深度 CU 的最优模式,之后在进行划分检测,因此在进行检测前需要判断当前的深度是否大于等于最小搜索深度。若是,则进行检测。在进入 QP 的 for 循环前加入以下判断:
#if PAPER_INTER_SHENLIQUAN
		//判断是否满足条件
    if(!pcLCU->bInterEarlyStopFlag || uiDepth>=pcLCU->iInterDepthMin)
#endif

		//编码器原本就有的代码
    for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++){...}

一共有两个地方:一个是 !bBoundary 下面,一个是 !earlyDetectionSkipMode 下面。

如果不进行当前深度的检测,那么当前深度的最优 RDCost 就会是 MAX_DOUBLE。也就是说在后面只要进行了下一深度的检测,最后一定不会选择到当前深度的 CU,因此不用考虑其它的问题。

  1. 在当前深度的 RDCost 测试完后,在进行分割测试之前可以开展 ET 检测和 ACUDR 的最大深度检测。如果满足 ET 条件,或者是当前深度等于 LCU 的最大深度范围,都可以不进行下一步的划分。这一部分的代码如下:
//这句代码是源码中就有的,用于标识新代码的位置 
 const Bool bSubBranch = bBoundary || !( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isSkipped(0) );

#if PAPER_INTER_SHENLIQUAN
  //如果使用了 ACUDR 算法,则判断通过该算法是否已经能够提前终止划分了
  //如果是,则没有必要再进行 ET 算法了
  Bool earlyStop = false;
  if(pcLCU->bInterEarlyStopFlag && uiDepth>=pcLCU->iInterDepthMax &&!bBoundary){
    earlyStop = true;
  }
#endif

#if PAPER_INTER_SHENLIQUAN_2
  //当前 CU 不为边界 CU, 为 LCU 左上角,深度小于3,为PB帧,且邻居 LCU 存在时,使用该方法
  //uiDepth>=pcLCU->iInterDepthMin 单独解释
  if(!bBoundary && 
#if PAPER_INTER_SHENLIQUAN
  !earlyStop && uiDepth>=pcLCU->iInterDepthMin &&
#endif
  uiDepth<3 && rpcBestCU->getZorderIdxInCtu() == 0
       && pcLCU->getSlice()->getSliceType() != I_SLICE 
      && aboveLCU && leftLCU && aboveleftLCU){

    //method 1,计算运动一致性
    Int mv_count = 0;
    std::vector<TComMv> allMv;

    Int leftMinIdx = 1;
    Int leftMaxIdx = -1;
    Int aboveMinIdx = 1;
    Int aboveMaxIdx = -1;
    Int aboveleftMinIdx = 1;
    Int aboveleftMaxIdx = -1;

    //得到各相邻 CU 需要遍历的 4x4 小 CU 的范围
    if(uiDepth == 0){
      leftMinIdx = 0;
      leftMaxIdx = 255;
      aboveMinIdx = 0;
      aboveMaxIdx = 255;
      aboveleftMinIdx = 0;
      aboveleftMaxIdx = 255;
    }
    else if(uiDepth == 1){
      leftMinIdx = 64;
      leftMaxIdx = 127;
      aboveMinIdx = 128;
      aboveMaxIdx =191;
      aboveleftMinIdx = 192;
      aboveleftMaxIdx = 255;
    }
    else if(uiDepth == 2){
      leftMinIdx = 80;
      leftMaxIdx = 95;
      aboveMinIdx = 160;
      aboveMaxIdx = 175;
      aboveleftMinIdx = 240;
      aboveleftMaxIdx = 255;
    }
    else{
      //如果当前深度为 3 ,说明已经达到最大深度,不会再继续划分。因此无需处理
    }

    //LeftCU
    for(Int idx=leftMinIdx;idx<=leftMaxIdx;){
      TComMv mv = leftLCU->getCUMvField(REF_PIC_LIST_0)->getMv(idx);
      Int step = 1 << (2*(4-leftLCU->getDepth(idx)));

      mv = TComMv(step*mv.getHor(),step*mv.getVer());
      mv_count += step;
      allMv.push_back(mv);
      idx += step;
    }

    //AboveCU
    for(Int idx=aboveMinIdx;idx<=aboveMaxIdx;){
      TComMv mv = aboveLCU->getCUMvField(REF_PIC_LIST_0)->getMv(idx);
      Int step = 1 << (2*(4-aboveLCU->getDepth(idx)));

      mv = TComMv(step*mv.getHor(),step*mv.getVer());
      mv_count += step;
      allMv.push_back(mv);
      idx += step;
    }

    //AboveleftCU
    for(Int idx=aboveleftMinIdx;idx<aboveleftMaxIdx;){
      TComMv mv = aboveleftLCU->getCUMvField(REF_PIC_LIST_0)->getMv(idx);
      Int step = 1 <<(2*(4-aboveleftLCU->getDepth(idx)));

      mv = TComMv(step*mv.getHor(),step*mv.getVer());
      mv_count += step;
      allMv.push_back(mv);
      idx += step;
    }

    //CurrentCU
    Int currentMaxIdx = 1 << (2*(4-uiDepth));
    for(Int idx=0;idx<currentMaxIdx;idx++){
      TComMv mv = rpcBestCU->getCUMvField(REF_PIC_LIST_0)->getMv(idx);
      allMv.push_back(mv);
      mv_count++;
    }

    //计算运动相似度
    Int Hor_sum = 0;
    Int Ver_sum = 0;
    Double Hor_mean = 0;
    Double Ver_mean = 0;
    for(Int i=0;i<allMv.size();i++){
      Hor_sum += allMv[i].getHor();
      Ver_sum += allMv[i].getVer();
    }

    Hor_mean = (double)Hor_sum/(double)mv_count;
    Ver_mean = (double)Ver_sum/(double)mv_count;
    // std::cout<<Hor_mean<<" "<<Ver_mean<<std::endl;

    Double Hor_diff = 0.0;
    Double Ver_diff = 0.0;

    for(Int i=0;i<allMv.size();i++){
      Hor_diff += std::abs((double)allMv[i].getHor()-Hor_mean);
      Ver_diff += std::abs((double)allMv[i].getVer()-Ver_mean);
    }

    Hor_diff /= (double)mv_count;
    Ver_diff /= (double)mv_count;

    if(Hor_diff < 0.1 && Ver_diff < 0.1){
      ETFlag = true;
    }
    //end of Method1

    //method2
    if(!ETFlag){
      Double colRdCost = pcColPic->audRDCostInCtu[rpcTempCU->getCtuRsAddr()]/std::pow(4,uiDepth);
      Double aboveRdCost = aboveLCU->getTotalCost()/std::pow(4,uiDepth);
      Double leftRdCost = leftLCU->getTotalCost()/std::pow(4,uiDepth);
      Double aboveleftRdCost = aboveleftLCU->getTotalCost()/std::pow(4,uiDepth);

      Double currentCost = rpcBestCU->getTotalCost();

      if(currentCost<0.5*(0.3*colRdCost+0.3*aboveRdCost+0.3*leftRdCost+0.1*aboveleftRdCost)){
        ETFlag = true;
      }
    }
    //method3
    if(!ETFlag){
      if(uiDepth>=1){
        if(rpcBestCU->parentCU->getSkipFlag(0) && rpcBestCU->getSkipFlag(0)){
          ETFlag = true;
        }
      }
    }
    
  } 
#endif

其中,uiDepth>=pcLCU->iInterDepthMin 用来判断当前深度是否进行了检测。显然,如果当前深度没有进行检测,并且 ET 算法又跳过了更大深度的 CU,相当于当前 CU 没有进行编码,这显然是不行的。因此,如果当前深度没有检测的话,则一定需要划分,因此不进行 ET 检测。

之后利用 earlyStop 和 ETFlag 两个参数判断是否进一步划分。如果两个 flag 均为 false,则需要进一步划分。代码如下:

  if(
#if PAPER_INTER_SHENLIQUAN
    !earlyStop && 
#endif
#if PAPER_INTER_SHENLIQUAN_2
    !ETFlag &&
#endif
    bSubBranch && uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() && (!getFastDeltaQp() || uiWidth > fastDeltaQPCuMaxSize || bBoundary))
	{
			//further split
	}

之后在 TypeDef.h 中将两个宏定义为 1,编译即可。

本地实验结果

我跑了几个测试序列,QP 取 22 27 32 37 四个值,分别对源编码器、只使用 ACUDR 算法、只使用 ET 算法、两个算法同时使用四种模式进行编码性能测试,数据如下:

视频序列使用的算法QP22QP27QP32QP37
耗时(s)比特率(kbps)PSNR(dB)耗时(s)比特率(kbps)PSNR(dB)耗时(s)比特率(kbps)PSNR(dB)耗时(s)比特率(kbps)PSNR(dB)
PeoPleOnStreet(2560x1600)源编码器2135.35143969.84841.75871687.42421190.63238.84091431.21811233.84836.07481270.9836353.0433.4698
ADRD1336.96744076.28841.74891008.49821321.26438.8236848.17911400.55236.0491754.0656535.84833.4203
ET2095.3944017.12841.75671641.83821230.1638.84041366.85511236.51236.06881178.886360.67233.4642
Overall1332.2144092.99241.74951002.34321368.66438.8291839.46811396.7636.0473747.3216534.69633.416
BasketballDrive(1920x1088)源编码器908.83517665.9241.1338716.3166457.4439.7688614.8843191.1638.226551.8021751.6436.438
ADRD586.60718170.7241.1035458.726739.4839.6682400.233420.6837.9914366.3881953.3636.0415
ET812.21717753.9641.1171639.5296552.7239.7528536.8793269.0838.2201471.8131778.236.4197
Overall580.50718169.9641.1019458.7056731.4439.6676393.3293431.238.0041358.6321960.1236.0328
Tennis(1920x1088)源编码器981.2618533.40242.0856805.1464141.45940.3336702.5892115.09138.2698625.5481124.33336.1714
ADRD619.0378743.9342.0591518.1874281.25440.2459445.3342240.02638.101385.7641247.07835.8406
ET921.4068639.53942.078753.1554178.07440.3222618.572144.98638.2579528.4261142.28536.1237
Overall614.3148736.34642.0556496.914282.65640.2404427.6082235.85938.1007379.8881246.57935.8241
BasketBallDrill(832x480)源编码器251.0774683.9641.5045192.6352315.1238.4939177.2341163.5235.7253167.045622.6433.3902
ADRD168.4954739.1641.464134.508234638.428109.2291197.8835.6638106.762661.233.2916
ET218.3884714.8841.5038173.6632322.6438.4996146.4921166.1235.7314120.898621.833.3793
Overall120.6374747.1641.694896.5762344.1238.639180.7731197.8835.887372.753659.4833.5085
RaceHorses(832x480)源编码器273.3847389.8440.0083208.7063416.11236.751168.9771686.57633.8526143.467839.0431.1826
ADRD188.4547435.00840.0186138.0953433.4436.7304110.7711713.3633.838793.656865.05631.1184
ET261.17414.87240.0039196.8823424.58436.7406158.5101690.5633.8524131.139841.17631.1813
Overall187.477429.70440.0112135.9743433.36836.724109.2921709.90433.818692.549862.6831.1269
BasketBallPass(416x240)源编码器34.9371212.7242.36230.165650.9638.998426.03434335.903223.599181.2433.1319
ADRD26.9691217.3642.356223.307654.0438.978820.190348.3235.86418.787189.633.0968
ET31.4921238.9242.344526.987657.0838.990322.858349.0435.883620.245182.4433.1312
Overall26.9341217.3642.356222.946654.0438.978419.842348.3235.864218.682189.6433.0968
RaceHorses(416x240)源编码器64.7711902.26440.398552.5751008.02436.677543.179528.02433.366536.258275.1630.6126
ADRD50.7251906.00840.399440.5851008.40836.672132.409532.94433.351927.092277.89630.5414
ET64.6181904.20840.406951.81007.8836.675242.210527.73633.356635.203274.00830.5776
Overall51.2721904.32840.397440.531012.36836.677632.392532.94433.351927.092279.45630.5576
KristenAndSara(1280x720)源编码器261.0073962.83244.3981223.2521913.2842.5937205.341051.39240.3836196.786614.83237.9179
ADRD174.3864065.50444.3857156.3431995.16842.5592146.2521113.07240.3143139.347657.21637.8022
ET212.8083965.00844.3769164.4631936.99242.5794138.2241061.56840.3822117.919618.57637.9045
Overall170.9024064.06444.387149.7261997.08842.5656139.0561114.70440.3132.739653.80837.784
SlideShow(1280x720)源编码器311.021466.46451.1738293.753951.21648.0506278.993661.90445.1391260.574490.86441.942
ADRD214.7191558.6450.9355200.1681022.68847.6767191.54732.6444.4725185.674548.2441.4421
ET142.8491692.33650.8845128.3171087.48847.5639116.821748.01644.5486117.227528.43241.2836
Overall206.2161563.53650.8881194.4121025.80847.6063183.759741.4444.3177177.327547.8441.2388
FourPeople(1280x720)源编码器245.2794815.26443.798209.6522457.40841.773197.3981443.02439.3763190.529863.42436.6326
ADRD167.4134854.09643.7862147.6882501.0441.7585139.6241488.62439.3557137.554903.07236.5938
ET167.9834788.19243.7617128.9862459.18441.7627105.4061446.04839.367194.543868.51236.6275
Overall163.244860.4843.7882137.9232510.8841.7617128.4341487.85639.3524124.892903.69636.5936

与源编码器的性能比较:

视频序列使用的算法QP22QP27QP32QP37
DT(%)BDBR(%)BDPSNR(dB)DT(%)BDBR(%)BDPSNR(dB)DT(%)BDBR(%)BDPSNR(dB)DT(%)BDBR(%)BDPSNR(dB)
PeoPleOnStreet(2560x1600)源编码器
ADRD37.39%0.24%-0.009840.23%0.62%-0.017340.74%1.48%-0.025740.67%2.88%-0.0495
ET1.87%0.11%-0.0022.70%0.19%-0.00054.50%0.02%-0.0067.25%0.12%-0.0056
Overall37.61%0.28%-0.009240.60%0.84%-0.011841.35%1.45%-0.027541.20%2.86%-0.0538
BasketballDrive(1920x1088)源编码器
ADRD35.46%2.86%-0.030335.96%4.37%-0.100634.91%7.19%-0.234633.60%11.52%-0.3965
ET10.63%0.50%-0.016710.72%1.48%-0.01612.69%2.44%-0.005914.50%1.52%-0.0183
Overall36.13%2.85%-0.031935.96%4.24%-0.101236.03%7.52%-0.221935.01%11.90%-0.4052
Tennis(1920x1088)源编码器
ADRD36.91%2.47%-0.026535.64%3.38%-0.087736.62%5.91%-0.168838.33%10.92%-0.3308
ET6.10%1.24%-0.00766.46%0.88%-0.011411.96%1.41%-0.011915.53%1.60%-0.0477
Overall37.40%2.38%-0.0338.28%3.41%-0.093239.14%5.71%-0.169139.27%10.87%-0.3473
BasketBallDrill(832x480)源编码器
ADRD32.89%1.18%-0.040530.17%1.33%-0.065938.37%2.95%-0.061536.09%6.19%-0.0986
ET13.02%0.66%-0.00079.85%0.32%0.005717.35%0.22%0.006127.63%-0.13%-0.0109
Overall51.95%1.35%0.190349.87%1.25%0.145254.43%2.95%0.16256.45%5.92%0.1183
RaceHorses(832x480)源编码器
ADRD31.07%0.61%0.010333.83%0.51%-0.020634.45%1.59%-0.013934.72%3.10%-0.0642
ET4.49%0.34%-0.00445.67%0.25%-0.01046.19%0.24%-0.00028.59%0.25%-0.0013
Overall31.43%0.54%0.002934.85%0.51%-0.02735.32%1.38%-0.03435.49%2.82%-0.0557
BasketBallPass(416x240)源编码器
ADRD22.81%0.38%-0.005822.73%0.47%-0.019622.45%1.55%-0.039220.39%4.61%-0.0351
ET9.86%2.16%-0.017510.54%0.94%-0.008112.20%1.76%-0.019614.21%0.66%-0.0007
Overall22.91%0.38%-0.005823.93%0.47%-0.0223.78%1.55%-0.03920.84%4.63%-0.0351
RaceHorses(416x240)源编码器
ADRD21.69%0.20%0.000922.81%0.04%-0.005424.94%0.93%-0.014625.28%0.99%-0.0712
ET0.24%0.10%0.00841.47%-0.01%-0.00232.24%-0.05%-0.00992.91%-0.42%-0.035
Overall20.84%0.11%-0.001122.91%0.43%1E-0424.98%0.93%-0.014625.28%1.56%-0.055
KristenAndSara(1280x720)源编码器
ADRD33.19%2.59%-0.012429.97%4.28%-0.034528.78%5.87%-0.069329.19%6.89%-0.1157
ET18.47%0.05%-0.021226.33%1.24%-0.014332.69%0.97%-0.001440.08%0.61%-0.0134
Overall34.52%2.55%-0.011132.93%4.38%-0.028132.28%6.02%-0.083632.55%6.34%-0.1339
SlideShow(1280x720)源编码器
ADRD30.96%6.29%-0.238331.86%7.51%-0.373931.35%10.69%-0.666628.74%11.69%-0.4999
ET54.07%15.40%-0.289356.32%14.33%-0.486758.13%13.01%-0.590555.01%7.65%-0.6584
Overall33.70%6.62%-0.285733.82%7.84%-0.444334.13%12.02%-0.821431.95%11.61%-0.7032
FourPeople(1280x720)源编码器
ADRD31.75%0.81%-0.011829.56%1.78%-0.014529.27%3.16%-0.020627.80%4.59%-0.0388
ET31.51%-0.56%-0.036338.48%0.07%-0.010346.60%0.21%-0.009250.38%0.59%-0.0051
Overall33.45%0.94%-0.009834.21%2.18%-0.011334.94%3.11%-0.023934.45%4.66%-0.039

跟文献中的数据对比,发现大多数情况下的编码时间减少的并没有那么多。经分析可能有以下几个原因:

  1. 由于时间和电脑的算力原因,我在编码时只编了前10帧,数据具有偶然性(因为有些序列提速的幅度也比文献中的结果来得大,例如SlideShow 和 FourPeople 在只使用 ET 的时候。而且前者比特率还炸了…)
  2. 文献中使用的参考帧结构是 Hierarchical B-picture,而我使用的结构是 HM 软件手册中的结构。这两种结构在相同的 GOPSize 下 B 帧的数量不同,前者会比后者来得多,因此使用后者在性能的提升上会比前者来得少。(主要是我还不太会在 HM 中指定参考帧结构,只会用默认的,TwT)

总结

这应该算是我第一篇完整复现并且进行过大量测试的文献了,也是我这段时间的一个工作成果。虽然一开始毫无头绪,盯着源码看了半天,还写了不少 bug。但在最后得到结果的时候,还是挺开心的(O(∩_∩)O~~)。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值