您的位置:首页 > 编程语言

JM8.6中重要结构体说明

2017-02-27 16:54 232 查看
原文地址:http://www.xuebuyuan.com/385498.html

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中的相似,可以考虑研究一下:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  代码分析