x264 - x264_macroblock_cache_load


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亮度像素内插图片


看X264代码遇到的问题(答案不一定正确)转(… - 老人与海 - 我的博客


(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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值