From 7f3ea1280228175664241ba5b8edaee48fd33439 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Mon, 31 Mar 2014 04:51:47 +0200 Subject: video: Better support for XYZ input With this change, XYZ input is directly converted to the output colorspace wherever possible, and to the colorspace specified by the tags and/or --primaries option, otherwise. This commit also restructures some of the CMS code in gl_video.c to hopefully make it clearer which decision is being done where and why. --- video/csputils.c | 30 ++++++++++++++++++++++++++++++ video/csputils.h | 3 +++ video/mp_image.c | 5 ++++- video/out/gl_video.c | 40 ++++++++++++++++++++++++++++++---------- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/video/csputils.c b/video/csputils.c index 8b36615de6..bd56a1e29f 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -435,6 +435,36 @@ static void luma_coeffs(float m[3][4], float lr, float lg, float lb) // Constant coefficients (m[x][3]) not set here } +/** + * \brief get the coefficients of an xyz -> rgb conversion matrix + * \param params parameters for the conversion, only brightness is used + * \param prim primaries of the RGB space to transform to + * \param m array to store the coefficients into + */ +void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, struct mp_csp_primaries prim, float m[3][4]) +{ + float tmp[3][3], brightness = params->brightness; + mp_get_rgb2xyz_matrix(prim, tmp); + mp_invert_matrix3x3(tmp); + + // Since this outputs linear RGB rather than companded RGB, we + // want to linearize any brightness additions. 2 is a reasonable + // approximation for any sort of gamma function that could be in use. + // As this is an aesthetic setting only, any exact values do not matter. + if (brightness < 0) { + brightness *= -brightness; + } else { + brightness *= brightness; + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) + m[i][j] = tmp[i][j]; + + m[i][COL_C] = brightness; + } +} + /** * \brief get the coefficients of the yuv -> rgb conversion matrix * \param params struct specifying the properties of the conversion like diff --git a/video/csputils.h b/video/csputils.h index 8a17c23110..f2e96beb3d 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -127,6 +127,7 @@ enum mp_csp_equalizer_param { | (1 << MP_CSP_EQ_SATURATION) ) #define MP_CSP_EQ_CAPS_GAMMA (1 << MP_CSP_EQ_GAMMA) +#define MP_CSP_EQ_CAPS_BRIGHTNESS (1 << MP_CSP_EQ_BRIGHTNESS) extern const char *const mp_csp_equalizer_names[MP_CSP_EQ_COUNT]; @@ -188,6 +189,8 @@ struct mp_csp_primaries mp_get_csp_primaries(enum mp_csp_prim csp); void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest, float cms_matrix[3][3]); void mp_get_rgb2xyz_matrix(struct mp_csp_primaries space, float m[3][3]); + +void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, struct mp_csp_primaries prim, float xyz2rgb[3][4]); void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]); void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size); diff --git a/video/mp_image.c b/video/mp_image.c index 521b3d8e90..eb754499d1 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -566,7 +566,10 @@ void mp_image_params_guess_csp(struct mp_image_params *params) // since that's the most likely scenario. Proper VOs should ignore // this field as well as the matrix and treat XYZ input as absolute, // but for VOs which use the matrix (and hence, consult this field) - // this is the correct parameter. + // this is the correct parameter. This doubles as a reasonable output + // gamut for VOs which *do* use the specialized XYZ matrix but don't + // know any better output gamut other than whatever the source is + // tagged with. if (params->primaries == MP_CSP_PRIM_AUTO) params->primaries = MP_CSP_PRIM_BT_709; } else { diff --git a/video/out/gl_video.c b/video/out/gl_video.c index c2ed11be5c..989c1792db 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -575,9 +575,13 @@ static void update_uniforms(struct gl_video *p, GLuint program) loc = gl->GetUniformLocation(program, "colormatrix"); if (loc >= 0) { - float yuv2rgb[3][4] = {{0}}; - mp_get_yuv2rgb_coeffs(&cparams, yuv2rgb); - gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &yuv2rgb[0][0]); + float m[3][4] = {{0}}; + if (p->image_desc.flags & MP_IMGFLAG_XYZ) { + mp_get_xyz2rgb_coeffs(&cparams, p->csp_src, m); + } else { + mp_get_yuv2rgb_coeffs(&cparams, m); + } + gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &m[0][0]); } gl->Uniform1f(gl->GetUniformLocation(program, "input_gamma"), @@ -880,15 +884,29 @@ static void compile_shaders(struct gl_video *p) bool convert_to_linear_gamma = !p->is_linear_rgb && use_cms || use_const_luma; // Figure out the right color spaces we need to convert, if any - enum mp_csp_prim dest = p->opts.srgb ? MP_CSP_PRIM_BT_709 : MP_CSP_PRIM_BT_2020; - bool use_cms_matrix = false; - - if (use_cms && p->image_params.primaries != dest) { - p->csp_src = mp_get_csp_primaries(p->image_params.primaries); - p->csp_dest = mp_get_csp_primaries(dest); - use_cms_matrix = true; + enum mp_csp_prim prim_src = p->image_params.primaries, prim_dest; + if (use_cms) { + // sRGB mode wants sRGB aka BT.709 primaries, but the 3DLUT is + // always built against BT.2020. + prim_dest = p->opts.srgb ? MP_CSP_PRIM_BT_709 : MP_CSP_PRIM_BT_2020; + } else { + // If no CMS is being done we just want to output stuff as-is, + // in the native colorspace of the source. + prim_dest = prim_src; } + // XYZ input has no defined input color space, so we can directly convert + // it to whatever output space we actually need. + if (p->image_desc.flags & MP_IMGFLAG_XYZ) + prim_src = prim_dest; + + // Set the colorspace primaries and figure out whether we need to perform + // an extra conversion. + p->csp_src = mp_get_csp_primaries(prim_src); + p->csp_dest = mp_get_csp_primaries(prim_dest); + + bool use_cms_matrix = prim_src != prim_dest; + if (p->gl_target == GL_TEXTURE_RECTANGLE) { shader_def(&header, "VIDEO_SAMPLER", "sampler2DRect"); shader_def_opt(&header, "USE_RECTANGLE", true); @@ -1368,6 +1386,8 @@ static void init_video(struct gl_video *p, const struct mp_image_params *params) int eq_caps = MP_CSP_EQ_CAPS_GAMMA; if (p->is_yuv && p->image_params.colorspace != MP_CSP_BT_2020_C) eq_caps |= MP_CSP_EQ_CAPS_COLORMATRIX; + if (p->image_desc.flags & MP_IMGFLAG_XYZ) + eq_caps |= MP_CSP_EQ_CAPS_BRIGHTNESS; p->video_eq.capabilities = eq_caps; debug_check_gl(p, "before video texture creation"); -- cgit v1.2.3