aboutsummaryrefslogtreecommitdiffstats
path: root/libavfilter/formats.c
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2023-12-31 13:35:03 -0800
committerNiklas Haas <git@haasn.dev>2023-12-31 13:35:03 -0800
commit8c7934f73ab6c568acaa47c821a6833f9145fdbb (patch)
tree1c7667bcabbe3ca66a65ac59bab34444f30ba5bb /libavfilter/formats.c
parente687a8485425e3d03ad8fea35b17ac8827ea1b82 (diff)
downloadffmpeg-8c7934f73ab6c568acaa47c821a6833f9145fdbb.tar.gz
avfilter: add negotiation API for color space/range
Motivated by YUVJ removal. This change will allow full negotiation between color ranges and matrices as needed. By default, all ranges and matrices are marked as supported. Because grayscale formats are currently handled very inconsistently (and in particular, assumed as forced full-range by swscale), we exclude them from negotiation altogether for the time being, to get this API merged. After filter negotiation is available, we can relax the grayscale-is-forced-jpeg restriction again, when it will be more feasible to do so without breaking a million test cases. Note that this commit updates one FATE test as a consequence of the sanity fallback for non-YUV formats. In particular, the test case now writes rgb24(pc, gbr/unspecified/unspecified) to the matroska file, instead of rgb24(unspecified/unspecified/unspecified) as before.
Diffstat (limited to 'libavfilter/formats.c')
-rw-r--r--libavfilter/formats.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 114886aeb2..681f0b1203 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -321,12 +321,46 @@ static int merge_channel_layouts(void *a, void *b)
return merge_channel_layouts_internal(a, b, 0);
}
+static int merge_generic_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, 0);
+
+ return 1;
+}
+
+static int can_merge_generic(const void *a, const void *b)
+{
+ return merge_generic_internal((AVFilterFormats *)a,
+ (AVFilterFormats *)b, 1);
+}
+
+static int merge_generic(void *a, void *b)
+{
+ return merge_generic_internal(a, b, 0);
+}
+
static const AVFilterFormatsMerger mergers_video[] = {
{
.offset = offsetof(AVFilterFormatsConfig, formats),
.merge = merge_pix_fmts,
.can_merge = can_merge_pix_fmts,
},
+ {
+ .offset = offsetof(AVFilterFormatsConfig, color_spaces),
+ .merge = merge_generic,
+ .can_merge = can_merge_generic,
+ },
+ {
+ .offset = offsetof(AVFilterFormatsConfig, color_ranges),
+ .merge = merge_generic,
+ .can_merge = can_merge_generic,
+ },
};
static const AVFilterFormatsMerger mergers_audio[] = {
@@ -594,6 +628,33 @@ AVFilterChannelLayouts *ff_all_channel_counts(void)
return ret;
}
+AVFilterFormats *ff_all_color_spaces(void)
+{
+ AVFilterFormats *ret = NULL;
+ if (ff_add_format(&ret, AVCOL_SPC_UNSPECIFIED) < 0)
+ return NULL;
+ for (int csp = 0; csp < AVCOL_SPC_NB; csp++) {
+ if (csp == AVCOL_SPC_RESERVED ||
+ csp == AVCOL_SPC_UNSPECIFIED)
+ continue;
+ if (ff_add_format(&ret, csp) < 0)
+ return NULL;
+ }
+
+ return ret;
+}
+
+AVFilterFormats *ff_all_color_ranges(void)
+{
+ AVFilterFormats *ret = NULL;
+ for (int range = 0; range < AVCOL_RANGE_NB; range++) {
+ if (ff_add_format(&ret, range) < 0)
+ return NULL;
+ }
+
+ return ret;
+}
+
#define FORMATS_REF(f, ref, unref_fn) \
void *tmp; \
\
@@ -763,6 +824,42 @@ int ff_set_common_all_samplerates(AVFilterContext *ctx)
return ff_set_common_samplerates(ctx, ff_all_samplerates());
}
+int ff_set_common_color_spaces(AVFilterContext *ctx,
+ AVFilterFormats *color_spaces)
+{
+ SET_COMMON_FORMATS(ctx, color_spaces, AVMEDIA_TYPE_VIDEO,
+ ff_formats_ref, ff_formats_unref);
+}
+
+int ff_set_common_color_spaces_from_list(AVFilterContext *ctx,
+ const int *color_ranges)
+{
+ return ff_set_common_color_spaces(ctx, ff_make_format_list(color_ranges));
+}
+
+int ff_set_common_all_color_spaces(AVFilterContext *ctx)
+{
+ return ff_set_common_color_spaces(ctx, ff_all_color_spaces());
+}
+
+int ff_set_common_color_ranges(AVFilterContext *ctx,
+ AVFilterFormats *color_ranges)
+{
+ SET_COMMON_FORMATS(ctx, color_ranges, AVMEDIA_TYPE_VIDEO,
+ ff_formats_ref, ff_formats_unref);
+}
+
+int ff_set_common_color_ranges_from_list(AVFilterContext *ctx,
+ const int *color_ranges)
+{
+ return ff_set_common_color_ranges(ctx, ff_make_format_list(color_ranges));
+}
+
+int ff_set_common_all_color_ranges(AVFilterContext *ctx)
+{
+ return ff_set_common_color_ranges(ctx, ff_all_color_ranges());
+}
+
/**
* A helper for query_formats() which sets all links to the same list of
* formats. If there are no links hooked to this filter, the list of formats is
@@ -818,6 +915,14 @@ int ff_default_query_formats(AVFilterContext *ctx)
ret = ff_set_common_formats(ctx, formats);
if (ret < 0)
return ret;
+ if (type != AVMEDIA_TYPE_AUDIO) {
+ ret = ff_set_common_all_color_spaces(ctx);
+ if (ret < 0)
+ return ret;
+ ret = ff_set_common_all_color_ranges(ctx);
+ if (ret < 0)
+ return ret;
+ }
if (type != AVMEDIA_TYPE_VIDEO) {
ret = ff_set_common_all_channel_counts(ctx);
if (ret < 0)
@@ -936,6 +1041,22 @@ int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts)
return check_list(log, "sample rate", fmts);
}
+int ff_formats_check_color_spaces(void *log, const AVFilterFormats *fmts)
+{
+ for (int i = 0; fmts && i < fmts->nb_formats; i++) {
+ if (fmts->formats[i] == AVCOL_SPC_RESERVED) {
+ av_log(log, AV_LOG_ERROR, "Invalid color range\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ return check_list(log, "color space", fmts);
+}
+
+int ff_formats_check_color_ranges(void *log, const AVFilterFormats *fmts)
+{
+ return check_list(log, "color range", fmts);
+}
+
static int layouts_compatible(const AVChannelLayout *a, const AVChannelLayout *b)
{
return !av_channel_layout_compare(a, b) ||