这个文件里面的函数都相对来说比较简单,主要就是对objectBuffer_t和ercVariables_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*8的Y块的状态
/* Array for conditions of U blocks */
int *uCondition; //++ 8*8的U块的状态
/* Array for conditions of V blocks */
int *vCondition; //++ 8*8的V块的状态
/* 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. nOfMBs和numOfSegments为什么传参的时候都用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 块的位置不是一样的吗,就是这么简单。