1、简述
使用avformat_alloc_output_context2创建封装器上下文AVFormatContext时,只需将封装器的名字传递给形参format_name,就可以获取对应的封装器。这篇博客就是追寻avformat_alloc_output_context2的调用关系,探明原因。
函数原型如下:
int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat,
const char *format_name, const char *filename);
2、FFmpeg对flv封装格式的支持
flv封装格式的实现源码在libavformat/flvenc.c中,如果将 AVClass 和 AVOutputFormat结构体看作调用封装的抽象类或者接口类,要实现对flv的支持,就要实现这些接口。flvenc.c中实现了这些接口,并初始化了两个结构体 AVClass flv_muxer_class 和 AVOutputFormat ff_flv_muxer,源码下
static const AVClass flv_muxer_class = {
.class_name = "flv muxer",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVOutputFormat ff_flv_muxer = {
.name = "flv",
.long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),
.mime_type = "video/x-flv",
.extensions = "flv",
.priv_data_size = sizeof(FLVContext),
.audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF,
.video_codec = AV_CODEC_ID_FLV1,
.init = flv_init,
.write_header = flv_write_header,
.write_packet = flv_write_packet,
.write_trailer = flv_write_trailer,
.check_bitstream= flv_check_bitstream,
.codec_tag = (const AVCodecTag* const []) {
flv_video_codec_ids, flv_audio_codec_ids, 0
},
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
AVFMT_TS_NONSTRICT,
.priv_class = &flv_muxer_class,
};
当加载libavformat库时,flv相关功能已经初始化好,静等调用。
3、通过字符串flv找到对应的封装器
将包含封装器的封装器上下文AVFormatContext和字符串flv传递给函数avformat_alloc_output_context2,该函数中通过调用av_guess_format来获取封装器AVOutputFormat,函数原型如下:
AVOutputFormat *av_guess_format(const char *short_name,
const char *filename,
const char *mime_type);
通过参数可以判读,获取封装器有三种方法,分别是:
- 使用封装器名字“short_name”和AVOutputFormat.name作比较,本例中是“flv”;
- 使用文件名“filename”的后缀和AVOutputFormat.extensions作比较,本例中是“flv”;
- 使用媒体类型“mime_type”和AVOutputFormat.mime_type作比较,本例中是"video/x-flv"
正常情况下只需传递一个参数,其它两个传空NULL;如果同时传递三个,优先级为:short_name > mime_type > filename。
当然了,在作比较之前,要获取封装器列表,依次循环比较。
av_guess_format通过循环调用av_muxer_iterate来获取封装器,每调用时,传入一个索引,返回这个索引对应的封装器。索引从0开始,索引的累加在av_muxer_iterate内部实现。
av_muxer_iterate中调用一个封装器指针数组muxer_list,并根据传入的索引,返回封装器数组中指定的封装器指针AVOutputFormat*。
封装器指针数组muxer_list在libavformat/muxer_list.c中初始化,其中就包含本例中用到的flv封装器ff_flv_muxer的指针。
找到所需封装器指针后,最终它赋值给AVFormatContext.oformat。