使用FFMPEG作编码操作时,会涉及到将yuv数据编码成h264数据,FFmpeg的libavcodec中的libx264.c会调用x264库的源码作编码:
1.x264库编译
下载X264,地址为:http://www.videolan.org/developers/x264.html,并解压。
mkdir my_build
./configure --enable-shared --prefix=./my_build/
make -j4
make install
2.编译后可以查看
.
|-- bin
| -- x264 |-- include | |-- x264.h |
– x264_config.h
-- lib |-- libx264.so -> libx264.so.164 |-- libx264.so.164
– pkgconfig
`-- x264.pc
其中bin目录下x264为可执行文件,我们通过此可执行文件来分析x264库的相关功能
3.运行
通过-h信令,我们大致可以了解x264的主要功能和使用方法
./x264 -h
$ ./x264 -h
x264 core:164
Syntax: x264 [options] -o outfile infile
Infile can be raw (in which case resolution is required),
or YUV4MPEG (*.y4m),
or Avisynth if compiled with support (yes).
or libav* formats if compiled with lavf support (no) or ffms support (no).
Outfile type is selected by filename:
.264 -> Raw bytestream
.mkv -> Matroska
.flv -> Flash Video
.mp4 -> MP4 if compiled with GPAC or L-SMASH support (no)
Output bit depth: 8/10
Options:
-h, --help List basic options
--longhelp List more options
--fullhelp List all options
Example usage:
Constant quality mode:
x264 --crf 24 -o <output> <input>
Two-pass with a bitrate of 1000kbps:
x264 --pass 1 --bitrate 1000 -o <output> <input>
x264 --pass 2 --bitrate 1000 -o <output> <input>
Lossless:
x264 --qp 0 -o <output> <input>
Maximum PSNR at the cost of speed and visual quality:
x264 --preset placebo --tune psnr -o <output> <input>
Constant bitrate at 1000kbps with a 2 second-buffer:
x264 --vbv-bufsize 2000 --bitrate 1000 -o <output> <input>
Presets:
--profile <string> Force the limits of an H.264 profile
Overrides all settings.
- baseline, main, high, high10, high422, high444
--preset <string> Use a preset to select encoding settings [medium]
Overridden by user settings.
- ultrafast,superfast,veryfast,faster,fast
- medium,slow,slower,veryslow,placebo
--tune <string> Tune the settings for a particular type of source
or situation
Overridden by user settings.
Multiple tunings are separated by commas.
Only one psy tuning can be used at a time.
- psy tunings: film,animation,grain,
stillimage,psnr,ssim
- other tunings: fastdecode,zerolatency
Frame-type options:
-I, --keyint <integer or "infinite"> Maximum GOP size [250]
--tff Enable interlaced mode (top field first)
--bff Enable interlaced mode (bottom field first)
--pulldown <string> Use soft pulldown to change frame rate
- none, 22, 32, 64, double, triple, euro (requires cfr input)
Ratecontrol:
-B, --bitrate <integer> Set bitrate (kbit/s)
--crf <float> Quality-based VBR (-12-51) [23.0]
--vbv-maxrate <integer> Max local bitrate (kbit/s) [0]
--vbv-bufsize <integer> Set size of the VBV buffer (kbit) [0]
-p, --pass <integer> Enable multipass ratecontrol
- 1: First pass, creates stats file
- 2: Last pass, does not overwrite stats file
Input/Output:
-o, --output <string> Specify output file
--sar width:height Specify Sample Aspect Ratio
--fps <float|rational> Specify framerate
--seek <integer> First frame to encode
--frames <integer> Maximum number of frames to encode
--level <string> Specify level (as defined by Annex A)
--quiet Quiet Mode
Filtering:
--vf, --video-filter <filter0>/<filter1>/... Apply video filtering to the input file
Filter options may be specified in <filter>:<option>=<value> format.
Available filters:
crop:left,top,right,bottom
select_every:step,offset1[,...]
4.建立一个工程,用于将YUV转成H264
编写测试程序
代码结构
.
|-- Makefile
|-- in420.yuv
|-- inc
|-- obj
| `-- test.o
|-- out.h264
|-- src
| `-- test.cpp
|-- third_lib
| `-- x264
| |-- include
| | |-- x264.h
| | `-- x264_config.h
| `-- lib
| `-- libx264.so
`-- video_prj
test.cpp内容:
#include <stdio.h>
#include <stdlib.h>
#include "stdint.h"
#if defined ( __cplusplus)
extern "C"
{
#include "x264.h"
};
#else
#include "x264.h"
#endif
int main(int argc, char** argv)
{
int ret;
int y_size;
int i,j;
FILE* fp_src = fopen("./in420.yuv", "rb");
FILE* fp_dst = fopen("out.h264", "wb");
int frame_num=50;
int csp=X264_CSP_I420;
int width=640,height=360;
int iNal = 0;
x264_nal_t* pNals = NULL;
x264_t* pHandle = NULL;
x264_picture_t* pPic_in = (x264_picture_t*)malloc(sizeof(x264_picture_t));
x264_picture_t* pPic_out = (x264_picture_t*)malloc(sizeof(x264_picture_t));
x264_param_t* pParam = (x264_param_t*)malloc(sizeof(x264_param_t));
//Check
if(fp_src==NULL||fp_dst==NULL){
printf("Error open files.\n");
return -1;
}
x264_param_default(pParam);
pParam->i_width = width;
pParam->i_height = height;
pParam->i_csp=csp;
x264_param_apply_profile(pParam, x264_profile_names[5]);
pHandle = x264_encoder_open(pParam);
x264_picture_init(pPic_out);
x264_picture_alloc(pPic_in, csp, pParam->i_width, pParam->i_height);
y_size = pParam->i_width * pParam->i_height;
//detect frame number
if(frame_num==0){
fseek(fp_src,0,SEEK_END);
switch(csp){
case X264_CSP_I444:frame_num=ftell(fp_src)/(y_size*3);break;
case X264_CSP_I420:frame_num=ftell(fp_src)/(y_size*3/2);break;
default:printf("Colorspace Not Support.\n");return -1;
}
fseek(fp_src,0,SEEK_SET);
}
//Loop to Encode
for( i=0;i<frame_num;i++){
switch(csp){
case X264_CSP_I444:{
fread(pPic_in->img.plane[0],y_size,1,fp_src); //Y
fread(pPic_in->img.plane[1],y_size,1,fp_src); //U
fread(pPic_in->img.plane[2],y_size,1,fp_src); //V
break;}
case X264_CSP_I420:{
fread(pPic_in->img.plane[0],y_size,1,fp_src); //Y
fread(pPic_in->img.plane[1],y_size/4,1,fp_src); //U
fread(pPic_in->img.plane[2],y_size/4,1,fp_src); //V
break;}
default:{
printf("Colorspace Not Support.\n");
return -1;}
}
pPic_in->i_pts = i;
ret = x264_encoder_encode(pHandle, &pNals, &iNal, pPic_in, pPic_out);
if (ret< 0){
printf("Error.\n");
return -1;
}
printf("Succeed encode frame: %5d\n",i);
for ( j = 0; j < iNal; ++j){
fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
}
}
i=0;
//flush encoder
while(1){
ret = x264_encoder_encode(pHandle, &pNals, &iNal, NULL, pPic_out);
if(ret==0){
break;
}
printf("Flush 1 frame.\n");
for (j = 0; j < iNal; ++j){
fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
}
i++;
}
x264_picture_clean(pPic_in);
x264_encoder_close(pHandle);
pHandle = NULL;
free(pPic_in);
free(pPic_out);
free(pParam);
fclose(fp_src);
fclose(fp_dst);
return 0;
}