ffmpeg example 4.视频文件封装和编码
今天学习 ffmpeg/doc/examples/muxing.c
该程序接受一个参数,指定输出的文件的路径,例如/tmp/mux.mp4
,/tmp/mux.mov
。 文件名的后缀会用来推测生成的AVFormatContext的格式,如果没有指定,就使用mpeg
。使用fmt 默认的视频编码器和音频编码器,编码10秒钟的音视频数据,交替写入文件。
操作封装需要操作AVFormatContext
创建AVFormatContext
1 |
|
给AVFormatContext添加 video / audio stream
1 |
|
我们看看add_stream做了什么
1 |
|
根据codec_id找到AVCodec
调用avformat_new_stream创建stream
设置stream的index
根据AVCodec创建编码器的上下文,配置编码器参数
设置stream的time_base
处理一下 stream headers 的标志位
音视频流创建好了,下一步为写入准备
上面创建好了stream, 创建了编码器上下文。open_video/open_audio继续为写入做准备
准备完成就打开文件准备写入
1 |
|
看看open_video 做了什么
1 |
|
打开编码器
申请资源,创建一个AVFrame用于存储编码前数据
调用avcodec_parameters_from_context将编码器的编码参数拷贝到stream的codecpar中
写音视频数据到文件
写文件头
1 |
|
交替写音视频帧
1 |
|
写trailer
1 |
|
关闭编码器,关闭文件,释放资源
1 |
|
write_video_frame
1 |
|
只是简单调用了write_frame
1 |
|
将AVFrame送给编码器去编码
读取pkt
调用av_packet_rescale_ts,调整pkt的时间戳,写入文件pkt的pts要以stream的time_base为基准
设置pkt的index
调用av_interleaved_write_frame将pkt写入文件
返回写入结果。当AVFrame为空时,会冲洗编码器,ret = AVERROR_EOF, 返回1, 结束写入
frame的每一帧数据,是来自于get_video_frame方法, 填充的假数据
1 |
|
调用av_compare_ts 判断是否继续生成新的frame,一开始规定了只写10秒钟的数据,超过了就不写了
av_frame_make_writable使当前的frame可写,被编码器引用的frame不可写,调用该方法如果被引用,内部会创建新buf,变成可写的
填充数据yuv,还做了缩放处理,暂不讨论
更新frame的pts
返回生成的frame
write_audio_frame
1 |
|
准备AVFrame,调用get_audio_frame获取一个AVFrame,内部根据编码格式,填充pcm假数据
调用av_rescale_rnd计算重采样个数,如果数据源和送入编码器的音频的采样率不同,需要转换采样率,示例程序只是变了采样格式,没有更改采样率,采样个数不变
做重采样,重采样数据保存在ost->frame中
重采样后,需要更新frame的pts
调用write_frame编码,将数据写入文件
总结:
学习了通过应用libavformat将音视频数据编码封装到文件中
创建AVFormatContext
添加stream
配置编解码器,stream 参数
编码frame,生成pkt,更新pts
交替写音视频pkt
关闭编解码器,结束写文件