视频编码

视频音频的解码介绍过了,接下来是编码,相对于解码来说,编码流程相对麻烦一些。不过不要担心,小编带你装一把。
视频编码流程 第一步:注册组件 av_register_all();
第二步:初始化封装格式上下文 avformat_alloc_context()
第三步:打开输出文件 avio_open()
第四步:创建输出码流(视频流 ) AVStream* av_video_stream = avformat_new_stream() //只是创建内存,目前不知道是什么类型的流,但是们希望是视频流
第五步:查找视频编码器 5.1 获取编码器上下文 AVCodecContext* avcodec_context = av_video_stream->codec;
5.2设置编码器上下文参数 avcodec_context->codec_id = avoutput_format->video_codec; //设置编码器ID
avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO; //设置编码器类型
avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P; //设置读取像素数据格式(编码的是像素数据格式),这个类型是根据解码的时候指定的视频像素数据格式类型
//设置视频宽高
avcodec_context->width = 640;
avcodec_context->height = 352;
//设置帧率
//这里设置为每秒25帧 fps(f:frame 帧,ps:每秒)
avcodec_context->time_base.num = 1;
avcodec_context->time_base.den = 25;
//设置码率(码率bps:单位时间内传输的二进制数据量),码率也是比特率,比特率越高,传输速度越快
//kbps:每秒传输千位
avcodec_context->bit_rate = 468000; //码率 = 视频大小(bit)/时间(秒)。码率越大证明视频越大
//设置GOP(GOP:画面组,一组连续的画面),影响视频质量问题
/**
*MPEG格式画面类型:I帧,P帧,B帧
*I帧:原始帧(原始视频数据,完整的画面),关键帧(必须要有,如果没有则不能进行编解码操作),视频的第一帧总是是I帧
*P帧:向前预测帧(帧间预测编码帧):预测前面一帧的类型,处理数据,前面一帧可能是I帧,也可能是B帧
*B帧:前后预测帧(双向预测编码帧),B帧压缩率高,但同时对解码性能要求也高
*I帧越少,视频越小。其实说白了。B 和 P 帧是对I帧的压缩处理,从而减小视频大小
*/
avcodec_context->gop_size = 250; //每250帧插入一个I帧
设置量化参数. 量化系数越小,视频越清晰(这个量化参数都是些数学算法,有兴趣可以了解一下。),这里采用默认值。
avcodec_context->qmin = 10; //最小量化系数
avcodec_context->qmax = 51; //最大量化系数
//设置B帧最大值
avcodec_context->max_b_frames = 0; //不需要B帧
5.3 查找编码器(h264),默认情况下FFmpeg没有编译进行h264库,所以要编译h264库 AVCodec* avcodec = avcodec_find_encoder(avcodec_context->codec_id);
第六步:打开编码器(h264编码器) 打开以前做一些编码延时问题优化。编码选项->编码设置
AVDictionary *param = 0;
if (avcodec_context->codec_id == AV_CODEC_ID_H264) {
//需要查看x264源码->x264.c文件
//第一个值:预备参数
//key: preset
//value: slow->慢
//value: superfast->超快
av_dict_set(¶m, "preset", "slow", 0);
//第二个值:调优
//key: tune->调优
//value: zerolatency->零延迟
av_dict_set(¶m, "tune", "zerolatency", 0);
}
打开:avcodec_open2();
第七步:写入文件头信息 avformat_write_header();
第八步:循环编码yuv文件(视频像素数据)->编码为视频压缩数据(h264格式) 这一步有很多设置操作,具体可以参考demo
第9步:视频编码处理 9.1 发送一帧视频像素数据 avcodec_send_frame()
9.2 接收一帧视频像素数据->编码为->视频压缩数据格式 avcodec_receive_packet();
9.3 判定是否编码成功 第10步:将视频压缩数据->写入到输出文件中 av_write_frame();
第11步:写入剩余帧数据->可能没有 flush_encoder();
第12步:写入文件尾部信息 【视频编码】av_write_trailer();
第13步:释放内存

步骤比较多,但实现代码不是特别复杂,为了大家能够更深入理解,请大家参考[demo](https://github.com/xiaoyuancai/FFMPEG_demo_VideoEncode)

    推荐阅读