int x264_macroblock_cache_init ( x264_t *h ) 这个函数主要对cache中与宏块相关的变量进行初始化,包括为它们分配对应的内存空间。在函数里,会有一些变量的赋值一开始让人摸不着头脑,经过查找资料和跟踪代码确认,现对如下变量进行解释:
int i_mb_count = h->mb.i_mb_count; //!< 一帧图像的宏块数
h->mb.i_mb_stride = h->sps->i_mb_width; //!< 以宏块为单位的每一行的跨度 h->mb.i_b8_stride = h->sps->i_mb_width * 2; //!< 以8x8块为单位的每一行的跨度 h->mb.i_b4_stride = h->sps->i_mb_width * 4; //!< 以4x4块为单位的每一行的跨度
接下来一组赋值需要画图说明:
上图代表的是fdec的内存存储方式,每个符号代表内存中的一个字节,符号“.”表示无用数据,大写字母代表当前宏块的数据,Y,U,V分别代表三个色彩分量,小写字母代表当前宏块的相邻像素点的数据。
对于fdec的初始化,有如下语句:
h->mb.pic.p_fdec[0] = h->mb.pic.fdec_buf + 2*FDEC_STRIDE; h->mb.pic.p_fdec[1] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE; h->mb.pic.p_fdec[2] = h->mb.pic.fdec_buf + 19*FDEC_STRIDE + 16;
代码中FDEC_STRIDE大小为32,该值就是上图内存一行的字节数(0~F,0~F)。
p_fdec[0]、p_fdec[1]、p_fdec[2]分别指向Y、U、V三个分量数据的首地址。
对于Y分量来说,第2行才是当前宏块的数据的首地址,因此要加上2*FDEC_STRIDE。
对于U分量来说,一个宏块所有Y分量数据存完后才开始存它的数据,由上图可以看出偏移量为(2+16+1)*FDEC_STRIDE。
对于V分量来说,每一行它都紧跟在相同行数的U分量后面,由上图可以看出偏移量为U分量的偏移量+16。
有了对fdec内存存储方式的了解后,回过头来看这么几句:
h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; h->mb.pic.p_fenc[1] = h->mb.pic.fenc_buf + 16*FENC_STRIDE; h->mb.pic.p_fenc[2] = h->mb.pic.fenc_buf + 16*FENC_STRIDE + 8;
我们知道,fenc对应的是待编码的数据,而fdec对应的是解码重建的数据,是要用来作为参考的,因此它需要保存邻点的像素值,而待编码数据是不需要保存相邻点的,所以fenc中直接存储的就是当前宏块的数据,则U、V的偏移量分别为16*FENC_STRIDE、16*FENC_STRIDE + 8。
接下来看下面这么几句:
h->mb.i_neighbour4[6] = h->mb.i_neighbour4[9] = h->mb.i_neighbour4[12] = h->mb.i_neighbour4[14] = MB_LEFT|MB_TOP|MB_TOPLEFT|MB_TOPRIGHT; h->mb.i_neighbour4[3] = h->mb.i_neighbour4[7] = h->mb.i_neighbour4[11] = h->mb.i_neighbour4[13] = h->mb.i_neighbour4[15] = h->mb.i_neighbour8[3] = MB_LEFT|MB_TOP|MB_TOPLEFT;
这里解释下i_neighbour4和i_neighbour8的含义。先看下它们的定义:
unsigned int i_neighbour8[4]; unsigned int i_neighbour4[16];
i_neightbour8把一个宏块分成4个8x8的子块,编号如下,用于记录它们邻块的可用性:
/* 0 1 2 3 */
i_neightbour4把一个宏块分成16个4x4的子块,编号如下,同样用于记录它们邻块的可用性:
/* 0 1 4 5 2 3 6 7 8 9 12 13 10 11 14 15 */
(转载请注明出处。)