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。