avformat_alloc_output_context2()

本文简单分析FFmpeg中常用的一个函数:avformat_alloc_output_context2()。在基于FFmpeg的视音频编码器程序中,该函数通常是第一个调用的函数(除了组件注册函数av_register_all())。avformat_alloc_output_context2()函数可以初始化一个用于输出的AVFormatContext结构体。它的声明位于libavformat\avformat.h,如下所示。/** * 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, AVOutputFormat *oformat,const char *format_name, const char *filename);代码中的英文注释写的已经比较详细了,在这里拿中文简单叙述一下。ctx:函数调用成功之后创建的AVFormatContext结构体。oformat:指定AVFormatContext中的AVOutputFormat,用于确定输出格式。如果指定为NULL,可以设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式。PS:使用该参数需要自己手动获取AVOutputFormat,相对于使用后两个参数来说要麻烦一些。format_name:指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,,“mkv”等等。filename:指定输出文件的名称。根据文件名称,FFmpeg会推测输出格式。文件名称可以是“xx.flv”,“yy.mkv”等等。

函数执行成功的话,其返回值大于等于0。

该函数最典型的例子可以参考:最简单的基于FFMPEG的视频编码器(YUV编码为H.264)

函数调用结构图

首先贴出来最终分析得出的函数调用结构图,如下所示。

单击查看更清晰图片

avformat_alloc_output_context2()下面看一下avformat_alloc_output_context2()的函数定义。该函数的定义位于libavformat\mux.c中,如下所示。int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat,const char *format, const char *filename){AVFormatContext *s = avformat_alloc_context();int ret = 0;*avctx = NULL;if (!s)goto nomem;if (!oformat) {if (format) {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 {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;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);}} elses->priv_data = NULL;if (filename)av_strlcpy(s->filename, filename, sizeof(s->filename));*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;}从代码中可以看出,avformat_alloc_output_context2()的流程如要包含以下2步:1)调用avformat_alloc_context()初始化一个默认的AVFormatContext。

2)如果指定了输入的AVOutputFormat,则直接将输入的AVOutputFormat赋值给AVOutputFormat的oformat。如果没有指定输入的AVOutputFormat,就需要根据文件格式名称或者文件名推测输出的AVOutputFormat。无论是通过文件格式名称还是文件名推测输出格式,都会调用一个函数av_guess_format()。

下面我们分别看看上文步骤中提到的两个重要的函数:avformat_alloc_context()和av_guess_format()。

avformat_alloc_context()avformat_alloc_context()的是一个FFmpeg的API,它的定义如下。AVFormatContext *avformat_alloc_context(void){AVFormatContext *ic;ic = av_malloc(sizeof(AVFormatContext));if (!ic) return ic;avformat_get_context_defaults(ic);ic->internal = av_mallocz(sizeof(*ic->internal));if (!ic->internal) {avformat_free_context(ic);return NULL;}return ic;}从代码中可以看出,avformat_alloc_context()首先调用av_malloc()为AVFormatContext分配一块内存。然后调用了一个函数avformat_get_context_defaults()用于给AVFormatContext设置默认值。avformat_get_context_defaults()的定义如下。static void avformat_get_context_defaults(AVFormatContext *s){memset(s, 0, sizeof(AVFormatContext));s->av_class = &av_format_context_class;av_opt_set_defaults(s);}

从代码中可以看出,avformat_alloc_context()首先调用memset()将AVFormatContext的内存置零;然后指定它的AVClass(指定了AVClass之后,该结构体就支持和AVOption相关的功能);最后调用av_opt_set_defaults()给AVFormatContext的成员变量设置默认值(av_opt_set_defaults()就是和AVOption有关的一个函数,专门用于给指定的结构体设定默认值,此处暂不分析)。

av_guess_format()放弃等于又一次可以选择的机会。

avformat_alloc_output_context2()

相关文章:

你感兴趣的文章:

标签云: