【FFmpeg】如何通過字符串到對應的封裝器,以flv爲例

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_classAVOutputFormat 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);

通過參數可以判讀,獲取封裝器有三種方法,分別是:

  1. 使用封裝器名字“short_name”和AVOutputFormat.name作比較,本例中是“flv”;
  2. 使用文件名“filename”的後綴AVOutputFormat.extensions作比較,本例中是“flv”;
  3. 使用媒體類型“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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章