diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 177ad4f610..c594a4f82e 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -360,6 +360,47 @@ static int formats_declared(AVFilterContext *f) return 1; } +static AVFilterFormats *clone_filter_formats(AVFilterFormats *arg) +{ + AVFilterFormats *a = av_memdup(arg, sizeof(*arg)); + if (a) { + a->refcount = 0; + a->refs = NULL; + a->formats = av_memdup(a->formats, sizeof(*a->formats) * a->nb_formats); + if (!a->formats && arg->formats) + av_freep(&a); + } + return a; +} + +static int can_merge_formats(AVFilterFormats *a_arg, + AVFilterFormats *b_arg, + enum AVMediaType type, + int is_sample_rate) +{ + AVFilterFormats *a, *b, *ret; + if (a == b) + return 1; + a = clone_filter_formats(a_arg); + b = clone_filter_formats(b_arg); + if (is_sample_rate) { + ret = ff_merge_samplerates(a, b); + } else { + ret = ff_merge_formats(a, b, type); + } + if (ret) { + av_freep(&ret->formats); + av_freep(&ret); + return 1; + } else { + av_freep(&a->formats); + av_freep(&b->formats); + av_freep(&a); + av_freep(&b); + return 0; + } +} + /** * Perform one round of query_formats() and merging formats lists on the * filter graph. @@ -404,20 +445,30 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) if (!link) continue; + if (link->in_formats != link->out_formats + && link->in_formats && link->out_formats) + if (!can_merge_formats(link->in_formats, link->out_formats, + link->type, 0)) + convert_needed = 1; + if (link->type == AVMEDIA_TYPE_AUDIO) { + if (link->in_samplerates != link->out_samplerates + && link->in_samplerates && link->out_samplerates) + if (!can_merge_formats(link->in_samplerates, + link->out_samplerates, + 0, 1)) + convert_needed = 1; + } + #define MERGE_DISPATCH(field, statement) \ if (!(link->in_ ## field && link->out_ ## field)) { \ count_delayed++; \ } else if (link->in_ ## field == link->out_ ## field) { \ count_already_merged++; \ - } else { \ + } else if (!convert_needed) { \ count_merged++; \ statement \ } - MERGE_DISPATCH(formats, - if (!ff_merge_formats(link->in_formats, link->out_formats, - link->type)) - convert_needed = 1; - ) + if (link->type == AVMEDIA_TYPE_AUDIO) { MERGE_DISPATCH(channel_layouts, if (!ff_merge_channel_layouts(link->in_channel_layouts, @@ -430,6 +481,11 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) convert_needed = 1; ) } + MERGE_DISPATCH(formats, + if (!ff_merge_formats(link->in_formats, link->out_formats, + link->type)) + convert_needed = 1; + ) #undef MERGE_DISPATCH if (convert_needed) {