[FFmpeg-devel] [PATCH 2/2] lavfi/formats: put merge functions in structures.
Nicolas George
george at nsup.org
Sat Jul 24 18:29:47 EEST 2021
It makes the code clearer and will allow adding new stages
of negotiation easier.
Signed-off-by: Nicolas George <george at 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
More information about the ffmpeg-devel
mailing list