美文网首页
(三)x264_frame_expand_border_lowr

(三)x264_frame_expand_border_lowr

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

    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

    相关文章

      网友评论

          本文标题:(三)x264_frame_expand_border_lowr

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