[FFmpeg-cvslog] swscale/utils: add helper function to infer colorspace metadata

Niklas Haas git at videolan.org
Mon Dec 23 13:44:32 EET 2024


ffmpeg | branch: master | Niklas Haas <git at haasn.dev> | Thu Nov 28 13:49:23 2024 +0100| [1f0c5007840932b30c162982219750f8c9ed89c7] | committer: Niklas Haas

swscale/utils: add helper function to infer colorspace metadata

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.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=1f0c5007840932b30c162982219750f8c9ed89c7
---

 libswscale/utils.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 libswscale/utils.h |  3 +++
 2 files changed, 69 insertions(+)

diff --git a/libswscale/utils.c b/libswscale/utils.c
index ff0ff41ad8..da1f4954bc 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -2805,6 +2805,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 0ab526b20b..6ffefbf6c3 100644
--- a/libswscale/utils.h
+++ b/libswscale/utils.h
@@ -117,4 +117,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 */



More information about the ffmpeg-cvslog mailing list