[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