ffmpeg中filter_query_formats主要起一个pix fmt引用指定的功能。
下下结论:
先看几个结构体定义:
//删除了一些与本次分析不必要的成员
struct AVFilterLink {AVFilterContext *src; ///< source filterAVFilterPad *srcpad; ///< output pad on the source filterAVFilterContext *dst; ///< dest filterAVFilterPad *dstpad; ///< input pad on the dest filterenum AVMediaType type; ///< filter media type/* These parameters apply only to video */int w; ///< agreed upon image widthint h; ///< agreed upon image heightAVRational sample_aspect_ratio; ///< agreed upon sample aspect ratio/* These parameters apply only to audio */uint64_t channel_layout; ///< channel layout of current buffer (see libavutil/channel_layout.h)int sample_rate; ///< samples per secondint format; ///< agreed upon media format/****************************************************************** All fields below this line are not part of the public API. They* may not be used outside of libavfilter and can be changed and* removed at will.* New public fields should be added right above.******************************************************************//*** Lists of supported formats / etc. supported by the input filter.*/AVFilterFormatsConfig incfg;/*** Graph the filter belongs to.*/struct AVFilterGraph *graph;...
};
结构体:AVFilterFormatsConfig
typedef struct AVFilterFormatsConfig {/*** List of supported formats (pixel or sample).*/AVFilterFormats *formats;/*** Lists of supported sample rates, only for audio.*/AVFilterFormats *samplerates;/*** Lists of supported channel layouts, only for audio.*/AVFilterChannelLayouts *channel_layouts;} AVFilterFormatsConfig;
再来看函数:
static int filter_query_formats(AVFilterContext *ctx)
{int ret, i;AVFilterFormats *formats;AVFilterChannelLayouts *chlayouts;AVFilterFormats *samplerates;enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :AVMEDIA_TYPE_VIDEO;if ((ret = ctx->filter->query_formats(ctx)) < 0) {if (ret != AVERROR(EAGAIN))av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n",ctx->name, av_err2str(ret));return ret;}ret = filter_check_formats(ctx);if (ret < 0)return ret;for (i = 0; i < ctx->nb_inputs; i++)sanitize_channel_layouts(ctx, ctx->inputs[i]->outcfg.channel_layouts);for (i = 0; i < ctx->nb_outputs; i++)sanitize_channel_layouts(ctx, ctx->outputs[i]->incfg.channel_layouts);
//如果query_formats函数有,那么这里其实什么也不做formats = ff_all_formats(type);if ((ret = ff_set_common_formats(ctx, formats)) < 0)return ret;if (type == AVMEDIA_TYPE_AUDIO) {samplerates = ff_all_samplerates();if ((ret = ff_set_common_samplerates(ctx, samplerates)) < 0)return ret;chlayouts = ff_all_channel_layouts();if ((ret = ff_set_common_channel_layouts(ctx, chlayouts)) < 0)return ret;}return 0;
}
核心函数:ff_set_common_formats
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{SET_COMMON_FORMATS(ctx, formats,ff_formats_ref, ff_formats_unref);
}
看宏定义:
#define SET_COMMON_FORMATS(ctx, fmts, ref_fn, unref_fn) \int count = 0, i; \\if (!fmts) \return AVERROR(ENOMEM); \\for (i = 0; i < ctx->nb_inputs; i++) { \if (ctx->inputs[i] && !ctx->inputs[i]->outcfg.fmts) { \int ret = ref_fn(fmts, &ctx->inputs[i]->outcfg.fmts); \if (ret < 0) { \return ret; \} \count++; \} \} \for (i = 0; i < ctx->nb_outputs; i++) { \if (ctx->outputs[i] && !ctx->outputs[i]->incfg.fmts) { \int ret = ref_fn(fmts, &ctx->outputs[i]->incfg.fmts); \if (ret < 0) { \return ret; \} \count++; \} \} \\if (!count) { \unref_fn(&fmts); \} \\return 0;
接着看ref
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
{FORMATS_REF(f, ref, ff_formats_unref);
}#define FORMATS_REF(f, ref, unref_fn) \void *tmp; \\if (!f) \return AVERROR(ENOMEM); \\tmp = av_realloc_array(f->refs, sizeof(*f->refs), f->refcount + 1); \if (!tmp) { \unref_fn(&f); \return AVERROR(ENOMEM); \} \f->refs = tmp; \f->refs[f->refcount++] = ref; \*ref = f; \return 0
主要看关键的三行代码:
f->refs = tmp; \f->refs[f->refcount++] = ref; \*ref = f;
这就是最开始图片指示的互相引用。