2011年4月24日9:30:25
JM8.6中重要结构体说明
[global.h文件]
-
下面是一些枚举类型的定义
数据分区方式:PAR_DP_TYPE[PAR_DP_1(不使用数据分区), PAR_DP_3(使用ABC3数据分区)]
输出文件的类型:PAR_OF_TYPE[PAR_OF_ANNEXB, PAR_OF_RTP]
编码的方式: CodingType [FRAME_CODING, FIELD_CODING, ADAPTIVE_CODING]
句法元素的类型: SE_type[SE_HEADER, SE_PTYPE, SE_MBTYPE, SE_REFFRAME, SE_INTRAPREDMODE, SE_MVD ….]
比特位类型: BitCountType[BITS_HEADER,
BITS_TOTAL_MB,
BITS_MB_MODE, //++ 宏块类型、宏块模式编码比特数(writeMBHeader函数)
BITS_INTER_MB, //++ 帧间宏块的参考帧、运动向量编码比特数(writeMotionInfo2NAL函数)
BITS_CBP_MB, //++ 宏块 CBP编码比特数(writeCBPandLumaCoeff函数)
BITS_COEFF_Y_MB, //++ 宏块亮度残差编码比特数(writeCBPandLumaCoeff函数)
BITS_COEFF_UV_MB, //++ 宏块色度残差编码比特数(writeChromaCoeff函数)
BITS_DELTA_QUANT_MB, //++ 宏块量化参数增量编码比特数(writeCBPandLumaCoeff函数)
MAX_BITCOUNTER_MB
];
图像结构类型: PictureStructure[FRAME, TOP_FIELD, BOTTOM_FIELD]
片结构类型: SliceType[ P_SLICE = 0, B_SLICE, I_SLICE, SP_SLICE, SI_SLICE];
定义这些枚举类型, 主要是为了使代码更加清晰易读, 便于识别一些变量的含义
-
一些重要的结构体的定义
CABAC所要使用的结构体: EncodingEnvironment和BiContextType[state,MPS,count]
MotionInfoContexts和TextureInfoContexts
PixelPos在代码中使用的很多, 主要是保存像素相关的一些信息,
句法元素: SyntaxElement, 包含一些基本的类型和两个函数指针(*mapping)和(*writing)
宏块结构体:Macroblock, 一些和宏块相关的信息, 宏块指针struct macroblock *mb_available_up和*mb_available_left
int mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][2]; //!< indices correspond to [forw,backw][block_y][block_x][x,y]
Bitstream结构体:保存了一些与正在写的比特流相关的信息
[int byte_pos; //!< current position in bitstream;
int bits_to_go; //!< current bitcounter]
数据分区结构体: DataPartition, 其中包括Bitstream *bitstream;
片结构体:Slice,其中包括了DataPartition *partArr;
图像结构体:Picture,其中包括了slice数组Slice *slices[MAXSLICEPERPICTURE];
同时定义了三个Picture指针
对这三个指针变量, 我们可以追踪一下他们的使用情况:
其实, 我们可以发现, frame_pic和top_pic(bottom_pic)出现的位置很相似, 一个是针对帧图像,另外两个是针对场图像的, 所以我们可也只对frame_pic进行追踪即可.
frame_pic出现的过程如下:
首先在global.h文件中定义了指针变量frame_pic, 然后再lencode.c函数中对frame_pic进行了内存分配, 即frame_pic=malloc_picture(),但是我们可以看看函数malloc_picutre(),发现在这个函数中只是分配了sizeof(Picture)大小的内存, 并不含有任何数据信息.
接下来在函数encode_one_frame()函数中调用了函数frame_picture(frame_pic),此时的frame_pic是空的, 所以猜想在函数frame_picture中会对frame_pic进行填充.
在函数frame_picture中frame_pic变为frame, 所以对frame追踪:
可以发现,未对frame做任何变化就将其传入了函数code_a_picture,接着进入该函数:
在函数code_a_picture中frame变为pic, 接下来,将pic赋给了img->currentPicture,这样这两个指针指向了同一个内存区域,可以同时对内存区域进行修改了.
对pic的几个成员进行了初始化之后就将pic传入了函数encode_one_slice (SliceGroup, pic);
由于pic中此时不含有输入序列的信息, 所以可以猜想在img变量中应该包含了输入文件的信息
我们进入encode_one_slice函数:可以发现该函数中没有对pic的修改, 所以pic根本没有必要作为一个参数传进来.
但是,通过对img->currentPicture进行追踪可以发现,在函数encode_one_slice中调用了一个函数init_slice, 而在这个函数中有,然后对currPic中的slice数组进行了分配空间, 其实看init_slice之后可以发现这儿确实是对currentPicture所指向的slice数组进行了初始化.[需要追踪一下img变量的变化情况]
通过这个追踪过程, 我们可以发现img的成员变量currentPicture其实是用来指向当前正在活动的图像(frame_pic, top_pic或bottom_pic)
结构体sourceframe:主要用来保存从.yuv文件中读取出来的原始的yuv三个分量数据,分别保存在(char *yf, *uf, *vf; 中)帧和场的情况不一样
Sourceframe定义了一个指针,利用函数AllocSourceframe为srcframe分配了内存空间, 利用函数ReadoneFrame将yuv文件中的数据读入到srcframe中去,然后利用
将srcframe中的数据保存到了二维数组byte**imgY_org_frm, imgUV_org_frm, imgUV_org_frm
对几个比较相似的byte**多维数组进行分析
下面是几个看起来比较类似的数组, 现在我们要搞清它们之间的联系与区别.
观察来看, 其实主要分为三类:
第一类:
这些数组中是对应的存储的原始图像的亮度,色度, 数组所存储的数据是从srcframe变量传递过来的.这些数组区别在于帧还是场.
第二类:
由于色度与亮度是类似的,我们只分析亮度.img_org与imgY_org_frm是类似的, 也是存储的原始图像的亮度.通过查找img_org所在的位置, 我们可以从下面的截图可以发现,
在函数中有imgY_org=imgy_org_frm和imgY_org=imgy_org_top及imgY_org=imgy_org_bot的语句.
这相当于将imgY_org指针指向了imgy_org_frm或imgY_org_top等.
这样我们就可以理解了,其实imgY_org是一个用来指示当前正在处理的图像的原始亮度值,根据帧编码还是场编码的不同,可以指向imgy_org_frm(帧)或imgY_org_top(场).
看代码到现在,其实总结起来可以发现有很多这样的情况:相当于有三个比较类似的量,两个分别指向帧和场,而还有一个变量作为比较灵活的中间量,根据当前的选择,指向另外两个中的一个.从这儿开始总结一下这样的三元量(暂时这样称呼它们吧).
第三类:
这两个和上面的区别比较大,这些是重建后的亮度和色度值,
在结构体enc_top_picture(StorablePicture)中的byte ** imgY;和byte *** imgUV;存储的是重建后的亮度和色度值,在函数combine_field中将imgY和imgUV中的值分别复制到了imgY_com和imgUV_com中
结构体Decoders, 对应的全局变量指针decs
结构体SNRParameters, 对应的全局变量指针snr
结构体InputParameters,对应全局变量指针input, 个人觉得这个不是很重要,因为它主要获得配置文件中的一些参数设置
结构体ImageParameters,这是一个很重要的结构体, 它的全局变量指针img,这个非常重要,要好好分析一下:
先看看这个结构体中比较重要的成员变量吧:
(1) int m7[16][16];这个变量的命名很有意思,我觉得,因为它是m1,m2或m3,m4,而是m7,为什么是m7呢??
我们先看看这些m数组都在哪儿出现过吧?!
这些数组都与DCT变换有关
M1[16][16]一个宏块(16x16)的残差值
M0[4][4][4][4]也是一个宏块(16x16)的残差值,相比M1只是分成了16个4x4小块
在函数dct_luma_16x16中有:
在函数find_sad_16x16中有
在函数dct_luma中有:
在函数dct_chroma中有:
可以发现,在函数中出现了M1,M0,M3,M4,M5,M6, 所以为了程序的可读性比较强出现了m7,并且我们可以看到有很多
地方是m7与m5或m6之间的计算.
其实m5或m6应该是进行DCT变换时的中间变量,m7应该与M1类似,是存储的是宏块残差值
(2) int ****cofAC; //!< AC coefficients [8x8block][4x4block][level/run][scan_pos]
int ***cofDC; //!< DC coefficients [yuv][level/run][scan_pos]
这两个数组的含义很明显, 就是用来存储AC系数和DC系数,
但是还是有些东西值得我们去查找探寻的:
首先在rdopt.c文件中有两个全局变量:
这个可以与[H.264知识点释疑]中对cofAC等变量的分析结合起来看
其实这也牵扯到了函数store_macroblock_parameters和函数set_stored_macroblock_parameters的作用了,这个在之后再讨论
(3)介绍一下下面的几个指针变量:
Picture *currentPicture; //指向当前处理的图像的指针
Slice *currentSlice; //指向当前的slice
Macroblock *mb_data; //指向当前的宏块
SyntaxElement MB_SyntaxElements[MAX_SYMBOLS_PER_MB];
(4) 结构体RD_DATA:这个结构体中的很多成员变量与ImageParameters中的相似,可以考虑研究一下: