X264_最简单的视频编码实现(YUV420编码H264)

版权声明: https://blog.csdn.net/u013470102/article/details/89475303

下面这个例子是X264项目中的example.c文件实现编码的实现。只是加了一些注释方便以后的理解。

#ifdef _WIN32
#include <io.h>       /* _setmode() */
#include <fcntl.h>    /* _O_BINARY */
#endif

#include <stdint.h>
#include <stdio.h>
#include <x264.h>

#define FAIL_IF_ERROR( cond, ... )\
do\
{\
    if( cond )\
    {\
        fprintf( stderr, __VA_ARGS__ );\
        goto fail;\
    }\
} while( 0 )

int main( int argc, char **argv )
{
    int width, height;
	
/********************************************************************************************
结构体x264_param_t是x264中最重要的结构体之一,主要用于初始化编码器
*********************************************************************************************/
    x264_param_t param;
/********************************************************************************************
压缩编码前的图像数据
*********************************************************************************************/
    x264_picture_t pic;
    x264_picture_t pic_out;
    x264_t *h;
    int i_frame = 0;
    int i_frame_size;
/****************************************************************************************************************
压缩编码后的图像数据
*****************************************************************************************************************/
    x264_nal_t *nal;
    int i_nal;

#ifdef _WIN32
    _setmode( _fileno( stdin ),  _O_BINARY );
    _setmode( _fileno( stdout ), _O_BINARY );
    _setmode( _fileno( stderr ), _O_BINARY );
#endif
	//参数错误检查
    FAIL_IF_ERROR( !(argc > 1), "Example usage: example 352x288 <input.yuv> output.h264\n" );
	
    FAIL_IF_ERROR( 2 != sscanf( argv[1], "%dx%d", &width, &height ), "resolution not specified or incorrect\n" );
	x264_log_internal( X264_LOG_ERROR, "width*height:%s\n",argv[1]);
    /* Get default params for preset/tuning */
    if( x264_param_default_preset( &param, "medium", NULL ) < 0 )
        goto fail;

    /* Configure non-default params */ 
    param.i_bitdepth = 8;
	// 编码比特流的CSP,仅支持i420,色彩空间设置
    param.i_csp = X264_CSP_I420;
	// 视频图像的宽
    param.i_width  = width;
	// 视频图像的高
    param.i_height = height;
	// VFR输入 1 :时间基和时间戳用于码率控制  0 :仅帧率用于码率控制
    param.b_vfr_input = 0;
	// 是否复制sps和pps放在每个关键帧的前面
    param.b_repeat_headers = 1;
	// 值为true,则NALU之前是4字节前缀码0x00000001
    param.b_annexb = 1;
	//profile也就是使用baseline还是main,还是high编码
    /* Apply profile restrictions. */
    if( x264_param_apply_profile( &param, "main" ) < 0 )
        goto fail;
	//为图像结构体X264_picture分配内存
    if( x264_picture_alloc( &pic, param.i_csp, param.i_width, param.i_height ) < 0 )
        goto fail;
#undef fail
#define fail fail2
	//打开编码器
    h = x264_encoder_open( &param );
    if( !h )
        goto fail;
#undef fail
#define fail fail3
	//亮度
    int luma_size = width * height;
    //色度,由于这里选择的是YUV420,UV是Y亮度的四分之一
    int chroma_size = luma_size / 4;
    /* Encode frames */
    for( ;; i_frame++ )
    {
        /* Read input frame */
        if( fread( pic.img.plane[0], 1, luma_size, stdin ) != luma_size )//Y
            break;
        if( fread( pic.img.plane[1], 1, chroma_size, stdin ) != chroma_size )//U
            break;
        if( fread( pic.img.plane[2], 1, chroma_size, stdin ) != chroma_size )//V
            break;
		// 一帧的显示时间戳
        pic.i_pts = i_frame;
		x264_log_internal( X264_LOG_ERROR, "pic.ip_pts:%d\n",pic.i_pts);
		//编码一帧图像
        i_frame_size = x264_encoder_encode( h, &nal, &i_nal, &pic, &pic_out );
        if( i_frame_size < 0 )
            goto fail;
        else if( i_frame_size )
        {
            if( !fwrite( nal->p_payload, i_frame_size, 1, stdout ) )
                goto fail;
        }
    }
	/*这一段是因为在编码数据时,可能会有延时,先保存着,等后面的数据先编。等后面的数据编完了,这一帧的数据最后才编*/
    /* Flush delayed frames */
    while( x264_encoder_delayed_frames( h ) )
    {
    	//编码一帧图像
        i_frame_size = x264_encoder_encode( h, &nal, &i_nal, NULL, &pic_out );
        if( i_frame_size < 0 )
            goto fail;
        else if( i_frame_size )
        {
            if( !fwrite( nal->p_payload, i_frame_size, 1, stdout ) )
                goto fail;
        }
    }
	//关闭编码器
    x264_encoder_close( h );
	//释放x264_picture_alloc()申请的资源
    x264_picture_clean( &pic );
    return 0;

#undef fail
fail3:
    x264_encoder_close( h );
fail2:
    x264_picture_clean( &pic );
fail:
    return -1;
}


在X264目录下编译

//编译
make example
//运行
./example 320x180  <test_yuv420p_320x180.yuv> out.h264

后面来细致讲解下AVC码流和视频编码原理。

猜你喜欢

转载自blog.csdn.net/u013470102/article/details/89475303