(三)x264_frame_expand_border_lowr

2018-08-20  本文已影响0人  奔向火星005

x264_frame_expand_border_lowres( x264_frame_t *frame )函数主要是对一帧图像的低分辨率子图像进行扩展边界,源码如下:

void x264_frame_expand_border_lowres( x264_frame_t *frame )
{
    for( int i = 0; i < 4; i++ )  //分别对O, V, H, C四个区域进行补边
        plane_expand_border( frame->lowres[i], frame->i_stride_lowres, frame->i_width_lowres, frame->i_lines_lowres, PADH, PADV, 1, 1, 0 );
}

从源码可以看出,x264_frame_expand_border_lowres主要是对O, V, H, C四块区域调用plane_expand_border进行补边,plane_expand_border函数如下:

static void ALWAYS_INLINE plane_expand_border( pixel *pix, int i_stride, int i_width, int i_height, int i_padh, int i_padv, int b_pad_top, int b_pad_bottom, int b_chroma )
{
    //实际上是将上,下,左,右都填充了32个字节
#define PPIXEL(x, y) ( pix + (x) + (y)*i_stride )
    for( int y = 0; y < i_height; y++ )
    {
        /* left band */
        pixel_memset( PPIXEL(-i_padh, y), PPIXEL(0, y), i_padh>>b_chroma, sizeof(pixel)<<b_chroma );  //pixel_memset(pix-32+y*336, pix-0+y*336, 32, 1);
        /* right band */
        pixel_memset( PPIXEL(i_width, y), PPIXEL(i_width-1-b_chroma, y), i_padh>>b_chroma, sizeof(pixel)<<b_chroma ); //pixel_memset(pix+272+y*336, pix+272-1+y*336, 32, 1);
    }
    /* upper band */
    if( b_pad_top )  //b_pad_top==1
        for( int y = 0; y < i_padv; y++ )
            memcpy( PPIXEL(-i_padh, -y-1), PPIXEL(-i_padh, 0), (i_width+2*i_padh) * sizeof(pixel) );
    /* lower band */
    if( b_pad_bottom )  //b_pad_bottom==1
        for( int y = 0; y < i_padv; y++ )
            memcpy( PPIXEL(-i_padh, i_height+y), PPIXEL(-i_padh, i_height-1), (i_width+2*i_padh) * sizeof(pixel) );
#undef PPIXEL
}

调试进去可以发现i_padh,i_padv都为32,其实该函数就是对图像的上,下,左,右四个方向的边界的像素拷贝,然后复制到它外围的32字节的区域,如下图:


lowres_expand_border.png

我们还可以顺带看下pixel_memset函数,它实际上只是一个简单的内存拷贝,但是它会根据CPU的位数,尽量选择一次拷贝多少个字节,如我的手机是64位系统,它会选择一次性拷贝8个字节(即64位),这样估计是为了优化性能吧。源码如下:

static void ALWAYS_INLINE pixel_memset( pixel *dst, pixel *src, int len, int size )
{
    uint8_t *dstp = (uint8_t*)dst;
    uint32_t v1 = *src;  //第一个字节的数值
    //size == 1, len == 4
    uint32_t v2 = size == 1 ? v1 + (v1 <<  8) : M16( src );  //v2=v1 + v1 * 2^8;
    uint32_t v4 = size <= 2 ? v2 + (v2 << 16) : M32( src );  //v4=v2 + v2 * 2^16;
    int i = 0;
    len *= size;

    /* Align the input pointer if it isn't already */
    if( (intptr_t)dstp & (WORD_SIZE - 1) )
    {
        if( size <= 2 && ((intptr_t)dstp & 3) )
        {
            if( size == 1 && ((intptr_t)dstp & 1) )
                dstp[i++] = v1;
            if( (intptr_t)dstp & 2 )
            {
                M16( dstp+i ) = v2;
                i += 2;
            }
        }
        if( WORD_SIZE == 8 && (intptr_t)dstp & 4 ) 
        {
            M32( dstp+i ) = v4;  
            i += 4;
        }
    }

    /* Main copy loop */
    if( WORD_SIZE == 8 )  //WORD_SIZE是一个宏定义:sizeof(void*),我的手机是8,表示64位系统
    {
        uint64_t v8 = v4 + ((uint64_t)v4<<32);
        for( ; i < len - 7; i+=8 )
            M64( dstp+i ) = v8; 
    }
    for( ; i < len - 3; i+=4 )
        M32( dstp+i ) = v4;

    /* Finish up the last few bytes */
    if( size <= 2 )
    {
        if( i < len - 1 )
        {
            M16( dstp+i ) = v2;
            i += 2;
        }
        if( size == 1 && i != len )
            dstp[i] = v1;
    }
}

源码中的v8的内存如下图:


v8.png
上一篇 下一篇

猜你喜欢

热点阅读