x264 分像素的运动估计总结

来源:互联网 发布:网络唱歌比赛 编辑:程序博客网 时间:2024/04/30 11:05

(1) 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;

/*src1和src2都分别指向的是1/2像素块,关键是这个hpel_ref0[qpel_idx]和hpel_ref1[qpel_idx],下面将详细介绍。

注意一点就是参考帧定义了uint8_t *p_fref[2][32][4+2]; /* last: lN, lH, lV, lHV, cU, cV */

这里面的 4+2 的这个2代表色度,而这个4分别代表整像素,在整像素水平右边的1/2像素,在整像素垂直下面的1/2像素和整像素右下角的1/2像素。1/2像素的值已经在前面函数里面插值存好了,只要调用就可以了,而如果要进行1/4像素估计,要临时插值。现在这个函数 get_ref 中,src[0]、src[1]、src[2]、src[3]这传进来的就是分别是 lN, lH, lV, lHV

*/

    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 );//1/4搜索时需要临时插值函数

        return dst;

    }

    else

    {

        *i_dst_stride = i_src_stride;

        return src1;

    }

}

按照 毕厚杰 的《新一代视频压缩编码标准——H.264/AVC》关于运动矢量那一节的介绍。看图6.22

那四个像素点,G为整像素点 b、h、i分别是lH, lV, lHV,也就是水平,垂直和对角线的值。

G  b

 h   i

对应为

src[0]  src[1]

src[2]  src[3]

现在看这两个数组

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};

也按像素的平面图画出来的话

src[hpel_ref0[qpel_idx]]为

0 1 1 1

0 1 1 1

2 3 3 3

0 1 1 1

src[hpel_ref1[qpel_idx]]为

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像素值,也就是毕厚杰书中的 G、b、h、I 。这里要注意src[hpel_ref0[qpel_idx]]最后一行的 0 1 1 1 和src[hpel_ref1[qpel_idx]]最右边一列0 2 2 2不是当前的整像素0的1/2像素,而分别是其下面和右边一个整像素的对应的1/2像素值,因为 ((mvy&3) == 3) * i_src_stride 和((mvx&3) == 3)。

为什么要这么来排,是因为要根据1/4像素是通过1/2像素线性插值的公式来的,具体看下面这个函数。

(2) static inline void pixel_avg( uint8_t *dst,  int i_dst_stride,

                              uint8_t *src1, int i_src1_stride,

                              uint8_t *src2, int i_src2_stride,

                              int i_width, int i_height )

{  //1/4搜索时需要临时插值函数

    int x, y;

    for( y = 0; y < i_height; y++ )

    {

        for( x = 0; x < i_width; x++ )

        {

            dst[x] = ( src1[x] + src2[x] + 1 ) >> 1;   //利用相邻半像素和两个像素取平均插值

        }

        dst  += i_dst_stride;

        src1 += i_src1_stride;

        src2 += i_src2_stride;

    }

} 不过最后我有个疑问,那就是1/4插值后,应该原来的1/2 值保持不变的.但是分析发现,这个 b 、h、 i 这三个1/2像素中,h和i是不变的,不过 b会发生变化. 个人觉得 static const int hpel_ref1[16] = {0,0,0,0,2,2,3,2,2,2,3,2,2,2,3,2};如果改为 static const int hpel_ref1[16] = {0,0,1,0,2,2,3,2,2,2,3,2,2,2,3,2};则  b也不会发生变化. 所以这里打个问号?

原创粉丝点击