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
网友评论