diff options
-rw-r--r-- | libavfilter/avfiltergraph.c | 129 | ||||
-rw-r--r-- | libavfilter/formats.c | 91 | ||||
-rw-r--r-- | libavfilter/formats.h | 44 |
3 files changed, 120 insertions, 144 deletions
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 6c2b6d03fa..746708d95c 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -372,61 +372,6 @@ 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_arg == b_arg) - return 1; - a = clone_filter_formats(a_arg); - b = clone_filter_formats(b_arg); - - if (!a || !b) { - if (a) - av_freep(&a->formats); - if (b) - av_freep(&b->formats); - - av_freep(&a); - av_freep(&b); - - return 0; - } - - 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->refs); - 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. @@ -473,45 +418,40 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) 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)) + if (!ff_can_merge_formats(link->in_formats, link->out_formats, + link->type)) 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)) + if (!ff_can_merge_samplerates(link->in_samplerates, + link->out_samplerates)) convert_needed = 1; } -#define MERGE_DISPATCH(field, statement) \ +#define CHECKED_MERGE(field, ...) ((ret = ff_merge_ ## field(__VA_ARGS__)) <= 0) +#define MERGE_DISPATCH(field, ...) \ if (!(link->in_ ## field && link->out_ ## field)) { \ count_delayed++; \ } else if (link->in_ ## field == link->out_ ## field) { \ count_already_merged++; \ } else if (!convert_needed) { \ count_merged++; \ - statement \ + if (CHECKED_MERGE(field, __VA_ARGS__)) { \ + if (ret < 0) \ + return ret; \ + convert_needed = 1; \ + } \ } if (link->type == AVMEDIA_TYPE_AUDIO) { - MERGE_DISPATCH(channel_layouts, - if (!ff_merge_channel_layouts(link->in_channel_layouts, - link->out_channel_layouts)) - convert_needed = 1; - ) - MERGE_DISPATCH(samplerates, - if (!ff_merge_samplerates(link->in_samplerates, - link->out_samplerates)) - convert_needed = 1; - ) + MERGE_DISPATCH(channel_layouts, link->in_channel_layouts, + link->out_channel_layouts) + MERGE_DISPATCH(samplerates, link->in_samplerates, + link->out_samplerates) } - MERGE_DISPATCH(formats, - if (!ff_merge_formats(link->in_formats, link->out_formats, - link->type)) - convert_needed = 1; - ) + MERGE_DISPATCH(formats, link->in_formats, + link->out_formats, link->type) #undef MERGE_DISPATCH if (convert_needed) { @@ -585,27 +525,26 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) av_assert0(outlink-> in_channel_layouts->refcount > 0); av_assert0(outlink->out_channel_layouts->refcount > 0); } - if (!ff_merge_formats( inlink->in_formats, inlink->out_formats, inlink->type) || - !ff_merge_formats(outlink->in_formats, outlink->out_formats, outlink->type)) - ret = AVERROR(ENOSYS); - if (inlink->type == AVMEDIA_TYPE_AUDIO && - (!ff_merge_samplerates(inlink->in_samplerates, - inlink->out_samplerates) || - !ff_merge_channel_layouts(inlink->in_channel_layouts, - inlink->out_channel_layouts))) - ret = AVERROR(ENOSYS); - if (outlink->type == AVMEDIA_TYPE_AUDIO && - (!ff_merge_samplerates(outlink->in_samplerates, - outlink->out_samplerates) || - !ff_merge_channel_layouts(outlink->in_channel_layouts, - outlink->out_channel_layouts))) - ret = AVERROR(ENOSYS); - - if (ret < 0) { + if (CHECKED_MERGE(formats, inlink->in_formats, + inlink->out_formats, inlink->type) || + CHECKED_MERGE(formats, outlink->in_formats, + outlink->out_formats, outlink->type) || + inlink->type == AVMEDIA_TYPE_AUDIO && + (CHECKED_MERGE(samplerates, inlink->in_samplerates, + inlink->out_samplerates) || + CHECKED_MERGE(channel_layouts, inlink->in_channel_layouts, + inlink->out_channel_layouts)) || + outlink->type == AVMEDIA_TYPE_AUDIO && + (CHECKED_MERGE(samplerates, outlink->in_samplerates, + outlink->out_samplerates) || + CHECKED_MERGE(channel_layouts, outlink->in_channel_layouts, + outlink->out_channel_layouts))) { + if (ret < 0) + return ret; av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); - return ret; + return AVERROR(ENOSYS); } } } diff --git a/libavfilter/formats.c b/libavfilter/formats.c index 2a40762897..78f698745c 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -56,15 +56,19 @@ do { \ /** * Add all formats common to a and b to a, add b's refs to a and destroy b. + * If check is set, nothing is modified and it is only checked whether + * the formats are compatible. * If empty_allowed is set and one of a,b->nb is zero, the lists are * merged; otherwise, it is treated as error. */ -#define MERGE_FORMATS(a, b, fmts, nb, type, fail_statement, empty_allowed) \ +#define MERGE_FORMATS(a, b, fmts, nb, type, check, empty_allowed) \ do { \ int i, j, k = 0, skip = 0; \ \ if (empty_allowed) { \ if (!a->nb || !b->nb) { \ + if (check) \ + return 1; \ if (!a->nb) \ FFSWAP(type *, a, b); \ skip = 1; \ @@ -74,28 +78,31 @@ do { for (i = 0; i < a->nb; i++) \ for (j = 0; j < b->nb; j++) \ if (a->fmts[i] == b->fmts[j]) { \ + if (check) \ + return 1; \ a->fmts[k++] = a->fmts[i]; \ break; \ } \ /* Check that there was at least one common format. \ * Notice that both a and b are unchanged if not. */ \ if (!k) \ - { fail_statement } \ + return 0; \ + av_assert2(!check); \ a->nb = k; \ } \ \ - MERGE_REF(a, b, fmts, type, fail_statement); \ + MERGE_REF(a, b, fmts, type, return AVERROR(ENOMEM);); \ } while (0) -AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, - enum AVMediaType type) +static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b, + enum AVMediaType type, int check) { int i, j; int alpha1=0, alpha2=0; int chroma1=0, chroma2=0; if (a == b) - return a; + return 1; /* Do not lose chroma or alpha in merging. It happens if both lists have formats with chroma (resp. alpha), but @@ -119,31 +126,58 @@ AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, // If chroma or alpha can be lost through merging then do not merge if (alpha2 > alpha1 || chroma2 > chroma1) - return NULL; + return 0; + + MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 0); + + return 1; +} - MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, return NULL;, 0); +int ff_can_merge_formats(const AVFilterFormats *a, const AVFilterFormats *b, + enum AVMediaType type) +{ + return merge_formats_internal((AVFilterFormats *)a, + (AVFilterFormats *)b, type, 1); +} - return a; +int ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, + enum AVMediaType type) +{ + av_assert2(a->refcount && b->refcount); + return merge_formats_internal(a, b, type, 0); } -AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a, - AVFilterFormats *b) +static int merge_samplerates_internal(AVFilterFormats *a, + AVFilterFormats *b, int check) { - if (a == b) return a; + if (a == b) return 1; - MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, return NULL;, 1); - return a; + MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 1); + return 1; } -AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, - AVFilterChannelLayouts *b) +int ff_can_merge_samplerates(const AVFilterFormats *a, const AVFilterFormats *b) +{ + return merge_samplerates_internal((AVFilterFormats *)a, (AVFilterFormats *)b, 1); +} + +int ff_merge_samplerates(AVFilterFormats *a, AVFilterFormats *b) +{ + av_assert2(a->refcount && b->refcount); + return merge_samplerates_internal(a, b, 0); +} + +int ff_merge_channel_layouts(AVFilterChannelLayouts *a, + AVFilterChannelLayouts *b) { uint64_t *channel_layouts; unsigned a_all = a->all_layouts + a->all_counts; unsigned b_all = b->all_layouts + b->all_counts; int ret_max, ret_nb = 0, i, j, round; - if (a == b) return a; + av_assert2(a->refcount && b->refcount); + + if (a == b) return 1; /* Put the most generic set in a, to avoid doing everything twice */ if (a_all < b_all) { @@ -159,16 +193,16 @@ AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, /* Not optimal: the unknown layouts of b may become known after another merge. */ if (!j) - return NULL; + return 0; b->nb_channel_layouts = j; } - MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, return NULL;); - return b; + MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, return AVERROR(ENOMEM);); + return 1; } ret_max = a->nb_channel_layouts + b->nb_channel_layouts; if (!(channel_layouts = av_malloc_array(ret_max, sizeof(*channel_layouts)))) - return NULL; + return AVERROR(ENOMEM); /* a[known] intersect b[known] */ for (i = 0; i < a->nb_channel_layouts; i++) { @@ -206,21 +240,20 @@ AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, channel_layouts[ret_nb++] = a->channel_layouts[i]; } - if (!ret_nb) - goto fail; + if (!ret_nb) { + av_free(channel_layouts); + return 0; + } if (a->refcount > b->refcount) FFSWAP(AVFilterChannelLayouts *, a, b); - MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, goto fail;); + MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, + { av_free(channel_layouts); return AVERROR(ENOMEM); }); av_freep(&b->channel_layouts); b->channel_layouts = channel_layouts; b->nb_channel_layouts = ret_nb; - return b; - -fail: - av_free(channel_layouts); - return NULL; + return 1; } int ff_fmt_is_in(int fmt, const int *fmts) diff --git a/libavfilter/formats.h b/libavfilter/formats.h index ffe7a12d53..dd0cbca6d5 100644 --- a/libavfilter/formats.h +++ b/libavfilter/formats.h @@ -110,17 +110,32 @@ typedef struct AVFilterChannelLayouts { (int)((l) & 0x7FFFFFFF) : 0) /** - * Return a channel layouts/samplerates list which contains the intersection of - * the layouts/samplerates of a and b. Also, all the references of a, all the - * references of b, and a and b themselves will be deallocated. + * Check the formats/samplerates lists for compatibility for merging + * without actually merging. * - * If a and b do not share any common elements, neither is modified, and NULL - * is returned. + * @return 1 if they are compatible, 0 if not. */ -AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, - AVFilterChannelLayouts *b); -AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a, - AVFilterFormats *b); +int ff_can_merge_formats(const AVFilterFormats *a, const AVFilterFormats *b, + enum AVMediaType type); +int ff_can_merge_samplerates(const AVFilterFormats *a, const AVFilterFormats *b); + +/** + * Merge the formats/channel layouts/samplerates lists if they are compatible + * and update all the references of a and b to point to the combined list and + * free the old lists as needed. The combined list usually contains the + * intersection of the lists of a and b. + * + * Both a and b must have owners (i.e. refcount > 0) for these functions. + * + * @return 1 if merging succeeded, 0 if a and b are incompatible + * and negative AVERROR code on failure. + * a and b are unmodified if 0 is returned. + */ +int ff_merge_channel_layouts(AVFilterChannelLayouts *a, + AVFilterChannelLayouts *b); +int ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, + enum AVMediaType type); +int ff_merge_samplerates(AVFilterFormats *a, AVFilterFormats *b); /** * Construct an empty AVFilterChannelLayouts/AVFilterFormats struct -- @@ -239,17 +254,6 @@ av_warn_unused_result AVFilterFormats *ff_planar_sample_fmts(void); /** - * Return a format list which contains the intersection of the formats of - * a and b. Also, all the references of a, all the references of b, and - * a and b themselves will be deallocated. - * - * If a and b do not share any common formats, neither is modified, and NULL - * is returned. - */ -AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, - enum AVMediaType type); - -/** * Add *ref as a new reference to formats. * That is the pointers will point like in the ascii art below: * ________ |