本文主要讲解FFmpeg的视频编码的具体流程,API使用。最后再以一个非常简单的demo演示将一个yuv数据文件编码为H264的视频文件,也就是YUV编码为H264。
FFmpeg的编码也有2套API接口,本文主要围绕编码新接口。其实新旧接口的大体流程是差不多的,只是在最终编码的时候的接口稍微不同。旧接口可以参考雷神大大的文章:最简单的基于FFMPEG的视频编码器(YUV编码为H.264),本文demo也是基本参考雷神的demo进行修改的。
前面本人也写过一篇关于解码的流程详解:FFmpeg视频解码流程详解及demo,里面有对相关的结构体等进行了一些说明。因此本文就不再阐述结构体相关。就直接进入 正题,编码流程讲解和demo演示。
一、视频编码API调用流程图
视频编码的API调用流程图如下:
API接口简单大体讲解如下:
av_register_all():注册FFmpeg所有编解码器。
avformat_alloc_context():初始化输出码流的AVFormatContext。
avio_open():打开输出文件。
av_new_stream():创建输出码流的AVStream。
avcodec_find_encoder():查找编码器。
avcodec_open2():打开编码器。
avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。
avcodec_send_frame():编码核心接口新接口,发送一帧视频给编码器。即是AVFrame(存储YUV像素数据)。
avcodec_receive_packet():编码核心接口新接口,接收编码器编码后的一帧视频,AVPacket(存储H.264等格式的码流数据)。
av_write_frame():将编码后的视频码流写入文件。
flush_encoder():输入的像素数据读取完成后调用此函数。用于输出编码器中剩余的AVPacket。
av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。
二、编码过程API调用流程
1、注册各大组件
这一步是ffmpeg的任何程序的第一步都是需要先注册ffmpeg相关的各大组件的:
//注册各大组件
av_register_all();
2、打开yuv文件
由于yuv文件是没有格式的,是视频原始数据,因此在编码前是需要提前知道它的分辨率等的,在这个简单的demo中,为了方便,先暂时在代码中直接指明。
同时为了简单验证需要,我们只编码framenum帧,不然若yuv太大,编码太久,可以指定自己想要的多少帧来做验证即可,赋值framenum。
FILE *in_file = fopen(inputPath, "rb"); //Input raw YUV data
if(!in_file){
LOGE(" fopen faile");
return false;
}
int in_w = 448, in_h = 960; //Input data's width and height
int framenum = 10000; //Frames to encode
3、初始化输出码流的AVFormatContext
有两种方式,这里我们用的方式一。
方式一:
//方式1
pFormatCtx = avformat_alloc_context();
//Guess Format
fmt = av_guess_format(NULL, o