美文网首页
(二)低分辨率图像生成函数x264_frame_init_low

(二)低分辨率图像生成函数x264_frame_init_low

作者: 奔向火星005 | 来源:发表于2018-08-18 14:13 被阅读0次

x264_frame_init_lowres函数中会根据原图像生成一个宽高都为原图一半的子图像,保存在frame->lowres中,首先我们看下其生成的源代码:

void x264_frame_init_lowres( x264_t *h, x264_frame_t *frame )
{
    pixel *src = frame->plane[0];
    int i_stride = frame->i_stride[0];   //等于frame->i_width[0] + 64
    int i_height = frame->i_lines[0];   //等于图像的height
    int i_width  = frame->i_width[0];   //图像的width,会被x264扩展为16的倍数

    // 1.duplicate last row and column so that their interpolation doesn't have to be special-cased
    for( int y = 0; y < i_height; y++ )   //将每行最后一个数值拷贝,放到它后面
        src[i_width+y*i_stride] = src[i_width-1+y*i_stride];
    //将最后一行数据拷贝,然后放到它后面
    memcpy( src+i_stride*i_height, src+i_stride*(i_height-1), (i_width+1) * sizeof(pixel) );
    
    //2.用4像素内插法将生成四分之一分辨率的子图像,保存在frame->lowres里
    h->mc.frame_init_lowres_core( src, frame->lowres[0], frame->lowres[1], frame->lowres[2], frame->lowres[3],
                                  i_stride, frame->i_stride_lowres, frame->i_width_lowres, frame->i_lines_lowres ); 
//3.对子图像上下左右边界进行填充
    x264_frame_expand_border_lowres( frame ); 

    memset( frame->i_cost_est, -1, sizeof(frame->i_cost_est) );

    for( int y = 0; y < h->param.i_bframe + 2; y++ )  
        for( int x = 0; x < h->param.i_bframe + 2; x++ )
            frame->i_row_satds[y][x][0] = -1;

    for( int y = 0; y <= !!h->param.i_bframe; y++ )  
        for( int x = 0; x <= h->param.i_bframe; x++ )
            frame->lowres_mvs[y][x][0][0] = 0x7FFF;
}

主要完成几件事:
1.对src(frame->plane[0])中的图像数据进行补边,代码如下:

    // duplicate last row and column so that their interpolation doesn't have to be special-cased
    for( int y = 0; y < i_height; y++ )   //将每行最后一个数值拷贝,放到它后面
        src[i_width+y*i_stride] = src[i_width-1+y*i_stride];
    //将最后一行数据拷贝,然后放到它后面
    memcpy( src+i_stride*i_height, src+i_stride*(i_height-1), (i_width+1) * sizeof(pixel) );

内存分布图如下:


copyplane内存图.png

2.调用h->mc.frame_init_lowres_core函数,用内插法生成半像素图像,保存在frame->lowres中,lowers是什么呢,我们可以看下x264_frame结构体中的形式:

typedef struct x264_frame
{
//省略
    //Orig:原点; H:水平; V:垂直 HV:对角
    pixel *lowres[4]; /* half-size copy of input frame: Orig, H, V, HV */
//省略
} x264_frame_t;

由源码可知,lowres是指向4块内存区域的指针数组,这4块内存指针分别为Orig:原点; H:水平; V:垂直 HV:对角,到底是什么意思呢,我们先看h->mc.frame_init_lowres_core函数,它实际上是frame_init_lowres_core函数,源码如下:

//半像素内插,实际上就是利用4个像素平均生成一个像素
static void frame_init_lowres_core( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc,
                                    intptr_t src_stride, intptr_t dst_stride, int width, int height )
{
    for( int y = 0; y < height; y++ )
    {
        pixel *src1 = src0+src_stride;
        pixel *src2 = src1+src_stride;
        
        for( int x = 0; x<width; x++ )
        {
            // slower than naive bilinear, but matches asm
            //以x==0为例
            //dst0[0] = ((src0[0]+src1[0])/2 + (src0[1]+src1[1])/2) / 2
            //dsth[0] = ((src0[1]+src1[1])/2 + (src0[2]+src1[2])/2) / 2
            //dstv[0] = ((src1[0]+src2[0])/2 + (src1[1]+src2[1])/2) / 2
            //dstc[0] = ((src0[1]+src2[1])/2 + (src1[2]+src2[2])/2) / 2
#define FILTER(a,b,c,d) ((((a+b+1)>>1)+((c+d+1)>>1)+1)>>1)
            dst0[x] = FILTER(src0[2*x  ], src1[2*x  ], src0[2*x+1], src1[2*x+1]);
            dsth[x] = FILTER(src0[2*x+1], src1[2*x+1], src0[2*x+2], src1[2*x+2]);
            dstv[x] = FILTER(src1[2*x  ], src2[2*x  ], src1[2*x+1], src2[2*x+1]);
            dstc[x] = FILTER(src1[2*x+1], src2[2*x+1], src1[2*x+2], src2[2*x+2]);
#undef FILTER
        }
        src0 += src_stride*2;
        dst0 += dst_stride;
        dsth += dst_stride;
        dstv += dst_stride;
        dstc += dst_stride;
    }
}

如源码,dst0,dst1,dst2,dst3对应着frame->lowres[0], frame->lowres[1], frame->lowres[2], frame->lowres[3],生成的方法如注释所言,这里再画个图辅助:


半像素内插.png

如图,每个dst等于它邻近的4个src像素平均值,看图中4个dst的位置,应该可以知道上面所说的原点,水平,垂直和对角是什么意思了吧...

3.调用 x264_frame_expand_border_lowres函数对子图像进行填充,将在下一章分析。

相关文章

网友评论

      本文标题:(二)低分辨率图像生成函数x264_frame_init_low

      本文链接:https://www.haomeiwen.com/subject/corfiftx.html