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