前言
从本章开始我们将要学习嵌入式音视频的学习了 ,使用的瑞芯微的开发板
🎬 个人主页:@ChenPi
🐻推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》✨✨✨
🔥 推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》✨✨✨
🛸推荐专栏3:《嵌入式音视频_@ChenPi的博客-CSDN博客》
🌺本篇简介 :本章主要讲解ffmpeg模块输出参数的初始化
今天讲解的部分就是继上章未讲完的部分继续讲解
首先我们看上图红框里面的函数,函数内部就是实现ffmpeg初始化,合成复合流以及推流
里面内容比价多,我可能分为三章去分别讲解,今天我们先讲一下ffmpeg的参数初始化
01 ffmpeg输出模块结构体
在FFMPEG输出模块中用到了很多个结构体,分别是:AVFormatContext 、A VS tream、 AVC odec、 AVC odec C ontext、 AVIOContext 。
- **AVFormatContext:**是存储音视频封装格式中包含的信息的结构体,它是FFMPEG中的核心,所有的文件封装、编码都是从它开始
- AVStream:AVStream主要存储了音频流、视频流的具体信息
- AVCodec:AVCodec是存储编解码信息的结构体
- AVCodecContext:AVCodecContext 是编解码上下文,它主要的功能是除了存储AVCodec的信息外,还保存了额外的编码属性
- AVIOContext:其中AVIOContext是FFMPEG管理输入输出数据的结构体
02 ffmpeg初始化代码分析
这个代我们要我们要先从这个结构体开始看
这个结构体会有些许复杂
cpp
typedef struct
{
AVStream *stream; /*主要储存了音视频流的具体信息*/
AVCodecContext *enc; //编解码上下文,它主要的功能是除了存储 AVCodec 的信息外,还保存了额外的编码属性
int64_t next_timestamp; //
int samples_count;
AVPacket *packet; //压缩后的数据和关于这些数据的一些附加的信息,如显示时间戳(pts),解码时间戳(dts),数据时长(duration),所在流媒体的索引(stream_index)等等。
} OutputStream;
typedef struct
{
unsigned int config_id;
int protocol_type; //流媒体TYPE
char network_addr[NETWORK_ADDR_LENGTH];//流媒体地址
enum AVCodecID video_codec; //视频编码器ID
enum AVCodecID audio_codec; //音频编码器ID
OutputStream video_stream; //VIDEO的STREAM配置
OutputStream audio_stream; //AUDIO的STREAM配置
AVFormatContext *oc; //是存储音视频封装格式中包含的信息的结构体,也是FFmpeg中统领全局的结构体,对文件的封装、编码操作从这里开始。
} RKMEDIA_FFMPEG_CONFIG; //FFMPEG配置
这个结构体很重要,这里面保存着配置相关的所有信息
其中最重要的结构体是AVFormatContext,里面存储音视频封装格式中包含的信息的结构体,
也是FFmpeg中统领全局的结构体,对文件的封装、编码操作从这里开始。
将一些简单的参数配置完后,我们看一下如何初始化FFmpeg
ffmpeg输出模块初始化大概就是这八步,我们一步一步解析
2.1 根据需要配置码流属性avformat_alloc_output_context2()
函数原型:
cpp
int avformat_alloc_output_context2(AVFormatContext **ctx,
AVOutputFormat *oformat, const char *format_name, const char *filename)
- 第一个传输参数: AVFormatContext结构体指针的指针,是存储音视频封装格式中包含的信息的结构体,所有对文件的封装、编码都是从这个结构体开始。
- 第二个传输参数: AVOutputFormat的结构体指针,它主要存储复合流信息的常规配置,默认为设置NULL。
- 第三个传输参数: format_name指的是复合流的格式,比方说:flv、ts、mp4等等
- 第四个传输参数: filename是输出地址,输出地址可以是本地文件(如:xxx.mp4、xxx.ts等等)。也可以是网络流地址(如:rtmp://xxx.xxx.xxx.xxx:1935/live/01)
2.2配置推流器编码参数和A VStream 结构体
A VS tream主要是存储流信息结构体,这个流信息包含音频流和视频流。
创建的API是avformat_new_stream ****,****如下
函数原型:
cpp
AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
- 参数1: AVFormatContext的结构体指针
- 参数2: AVDictionary结构体指针的指针
- 返回值:成功返回 AVStream结构体指针,失败返回NULL
创建输出码流AVStream, AVStream是存储每一个视频/音频流信息的结构体
2.3找到编码器avcodec_find_encoder
找到对应的编码ID
函数原型:
cpp
AVCodec *avcodec_find_encoder(AVCodecID id)
- 参数1:请求编码器的编号
- 返回值:返回查找到的解码器(没有找到就返回
NULL
)
2.4 avcodec_alloc_context3分配AVCodecContext结构体
函数原型:
cpp
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
功能
- 分配一个AVCodecContext,并将其字段设置为默认值。
- 结果由avcodec_free_context()释放
参数
- 如果非null,分配私有数据并初始化给定编解码器的默认值。使用不同的编解码器调用avcodec_open2()是非法的。
- 如果为NULL,那么特定于编解码器的默认值将不会被初始化,这可能会导致默认设置不理想(这对于编码器(例如libx264)尤为重要)。
返回值
- 一个用默认值填充的AVCodecContext,失败时为NULL。
2.5 设置AVCodecContext的参数
FFMPEG的视频编码参数如:分辨率(WIDTH 、H EIGHT )、时间基(time_base )、 帧率(r_frame_rate )、GOP_SIZE等都需要和右边VENC的参数要一一对应起来。其中time_base的值要和视频帧率必须要一致。
FFMPEG的音频编码参数如:音频采样格式(sample_fmt )、音频码率(bit_rate )、 音频采样率(sample_rate )、 音频布局(channel_layout )、 音频通道(channels )、 时间基(time_base )等都需要和右边A ENC的参数一一对应。其中time_base的值必须要和音频采样率要一致。
AV_CODEC_FLAG_GLOBAL_HEADER ****:****发送视频数据的时候都会在关键帧前面添加SPS/PPS,这个标识符在FFMPEG初始化的时候都需要添加。
2.6 使能推流编码器
这里的o pen _ video 、o pen _ audio 就是使能推流编码器,其中avcodec _open2 让编码器和编码器上下文进行关联。并用avcodec_parameters_from_context 把刚初始化的上下文传输到A VStream的编解码器。
2.7打开I O 文件操作
使用avio_open 打开对应的文件,注意这里的文件不仅是指本地的文件也指的是网络流媒体文件,下面是a vio_open的定义。
cpp
int avio_open(AVIOContext **s, const char *url, int flags);
- ****第一个参数:****AVIOContext的结构体指针,它主要是管理数据输入输出的结构体
- 第二个参数: url地址,这个URL地址既包括本地文件如(xxx.ts、xxx.mp4),也可以是网络流媒体地址,如(rtmp://192.168.22.22:1935/live/01)等
- ****第三个参数:****flags标识符
#define AVIO_FLAG_READ 1 /**< read-only */
#define AVIO_FLAG_WRITE 2 /**< write-only */
#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */
2.8 avformat_write_header 对头部进行初始化
cpp
int avformat_write_header(AVFormatContext *s, AVDictionary **options);
- 第一个参数: 传递AVFormatContext结构体指针
- 第二个参数: 传递AVDictionary结构体指针的指针