欢迎诸位来阅读在下的博文~
在这里,在下会不定期发表一些浅薄的知识和经验,望诸位能与在下多多交流,共同努力
前期博客
FFmpeg的入门实践系列一(环境搭建)
FFmpeg的入门实践系列二(基础知识)
FFmpeg的入门实践系列三(基础知识)
FFmpeg的入门实践系列四(AVS)
FFmpeg的入门实践系列五(编程入门之属性查看)
参考书籍
《FFmpeg开发实战——从零基础到短视频上线》——欧阳燊
一、FFmpeg常见的处理流程
承接上章,上一章其实讲了三个对象,一个是AVFormatContext,代表音视频文件,然后是其相关的属性;一个是AVStream,代表音视频文件里面的数据流(音频流、视频流、字幕流等等),然后是其相关属性;一个是AVCodec,代表数据流里面的编解码器规格,然后是其相关属性。整个过程是一个由大到小的,层层深入的过程。这一章,将继续讲解编解码器的相关内容。
复制编解码器的参数
其实,AVCodec结构仅仅是规格定义,它在描述一个编解码器是怎么样的,但是它没有真正执行编码解码的功能,就是一个”光说不做的主“。要想执行真正的编码解码操作,还需要引入AVCodecContext才行。
具体的写代码流程如下:
- 打开编解码器实例的完整流程:avcodec_alloc_context3–>avcodec_parameters_to_context–>avcodec_open2
- 关闭编解码器实例的完整流程:avcodec_close–>avcodec_free_context
在编解码器实例打开之后,才能对数据包或者数据帧进行编解码操作,具体而言,就是数据包AVPacket经过解码生成数据帧AVFrame;反之亦然。下面代码片段演示如何打开编解码的实例:
AVCodecContext *video_decode_ctx = NULL;
video_decode_ctx = avcodec_alloc_context3(video_codec);
if(video_decode_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate video decode context\n");
return -1;
}
// 把视频流中的编解码参数复制给解码器的实例
avcodec_parameters_to_context(video_decode_ctx, video_stream->codecpar);
av_log(NULL, AV_LOG_INFO, "success copy video stream parameters to video decode context\n");
ret = avcodec_open2(video_decode_ctx, video_codec, NULL);// 打开解码器
av_log(NULL, AV_LOG_INFO, "success open video decode context\n");
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open video decoder\n");
return -1;
}
avcodec_close(video_decode_ctx); // 关闭解码器
avcodec_free_context(&video_decode_ctx); // 释放解码器资源
其实只要调用了avcodec_paramters_to_context函数,就能获取音视频文件的详细编码参数,具体参数保存在AVCodecContext结构中,该结构的常见字段说明如下:
- codec_id: 编解码器的编号。//比如AV_CODEC_ID_MJPEG 7 JPEG图像编码标准
- codec_type: 编解码器的类型。// AVMEDIA_TYPE_VIDEO 0 视频流
- width: 视频画面的宽度
- height: 视频画面的高度
- gop_size: 每两个关键帧(I帧)间隔多少帧
- max_b_frames: 双向预测帧(B帧)的最大数量
- pix_fmt: 视频的像素格式。像素格式的定义来自AVPixelFormat枚举,详细的像素格式类型及其说明见附页
- profile: 指定编解码器的配置文件,主要用于细分AAC音频的种类,详细的AAC种类定义及其说明见附页
- ch_layout: 音频的声道布局,该字段为AVChannelLayout结构,声道数量是该结构的nb_channels字段。声道数量及其定义见附页
- sample_fmt: 音频的采样格式。采样格式的定义来自AVSampleFormat枚举,详细的采样格式定义见附页
- sample_rate: 音频的采样频率,单位为赫兹(次每秒)
- frame_size: 音频的帧大小,也叫采样个数,即每个音频帧采集的样本数量
- bit_rate: 码率,也叫比特率,单位为比特每秒
- time_base: 音视频的时间基,该字段为AVRatianal结构
完整代码
接下来把AVStream到AVCodec再到AVCodecContext的完整流程串起来,分别在视频流和音频流中寻找它们的解码器的实例,并执行实例的打开和关闭操作。
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#ifdef __cplusplus
};
#endif
int main(int argc, char** argv){
const char* filename = "../fuzhou.mp4";
if(argc > 1)
filename = argv[1];
AVFormatContext* fmt_ctx = NULL;
int ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL);
if(ret < 0){
av_log(NULL, AV_LOG_ERROR, "Could not open file %s\n", filename);
return -1;
}
av_log(NULL, AV_LOG_INFO, "Opened file %s\n", filename);
//查找音视频文件中的流信息
ret = avformat_find_stream_info(fmt_ctx, NULL);
if(ret < 0){
av_log(NULL,