解码端去方块滤波代码详述

解码端去方块滤波代码详述

作者:张戟(E-mail:[email protected])

       这部分在标准的8.7 Deblocking filter process有详细的描述,技术白皮书中也有专门讲去方块滤波的部分,因此在资料方面应该是不成问题。去方块滤波的代码主要集中在JM8.6 DecoderloopFilter.c文件中,入口函数为DeblockPicture(),此函数在image.cexit_picture()中被调用,也就是说这个去方块滤波模块是在解码完一幅图像后被调用的。这里,我不得不说,H.264中的去方块滤波做的太好了,朋友们可以自己尝试一下,在exit_picture()中注释掉DeblockPicture(),你会发现解码的PSNR会下降那么多。另外,我这边还要提醒做误码掩盖的朋友们,不知道你们是否注意过DeblockPicture()是在误码掩盖前被调用的,也就是说此时去方块滤波对丢失块的边界并没有使用滤波,所以在误码掩盖后再进行一次去方块滤波你可能会有不一样的收获,当然,我相信你不会傻乎乎的直接在误码掩盖后直接再次调用DeblockPicture()就完事了。

       虽然这部分的代码不是很长,但我并不认为就很好理解,我下面只是把我的注释代码公布了下(本来想写详细过程的,但写了一半觉得不好,全部删除了),如果有误,请大家指正。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include <stdlib.h>

#include <string.h>

#include "global.h"

#include "image.h"

#include "mb_access.h"

#include "loopfilter.h"

 

extern const byte QP_SCALE_CR[52] ;

extern StorablePicture *dec_picture;

 

byte mixedModeEdgeFlag, fieldModeFilteringFlag;

 

/*********************************************************************************************************/

 

#define  IClip( Min, Max, Val) (((Val)<(Min))? (Min):(((Val)>(Max))? (Max):(Val)))

 

// NOTE: to change the tables below for instance when the QP doubling is changed from 6 to 8 values

//       send an e-mail to [email protected] to get a little programm that calculates them automatically

 

///////////////////////////////

//标准204页的表8-16或毕书141页的表6.23

byte ALPHA_TABLE[52]  = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,4,4,5,6,  7,8,9,10,12,13,15,17,  20,22,25,28,32,36,40,45,  50,56,63,71,80,90,101,113,  127,144,162,182,203,226,255,255} ;

byte  BETA_TABLE[52]  = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,2,2,3,  3,3,3, 4, 4, 4, 6, 6,   7, 7, 8, 8, 9, 9,10,10,  11,11,12,12,13,13, 14, 14,   15, 15, 16, 16, 17, 17, 18, 18} ;

///////////////////////////////

 

//这边对应标准206页的表8-17或毕书144页的表6.24

//但是稍微有点不同,二维数组中的52指量化参数,5Bs强度从0-4

//从表中知道,Bs=34,他们的CLIP_TAB是相同的

byte CLIP_TAB[52][5]  =

{

  { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},

  { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},

  { 0, 0, 0, 0, 0},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 1, 1, 1, 1},

  { 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 2, 3, 3},

  { 0, 1, 2, 3, 3},{ 0, 2, 2, 3, 3},{ 0, 2, 2, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 3, 3, 5, 5},{ 0, 3, 4, 6, 6},{ 0, 3, 4, 6, 6},

  { 0, 4, 5, 7, 7},{ 0, 4, 5, 8, 8},{ 0, 4, 6, 9, 9},{ 0, 5, 7,10,10},{ 0, 6, 8,11,11},{ 0, 6, 8,13,13},{ 0, 7,10,14,14},{ 0, 8,11,16,16},

  { 0, 9,12,18,18},{ 0,10,13,20,20},{ 0,11,15,23,23},{ 0,13,17,25,25}

} ;

 

void GetStrength(byte Strength[16],struct img_par *img,int MbQAddr,int dir,int edge, int mvlimit,StorablePicture *p);

void EdgeLoop(byte** Img, byte Strength[16],struct img_par *img, int MbQAddr, int AlphaC0Offset, int BetaOffset, int dir, int edge, int width, int yuv);

void DeblockMb(ImageParameters *img, StorablePicture *p, int MbQAddr, int flag);

void CheckNeighbors(int mb_nr);

void searchErrorMB( int *errorMB, int downMB, int rightMB );

 

/*!

 *****************************************************************************************

 * /brief

 *    Filter all macroblocks in order of increasing macroblock address.

 *****************************************************************************************

 */

//deblock会减轻block效应,但同时会导致画面模糊,不过这样看起来会舒服很多,

//在某些方面来说确实是“提高”质量吧。

void DeblockPicture(ImageParameters *img, StorablePicture *p, int flag, int *errorMB)

{

  unsigned int i;

  unsigned int currLen = 0;

  int downMB, rightMB;

 

  if( flag )

  {

         for (i=0; i<p->PicSizeInMbs; i++)//循环遍历图像内的所有宏块

         {

                DeblockMb( img, p, i, flag );

         }

  }

  else

  {

         while( errorMB[currLen] != errorMBInit )

                currLen++;

               

         i = 0;

         while( errorMB[i] != errorMBInit && i < currLen )

         {

                downMB  = errorMB[i] + p->PicWidthInMbs;

                rightMB = errorMB[i] + 1;

               

                searchErrorMB( errorMB, downMB, rightMB );

                i++;

         }

 

         i = 0;

         while( errorMB[i] != errorMBInit )

         {

                DeblockMb( img, p, errorMB[i], flag );

                i++;

         }

  }

}

 

 

/*!

 *****************************************************************************************

 * /brief

 *    Deblocking filter for one macroblock.

 *****************************************************************************************

 */

 

void DeblockMb(ImageParameters *img, StorablePicture *p, int MbQAddr, int flag)

{

  int           EdgeCondition;

  int           dir,edge;

  byte          Strength[16];

  int           mb_x, mb_y;

 

  int           filterLeftMbEdgeFlag;

  int           filterTopMbEdgeFlag;

  int           fieldModeMbFlag;

  int           mvlimit=4;

  int           i, StrengthSum;

  Macroblock    *MbQ;

  byte **imgY   = p->imgY;

  byte ***imgUV = p->imgUV;

 

  img->DeblockCall = 1;//滤波的标志位

  get_mb_pos (MbQAddr, &mb_x, &mb_y);//MbQAddr0~nOfMB的序号

  //mb_xmb_y表示当前宏块的左上顶点的整像素的横纵坐标

  filterLeftMbEdgeFlag  = (mb_x != 0);

  filterTopMbEdgeFlag   = (mb_y != 0);

  //为什么要判断filterLeftMbEdgeFlagfilterTopMbEdgeFlag

  //因为对于一幅图像的第一行和第一列是没有上宏块和左宏块的

 

  MbQ  = &(img->mb_data[MbQAddr]) ; // current Mb

 

  if (p->MbaffFrameFlag && mb_y==16 && MbQ->mb_field)

    filterTopMbEdgeFlag = 0;

 

  /*

  标准中对于变量fieldModeMbFlag的说明

  -  If any of the following conditions is true, fieldModeMbFlag is set equal to 1.

  -  field_pic_flag is equal to 1

  -  MbaffFrameFlag is equal to 1 and the macroblock CurrMbAddr is a field macroblock

  -  Otherwise, fieldModeMbFlag is set equal to 0.  

  */

  fieldModeMbFlag = (p->structure!=FRAME) || (p->MbaffFrameFlag && MbQ->mb_field);

  /*

  NOTE - A vertical difference of 4 in units of quarter luma frame samples

  is a difference of 2 in units of quarter luma field samples

  对于场,标准规定mvlimit = 2

  */

  if (fieldModeMbFlag)

    mvlimit = 2;

  //else

       //mvlimit = 4;

 

  // return, if filter is disabled

  //MbQ->LFDisableIdc指定了在块的边界是否要用滤波,同时指明哪个块的边界不用块的滤波

  if (MbQ->LFDisableIdc==1) {

    img->DeblockCall = 0;

    return;

  }

 

  /*

  LFDisableIdc没有出现在SliceHeader中,LFDisableIdc的值推断为0

  LFDisableIdc的值范围在0-2之间

 

  However, for purposes of determining which edges are to be filtered

  when disable_deblocking_filter_idc is equal to 2,

  macroblocks in different slices are considered not available

  during specified steps of the operation of the deblocking filter process.

  */

  if (MbQ->LFDisableIdc==2)

  {

    // don't filter at slice boundaries

       //标准上说的很明白,当LFDisableIdc等于2时,来自不同Slice的宏块视为不可用

       //在程序中判断一个宏块的ABCD是否可用,就是判断是否在同一个Slice

    filterLeftMbEdgeFlag = MbQ->mbAvailA;

    filterTopMbEdgeFlag  = MbQ->mbAvailB;

  }

 

  img->current_mb_nr = MbQAddr;

  CheckAvailabilityOfNeighbors();

  /*

  if( flag )

       CheckAvailabilityOfNeighbors();//检测周围A,B,C,D四个宏块的可用度

  else

       CheckNeighbors(MbQAddr);

  */

 

  for( dir=0 ; dir<2 ; dir++ ) // vertical edges, than horicontal edges

  {

    EdgeCondition = (dir && filterTopMbEdgeFlag) || (!dir && filterLeftMbEdgeFlag); // can not filter beyond picture boundaries

    for( edge=0 ; edge<4 ; edge++ ) // first 4 vertical strips of 16 pel

    {                                                                                   // then  4 horicontal

      //现在对于这个判断条件应该很清楚了

         //对于edge=1,2,3当然不用关心EdgeCondition

         //但是当edge=0时,就要考虑左宏块或上宏块是否可用

         if( edge || EdgeCondition )

      {

        GetStrength(Strength,img,MbQAddr,dir,edge, mvlimit, p); // Strength for 4 blks in 1 stripe

        StrengthSum = Strength[0];

        for (i = 1; i < 16; i++) StrengthSum += Strength[i];

        if( StrengthSum )                      // only if one of the 16 Strength bytes is != 0

        {

          EdgeLoop( imgY, Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, edge, p->size_x, 0) ;

          //!(edge & 1)表明只有当edge=0,2时成立

                //调用EdgeLoop的时候有edge/2操作,转换到01

                if( (imgUV != NULL) && !(edge & 1) )

          {

            EdgeLoop( imgUV[0], Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, edge/2, p->size_x_cr, 1 ) ;

            EdgeLoop( imgUV[1], Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, edge/2, p->size_x_cr, 1 ) ;

          }

        }

 

              //this is the extra horizontal edge between a frame macroblock pair and a field above it

        if (dir && !edge && !MbQ->mb_field && mixedModeEdgeFlag)

              {

          img->DeblockCall = 2;

          GetStrength(Strength,img,MbQAddr,dir,4, mvlimit, p); // Strength for 4 blks in 1 stripe

          if( *((int*)Strength) )                      // only if one of the 4 Strength bytes is != 0

          {

            EdgeLoop( imgY, Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, 4, p->size_x, 0) ;

            if( (imgUV != NULL) && !(edge & 1) )

            {

              EdgeLoop( imgUV[0], Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, 4, p->size_x_cr, 1 ) ;

              EdgeLoop( imgUV[1], Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, 4, p->size_x_cr, 1 ) ;

            }

          }

          img->DeblockCall = 1;

        }

      }//if( edge || EdgeCondition )

    }//for( edge=0 ; edge<4 ; edge++ )

  }//for( dir=0 ; dir<2 ; dir++ )

  img->DeblockCall = 0;

}

 

  /*!

 *********************************************************************************************

 * /brief

 *    returns a buffer of 16 Strength values for one stripe in a mb (for different Frame types)

 *********************************************************************************************

 */

 

///////////////////////////////////////////////////////////////////////////////////////

//这一块在程序并没有真正用到

int  ININT_STRENGTH[4] = {0x04040404, 0x03030303, 0x03030303, 0x03030303} ;

byte BLK_NUM[2][4][4]  = {{{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}},{{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}} ;

byte BLK_4_TO_8[16]    = {0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3} ;

#define ANY_INTRA (MbP->mb_type==I4MB||MbP->mb_type==I16MB||MbP->mb_type==IPCM||MbQ->mb_type==I4MB||MbQ->mb_type==I16MB||MbQ->mb_type==IPCM)

///////////////////////////////////////////////////////////////////////////////////////

 

//输出Bs,处理以4x4块为基本单位

//GetStrength(Strength,img,MbQAddr,dir,edge, mvlimit, p);

//dir=0表示现在处理的是垂直方向的边界,dir=1表示现在处理的是水平方向的边界

//对照标准 8.7.2 .1,为什么选用PQ来命名宏块,查看标准200页的图8-11

//Q表示当前块,P表示左方或上方的邻近块

//这边的edge就是指毕书142页图6.65中的a,b,c等边界,不过这边对应的是0,1,2

void GetStrength(byte Strength[16],struct img_par *img,int MbQAddr,int dir,int edge, int mvlimit, StorablePicture *p)

{

  int    blkP, blkQ, idx;

  int    blk_x, blk_x2, blk_y, blk_y2 ;

  int    ***list0_mv = p->mv[LIST_0];

  int    ***list1_mv = p->mv[LIST_1];

  int    **list0_refIdxArr = p->ref_idx[LIST_0];

  int    **list1_refIdxArr = p->ref_idx[LIST_1];

  int64    **list0_refPicIdArr = p->ref_pic_id[LIST_0];

  int64    **list1_refPicIdArr = p->ref_pic_id[LIST_1];

  int    xQ, xP, yQ, yP;

  int    mb_x, mb_y;

  int       condition1, condition2, condition3;

  Macroblock    *MbQ;

  Macroblock    *MbP;

  PixelPos pixP;

 

  MbQ = &(img->mb_data[MbQAddr]);//CurrentMB

 

  //去方块滤波的基本单位是4x4块,这样的理解是错误的

  //这边的idx=0~15指一个宏块的正像素范围,这样xQyQ就可以很好解释

  for( idx=0 ; idx<16 ; idx++ )

  {       

       //dir=0表示现在处理的是垂直方向的边界,dir=1表示现在处理的是水平方向的边界

       /*

       dir=0

       xQ=edge<<2,因为edge0-4范围,即这边扩展到整像素范围

       yQ=idx=0-15,就是一个宏块的垂直整像素范围

       dir=1

       xQ=dix=0-15,就是一个宏块的水平整像素范围

       yQ=edge < 4 ? edge << 2 : 1,edge>=4时,yQ=1,注意,这边是整像素单位的

       */

    xQ = dir ? idx : edge << 2;

    yQ = dir ? (edge < 4 ? edge << 2 : 1) : idx;

    getNeighbour(MbQAddr, xQ - (1 - dir), yQ - dir, 1, &pixP);//getNeighbour(int curr_mb_nr, int xN, int yN, int luma, PixelPos *pix)

    xP = pixP.x;//pixP点在当前宏块中整像素横坐标

    yP = pixP.y;//pixP点在当前宏块中整像素纵坐标

    MbP = &(img->mb_data[pixP.mb_addr]);//对于dir=0,取左边邻近块,对于dir=1,取上边邻近块

       //in different macroblock pairs 完全不合,如果没有宏块对,mb_field肯定都是0

       /*

       当然如果按照标准的定义应该这样

       if(img->MbaffFrameFlag && MbQ->mb_field != MbP->mb_field)

              mixedModeEdgeFlag = 1

       else

              mixedModeEdgeFlag = 0

       */

       //当相邻两个块来自同一个场,那么mixedModeEdgeFlag=0

       //当相邻两个块来自不同的场,那么mixedModeEdgeFlag=1

    mixedModeEdgeFlag = MbQ->mb_field != MbP->mb_field;//标准上我已经标注

 

    blkQ = ((yQ>>2)<<2) + (xQ>>2);//((yQ>>2)<<2)可能取值0,4,8,12 (xQ>>2)可能取值0,1,2,3

       //blkQ表示当前4x4块在整个宏块中的序号

    blkP = ((yP>>2)<<2) + (xP>>2);

 

       //毕书上描述有误

       //当边界两边一个或两个块为帧内预测并且边界为宏块边界,Bs=4

       //当边界两边一个或两个块为帧内预测,Bs=3

    if ((p->slice_type==SP_SLICE)||(p->slice_type==SI_SLICE) )

    {

         condition1 = (!p->MbaffFrameFlag && (p->structure==FRAME));

         condition2 = (p->MbaffFrameFlag && !MbP->mb_field && !MbQ->mb_field);

         condition3 = ((p->MbaffFrameFlag || (p->structure != FRAME)) && !dir);//dir=0垂直

         //这边的dir=0倒是标准上指定 verticalEdgeFlag is equal to 1

      Strength[idx] = (edge == 0 && (( condition1 || condition2 ) || condition3 )) ? 4 : 3;

         //edge=0时即表明是宏块边界

       }

    else

    {

      // Start with Strength=3. or Strength=4 for Mb-edge

      //edge==0对应the block edge is also a macroblock edge

      Strength[idx] = (edge == 0 && (((!p->MbaffFrameFlag && (p->structure==FRAME)) ||

        (p->MbaffFrameFlag && !MbP->mb_field && !MbQ->mb_field)) ||

        ((p->MbaffFrameFlag || (p->structure!=FRAME)) && !dir))) ? 4 : 3;

 

         //说明PQ都不是帧内编码

         //也就是说,只有当相邻块都不是帧内预测的时候,程序才有可能执行下面,即bs才会=012

      if(  !(MbP->mb_type==I4MB || MbP->mb_type==I16MB || MbP->mb_type==IPCM)

        && !(MbQ->mb_type==I4MB || MbQ->mb_type==I16MB || MbQ->mb_type==IPCM) )

      {

              //这个判断条件标准上有

              /*

              -      the luma block containing sample p0 or the luma block containing sample q0

              contains non-zero transform coefficient levels

              */

              //亮度或色度包含非零变换系数等级

              //边界两边一个图像块为残差编码

              //cbp的每个bit用来表示8x8块中是否含有变换系数

              //cbp_blk的每个比特用来表示4x4块中是否含有变换系数

        if( ((MbQ->cbp_blk &  (1 << blkQ )) != 0) || ((MbP->cbp_blk &  (1 << blkP)) != 0) )

          Strength[idx] = 2;//blkQ代表当前处理的4x4块的序号

        else

              //bs=1的大概条件

              //边界两边图像块运动矢量之差不小于1个亮度图像点的距离

              //边界两边图像块运动补偿的参考帧不同

        { // if no coefs, but vector difference >= 1 set Strength=1

          // if this is a mixed mode edge then one set of reference pictures will be frame and the

          // other will be field

          if (mixedModeEdgeFlag)

          {

            (Strength[idx] = 1);

          }

          else//mixedModeEdgeFlag=0,严格按照标准

          {

                     //注意:这边的mb_xmb_y得到的是当前宏块的以宏块为单位的坐标

            get_mb_block_pos (MbQAddr, &mb_x, &mb_y);

            blk_y  = (mb_y<<2) + (blkQ >> 2);//当前4x4块在整个图像中的坐标

            blk_x  = (mb_x<<2) + (blkQ  & 3);

            blk_y2 = pixP.pos_y >> 2;//相邻块在整个图像中的坐标

            blk_x2 = pixP.pos_x >> 2;

//            if( (img->type == B_SLICE) )

            {

              int64 ref_p0,ref_p1,ref_q0,ref_q1;     

              ref_p0 = list0_refIdxArr[blk_x][blk_y]<0 ? -1 : list0_refPicIdArr[blk_x][blk_y];

              ref_q0 = list0_refIdxArr[blk_x2][blk_y2]<0 ? -1 : list0_refPicIdArr[blk_x2][blk_y2];

              ref_p1 = list1_refIdxArr[blk_x][blk_y]<0 ? -1 : list1_refPicIdArr[blk_x][blk_y];

              ref_q1 = list1_refIdxArr[blk_x2][blk_y2]<0 ? -1 : list1_refPicIdArr[blk_x2][blk_y2];

              if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) ||

                ((ref_p0==ref_q1) && (ref_p1==ref_q0)))//为什么这么判断,注意标准202页的Note部分

              {

                Strength[idx]=0;

                // L0 and L1 reference pictures of p0 are different; q0 as well

                if (ref_p0 != ref_p1)

                {

                  // compare MV for the same reference picture

 

                              /*

                              NOTE - A vertical difference of 4 in units of quarter luma frame samples

                              is a difference of 2 in units of quarter luma field samples

 

                              这样也就明白了为什么mvlimit=24的原因

                              */

                  if (ref_p0==ref_q0) //这边为什么是4,因为相当于1个整象素点

                  {

                    Strength[idx] =  (abs( list0_mv[blk_x][blk_y][0] - list0_mv[blk_x2][blk_y2][0]) >= 4) |

                      (abs( list0_mv[blk_x][blk_y][1] - list0_mv[blk_x2][blk_y2][1]) >= mvlimit) |

                      (abs( list1_mv[blk_x][blk_y][0] - list1_mv[blk_x2][blk_y2][0]) >= 4) |

                      (abs( list1_mv[blk_x][blk_y][1] - list1_mv[blk_x2][blk_y2][1]) >= mvlimit);

                  }

                  else

                  {

                    Strength[idx] =  (abs( list0_mv[blk_x][blk_y][0] - list1_mv[blk_x2][blk_y2][0]) >= 4) |

                      (abs( list0_mv[blk_x][blk_y][1] - list1_mv[blk_x2][blk_y2][1]) >= mvlimit) |

                      (abs( list1_mv[blk_x][blk_y][0] - list0_mv[blk_x2][blk_y2][0]) >= 4) |

                      (abs( list1_mv[blk_x][blk_y][1] - list0_mv[blk_x2][blk_y2][1]) >= mvlimit);

                  }

                }

                else //if (ref_p0 == ref_p1)

                { // L0 and L1 reference pictures of p0 are the same; q0 as well

 

                  Strength[idx] =  ((abs( list0_mv[blk_x][blk_y][0] - list0_mv[blk_x2][blk_y2][0]) >= 4) |

                    (abs( list0_mv[blk_x][blk_y][1] - list0_mv[blk_x2][blk_y2][1]) >= mvlimit ) |

                    (abs( list1_mv[blk_x][blk_y][0] - list1_mv[blk_x2][blk_y2][0]) >= 4) |

                    (abs( list1_mv[blk_x][blk_y][1] - list1_mv[blk_x2][blk_y2][1]) >= mvlimit))

                    &&

                    ((abs( list0_mv[blk_x][blk_y][0] - list1_mv[blk_x2][blk_y2][0]) >= 4) |

                    (abs( list0_mv[blk_x][blk_y][1] - list1_mv[blk_x2][blk_y2][1]) >= mvlimit) |

                    (abs( list1_mv[blk_x][blk_y][0] - list0_mv[blk_x2][blk_y2][0]) >= 4) |

                    (abs( list1_mv[blk_x][blk_y][1] - list0_mv[blk_x2][blk_y2][1]) >= mvlimit));

                }      

              }

              else

                       //if(((ref_p0==ref_q0)&&(ref_p1==ref_q1)) || ((ref_p0==ref_q1)&&(ref_p1==ref_q0)))

              {

                Strength[idx] = 1;       

              }

            }//Empty

/*            else 

            { // P slice

              int64 ref_p0,ref_q0;     

              ref_p0 = list0_refIdxArr[blk_x][blk_y]<0 ? -1 : list0_refPicIdArr[blk_x][blk_y];

              ref_q0 = list0_refIdxArr[blk_x2][blk_y2]<0 ? -1 : list0_refPicIdArr[blk_x2][blk_y2];

              Strength[idx] =  (ref_p0 != ref_q0 ) |

                (abs( list0_mv[blk_x][blk_y][0] - list0_mv[blk_x2][blk_y2][0]) >= 4 ) |

                (abs( list0_mv[blk_x][blk_y][1] - list0_mv[blk_x2][blk_y2][1]) >= mvlimit );

            } */

          }//if (mixedModeEdgeFlag)

        }//这边是判断是否含非零系数

      }//判断PQ是否是帧内宏块

    }//if ((p->slice_type==SP_SLICE)||(p->slice_type==SI_SLICE) )

  }//for( idx=0 ; idx<16 ; idx++ )

}

 

/*

chroma_qp_index_offset指色度分量的量化参数是根据亮度分量的量化参数计算出来的

此句法元素用以指明计算时用到的参数

 

色度量化参数=亮度量化参数+chroma_qp_index_offset

*/

#define CQPOF(qp) (Clip3(0, 51, qp + active_pps->chroma_qp_index_offset))

 

/*!

 *****************************************************************************************

 * /brief

 *    Filters one edge of 16 (luma) or 8 (chroma) pel

 *****************************************************************************************

 */

//核心滤波过程

//EdgeLoop( imgUV[0], Strength, img, MbQAddr, MbQ->LFAlphaC0Offset, MbQ->LFBetaOffset, dir, edge/2, p->size_x_cr, 1 ) ;

//最后的yuv用来判断当前滤波是亮度还是色度

void EdgeLoop(byte** Img, byte Strength[16],struct img_par *img, int MbQAddr, int AlphaC0Offset, int BetaOffset,

              int dir, int edge, int width, int yuv)

{

  int      pel, ap = 0, aq = 0, Strng ;

  int      incP, incQ;

  int      C0, c0, Delta, dif, AbsDelta ;

  int      L2 = 0, L1, L0, R0, R1, R2 = 0, RL0, L3, R3 ;

  int      Alpha = 0, Beta = 0 ;

  byte*    ClipTab = NULL;  

  int      small_gap;

  int      indexA, indexB;

  int      PelNum;

  int      StrengthIdx;

  byte     *SrcPtrP, *SrcPtrQ;

  int      QP;

  int      xP, xQ, yP, yQ;

  Macroblock *MbQ, *MbP;

  PixelPos pixP, pixQ;

 

  PelNum = yuv ? 8 : 16;//亮度和色度宽

 

  //注意这边对于dir=01不同的扫描方式

  for( pel=0 ; pel<PelNum ; pel++ )

  {

    xQ = dir ? pel : edge << 2;

    yQ = dir ? (edge < 4 ? edge << 2 : 1) : pel;

       //xQyQ类似GetStrength函数中的两个变量

    getNeighbour(MbQAddr, xQ, yQ, 1-yuv, &pixQ);//冗余代码

    getNeighbour(MbQAddr, xQ - (1 - dir), yQ - dir, 1-yuv, &pixP);

       //对于dir=0,取左边邻近块,对于dir=1,取上边邻近块

    xP = pixP.x;

    yP = pixP.y;

       //所以到这边xQ,yQ,xPyP得到的值都是指当前像素点相对于本宏块内坐上点的整像素坐标

    MbQ = &(img->mb_data[MbQAddr]);

    MbP = &(img->mb_data[pixP.mb_addr]);

    fieldModeFilteringFlag = MbQ->mb_field || MbP->mb_field;

    StrengthIdx = yuv ? ((MbQ->mb_field && !MbP->mb_field) ? pel<<1 : ((pel>>1)<<2)+(pel%2)) : pel ;

       //当处理亮度的时候,yuv=0,StrengthIdx=pel=0-15

       //当处理色度的时候,yuv=1,StrengthIdx=(MbQ->mb_field && !MbP->mb_field) ? pel<<1 : ((pel>>1)<<2)+(pel%2)

       //idx=((pel>>1)<<2)+(pel%2)=(pel/2)*4+(pel%2)

       /*

       pel=0,idx=0

       pel=1,idx=1

       pel=2,idx=4

       pel=3,idx=5

       pel=4,idx=8

       pel=5,idx=9

       pel=6,idx=12

       pel=7,idx=13

       色度块边界滤波的Bs值不另外计算,而是从相应亮度块边界的Bs值复制而来

       */

 

    if (pixP.available || (MbQ->LFDisableIdc== 0))

       {

      incQ = dir ? ((fieldModeFilteringFlag && !MbQ->mb_field) ? 2 * width : width) : 1;

      incP = dir ? ((fieldModeFilteringFlag && !MbP->mb_field) ? 2 * width : width) : 1;

         /*

         如果dir=0,即处理垂直边界

         incQ=incP=1

         如果dir=1,即处理水平边界

         由于我们的情况MbQ->mb_field=MbP->mb_field=0,所以incQ=incP=width

 

      这边的width,如QCIF,对于亮度就是176,对于色度就是88

         */

 

         //pos_xpos_y表示所求点在整幅图像中的整像素横纵坐标

      SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]);//QP的象素值

      SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]);

 

      // Average QP of the two blocks

         //这边的QP用的是相邻两块的平均值,且在标准203页的公式8-461已经指出

      QP  = yuv ? (QP_SCALE_CR[CQPOF(MbP->qp)] + QP_SCALE_CR[CQPOF(MbQ->qp)] + 1) >> 1 : (MbP->qp + MbQ->qp + 1) >> 1;

 

         //这边就是毕书141页上的QP+OffsetAQP+OffsetB

      indexA = IClip(0, MAX_QP, QP + AlphaC0Offset);

      indexB = IClip(0, MAX_QP, QP + BetaOffset);

   

         //AlphaBeta都是通过查表得到

      Alpha=ALPHA_TABLE[indexA];

      Beta=BETA_TABLE[indexB]; 

      ClipTab=CLIP_TAB[indexA];//限幅变量由indexA决定查表得到

 

         /*

         L0,L1,L2,L3表示P块中处理边界的同一行或同一列的4个像素点的像素值

         R0,R1,R2,R3表示Q块中处理边界的同一行或同一列的4个像素点的像素值

 

      dir=0时,排列方式

         L 3 L 2 L 1 L 0 R0 R1 R2 R3

         dir=1时,排列方式

         L3

         L2

         L1

         L0

         R0

         R1

         R2

         R3

         */

      L0  = SrcPtrP[0] ;//相当于*(SrcPtrP)

      R0  = SrcPtrQ[0] ;//相当于*(SrcPtrQ)

      L1  = SrcPtrP[-incP] ;//相当于*(SrcPtrP-incP)

      R1  = SrcPtrQ[ incQ] ;

      L2  = SrcPtrP[-incP*2] ;//相当于*(SrcPtrP-incP*2)

      R2  = SrcPtrQ[ incQ*2] ;

      L3  = SrcPtrP[-incP*3] ;//相当于*(SrcPtrP-incP*3)

      R3  = SrcPtrQ[ incQ*3] ;

         //也就是说非零强度才会被滤波

      if( (Strng = Strength[StrengthIdx]) )//只要Strng0,这边就是true

      {

        AbsDelta  = abs( Delta = R0 - L0 )  ;

     

              //这边就是毕书140页上说的,为了区别真假边界所需要满足的3个条件

        if( AbsDelta < Alpha )

        {

          C0  = ClipTab[ Strng ] ;//通过Bs确定最后限幅值

          if( ((abs( R0 - R1) - Beta )  & (abs(L0 - L1) - Beta )) < 0  )

          {

            if( !yuv)//只对亮度

                     //这边对应毕书142页的公式6.626.63,用来决定亮度点的滤波范围

                     //当两个条件都成立的时候,说明边界变化强度不大,滤波强度的设定值相对于实际

                     //滤波来说偏大

            {

              aq  = (abs( R0 - R2) - Beta ) < 0  ;

              ap  = (abs( L0 - L2) - Beta ) < 0  ;

                       //aqap都等于1

            }

         

            RL0             = L0 + R0 ;

         

                     //特殊超强滤波

            //只是简单的套公式了,但真正为什么要这么做,原理就不清楚了

                     if(Strng == 4 )    // INTRA strong filtering

            {

              if( yuv)  // Chroma 色度

              {

                SrcPtrQ[0] = ((R1 << 1) + R0 + L1 + 2) >> 2;

                SrcPtrP[0] = ((L1 << 1) + L0 + R1 + 2) >> 2;                                           

              }

              else  // Luma 亮度

              {

                            //这部分要看标准206页,毕书没有讲的很详细

                small_gap = (AbsDelta < ((Alpha >> 2) + 2));

             

                aq &= small_gap;

                ap &= small_gap;

             

                SrcPtrQ[0]   = aq ? ( L1 + ((R1 + RL0) << 1) +  R2 + 4) >> 3 : ((R1 << 1) + R0 + L1 + 2) >> 2 ;

                SrcPtrP[0]   = ap ? ( R1 + ((L1 + RL0) << 1) +  L2 + 4) >> 3 : ((L1 << 1) + L0 + R1 + 2) >> 2 ;

              

                SrcPtrQ[ incQ] =   aq  ? ( R2 + R0 + R1 + L0 + 2) >> 2 : R1;

                SrcPtrP[-incP] =   ap  ? ( L2 + L1 + L0 + R0 + 2) >> 2 : L1;

             

                SrcPtrQ[ incQ*2] = aq ? (((R3 + R2) <<1) + R2 + R1 + RL0 + 4) >> 3 : R2;

                SrcPtrP[-incP*2] = ap ? (((L3 + L2) <<1) + L2 + L1 + RL0 + 4) >> 3 : L2;

              }

            }

                     //普通滤波

            else//Strng=0,1,2,3                                                                                // normal filtering

            {

              c0               = yuv? (C0+1):(C0 + ap + aq) ;

                       //dif的公式即毕书143页的6.66

              dif              = IClip( -c0, c0, ( (Delta << 2) + (L1 - R1) + 4) >> 3 );

              SrcPtrP[0]  = IClip(0, 255, L0 + dif) ;//公式6.64

              SrcPtrQ[0]  = IClip(0, 255, R0 - dif) ;//公式6.65

           

              if( !yuv )

              {

                            //公式6.69

                if( ap )

                  SrcPtrP[-incP] += IClip( -C0,  C0, ( L2 + ((RL0 + 1) >> 1) - (L1<<1)) >> 1 ) ;

                if( aq  )

                  SrcPtrQ[ incQ] += IClip( -C0,  C0, ( R2 + ((RL0 + 1) >> 1) - (R1<<1)) >> 1 ) ;

              } ;

            } ;//if(Strng == 4 )

          } ;

        } ;//if( AbsDelta < Alpha )

      } ;//if( (Strng = Strength[StrengthIdx]) )

    } ;//if (pixP.available || (MbQ->LFDisableIdc== 0))

  }//for( pel=0 ; pel<PelNum ; pel++ )

}

 

你可能感兴趣的:(list,struct,filter,table,byte,reference)