http://blog.163.com/laorenyuhai126@126/blog/static/193507792010329400744/
在void x264_macroblock_cache_load()函数里
unsigned int i_neighbour8[4];
unsigned int i_neighbour4[16];
......................................................................................
h->mb.i_neighbour4[0] =
h->mb.i_neighbour8[0] = (h->mb.i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT))
| ((h->mb.i_neighbour & MB_TOP) ? MB_TOPRIGHT : 0);
h->mb.i_neighbour4[4] =
h->mb.i_neighbour4[1] = MB_LEFT
| ((h->mb.i_neighbour & MB_TOP) ? (MB_TOP|MB_TOPLEFT|MB_TOPRIGHT) : 0);
h->mb.i_neighbour4[2] =
h->mb.i_neighbour4[8] =
h->mb.i_neighbour4[10] =
h->mb.i_neighbour8[2] = MB_TOP|MB_TOPRIGHT
| ((h->mb.i_neighbour & MB_LEFT) ? (MB_LEFT|MB_TOPLEFT) : 0);
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;
h->mb.i_neighbour4[5] =
h->mb.i_neighbour8[1] = MB_LEFT | (h->mb.i_neighbour & MB_TOPRIGHT)
| ((h->mb.i_neighbour & MB_TOP) ? MB_TOP|MB_TOPLEFT : 0);
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_neighbour8[]表示可参考的相邻块状态(这个懂,不管它),h->mb.i_neighbour4[]表示当前编码的块,那么我想h->mb.i_neighbour4[0]到h->mb.i_neighbour4[15]值应该是一样的,都表示该块有没有被编码,这里为什么不赋一样的值?
解答:这里不是表示当前编码的块,而是表示的位置信息,这个从赋值关系中可以看出来
先对照宏块里面块的编码数序看
0 1 4 5
2 3 6 7
8 9 12 13
10 11 14 15
(1)h->mb.i_neighbour4[0] =
h->mb.i_neighbour8[0] = (h->mb.i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT))
| ((h->mb.i_neighbour & MB_TOP) ? MB_TOPRIGHT : 0);
0的左、上、左上、右上参考块都不确定
(2)h->mb.i_neighbour4[4] =
h->mb.i_neighbour4[1] = MB_LEFT
| ((h->mb.i_neighbour & MB_TOP) ? (MB_TOP|MB_TOPLEFT|MB_TOPRIGHT) : 0);
4、1的左参考块确定,而上、左上、右上参考块都不确定
(3)h->mb.i_neighbour4[2] =
h->mb.i_neighbour4[8] =
h->mb.i_neighbour4[10] =
h->mb.i_neighbour8[2] = MB_TOP|MB_TOPRIGHT
| ((h->mb.i_neighbour & MB_LEFT) ? (MB_LEFT|MB_TOPLEFT) : 0);
2、8、10的上、右上参考块确定,而左、左上参考块都不确定
(4)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;
这里有点让我看不懂,7、13、15好理解,7、13、15左、上、左上参考块都确定,这里不写右上(7、13、15的右上和0的右上是不同的,宏块编码顺序和块的编码顺序也是一样的,0的右上是右上角的宏块,而7、13、15的右上是右边的宏块。右边的宏块总是在左边的宏块之后编码。如下图宏块1在宏块2之前编码,宏块3在宏块2之后编码。)
附宏块的编码顺序(和块是一样的)
0 1
2 3
3、11有点让人看不懂,3、11左、上、左上、右上参考块都确定,为什么和7、13、15放一起呢?如果看下编码顺序就不难发现了,3右上是4,而4是在3之后编码。所以3右上参考块是不确定的,也就将3和7、13、15放在一起了。(11同理)
(5)h->mb.i_neighbour4[5] =
h->mb.i_neighbour8[1] = MB_LEFT | (h->mb.i_neighbour & MB_TOPRIGHT)
| ((h->mb.i_neighbour & MB_TOP) ? MB_TOP|MB_TOPLEFT : 0);
5左参考块确定,上、左上、右上参考块都不确定
(6) 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;
6、9、12、14的左、上、左上、右上参考块都确定
9、来自264乐园的兄弟“遥远”,问我
h->mc.copy[i?PIXEL_8x8:PIXEL_16x16]( h->mb.pic.p_fenc[i], FENC_STRIDE,
&h->fenc->plane[i][ w * (i_mb_x + i_mb_y * i_stride) ], i_stride, w );
(1)w * (i_mb_x + i_mb_y * i_stride) 不明白为什么要* w( 这只考虑i=0情况,即Y情况,U、V类似)
(2)h->mc.copy这个函数定义在哪?
解答:
(1)汗一个,刚开始我也没弄懂,真是惭愧。i_stride=240是像素点Y的步长,所以这里坐标表示的是像素点Y的位置,
(i_mb_x + i_mb_y * i_stride)是每个像素点Y位置的索引,w * (i_mb_x + i_mb_y * i_stride)是每个宏块Y的索引.
(2)根据h->mc.copy找 copy定义 ,发现带5个参数,直接搜索copy,会发现好多带6个参数,那是不对的,是其他的copy函数。这时要利用i?PIXEL_8x8:PIXEL_16x16这个信息,我找到了
pf->copy[PIXEL_16x16] = mc_copy_w16;
pf->copy[PIXEL_8x8] = mc_copy_w8;
pf->copy[PIXEL_4x4] = mc_copy_w4;
再根据其中一个
pf->copy[PIXEL_16x16] = mc_copy_w16;
我找到了
#define MC_COPY( name, a ) \
static void name( uint8_t *src, int i_src, \
uint8_t *dst, int i_dst, int i_height ) \
{ \
int y; \
for( y = 0; y < i_height; y++ ) \
{ \
memcpy( dst, src, a ); \
src += i_src; \
dst += i_dst; \
} \
}
MC_COPY( mc_copy_w4, 4 )
MC_COPY( mc_copy_w8, 8 )
MC_COPY( mc_copy_w16, 16 )
应该就是这个了。
10、static uint8_t *get_ref( uint8_t *src[4], int i_src_stride,
uint8_t *dst, int * i_dst_stride,
int mvx,int mvy,
int i_width, int i_height )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
int offset = (mvy>>2)*i_src_stride + (mvx>>2);
uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;
if( qpel_idx & 5 )
{
uint8_t *src2 = src[hpel _ref1[qpel_idx]] + offset + ((mvx&3) == 3);
pixel_avg( dst, *i_dst_stride, src1, i_src_stride,
src2, i_src_stride, i_width, i_height );
return dst;
}
else
{
*i_dst_stride = i_src_stride;
return src1;
}
}
红色字体标出来的都是什么意思?
解答:1/4亮度像素内插图片
(1)、int qpel_idx = ((mvy&3)<<2) + (mvx&3);
(mvx,mvy)最后一位是1/4精度的坐标,倒数第二位是1/2精度的坐标,倒数第三位是整像素精度坐标
G a b c M x x x
d e f g x x x x
h i j k o x r x
n p q r x x x x
P x q x
x x x x
x x x x
x x x x
其中G是4*4块像素点,b、h、j是1/2内插点,其他是1/4内插点,M、P是相邻块的整像素点,o、p是相邻块1/2内差点
int qpel_idx = ((mvy&3)<<2) + (mvx&3); 这里&3是保留最后两位,<<2是乘以4,qpel_idx 表示的意思就是取出运动矢量的分像素部分
另外mvx、mvy会是负数,因为定义为int,所以都是正的表示,如 -1=11111111 11111111 11111111 11111111
-2=11111111 11111111 11111111 11111110
(2)、int offset = (mvy>>2)*i_src_stride + (mvx>>2);
i_stride=240,所以这个offset是针对每个像素点来说的,offset是偏移到所选的整像素点。
(3)、uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;
在1/4像素内插以后(mvy&3) == 3,就意味着到快要从一行到下一行了,对着上图,可以看成G那行到M那行。这时候需要乘以i_src_stride。
(4)、 qpel_idx & 5 ,5是0101, qpel_idx 在最后1位为1或者倒数第3位为1时,只有1/4内插的点才会qpel_idx & 5!=0
(5)、 static const int hpel_ref 0[ 16 ] = {0, 1,1,1,0, 1,1,1,2, 3,3,3, 0,1,1,1 };
static const int hpel_ref1[16] = {0,0,0,0,2,2,3,2,2,2,3,2,2,2,3,2};
现在画个图
mvy :
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
mvx :
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
hpel_ref0[16] :
0 1 1 1 0 1 1 1 2 3 3 3 0 1 1 1
hpel_ref1[16] :
0 0 0 0 2 2 3 2 2 2 3 2 2 2 3 2
这里 mvy、mvx是用二进制表示的,而不是十进制,竖着看
mvy mvx hpel_ref0[16] hpel_ref1[16]
00 00 没有1/2像素的偏移也没有1/4像素的偏移 0 0
00 01 x方向1/4像素的偏移,需要b和G 1 0
00 10 x方向1/2像素的偏移,需要b 1 0
00 11 x方向1/4再1/2像素偏移,需要M和b 1 0
01 00 y方向1/4像素的偏移,需要G和h 0 2
01 01 x、y方向1/4像素的偏移,需要b和h 1 2
01 10 y方向1/4像素的偏移,x方向1/2像素的偏移,需要b和j 1 3
01 11 y方向1/4像素的偏移,x方向1/4再1/2像素的偏移,需要b和o 1 2
10 00 y方向有1/2像素的偏移,需要h 2 2
10 01 y方向1/2像素的偏移,x方向1/4像素的偏移,需要j和h 3 2
10 10 y方向1/2像素的偏移,x方向1/2像素的偏移,需要j和r 3 3
10 11 y方向1/2像素偏移,x方向1/4再1/2像素偏移,需要j和o 3 2
11 00 x方向1/4再1/2像素偏移,需要P和h 0 2
11 01 y方向1/4像素偏移,x方向1/4再1/2像素偏移,需要q和h 1 2
11 10 y方向1/2像素偏移,x方向1/4再1/2像素偏移,需要q和j 1 3
11 11 y方向1/4再1/2像素偏移,x方向1/4再1/2偏移,需要q和o 1 2