It makes the code clearer and will allow adding new stages of negotiation easier.
Signed-off-by: Nicolas George <geo...@nsup.org> --- libavfilter/avfiltergraph.c | 96 +++++++++++++----------------- libavfilter/formats.c | 114 ++++++++++++++++++++++++++++++++---- libavfilter/formats.h | 41 ++++--------- 3 files changed, 157 insertions(+), 94 deletions(-) diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 5389d82d9f..37f09cb686 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -458,48 +458,41 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) for (j = 0; j < filter->nb_inputs; j++) { AVFilterLink *link = filter->inputs[j]; + const AVFilterNegotiation *neg; + unsigned neg_step; int convert_needed = 0; if (!link) continue; - if (link->incfg.formats != link->outcfg.formats - && link->incfg.formats && link->outcfg.formats) - if (!ff_can_merge_formats(link->incfg.formats, link->outcfg.formats, - link->type)) + neg = ff_filter_get_negotiation(link); + av_assert0(neg); + for (neg_step = 1; neg_step < neg->nb; neg_step++) { + const AVFilterFormatsMerger *m = &neg->mergers[neg_step]; + void *a = FF_FIELD_AT(void *, m->offset, link->incfg); + void *b = FF_FIELD_AT(void *, m->offset, link->outcfg); + if (a && b && a != b && !m->can_merge(a, b)) { convert_needed = 1; - if (link->type == AVMEDIA_TYPE_AUDIO) { - if (link->incfg.samplerates != link->outcfg.samplerates - && link->incfg.samplerates && link->outcfg.samplerates) - if (!ff_can_merge_samplerates(link->incfg.samplerates, - link->outcfg.samplerates)) - convert_needed = 1; - } - -#define CHECKED_MERGE(field, ...) ((ret = ff_merge_ ## field(__VA_ARGS__)) <= 0) -#define MERGE_DISPATCH(field, ...) \ - if (!(link->incfg.field && link->outcfg.field)) { \ - count_delayed++; \ - } else if (link->incfg.field == link->outcfg.field) { \ - count_already_merged++; \ - } else if (!convert_needed) { \ - count_merged++; \ - if (CHECKED_MERGE(field, __VA_ARGS__)) { \ - if (ret < 0) \ - return ret; \ - convert_needed = 1; \ - } \ + break; + } } - - if (link->type == AVMEDIA_TYPE_AUDIO) { - MERGE_DISPATCH(channel_layouts, link->incfg.channel_layouts, - link->outcfg.channel_layouts) - MERGE_DISPATCH(samplerates, link->incfg.samplerates, - link->outcfg.samplerates) + for (neg_step = 0; neg_step < neg->nb; neg_step++) { + const AVFilterFormatsMerger *m = &neg->mergers[neg_step]; + void *a = FF_FIELD_AT(void *, m->offset, link->incfg); + void *b = FF_FIELD_AT(void *, m->offset, link->outcfg); + if (!(a && b)) { + count_delayed++; + } else if (a == b) { + count_already_merged++; + } else if (!convert_needed) { + count_merged++; + ret = m->merge(a, b); + if (ret < 0) + return ret; + if (!ret) + convert_needed = 1; + } } - MERGE_DISPATCH(formats, link->incfg.formats, - link->outcfg.formats, link->type) -#undef MERGE_DISPATCH if (convert_needed) { AVFilterContext *convert; @@ -572,26 +565,21 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) av_assert0(outlink-> incfg.channel_layouts->refcount > 0); av_assert0(outlink->outcfg.channel_layouts->refcount > 0); } - if (CHECKED_MERGE(formats, inlink->incfg.formats, - inlink->outcfg.formats, inlink->type) || - CHECKED_MERGE(formats, outlink->incfg.formats, - outlink->outcfg.formats, outlink->type) || - inlink->type == AVMEDIA_TYPE_AUDIO && - (CHECKED_MERGE(samplerates, inlink->incfg.samplerates, - inlink->outcfg.samplerates) || - CHECKED_MERGE(channel_layouts, inlink->incfg.channel_layouts, - inlink->outcfg.channel_layouts)) || - outlink->type == AVMEDIA_TYPE_AUDIO && - (CHECKED_MERGE(samplerates, outlink->incfg.samplerates, - outlink->outcfg.samplerates) || - CHECKED_MERGE(channel_layouts, outlink->incfg.channel_layouts, - outlink->outcfg.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 AVERROR(ENOSYS); + for (neg_step = 0; neg_step < neg->nb; neg_step++) { + const AVFilterFormatsMerger *m = &neg->mergers[neg_step]; + void *ia = FF_FIELD_AT(void *, m->offset, inlink->incfg); + void *ib = FF_FIELD_AT(void *, m->offset, inlink->outcfg); + void *oa = FF_FIELD_AT(void *, m->offset, outlink->incfg); + void *ob = FF_FIELD_AT(void *, m->offset, outlink->outcfg); + if ((ret = m->merge(ia, ib)) <= 0 || + (ret = m->merge(oa, ob)) <= 0) { + 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 AVERROR(ENOSYS); + } } } } diff --git a/libavfilter/formats.c b/libavfilter/formats.c index 6c05b118c9..eceae8ba9c 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -100,6 +100,8 @@ static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b, int alpha1=0, alpha2=0; int chroma1=0, chroma2=0; + av_assert2(check || (a->refcount && b->refcount)); + if (a == b) return 1; @@ -132,43 +134,86 @@ static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b, return 1; } -int ff_can_merge_formats(const AVFilterFormats *a, const AVFilterFormats *b, - enum AVMediaType type) + +/** + * Check the formats lists for compatibility for merging without actually + * merging. + * + * @return 1 if they are compatible, 0 if not. + */ +static int can_merge_pix_fmts(const void *a, const void *b) { return merge_formats_internal((AVFilterFormats *)a, - (AVFilterFormats *)b, type, 1); + (AVFilterFormats *)b, AVMEDIA_TYPE_VIDEO, 1); +} + +/** + * Merge the formats 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. + */ +static int merge_pix_fmts(void *a, void *b) +{ + return merge_formats_internal(a, b, AVMEDIA_TYPE_VIDEO, 0); } -int ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b, - enum AVMediaType type) +/** + * See can_merge_pix_fmts(). + */ +static int can_merge_sample_fmts(const void *a, const void *b) { - av_assert2(a->refcount && b->refcount); - return merge_formats_internal(a, b, type, 0); + return merge_formats_internal((AVFilterFormats *)a, + (AVFilterFormats *)b, AVMEDIA_TYPE_AUDIO, 1); +} + +/** + * See merge_pix_fmts(). + */ +static int merge_sample_fmts(void *a, void *b) +{ + return merge_formats_internal(a, b, AVMEDIA_TYPE_AUDIO, 0); } static int merge_samplerates_internal(AVFilterFormats *a, AVFilterFormats *b, int check) { + av_assert2(check || (a->refcount && b->refcount)); if (a == b) return 1; MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 1); return 1; } -int ff_can_merge_samplerates(const AVFilterFormats *a, const AVFilterFormats *b) +/** + * See can_merge_pix_fmts(). + */ +static int can_merge_samplerates(const void *a, const void *b) { return merge_samplerates_internal((AVFilterFormats *)a, (AVFilterFormats *)b, 1); } -int ff_merge_samplerates(AVFilterFormats *a, AVFilterFormats *b) +/** + * See merge_pix_fmts(). + */ +static int merge_samplerates(void *a, void *b) { - av_assert2(a->refcount && b->refcount); return merge_samplerates_internal(a, b, 0); } -int ff_merge_channel_layouts(AVFilterChannelLayouts *a, - AVFilterChannelLayouts *b) +/** + * See merge_pix_fmts(). + */ +static int merge_channel_layouts(void *va, void *vb) { + AVFilterChannelLayouts *a = va; + AVFilterChannelLayouts *b = vb; uint64_t *channel_layouts; unsigned a_all = a->all_layouts + a->all_counts; unsigned b_all = b->all_layouts + b->all_counts; @@ -255,6 +300,51 @@ int ff_merge_channel_layouts(AVFilterChannelLayouts *a, return 1; } +static const AVFilterFormatsMerger mergers_video[] = { + { + .offset = offsetof(AVFilterFormatsConfig, formats), + .merge = merge_pix_fmts, + .can_merge = can_merge_pix_fmts, + }, +}; + +static const AVFilterFormatsMerger mergers_audio[] = { + { + .offset = offsetof(AVFilterFormatsConfig, channel_layouts), + .merge = merge_channel_layouts, + .can_merge = NULL, + }, + { + .offset = offsetof(AVFilterFormatsConfig, samplerates), + .merge = merge_samplerates, + .can_merge = can_merge_samplerates, + }, + { + .offset = offsetof(AVFilterFormatsConfig, formats), + .merge = merge_sample_fmts, + .can_merge = can_merge_sample_fmts, + }, +}; + +static const AVFilterNegotiation negotiate_video = { + .nb = FF_ARRAY_ELEMS(mergers_video), + .mergers = mergers_video, +}; + +static const AVFilterNegotiation negotiate_audio = { + .nb = FF_ARRAY_ELEMS(mergers_audio), + .mergers = mergers_audio, +}; + +const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link) +{ + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: return &negotiate_video; + case AVMEDIA_TYPE_AUDIO: return &negotiate_audio; + default: return NULL; + } +} + int ff_fmt_is_in(int fmt, const int *fmts) { const int *p; diff --git a/libavfilter/formats.h b/libavfilter/formats.h index 65acc939e3..7a1f8408ac 100644 --- a/libavfilter/formats.h +++ b/libavfilter/formats.h @@ -69,6 +69,19 @@ struct AVFilterFormats { struct AVFilterFormats ***refs; ///< references to this list }; +typedef struct AVFilterFormatMerger { + unsigned offset; + int (*merge)(void *a, void *b); + int (*can_merge)(const void *a, const void *b); +} AVFilterFormatsMerger; + +typedef struct AVFilterNegotiation { + unsigned nb; + const AVFilterFormatsMerger *mergers; +} AVFilterNegotiation; + +const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link); + /** * A list of supported channel layouts. * @@ -108,34 +121,6 @@ struct AVFilterChannelLayouts { #define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \ (int)((l) & 0x7FFFFFFF) : 0) -/** - * Check the formats/samplerates lists for compatibility for merging - * without actually merging. - * - * @return 1 if they are compatible, 0 if not. - */ -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 -- * representing any channel layout (with known disposition)/sample rate. -- 2.30.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".