[FFmpeg-devel] [PATCH 15/17] swscale/graph: add color mapping pass

Niklas Haas ffmpeg at haasn.xyz
Thu Dec 5 13:30:24 EET 2024


From: Niklas Haas <git at haasn.dev>

This leverages the previously introduced color management subsystem in order
to adapt between transfer functions and color spaces, as well as for HDR tone
mapping.
---
 libswscale/graph.c | 81 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/libswscale/graph.c b/libswscale/graph.c
index 34621c784b..5a2d7947fc 100644
--- a/libswscale/graph.c
+++ b/libswscale/graph.c
@@ -30,6 +30,8 @@
 #include "libswscale/swscale.h"
 #include "libswscale/utils.h"
 
+#include "cms.h"
+#include "lut3d.h"
 #include "swscale_internal.h"
 #include "graph.h"
 
@@ -463,6 +465,75 @@ static int add_legacy_sws_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst,
     return 0;
 }
 
+/**************************
+ * Gamut and tone mapping *
+ **************************/
+
+static void free_lut3d(void *priv)
+{
+    SwsLut3D *lut = priv;
+    sws_lut3d_free(&lut);
+}
+
+static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base,
+                      int y, int h, const SwsPass *pass)
+{
+    SwsLut3D *lut = pass->priv;
+    const SwsImg in  = shift_img(in_base,  y);
+    const SwsImg out = shift_img(out_base, y);
+
+    sws_lut3d_apply(lut, in.data[0], in.linesize[0], out.data[0],
+                    out.linesize[0], pass->width, h);
+}
+
+static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst,
+                        SwsPass *input, SwsPass **output)
+{
+    enum AVPixelFormat fmt_in, fmt_out;
+    SwsLut3D *lut;
+    SwsPass *pass;
+    int ret;
+
+    SwsColorMap map = {
+        .intent = graph->ctx->intent,
+        .src    = src.color,
+        .dst    = dst.color,
+    };
+
+    if (sws_color_map_noop(&map))
+        return 0;
+
+    lut = sws_lut3d_alloc();
+    if (!lut)
+        return AVERROR(ENOMEM);
+
+    fmt_in  = sws_lut3d_pick_pixfmt(src, 0);
+    fmt_out = sws_lut3d_pick_pixfmt(dst, 1);
+    if (fmt_in != src.format) {
+        SwsFormat tmp = src;
+        tmp.format = fmt_in;
+        ret = add_legacy_sws_pass(graph, src, tmp, input, &input);
+        if (ret < 0)
+            return ret;
+    }
+
+    ret = sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
+    if (ret < 0) {
+        sws_lut3d_free(&lut);
+        return ret;
+    }
+
+    pass = pass_add(graph, lut, fmt_out, src.width, src.height,
+                    input, 1, run_lut3d);
+    if (!pass) {
+        sws_lut3d_free(&lut);
+        return AVERROR(ENOMEM);
+    }
+    pass->free = free_lut3d;
+
+    *output = pass;
+    return 0;
+}
 
 /***************************************
  * Main filter graph construction code *
@@ -470,11 +541,17 @@ static int add_legacy_sws_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst,
 
 static int init_passes(SwsGraph *graph)
 {
-    const SwsFormat src = graph->src;
-    const SwsFormat dst = graph->dst;
+    SwsFormat src = graph->src;
+    SwsFormat dst = graph->dst;
     SwsPass *pass = NULL; /* read from main input image */
     int ret;
 
+    ret = adapt_colors(graph, src, dst, pass, &pass);
+    if (ret < 0)
+        return ret;
+    src.format = pass ? pass->format : src.format;
+    src.color  = dst.color;
+
     if (!ff_fmt_equal(&src, &dst)) {
         ret = add_legacy_sws_pass(graph, src, dst, pass, &pass);
         if (ret < 0)
-- 
2.47.0



More information about the ffmpeg-devel mailing list