[FFmpeg-devel] [PATCH v2 06/16] swscale/utils: add helper function to infer colorspace metadata

Niklas Haas ffmpeg at haasn.xyz
Fri Dec 6 16:32:05 EET 2024


From: Niklas Haas <git at haasn.dev>

Logic is loosely on equivalent decisions in libplacebo. The basic idea is to try
and be a bit conservative by treating AVCOL_*_UNSPECIFIED as a no-op, unless the
other primaries set are non-standard / wide-gamut or HDR. This helps avoid
unintended or unexpected colorspace conversions, while forcing it in cases where
we are almost certain it is needed. The major departure from libplacebo semantics
is that we no default to a 1000:1 contrast ration for SDR displays, instead modelling
them as idealized devices with an infinite contrast ratio.

In either case, setting SWS_STRICT overrides this behavior in favor of always
requiring explicit colorspace metadata.
---
 libswscale/utils.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
 libswscale/utils.h |  3 +++
 2 files changed, 69 insertions(+)

diff --git a/libswscale/utils.c b/libswscale/utils.c
index b097ec51b2..adbfda10a5 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -2802,6 +2802,72 @@ skip_hdr10:
     return fmt;
 }
 
+static int infer_prim_ref(SwsColor *csp, const SwsColor *ref)
+{
+    if (csp->prim != AVCOL_PRI_UNSPECIFIED)
+        return 0;
+
+    /* Re-use the reference gamut only for "safe", similar primaries */
+    switch (ref->prim) {
+    case AVCOL_PRI_BT709:
+    case AVCOL_PRI_BT470M:
+    case AVCOL_PRI_BT470BG:
+    case AVCOL_PRI_SMPTE170M:
+    case AVCOL_PRI_SMPTE240M:
+        csp->prim  = ref->prim;
+        csp->gamut = ref->gamut;
+        break;
+    default:
+        csp->prim  = AVCOL_PRI_BT709;
+        csp->gamut = av_csp_primaries_desc_from_id(csp->prim)->prim;
+        break;
+    }
+
+    return 1;
+}
+
+static int infer_trc_ref(SwsColor *csp, const SwsColor *ref)
+{
+    if (csp->trc != AVCOL_TRC_UNSPECIFIED)
+        return 0;
+
+    /* Pick a suitable SDR transfer function, to try and minimize conversions */
+    switch (ref->trc) {
+    case AVCOL_TRC_UNSPECIFIED:
+    /* HDR curves, never default to these */
+    case AVCOL_TRC_SMPTE2084:
+    case AVCOL_TRC_ARIB_STD_B67:
+        csp->trc = AVCOL_TRC_BT709;
+        csp->min_luma = av_make_q(0, 1);
+        csp->max_luma = av_make_q(203, 1);
+        break;
+    default:
+        csp->trc = ref->trc;
+        csp->min_luma = ref->min_luma;
+        csp->max_luma = ref->max_luma;
+        break;
+    }
+
+    return 1;
+}
+
+int ff_infer_colors(SwsColor *src, SwsColor *dst)
+{
+    int incomplete = 0;
+
+    incomplete |= infer_prim_ref(dst, src);
+    incomplete |= infer_prim_ref(src, dst);
+    av_assert0(src->prim != AVCOL_PRI_UNSPECIFIED);
+    av_assert0(dst->prim != AVCOL_PRI_UNSPECIFIED);
+
+    incomplete |= infer_trc_ref(dst, src);
+    incomplete |= infer_trc_ref(src, dst);
+    av_assert0(src->trc != AVCOL_TRC_UNSPECIFIED);
+    av_assert0(dst->trc != AVCOL_TRC_UNSPECIFIED);
+
+    return incomplete;
+}
+
 int sws_test_format(enum AVPixelFormat format, int output)
 {
     return output ? sws_isSupportedOutput(format) : sws_isSupportedInput(format);
diff --git a/libswscale/utils.h b/libswscale/utils.h
index 1263e3f8ed..69ae7da39f 100644
--- a/libswscale/utils.h
+++ b/libswscale/utils.h
@@ -112,4 +112,7 @@ static inline int ff_fmt_align(enum AVPixelFormat fmt)
 
 int ff_test_fmt(const SwsFormat *fmt, int output);
 
+/* Returns 1 if the formats are incomplete, 0 otherwise */
+int ff_infer_colors(SwsColor *src, SwsColor *dst);
+
 #endif /* SWSCALE_UTILS_H */
-- 
2.47.0



More information about the ffmpeg-devel mailing list