[vlc-devel] [PATCH] Enable display color correction from ICC profile provided by user (opengl output only) - Add file search menu to opengl menu - File reading and RGB correction table creation with Lcms - Correction is applied by GPU via OpenGL 3D-LUT interpolation (GLSL >= 3.3) - Inserted within liplacebo processings as libplacebo already requires Lcms

Fabien fabi_motta at hotmail.fr
Fri May 5 14:48:36 UTC 2023


---
 modules/video_output/Makefile.am              |   2 +-
 modules/video_output/opengl/converter.h       |   9 +
 modules/video_output/opengl/display.c         |  22 ++
 .../video_output/opengl/fragment_shaders.c    |  44 +++
 modules/video_output/opengl/vout_helper.c     | 333 ++++++++++++++++++
 modules/video_output/opengl/vout_helper.h     |  30 ++
 6 files changed, 439 insertions(+), 1 deletion(-)

diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index da559cf329..74e147c77c 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -8,7 +8,7 @@ OPENGL_COMMONSOURCES = video_output/opengl/vout_helper.c \
 	video_output/opengl/internal.h video_output/opengl/fragment_shaders.c \
 	video_output/opengl/converter_sw.c
 
-OPENGL_COMMONCLFAGS = $(LIBPLACEBO_CFLAGS)
+OPENGL_COMMONCLFAGS = $(LIBPLACEBO_CFLAGS) -llcms2
 OPENGL_COMMONLIBS = $(LIBPLACEBO_LIBS)
 
 if HAVE_DECKLINK
diff --git a/modules/video_output/opengl/converter.h b/modules/video_output/opengl/converter.h
index 7000e1f38e..dc0b14c589 100644
--- a/modules/video_output/opengl/converter.h
+++ b/modules/video_output/opengl/converter.h
@@ -170,6 +170,9 @@ typedef struct {
     PFNGLGETSTRINGPROC      GetString;
     PFNGLPIXELSTOREIPROC    PixelStorei;
     PFNGLTEXIMAGE2DPROC     TexImage2D;
+    /* <color_correction> */
+    PFNGLTEXIMAGE3DPROC     TexImage3D;
+    /* </color_correction> */
     PFNGLTEXPARAMETERFPROC  TexParameterf;
     PFNGLTEXPARAMETERIPROC  TexParameteri;
     PFNGLTEXSUBIMAGE2DPROC  TexSubImage2D;
@@ -339,6 +342,12 @@ struct opengl_tex_converter_t
 
     struct pl_shader *pl_sh;
     const struct pl_shader_res *pl_sh_res;
+    /* <color_correction>
+    Data needed to the icc color correction LUT (Texture3D) */
+    GLint clutId;
+    GLuint clut_tex;
+    GLfloat *g_3dlut;
+    /*</color_correction> */
 
     /* Private context */
     void *priv;
diff --git a/modules/video_output/opengl/display.c b/modules/video_output/opengl/display.c
index ec671109bc..f0c0393b97 100644
--- a/modules/video_output/opengl/display.c
+++ b/modules/video_output/opengl/display.c
@@ -69,6 +69,28 @@ vlc_module_begin ()
                 GL_TEXT, PROVIDER_LONGTEXT, true)
 #endif
     add_glopts ()
+
+/* <color_correction> */
+#ifdef HAVE_LIBPLACEBO
+    set_section("ICC profile color correction", NULL) \
+    add_loadfile("icc_profile", "", "File path to display icc profile",\
+                 "File path to an icc profile (.icc, .icm) for color \
+                 correction by a 3DLut generated at video beginning \
+                 (can take a few seconds, depending on your machine).", true )
+    add_integer("icc_bp_offset_mode", ICC_BP_MODE_DEFAULT, "Black point offset mode",\
+    "Black point offset evaluation mode, change this if image constrast\
+    is not satisfactory.", true) \
+    change_integer_list( icc_bp_mode_list, icc_bp_mode_text) \
+    add_float("icc_bp_offset", 0.05, "Black point offset [0.0;1.0]", "Modify this \
+    if image is too dark (increase it), or too light (decrease it). As a\
+    starting point, select VLC estimation mode, launch VLC in debugging mode\
+    (-vv) and look for black point offset estimation values in the messages.",\
+     true ) \
+     add_bool("force_bt709", false, "Force BT709 colorspace (HDTV)", "Try this \
+          with webcam or usb sources if colors seem wrong.", true)
+#endif
+/* </color_correction> */
+
 vlc_module_end ()
 
 struct vout_display_sys_t
diff --git a/modules/video_output/opengl/fragment_shaders.c b/modules/video_output/opengl/fragment_shaders.c
index 2246e33afd..89a10059af 100644
--- a/modules/video_output/opengl/fragment_shaders.c
+++ b/modules/video_output/opengl/fragment_shaders.c
@@ -363,6 +363,14 @@ tc_base_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
         struct pl_shader_var sv = res->variables[i];
         tc->uloc.pl_vars[i] = tc->vt->GetUniformLocation(program, sv.var.name);
     }
+
+    /* <color_correction> */
+    if ( tc->g_3dlut != NULL ) {
+        tc->clutId = tc->vt->GetUniformLocation(program, "clut3d");
+        if (tc->clutId == -1)
+            return VLC_EGENERIC;
+    }
+    /* </color_correction> */
 #endif
 
     return VLC_SUCCESS;
@@ -429,6 +437,11 @@ tc_base_prepare_shader(const opengl_tex_converter_t *tc,
             break;
         }
     }
+
+    /* <color_correction> */
+    if ( tc->g_3dlut != NULL )
+        tc->vt->Uniform1i(tc->clutId, tc->tex_count );
+    /* </color_correction> */
 #endif
 }
 
@@ -600,6 +613,25 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
     if (vlc_memstream_open(&ms) != 0)
         return 0;
 
+/* <color_correction>
+ * Forcing GLSL 3.3 to be able to use TexImage3D */
+#ifdef HAVE_LIBPLACEBO
+    if ( tc->g_3dlut != NULL ) {
+        if ( tc->glsl_version < 300 ) {
+            msg_Warn(tc->gl,"GLSL version used by VLC is %u", tc->glsl_version);
+            tc->glsl_version = 330;
+            msg_Warn(tc->gl,"Forcing the use of %u glsl version", \
+            tc->glsl_version);
+        }
+
+        else {
+           msg_Dbg(tc->gl,"Using %u glsl version, \n%s", tc->glsl_version, \
+            tc->glsl_precision_header);
+        }
+    }
+#endif
+/* </color_correction> */
+
 #define ADD(x) vlc_memstream_puts(&ms, x)
 #define ADDF(x, ...) vlc_memstream_printf(&ms, x, ##__VA_ARGS__)
 
@@ -703,6 +735,13 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
     if (is_yuv)
         ADD("uniform vec4 Coefficients[4];\n");
 
+/* <color_correction> */
+#ifdef HAVE_LIBPLACEBO
+    if ( tc->g_3dlut != NULL )
+        ADD("uniform sampler3D clut3d ;\n");
+#endif
+/* </color_correction> */
+
     ADD("uniform vec4 FillColor;\n"
         "void main(void) {\n"
         " float val;vec4 colors;\n");
@@ -770,7 +809,12 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
         assert(res->input  == PL_SHADER_SIG_COLOR);
         assert(res->output == PL_SHADER_SIG_COLOR);
         ADDF(" result = %s(result);\n", res->name);
+
     }
+    /* <color_correction> */
+    if ( tc->g_3dlut != NULL )
+        ADD(" result.rgb = texture( clut3d, result.rgb ).rgb;\n" );
+    /* </color_correction> */
 #endif
 
     ADD(" gl_FragColor = result * FillColor;\n"
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index 13d65e04c8..74de9309e9 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -43,6 +43,11 @@
 
 #include "vout_helper.h"
 #include "internal.h"
+/* <color_correction> */
+#ifdef HAVE_LIBPLACEBO
+#include <lcms2.h>
+#endif
+/* </color_correction> */
 
 #ifndef GL_CLAMP_TO_EDGE
 # define GL_CLAMP_TO_EDGE 0x812F
@@ -572,6 +577,11 @@ opengl_deinit_program(vout_display_opengl_t *vgl, struct prgm *prgm)
     FREENULL(tc->uloc.pl_vars);
     if (tc->pl_ctx)
         pl_context_destroy(&tc->pl_ctx);
+
+    /* <color_correction> */
+    if ( tc->g_3dlut != NULL )
+        free( tc->g_3dlut );
+    /* </color_correction> */
 #endif
 
     vlc_object_release(tc);
@@ -640,6 +650,47 @@ opengl_init_program(vout_display_opengl_t *vgl, struct prgm *prgm,
 #   endif
         }
     }
+
+    /* <color_correction> */
+    /* Icc file reading, GLSL version check, 3D LUT allocation */
+    if (!subpics) {
+        tc->g_3dlut = NULL;
+
+        char *filename = var_InheritString( tc->gl, "icc_profile" );
+        if ( filename != NULL ) {
+
+            char *glsl_version;
+            glsl_version = (char*) tc->vt->GetString(GL_SHADING_LANGUAGE_VERSION );
+            msg_Dbg( tc->gl, "Available GLSL version %s", glsl_version );
+            if ( atof( glsl_version ) < 2.99 ) {
+              msg_Dbg( tc->gl, "Max available GLSL version %s too old for color\
+               correction (needs version > 3.3 )",\
+                     glsl_version );
+            }
+            else {
+
+                tc->g_3dlut = ( GLfloat* ) malloc( sizeof(GLfloat) * \
+                            g_3d_lut_size * g_3d_lut_size * g_3d_lut_size * 3 );
+                if ( tc->g_3dlut == NULL ) {
+                    msg_Dbg( tc->gl, "Could not allocate color correction table");
+                }
+                else {
+                    int err = CreateCorrectionLUT( tc->g_3dlut, tc->gl, fmt, filename );
+                    if ( err != VLC_SUCCESS ) {
+                        msg_Dbg( tc->gl, "Could not create Color Correction LUT, \
+                        disabling color correction" );
+                        free( tc->g_3dlut );
+                        tc->g_3dlut = NULL;
+                    }
+                }
+            }
+        }
+        else {
+            msg_Dbg( tc->gl, "Absent or invalid path to icc correction profile, \
+            disabling color correction" );
+        }
+    }
+    /* </color_correction> */
 #endif
 
     int ret;
@@ -736,6 +787,255 @@ ResizeFormatToGLMaxTexSize(video_format_t *fmt, unsigned int max_tex_size)
     }
 }
 
+/* <color_correction>
+ * Creates the 3D-LUT from image/video reported colorspace, icc profile file
+ * and lcms2 functions
+ */
+#ifdef HAVE_LIBPLACEBO
+int CreateCorrectionLUT( GLfloat *lut, vlc_gl_t *gl, \
+                         const video_format_t *fmt, char *filename )
+{
+    /* Some colorimetric data for BT601/709/2020 and sRGB standards which are
+     * the only provided by VLC video format
+     * D65 whitepoint is common to all these standards
+     * The primaries and tone response curve (TRC) differ between BT and sRGB
+     * We use LittleCMS to compute the correction 3DLUT
+     * Video profile is built with LCMS routines
+     * Display profile is read from the path given by the user in the advanced
+     * configuration parameters. */
+
+    struct trc_param {
+        uint8_t          type_nb;
+        cmsFloat64Number param[10];
+    };
+
+    static cmsCIExyY d65_wp = { 0.3127, 0.3290, 1.0 };
+
+    static cmsCIExyYTRIPLE bt709_prim = { { 0.640, 0.330, 1.00 }, \
+                                          { 0.300, 0.600, 1.00 }, \
+                                          { 0.150, 0.060, 1.00 } };
+
+    static cmsCIExyYTRIPLE bt601_525_prim = { { 0.630, 0.340, 1.00 }, \
+                                              { 0.310, 0.595, 1.00 }, \
+                                              { 0.155, 0.070, 1.00 } };
+
+    static cmsCIExyYTRIPLE bt601_625_prim = { { 0.640, 0.330, 1.00 }, \
+                                              { 0.290, 0.600, 1.00 }, \
+                                              { 0.150, 0.060, 1.00 } };
+
+    static cmsCIExyYTRIPLE bt2020_prim = { { 0.708, 0.292, 1.0 }, \
+                                           { 0.170, 0.797, 1.0 }, \
+                                           { 0.131, 0.046, 1.0 } };
+
+    static struct trc_param srgb_trc_params = { \
+        4, { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 } };
+
+    /* The Tone Response Curve (or Gamma curve) values are the same for BT709,
+     * BT601 and BT2020.
+     * They depend on the display black point luminance, according to BT1886,
+     * one per color component. Below are default values, but they will be
+     * computed at correction initialisation */
+    static struct trc_param bt_trc_params = { 6, { 2.4, 0.94, 0.06, 0. } };
+
+
+
+    // Icc profile correction cLUT computation
+    // First, creatign a profile from video format colorspace data
+    msg_Dbg(gl, "Create source colorspace profile from video format");
+    cmsToneCurve *trc[3];
+
+    cmsContext cms_ctx = cmsCreateContext(NULL, NULL);
+
+    if ( cms_ctx == NULL) {
+        msg_Dbg( gl,"Could not create cms context\n" );
+        return VLC_ENOMEM;
+    }
+
+    msg_Dbg( gl, "User icc profile path %s", filename );
+    cmsHPROFILE  hOutProfile = cmsOpenProfileFromFile( filename, "r");
+    if ( hOutProfile == NULL ) {
+        msg_Dbg( gl, "Could not read user display icc profile" );
+        return VLC_ENOMEM;
+    }
+
+    /* Building TRC curve for BT standards according to BT 1886 recommendations
+    *  It requires the black point of the display to build a modified
+    *  gamma 2.4 curve.
+    *  This type of curve corresponds to type number 6 for lcms
+    *  Determination of black point offset is skipped if a user value is provi-
+    *  ded. */
+    float bp_offset[3];
+    int icc_bp_offset_mode = var_InheritInteger(gl, "icc_bp_offset_mode");
+    msg_Dbg( gl, "Black point offset mode = %s",\
+                  icc_bp_mode_text[ icc_bp_offset_mode ]  );
+
+    switch ( icc_bp_offset_mode )
+    {
+        case ICC_BP_MODE_USER:
+            bp_offset[0] = var_InheritFloat(gl, "icc_bp_offset");
+            bp_offset[0] = fminf( fmaxf( 0.0, bp_offset[0] ), 1.0 );
+            msg_Dbg( gl, "Black point offset provided by user = %f", bp_offset[0] );
+            bp_offset[1] = bp_offset[0];
+            bp_offset[2] = bp_offset[0];
+            break;
+
+        case ICC_BP_MODE_VLC:
+            float bp_XYZ[3], bp_rgb[3];
+            cmsCIEXYZ cms_bp_XYZ;
+            cmsDetectBlackPoint( &cms_bp_XYZ, hOutProfile,\
+                                 INTENT_RELATIVE_COLORIMETRIC, 0);
+            bp_XYZ[0] = cms_bp_XYZ.X;
+            bp_XYZ[1] = cms_bp_XYZ.Y;
+            bp_XYZ[2] = cms_bp_XYZ.Z;
+
+            msg_Dbg( gl, "Detected black point in CIE XYZ = %f %f %f", \
+                     bp_XYZ[0], bp_XYZ[1], bp_XYZ[2] );
+
+            // Compute black point in BT709 components from XYZ
+
+            cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
+            cmsToneCurve *lin_trc = cmsBuildGamma( cms_ctx, 1.0);
+
+            cmsHPROFILE hInProfile_lin = cmsCreateRGBProfile( &d65_wp, \
+                &bt709_prim, \
+                ( cmsToneCurve*[3] ) { lin_trc, lin_trc, lin_trc } );
+
+            cmsHTRANSFORM hTransform = cmsCreateTransform( \
+                XYZProfile,  TYPE_XYZ_FLT, \
+                hInProfile_lin, TYPE_RGB_FLT, \
+                INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_HIGHRESPRECALC | \
+                                   cmsFLAGS_BLACKPOINTCOMPENSATION );
+
+            cmsDoTransform( hTransform, &bp_XYZ, &bp_rgb, 1 );
+
+            msg_Dbg( gl, "Detected black point in BT709 RGB lin = %f %f %f", \
+                 bp_rgb[0], bp_rgb[1], bp_rgb[2] );
+
+            bp_offset[0] = powf( bp_rgb[0], 1.0 / 2.4 );
+            bp_offset[1] = powf( bp_rgb[1], 1.0 / 2.4 );
+            bp_offset[2] = powf( bp_rgb[2], 1.0 / 2.4 );
+
+            cmsDeleteTransform( hTransform );
+            cmsCloseProfile( hInProfile_lin );
+            cmsCloseProfile( XYZProfile );
+            cmsFreeToneCurve( lin_trc );
+
+            break;
+
+            default:
+                bp_offset[0] = 0.05;
+                bp_offset[1] = 0.05;
+                bp_offset[2] = 0.05;
+
+    }
+
+    // Compute BT 1886 curve
+    bt_trc_params.param[0] = 2.4;
+    bt_trc_params.param[3] = 0.0;
+    for (int i = 0; i < 3 ; i++ ) {
+        bt_trc_params.param[2] = bp_offset[i];
+        msg_Dbg( gl, "Black point offset = %f", bt_trc_params.param[2] );
+        bt_trc_params.param[1] = 1.0 - bt_trc_params.param[2];
+        trc[i] = cmsBuildParametricToneCurve( cms_ctx, \
+            bt_trc_params.type_nb, bt_trc_params.param );
+        }
+
+    cmsCIExyYTRIPLE *m_prim;
+    int colorspace = fmt->space;
+    if ( var_InheritBool(gl, "force_bt709") ) {
+        colorspace = COLOR_SPACE_BT709;
+    }
+
+    switch ( colorspace ) {
+
+        case COLOR_SPACE_UNDEF:
+            msg_Dbg( gl, "Image colorspace is undefined, taking sRGB\n" );
+            trc[0] = cmsBuildParametricToneCurve( cms_ctx,\
+                                                  srgb_trc_params.type_nb, \
+                                                  srgb_trc_params.param );
+            trc[1] = cmsBuildParametricToneCurve( cms_ctx,\
+                                                  srgb_trc_params.type_nb, \
+                                                  srgb_trc_params.param );
+            trc[2] = cmsBuildParametricToneCurve( cms_ctx,\
+                                                  srgb_trc_params.type_nb, \
+                                                  srgb_trc_params.param );
+            // BT709 and sRGB have the same primaries
+            m_prim = &bt709_prim;
+            break;
+
+        case COLOR_SPACE_BT601:
+            msg_Dbg( gl, "Image colorspace is BT 601" );
+
+            if ( fmt->i_height > 500 ) {
+                msg_Dbg( gl, "Detected PAL, adjusting RGB primaries" );
+                m_prim = &bt601_625_prim;
+            }
+            else {
+                msg_Dbg( gl, "Detected NTSC, adjusting RGB primaries" );
+                m_prim = &bt601_525_prim;
+            }
+            break;
+
+        case COLOR_SPACE_BT2020:
+            msg_Dbg( gl, "Image colorspace is BT 2020" );
+            m_prim = &bt2020_prim;
+            break;
+
+        case COLOR_SPACE_BT709:
+            msg_Dbg( gl, "Image colorspace is BT 709" );
+            m_prim = &bt709_prim;
+            break;
+
+        default:
+            msg_Dbg( gl, "Image colorspace is unknown, taking BT 709" );
+            m_prim = &bt709_prim;
+
+    }
+
+    cmsHPROFILE hInProfile = cmsCreateRGBProfile( &d65_wp, m_prim, trc );
+    if ( hInProfile == NULL ) {
+        msg_Dbg( gl, "Could not create image colorspace profile" );
+        return VLC_EGENERIC;
+    }
+
+    msg_Dbg(gl, "Creating lcms Transform");
+    cmsHTRANSFORM hTransform = cmsCreateTransform( \
+        hInProfile,  TYPE_RGB_16, \
+        hOutProfile, TYPE_RGB_16, \
+        INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_HIGHRESPRECALC | \
+                           cmsFLAGS_BLACKPOINTCOMPENSATION );
+
+    msg_Dbg(gl, "Creating lut table");
+    uint16_t rgb[3], icc_rgb[3];
+    int index;
+    int ratio = ( 1 << (sizeof(uint16_t) * 8 ) ) / g_3d_lut_size;
+    for (int b = 0 ; b < g_3d_lut_size ; b++ ) {
+        for (int g = 0 ; g < g_3d_lut_size ; g++ ) {
+            for (int r = 0 ; r < g_3d_lut_size ; r++ ) {
+                rgb[0] = r * ratio;
+                rgb[1] = g * ratio;
+                rgb[2] = b * ratio;
+                cmsDoTransform( hTransform, &rgb, &icc_rgb, 1 );
+                index = ( ( b*g_3d_lut_size + g )*g_3d_lut_size + r )*3;
+                lut[ index ]    = (float) icc_rgb[0] /\
+                                  (float) ( g_3d_lut_size * ratio - 1 );
+                lut[ index + 1] = (float) icc_rgb[1] /\
+                                  (float) ( g_3d_lut_size * ratio - 1 );
+                lut[ index + 2] = (float) icc_rgb[2] /\
+                                  (float) ( g_3d_lut_size * ratio - 1 );
+            }
+        }
+    }
+    msg_Dbg(gl, "Lut table created");
+    cmsDeleteTransform( hTransform );
+    cmsCloseProfile(hInProfile);
+    cmsCloseProfile(hOutProfile);
+    cmsFreeToneCurveTriple(trc);
+    return VLC_SUCCESS;
+}
+#endif
+/* </color_correction> */
+
 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
                                                const vlc_fourcc_t **subpicture_chromas,
                                                vlc_gl_t *gl,
@@ -792,6 +1092,11 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     GET_PROC_ADDR_CORE(GetString);
     GET_PROC_ADDR_CORE(PixelStorei);
     GET_PROC_ADDR_CORE(TexImage2D);
+    /* <color_correction> */
+    #ifdef HAVE_LIBPLACEBO
+    GET_PROC_ADDR_CORE(TexImage3D);
+    #endif
+    /* </color_correction> */
     GET_PROC_ADDR_CORE(TexParameterf);
     GET_PROC_ADDR_CORE(TexParameteri);
     GET_PROC_ADDR_CORE(TexSubImage2D);
@@ -956,6 +1261,25 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
         }
     }
 
+    /* <color_correction> */
+#ifdef HAVE_LIBPLACEBO
+    if ( vgl->prgm->tc->g_3dlut != NULL ) {
+        vgl->vt.GenTextures(1, &vgl->prgm->tc->clut_tex);
+        vgl->vt.BindTexture(GL_TEXTURE_3D, vgl->prgm->tc->clut_tex);
+        vgl->vt.TexImage3D( GL_TEXTURE_3D, 0, GL_RGB,\
+                            g_3d_lut_size, g_3d_lut_size, g_3d_lut_size, 0,\
+                            GL_RGB, GL_FLOAT, vgl->prgm->tc->g_3dlut );
+        // Set sampling parameters, clamp to edge, weird colors otherwise
+        vgl->vt.TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        vgl->vt.TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        vgl->vt.TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        vgl->vt.TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        vgl->vt.TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+        msg_Dbg(gl, "Icc correction texture allocated");
+    }
+#endif
+/* </color_correction> */
+
     /* */
     vgl->vt.Disable(GL_BLEND);
     vgl->vt.Disable(GL_DEPTH_TEST);
@@ -1602,6 +1926,15 @@ static void DrawWithShaders(vout_display_opengl_t *vgl, struct prgm *prgm)
                                      0, 0, 0);
     }
 
+/* <color_correction> */
+ #ifdef HAVE_LIBPLACEBO
+    if ( vgl->prgm->tc->g_3dlut != NULL ) {
+        vgl->vt.ActiveTexture(GL_TEXTURE0  + vgl->prgm->tc->tex_count );
+        vgl->vt.BindTexture(GL_TEXTURE_3D, vgl->prgm->tc->clut_tex );
+    }
+#endif
+/* </color_correction> */
+
     vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->vertex_buffer_object);
     vgl->vt.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, vgl->index_buffer_object);
     vgl->vt.EnableVertexAttribArray(prgm->aloc.VertexPosition);
diff --git a/modules/video_output/opengl/vout_helper.h b/modules/video_output/opengl/vout_helper.h
index 48014b454c..dc20e347eb 100644
--- a/modules/video_output/opengl/vout_helper.h
+++ b/modules/video_output/opengl/vout_helper.h
@@ -33,6 +33,13 @@
 
 #ifdef HAVE_LIBPLACEBO
 #include <libplacebo/shaders/colorspace.h>
+/* <color correction
+ * A 3D LUT size of 256 bytes per channel is chosen to have a full correction of
+ * 8-bit images, and interpolation above
+ */
+#include <lcms2.h>
+static int g_3d_lut_size = 256;
+/* </color_correction> */
 
 # if PL_MAJOR_VER >= 5
 # define pl_context_create pl_log_create
@@ -226,6 +233,29 @@ static const char * const dither_text[] = {
             change_integer_list(dither_values, dither_text) \
     add_integer_with_range("dither-depth", 0, 0, 16, DEPTH_TEXT, DEPTH_LONGTEXT, false) \
     add_desat_params()
+
+    /* <color_correction> */
+    enum icc_bp_mode {
+        ICC_BP_MODE_DEFAULT = 0,
+        ICC_BP_MODE_VLC,
+        ICC_BP_MODE_USER
+    };
+
+    static const int icc_bp_mode_list[] = {
+        ICC_BP_MODE_DEFAULT,\
+        ICC_BP_MODE_VLC,
+        ICC_BP_MODE_USER
+    };
+
+    static const char * const icc_bp_mode_text[] = {
+        "Default value (0.05)",\
+        "VLC estimation from profile",\
+        "User defined value"
+    };
+
+    int CreateCorrectionLUT( GLfloat *g_3dlut, vlc_gl_t *gl, \
+                         const video_format_t *fmt, char *filename );
+    /* </color_correction> */
 #else
 #define add_glopts_placebo()
 #endif
-- 
2.39.2



More information about the vlc-devel mailing list