jm86之erc

    技术2022-05-11  62

    这个文件里面的函数都相对来说比较简单,主要就是对objectBuffer_tercVariables_t两个结构体一些控制。

     

    void ercInit(int pic_sizex, int pic_sizey, int flag)

    函数被调用时ercInit(img->width, img->height, 1);

    flag=1设置是否将解码器的误码掩盖功能开启,通过ercSetErrorConcealment(erc_errorVar, flag);设置。在函数中一开始就是对erc_object_list分配了内存:

    erc_object_list = (objectBuffer_t *) calloc((pic_sizex * pic_sizey) >> 6, sizeof(objectBuffer_t));

    (pic_sizex * pic_sizey) >> 6为了方便,我们可以写成(pic_sizex/8)*( pic_sizey/8),这样我们就明白了,erc_object_list存储了一帧图像中所有8x8块的该结构体容量。

     

     

    ercVariables_t *ercOpen( void )

    这个函数相当于C++中私有性质,它只被ercInit()所调用。这个函数主要是对ercVariables_t结构体的一些初始化设置,所以我想大家更关心的是这个结构体中变量所代表的具体含义,我在这边提一下我个人的理解。

    /* Error detector & concealment instance data structure */

    typedef struct ercVariables_s

    {

      /*  Number of macroblocks (size or size/4 of the arrays) */

      int   nOfMBs;

      /* Number of segments (slices) in frame */

      int     nOfSegments;

     

      /*  Array for conditions of Y blocks */

      int     *yCondition;   //++ 8*8Y块的状态

      /*  Array for conditions of U blocks */

      int     *uCondition;   //++ 8*8U块的状态

      /*  Array for conditions of V blocks */

      int     *vCondition;   //++ 8*8V块的状态

     

      /* Array for Slice level information */

      ercSegment_t *segments;

      int     currSegment;

     

      /* Conditions of the MBs of the previous frame */

      int   *prevFrameYCondition;

     

      /* Flag telling if the current segment was found to be corrupted */

      int   currSegmentCorrupted;

      /* Counter for corrupted segments per picture */

      int   nOfCorruptedSegments;

     

      /* State variables for error detector and concealer */

      int   concealment;

     

    } ercVariables_t;

     

    nOfMBs表示一帧中宏块的数目

    nOfSegments表示一帧中slice的数目

    *yCondition

    *uCondition 都是指针数组,分别代表了一帧中所有8x8YUV块的状态标志(Status Map)

    *vCondition

    ercSegment_t *segments; 表示一个Slice的数据结构,等下介绍

    currSegment 根据命名规则来看,应该表示当前的Slice序号(不确定,但是根据exit_picture()中传递参数的情况来看猜测应该是正确的)

    prevFrameYCondition 也是指针数组,表示前一帧中Y块的状态标志

    currSegmentCorrupted 用来判断当前Slice是否被误码

    nOfCorruptedSegments 一帧图像中误码Slice的数目

    concealment 该帧图像解码后是否需要误码掩盖的设置开关

     

    /* segment data structure */

    typedef struct ercSegment_s

    {

      int      startMBPos;

      int      endMBPos;

      int      fCorrupted;

    } ercSegment_t;

     

    一个Slice的结构,从变量的命名规则我们已经可以很清楚地很明白各自所代表的含义。

    startMBPos Slice的起始宏块位置

    endMBPos Slice的结束宏块位置

    fCorrupted 状态标志,判断该Slice是否被误码了

     

     

    void ercReset( ercVariables_t *errorVar, int nOfMBs, int numOfSegments, int32 picSizeX )

    这个函数里面有些重复给变量赋值,我自己还没有搞明白。该函数被image.c里面的init_picture()所调用,在解每一帧之前重置ercVariables_t。顺便提下,dec_picture是通过alloc_storable_picture()分配相应的内存空间的。

    这边的代码相对来说还是比较简单,我主要有以下几点的疑问:

    1.  nOfMBsnumOfSegments为什么传参的时候都用img->PicSizeInMbs

    2.  for ( i = 0; i < errorVar->nOfSegments; i++ )

    for ( j = 0; j < nOfMBs; j++ )

           这两个for循环结合在一起什么意思?

     

    我自己的解释(我自己都觉得错)

    第一问:ercReset()的作用相当于初始化,所以numOfSegments这边传递可能的最大值,即一个宏块就是一个Slice

    第二问:同第一问的解释雷同,且设置一个Slice的最大范围。

              errorVar->segments[i].fCorrupted = 1;

              errorVar->segments[i].startMBPos = 0;

              errorVar->segments[i].endMBPos = nOfMBs - 1;

     

     

    void ercClose( ercVariables_t *errorVar )

    释放errorVar资源,很简单。

     

     

    void ercSetErrorConcealment( ercVariables_t *errorVar, int value )

    这个函数就是在ercInit()被调用用来设置一帧图片是否进行误码掩盖的状态标志。

     

     

    void ercStartSegment( int currMBNum, int segment, u_int32 bitPos, ercVariables_t *errorVar )

    void ercStopSegment( int currMBNum, int segment, u_int32 bitPos, ercVariables_t *errorVar )

    两个函数结构相似,可以一起介绍。

    注意:bitPos这个参数在函数体内其实并没有用到。

    ercStartSegment()

    errorVar->currSegmentCorrupted = 0;

    errorVar->segments[ segment ].fCorrupted = 0;

    errorVar->segments[ segment ].startMBPos = currMBNum;

    设定一个Slice的起始宏块位置。

    ercStopSegment()

    errorVar->segments[ segment ].endMBPos = currMBNum;

    errorVar->currSegment++;

    设定一个Slice的结束宏块位置,并使当前Slice游标加1

     

     

    void ercMarkCurrSegmentLost(int32 picSizeX, ercVariables_t *errorVar )

    void ercMarkCurrSegmentOK(int32 picSizeX, ercVariables_t *errorVar )

    current_segment = errorVar->currSegment-1;这边之所以要减1,因为在调用这个函数之前,会先调用ercStopSegment(),而正是这个函数会使errorVar->currSegment++,这个currSegment已经指向了后面的Segment。里面的一些都比较好理解。

     

     

    void ercMarkCurrMBConcealed( int currMBNum, int comp, int32 picSizeX, ercVariables_t *errorVar )

    这是在帧间误码掩盖中被调用的函数,里面的动作都很了解,这边我只对

    errorVar->uCondition[currMBNum] = ERC_BLOCK_CONCEALED;

    errorVar->vCondition[currMBNum] = ERC_BLOCK_CONCEALED;

    因为初看可能会觉得奇怪,因为 uCondition vCondition 都是存储 8x8 块的状态标志,但这边却用 currMBNum ,这是宏块的位置,不是矛盾了吗?但是仔细想一下,亮度中宏块的位置和色度中 8x8 块的位置不是一样的吗,就是这么简单。 

    最新回复(0)