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 ) /* qpel interpolation needed */ { 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; } }
(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 x x n p q r x x x x
L x v x x x x x x x x x x x x x 其中G是4*4块像素点,b、h、j是1/2内插点,其他是1/4内插点,M、L是相邻块的整像素点,o、v是相邻块1/2内差点。 int qpel_idx = ((mvy&3)<<2) + (mvx&3); 另外mvx、mvy会是负数,因为定义为int,所以都是正的表示,如 -1=11111111 11111111 11111111 11111111 -2=11111111 11111111 11111111 11111110 (2)int offset = (mvy>>2)*i_src_stride + (mvx>>2); offset是补偿后的宏块相对当前宏块的整数偏移量。 (3)uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride; 在1/4像素内插以后(mvy&3) == 3,就意味着到快要从一行到下一行了,这时候需要乘以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_ref0[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}; 数组元素共有四个取值:0,1,2,3。这四个值分别代表整数像素,水平1/2像素,垂直1/2像素,对角线1/2像素。
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 3 3 10 11 y方向1/2像素偏移,x方向1/4再1/2像素偏移,需要j和o 3 2 11 00 y方向1/4再1/2像素偏移,需要L和h 0 2 11 01 y方向1/4再1/2像素偏移,x方向1/4像素偏移,需要v和h 1 2 11 10 y方向1/4再1/2像素偏移,x方向1/2像素偏移,需要v和j 1 3 11 11 y方向1/4再1/2像素偏移,x方向1/4再1/2偏移,需要v和o 1 2
d e f g x x x x h i j k o x x x n p q r x x x x x x x x x x x x x x x x 一套if...else语句将代码的走向分流,判断的条件就是‘qpel_idx & 5’是否为0,即判断qpel_idx的第0位与第3位是否为1,也就是判断1/4像素在图1中的位置是否属于奇数行或奇数列。 首先来看else分支的语句。 接下来分析if部分,揭开hpel_ref0与hpel_ref1的完整面纱。 细节上需要注意的是,在计算src1与src2时,都由三部分数值加和得到。前两部分很好理解,分别是基地址与偏移。 |