版权声明: 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( ¶m, "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( ¶m, "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( ¶m );
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码流和视频编码原理。