从头用脚分析FFmpeg源码 ---avformat_alloc_output_context2

本文所使用的是FFmpeg n4.4的源码,所有分析均来自博主瞎猜,如果有误,欢迎批评指正。

avformat_alloc_output_context2 作用

先看一下FFmpeg是怎么定义这个函数的

/**
 * Allocate an AVFormatContext for an output format.
 * avformat_free_context() can be used to free the context and
 * everything allocated by the framework within it.
 *
 * @param *ctx is set to the created format context, or to NULL in
 * case of failure
 * @param oformat format to use for allocating the context, if NULL
 * format_name and filename are used instead
 * @param format_name the name of output format to use for allocating the
 * context, if NULL filename is used instead
 * @param filename the name of the filename to use for allocating the
 * context, may be NULL
 * @return >= 0 in case of success, a negative AVERROR code in case of
 * failure
 */
int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat,
                                   const char *format_name, const char *filename);

这个函数就是为输出文件创建AVFormatContext,最后使用avformat_free_context函数释放AVFormatContext。

avformat_alloc_output_context2源码分析

int avformat_alloc_output_context2(AVFormatContext **avctx, ff_const59 AVOutputFormat *oformat,
                                   const char *format, const char *filename)
{
	//创建一个空的AVFormatContext 这个和在avformat_open_input 方法中,创建
	//input的AVFormatContext调用的方法是一致的。
    AVFormatContext *s = avformat_alloc_context();
    int ret = 0;

    *avctx = NULL;
    if (!s)
        goto nomem;

    if (!oformat) {
        if (format) {
        	// 比较重要的就是这个方法,根据foramt或者filename找到对应的AVOuputFormat
            oformat = av_guess_format(format, NULL, NULL);
            if (!oformat) {
                av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
                ret = AVERROR(EINVAL);
                goto error;
            }
        } else {
        	//找到对应的AVOuputFormat
            oformat = av_guess_format(NULL, filename, NULL);
            if (!oformat) {
                ret = AVERROR(EINVAL);
                av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n",
                       filename);
                goto error;
            }
        }
    }

    s->oformat = oformat;
    //  创建AVOuputFormat中Context大小的空间,在接下来的write_header等流程中会使用到
    if (s->oformat->priv_data_size > 0) {
        s->priv_data = av_mallocz(s->oformat->priv_data_size);
        if (!s->priv_data)
            goto nomem;
        if (s->oformat->priv_class) {
            *(const AVClass**)s->priv_data= s->oformat->priv_class;
            av_opt_set_defaults(s->priv_data);
        }
    } else
        s->priv_data = NULL;

    if (filename) {
#if FF_API_FORMAT_FILENAME
FF_DISABLE_DEPRECATION_WARNINGS
        av_strlcpy(s->filename, filename, sizeof(s->filename));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
        if (!(s->url = av_strdup(filename)))
            goto nomem;

    }
    *avctx = s;
    return 0;
nomem:
    av_log(s, AV_LOG_ERROR, "Out of memory\n");
    ret = AVERROR(ENOMEM);
error:
    avformat_free_context(s);
    return ret;
}

这个函数较之前的几个相比来说,还是比较简单的,里面总共就干了三件事

  1. 初始化一个空的AVFormatContext
  2. 根据输入的filename或者format找到对应的AVOuputFormat
  3. 初始化AVOuputFormat中context所需要的空间

av_guess_format源码

//short_name 相当于format,就比如说mp4视频格式,short_name就是mp4
ff_const59 AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
                                const char *mime_type)
{
    const AVOutputFormat *fmt = NULL;
    AVOutputFormat *fmt_found = NULL;
    void *i = 0;
    int score_max, score;

    /* specific test for image sequences */
#if CONFIG_IMAGE2_MUXER
	//这里判断输出是否为image类型,ff_guess_image2_codec里面就是列举
	//所有的image的format(比如png)和对应的codec id(比如AV_CODEC_ID_PNG)
	//所有的image类型的AVOuputformat都是使用的“image2”
    if (!short_name && filename &&
        av_filename_number_test(filename) &&
        ff_guess_image2_codec(filename) != AV_CODEC_ID_NONE) {
        return av_guess_format("image2", NULL, NULL);
    }
#endif
    /* Find the proper file type. */
    score_max = 0;
    // 和打开input的时候类似,寻找output也是依靠这种方法
    // av_muxer_iterate会枚举所有AVOuputFormat类型,
    // 看看哪种和short_name或者filename匹配。
    while ((fmt = av_muxer_iterate(&i))) {
        score = 0;
        //根据short_name进行匹配,也就是根据format进行匹配
        if (fmt->name && short_name && av_match_name(short_name, fmt->name))
            score += 100;
        //mime_type感觉就是在format之前加一个video或者audio标识,标志这种格式的类型。
        //调用avformat_alloc_output_context2并没有设置这个
        if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
            score += 10;
        //av_match_ext会从最后一个'.'符号开始,和fmt->extensions进行匹配,如果一致,就返回1
        //所以这里就是判断输出地址的格式和AVformatOutput的后缀名是否一样
        if (filename && fmt->extensions &&
            av_match_ext(filename, fmt->extensions)) {
            score += 5;
        }
        if (score > score_max) {
            score_max = score;
            fmt_found = (AVOutputFormat*)fmt;
        }
    }
    return fmt_found;
}

总体而言,av_guess_format就是根据输入的format或者filename找到最匹配的AVOutputFormat,总体而言还是比较简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值