转:JM8.6的解码端去方块滤波代码详述

作者:张戟(E-mail:bearriezj@gmail.com)

    这部分在标准的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 Peter.List@t-systems.com 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时,排列方式

     L3 L2 L1 L0 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++ )

}

   

参考:http://blog.csdn.net/zhangji1983/article/details/1568892

posted @ 2012-07-28 20:19  Mr.Rico  阅读(1107)  评论(0编辑  收藏  举报