@@ -98,6 +98,41 @@ const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx);
*/
enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx);
+/**
+ * Lists of formats / etc. supported by an end of a link.
+ *
+ * This structure is directly part of AVFilterLink, in two copies:
+ * one for the source filter, one for the destination filter.
+
+ * These lists are used for negotiating the format to actually be used,
+ * which will be loaded into the format and channel_layout members of
+ * AVFilterLink, when chosen.
+ */
+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;
+
+ /**
+ * Lists of supported YUV color metadata, only for YUV video.
+ */
+ AVFilterFormats *color_spaces; ///< AVColorSpace
+ AVFilterFormats *color_ranges; ///< AVColorRange
+
+} AVFilterFormatsConfig;
+
/**
* The number of the filter inputs is not determined just by AVFilter.inputs.
* The filter might add additional inputs during initialization depending on the
@@ -324,6 +359,21 @@ typedef struct AVFilter {
* AVERROR code otherwise
*/
int (*query_func)(AVFilterContext *);
+
+ /**
+ * Same as query_func(), except this function writes the results into
+ * provided arrays.
+ *
+ * @param cfg_in array of input format configurations with as many
+ * members as the filters has inputs (NULL when there are
+ * no inputs);
+ * @param cfg_out array of output format configurations with as many
+ * members as the filters has outputs (NULL when there
+ * are no outputs);
+ */
+ int (*query_func2)(const AVFilterContext *,
+ struct AVFilterFormatsConfig **cfg_in,
+ struct AVFilterFormatsConfig **cfg_out);
/**
* A pointer to an array of admissible pixel formats delimited
* by AV_PIX_FMT_NONE. The generic code will use this list
@@ -492,41 +542,6 @@ struct AVFilterContext {
int extra_hw_frames;
};
-/**
- * Lists of formats / etc. supported by an end of a link.
- *
- * This structure is directly part of AVFilterLink, in two copies:
- * one for the source filter, one for the destination filter.
-
- * These lists are used for negotiating the format to actually be used,
- * which will be loaded into the format and channel_layout members of
- * AVFilterLink, when chosen.
- */
-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;
-
- /**
- * Lists of supported YUV color metadata, only for YUV video.
- */
- AVFilterFormats *color_spaces; ///< AVColorSpace
- AVFilterFormats *color_ranges; ///< AVColorRange
-
-} AVFilterFormatsConfig;
-
/**
* A link between two filters. This contains pointers to the source and
* destination filters between which this link exists, and the indexes of
@@ -352,6 +352,49 @@ static int filter_query_formats(AVFilterContext *ctx)
ctx->name, av_err2str(ret));
return ret;
}
+ } else if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) {
+ AVFilterFormatsConfig *cfg_in_stack[64], *cfg_out_stack[64];
+ AVFilterFormatsConfig **cfg_in_dyn = NULL, **cfg_out_dyn = NULL;
+ AVFilterFormatsConfig **cfg_in, **cfg_out;
+
+ if (ctx->nb_inputs > FF_ARRAY_ELEMS(cfg_in_stack)) {
+ cfg_in_dyn = av_malloc_array(ctx->nb_inputs, sizeof(*cfg_in_dyn));
+ if (!cfg_in_dyn)
+ return AVERROR(ENOMEM);
+ cfg_in = cfg_in_dyn;
+ } else
+ cfg_in = ctx->nb_inputs ? cfg_in_stack : NULL;
+
+ for (unsigned i = 0; i < ctx->nb_inputs; i++) {
+ AVFilterLink *l = ctx->inputs[i];
+ cfg_in[i] = &l->outcfg;
+ }
+
+ if (ctx->nb_outputs > FF_ARRAY_ELEMS(cfg_out_stack)) {
+ cfg_out_dyn = av_malloc_array(ctx->nb_outputs, sizeof(*cfg_out_dyn));
+ if (!cfg_out_dyn)
+ return AVERROR(ENOMEM);
+ cfg_out = cfg_out_dyn;
+ } else
+ cfg_out = ctx->nb_outputs ? cfg_out_stack : NULL;
+
+ for (unsigned i = 0; i < ctx->nb_outputs; i++) {
+ AVFilterLink *l = ctx->outputs[i];
+ cfg_out[i] = &l->incfg;
+ }
+
+ ret = ctx->filter->formats.query_func2(ctx, cfg_in, cfg_out);
+ av_freep(&cfg_in_dyn);
+ av_freep(&cfg_out_dyn);
+ if (ret < 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;
+ }
+ }
+
+ if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) {
ret = filter_check_formats(ctx);
if (ret < 0)
@@ -226,6 +226,7 @@ enum FilterFormatsState {
*/
FF_FILTER_FORMATS_PASSTHROUGH = 0,
FF_FILTER_FORMATS_QUERY_FUNC, ///< formats.query active.
+ FF_FILTER_FORMATS_QUERY_FUNC2, ///< formats.query_func2 active.
FF_FILTER_FORMATS_PIXFMT_LIST, ///< formats.pixels_list active.
FF_FILTER_FORMATS_SAMPLEFMTS_LIST, ///< formats.samples_list active.
FF_FILTER_FORMATS_SINGLE_PIXFMT, ///< formats.pix_fmt active
@@ -235,6 +236,9 @@ enum FilterFormatsState {
#define FILTER_QUERY_FUNC(func) \
.formats.query_func = func, \
.formats_state = FF_FILTER_FORMATS_QUERY_FUNC
+#define FILTER_QUERY_FUNC2(func) \
+ .formats.query_func2 = func, \
+ .formats_state = FF_FILTER_FORMATS_QUERY_FUNC2
#define FILTER_PIXFMTS_ARRAY(array) \
.formats.pixels_list = array, \
.formats_state = FF_FILTER_FORMATS_PIXFMT_LIST
@@ -876,6 +876,153 @@ int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts)
return ff_set_common_formats(ctx, ff_make_format_list(fmts));
}
+#define SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, fmts, media_type, \
+ ref_fn, unref_fn) \
+ if (!fmts) \
+ return AVERROR(ENOMEM); \
+ \
+ for (unsigned i = 0; i < ctx->nb_inputs; i++) { \
+ AVFilterLink *const link = ctx->inputs[i]; \
+ if (!cfg_in[i]->fmts && \
+ (media_type == AVMEDIA_TYPE_UNKNOWN || \
+ link->type == media_type)) { \
+ int ret = ref_fn(fmts, &cfg_in[i]->fmts); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ } \
+ } \
+ for (unsigned i = 0; i < ctx->nb_outputs; i++) { \
+ AVFilterLink *const link = ctx->outputs[i]; \
+ if (!cfg_out[i]->fmts && \
+ (media_type == AVMEDIA_TYPE_UNKNOWN || \
+ link->type == media_type)) { \
+ int ret = ref_fn(fmts, &cfg_out[i]->fmts); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ } \
+ } \
+ \
+ if (!fmts->refcount) \
+ unref_fn(&fmts); \
+ \
+ return 0;
+
+int ff_set_common_channel_layouts2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterChannelLayouts *channel_layouts)
+{
+ SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, channel_layouts, AVMEDIA_TYPE_AUDIO,
+ ff_channel_layouts_ref, ff_channel_layouts_unref);
+}
+
+int ff_set_common_channel_layouts_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const AVChannelLayout *fmts)
+{
+ return ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, ff_make_channel_layout_list(fmts));
+}
+
+int ff_set_common_all_channel_counts2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out)
+{
+ return ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, ff_all_channel_counts());
+}
+
+int ff_set_common_samplerates2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *samplerates)
+{
+ SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, samplerates, AVMEDIA_TYPE_AUDIO,
+ ff_formats_ref, ff_formats_unref);
+}
+
+int ff_set_common_samplerates_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *samplerates)
+{
+ return ff_set_common_samplerates2(ctx, cfg_in, cfg_out, ff_make_format_list(samplerates));
+}
+
+int ff_set_common_all_samplerates2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out)
+{
+ return ff_set_common_samplerates2(ctx, cfg_in, cfg_out, ff_all_samplerates());
+}
+
+int ff_set_common_color_spaces2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *color_spaces)
+{
+ SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, color_spaces, AVMEDIA_TYPE_VIDEO,
+ ff_formats_ref, ff_formats_unref);
+}
+
+int ff_set_common_color_spaces_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *color_ranges)
+{
+ return ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, ff_make_format_list(color_ranges));
+}
+
+int ff_set_common_all_color_spaces2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out)
+{
+ return ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, ff_all_color_spaces());
+}
+
+int ff_set_common_color_ranges2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *color_ranges)
+{
+ SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, color_ranges, AVMEDIA_TYPE_VIDEO,
+ ff_formats_ref, ff_formats_unref);
+}
+
+int ff_set_common_color_ranges_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *color_ranges)
+{
+ return ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, ff_make_format_list(color_ranges));
+}
+
+int ff_set_common_all_color_ranges2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out)
+{
+ return ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, ff_all_color_ranges());
+}
+
+int ff_set_common_formats2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *formats)
+{
+ SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, formats, AVMEDIA_TYPE_UNKNOWN,
+ ff_formats_ref, ff_formats_unref);
+}
+
+int ff_set_common_formats_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *fmts)
+{
+ return ff_set_common_formats2(ctx, cfg_in, cfg_out, ff_make_format_list(fmts));
+}
+
+
int ff_default_query_formats(AVFilterContext *ctx)
{
const AVFilter *const f = ctx->filter;
@@ -905,6 +1052,7 @@ int ff_default_query_formats(AVFilterContext *ctx)
/* Intended fallthrough */
case FF_FILTER_FORMATS_PASSTHROUGH:
case FF_FILTER_FORMATS_QUERY_FUNC:
+ case FF_FILTER_FORMATS_QUERY_FUNC2:
type = AVMEDIA_TYPE_UNKNOWN;
formats = ff_all_formats(ctx->nb_inputs ? ctx->inputs [0]->type :
ctx->nb_outputs ? ctx->outputs[0]->type :
@@ -225,6 +225,90 @@ int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
av_warn_unused_result
int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts);
+/**
+ * Helpers for query_formats2() which set all free audio links to the same list
+ * of channel layouts/sample rates. If there are no links hooked to this list,
+ * the list is freed.
+ */
+av_warn_unused_result
+int ff_set_common_channel_layouts2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterChannelLayouts *channel_layouts);
+
+av_warn_unused_result
+int ff_set_common_channel_layouts_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const AVChannelLayout *fmts);
+av_warn_unused_result
+int ff_set_common_all_channel_counts2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out);
+
+av_warn_unused_result
+int ff_set_common_samplerates2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *samplerates);
+
+av_warn_unused_result
+int ff_set_common_samplerates_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *samplerates);
+
+av_warn_unused_result
+int ff_set_common_all_samplerates2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out);
+
+av_warn_unused_result
+int ff_set_common_color_spaces2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *color_spaces);
+
+av_warn_unused_result
+int ff_set_common_color_spaces_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *color_ranges);
+
+av_warn_unused_result
+int ff_set_common_all_color_spaces2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out);
+
+av_warn_unused_result
+int ff_set_common_color_ranges2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *color_ranges);
+
+av_warn_unused_result
+int ff_set_common_color_ranges_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *color_ranges);
+
+av_warn_unused_result
+int ff_set_common_all_color_ranges2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out);
+
+av_warn_unused_result
+int ff_set_common_formats2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ AVFilterFormats *formats);
+
+av_warn_unused_result
+int ff_set_common_formats_from_list2(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out,
+ const int *fmts);
+
av_warn_unused_result
int ff_add_channel_layout(AVFilterChannelLayouts **l,
const AVChannelLayout *channel_layout);
@@ -143,7 +143,24 @@ int main(int argc, char **argv)
if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC)
ret = filter->formats.query_func(filter_ctx);
- else
+ else if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) {
+ AVFilterFormatsConfig **cfg_in = NULL, **cfg_out = NULL;
+
+ if (filter_ctx->nb_inputs) {
+ cfg_in = av_malloc_array(filter_ctx->nb_inputs, sizeof(*cfg_in));
+ for (unsigned i = 0; i < filter_ctx->nb_inputs; i++)
+ cfg_in[i] = &filter_ctx->inputs[i]->outcfg;
+ }
+ if (filter_ctx->nb_outputs) {
+ cfg_out = av_malloc_array(filter_ctx->nb_outputs, sizeof(*cfg_out));
+ for (unsigned i = 0; i < filter_ctx->nb_outputs; i++)
+ cfg_out[i] = &filter_ctx->outputs[i]->incfg;
+ }
+
+ ret = filter->formats.query_func2(filter_ctx, cfg_in, cfg_out);
+ av_freep(&cfg_in);
+ av_freep(&cfg_out);
+ } else
ret = ff_default_query_formats(filter_ctx);
print_formats(filter_ctx);