ffmpeg中filter_query_formats主要起一个pix fmt引用指定的功能。
下下结论:
先看几个结构体定义:
//删除了一些与本次分析不必要的成员
struct AVFilterLink {
AVFilterContext *src; ///< source filter
AVFilterPad *srcpad; ///< output pad on the source filter
AVFilterContext *dst; ///< dest filter
AVFilterPad *dstpad; ///< input pad on the dest filter
enum AVMediaType type; ///< filter media type
/* These parameters apply only to video */
int w; ///< agreed upon image width
int h; ///< agreed upon image height
AVRational 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 second
int 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;
这就是最开始图片指示的互相引用。