diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 549fe6ce3a..1401577c50 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -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 diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 68e392b826..c84dd3cf25 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -352,7 +352,50 @@ 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 || + ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { ret = filter_check_formats(ctx); if (ret < 0) return ret; diff --git a/libavfilter/filters.h b/libavfilter/filters.h index 0053ad4303..fdc7a95cee 100644 --- a/libavfilter/filters.h +++ b/libavfilter/filters.h @@ -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 diff --git a/libavfilter/formats.c b/libavfilter/formats.c index 2b570b466e..21539b35d1 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -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++) { \ + const 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++) { \ + const 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 : diff --git a/libavfilter/formats.h b/libavfilter/formats.h index 82b3af4be1..380e9dfd00 100644 --- a/libavfilter/formats.h +++ b/libavfilter/formats.h @@ -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); diff --git a/libavfilter/tests/filtfmts.c b/libavfilter/tests/filtfmts.c index bc8c65c0ad..4ef6968826 100644 --- a/libavfilter/tests/filtfmts.c +++ b/libavfilter/tests/filtfmts.c @@ -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);