From 634b4afa2bea64a6e9f194b3bd56f941ab5edb89 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Fri, 27 Mar 2015 11:12:46 +0100 Subject: vo_opengl: treat non-blended subtitles as sRGB Currently, the code just skipped CMS completely. This commit treats them as sRGB by default, instead. This also refactors much of the color management code to make it more generalized and re-usable. --- video/out/gl_video.c | 76 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 0afd1bed7e..ec8f435b12 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -1421,10 +1421,11 @@ static void get_scale_factors(struct gl_video *p, double xy[2]) (double)(p->src_rect.y1 - p->src_rect.y0); } -static void pass_linearize(struct gl_video *p) +// Linearize, given a TRC as input +static void pass_linearize(struct gl_video *p, enum mp_csp_trc trc) { GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) - switch (p->image_params.gamma) { + switch (trc) { case MP_CSP_TRC_SRGB: GLSL(color.rgb = mix(color.rgb / vec3(12.92), pow((color.rgb + vec3(0.055))/vec3(1.055), @@ -1463,16 +1464,11 @@ static void pass_scale_main(struct gl_video *p) scale_factor = FFMAX(1.0, 1.0 / f); } - bool use_cms = p->use_lut_3d || p->opts.target_prim != MP_CSP_PRIM_AUTO - || p->opts.target_trc != MP_CSP_TRC_AUTO; - // Pre-conversion, like linear light/sigmoidization GLSLF("// scaler pre-conversion\n"); - p->use_linear = p->opts.linear_scaling || p->opts.sigmoid_upscaling - || use_cms || p->image_params.gamma == MP_CSP_TRC_LINEAR; if (p->use_linear) { p->use_indirect = true; - pass_linearize(p); + pass_linearize(p, p->image_params.gamma); } bool use_sigmoid = p->use_linear && p->opts.sigmoid_upscaling && upscaling; @@ -1536,21 +1532,14 @@ static void pass_scale_main(struct gl_video *p) } } -// Adapts the colors to the display device's native gamut. Assumes the input -// is in linear RGB. -static void pass_colormanage(struct gl_video *p) +// Adapts the colors from the given color space to the display device's native +// gamut. +static void pass_colormanage(struct gl_video *p, enum mp_csp_prim prim_src, + enum mp_csp_trc trc_src) { GLSLF("// color management\n"); enum mp_csp_trc trc_dst = p->opts.target_trc; - enum mp_csp_prim prim_src = p->image_params.primaries, - prim_dst = p->opts.target_prim; - - if (p->user_gamma != 1) { - p->use_indirect = true; - gl_sc_uniform_f(p->sc, "user_gamma", p->user_gamma); - GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) - GLSL(color.rgb = pow(color.rgb, vec3(user_gamma));) - } + enum mp_csp_prim prim_dst = p->opts.target_prim; if (p->use_lut_3d) { // The 3DLUT is hard-coded against BT.2020's gamut during creation, and @@ -1562,12 +1551,20 @@ static void pass_colormanage(struct gl_video *p) if (prim_dst == MP_CSP_PRIM_AUTO) prim_dst = prim_src; if (trc_dst == MP_CSP_TRC_AUTO) { - trc_dst = p->image_params.gamma; - // Pick something more reasonable for linear light inputs - if (p->image_params.gamma == MP_CSP_TRC_LINEAR) + trc_dst = trc_src; + // Avoid outputting linear light at all costs + if (trc_dst == MP_CSP_TRC_LINEAR) + trc_dst = p->image_params.gamma; + if (trc_dst == MP_CSP_TRC_LINEAR) trc_dst = MP_CSP_TRC_GAMMA22; } + bool need_cms = prim_src != prim_dst || p->use_lut_3d; + bool need_gamma = trc_src != trc_dst || need_cms; + if (need_gamma && trc_src != MP_CSP_TRC_LINEAR) { + pass_linearize(p, trc_src); + } + // Adapt to the right colorspace if necessary if (prim_src != prim_dst) { struct mp_csp_primaries csp_src = mp_get_csp_primaries(prim_src), @@ -1587,9 +1584,7 @@ static void pass_colormanage(struct gl_video *p) GLSL(color.rgb = texture3D(lut_3d, color.rgb).rgb;) } - // Don't perform any gamut mapping unless linear light input is present to - // begin with - if (p->use_linear && trc_dst != MP_CSP_TRC_LINEAR) { + if (need_gamma && trc_dst != MP_CSP_TRC_LINEAR) { GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) switch (trc_dst) { case MP_CSP_TRC_SRGB: @@ -1707,11 +1702,11 @@ static void pass_dither(struct gl_video *p) dither_quantization); } -// Draws the OSD. If linearize is true, the output will be converted to -// linear light. +// Draws the OSD, in linear light. If blend is true, subtitles are treated as +// scene-referred, otherwise they are assumed sRGB and adapted to the output static void pass_draw_osd(struct gl_video *p, int draw_flags, double pts, struct mp_osd_res rect, int vp_w, int vp_h, int fbo, - bool linearize) + bool blend) { mpgl_osd_generate(p->osd, rect, pts, p->image_params.stereo_out, draw_flags); @@ -1736,8 +1731,14 @@ static void pass_draw_osd(struct gl_video *p, int draw_flags, double pts, default: abort(); } - if (linearize) - pass_linearize(p); + // subtitle color management + if (blend) { + // Scene referred: no gamut adaptation needed, and implicit trc + pass_linearize(p, p->image_params.gamma); + } else { + // Assume sRGB (BT.709 primaries) and adapt to output + pass_colormanage(p, MP_CSP_PRIM_BT_709, MP_CSP_TRC_SRGB); + } gl_sc_set_vao(p->sc, mpgl_osd_get_vao(p->osd)); gl_sc_gen_shader_and_reset(p->sc); mpgl_osd_draw_part(p->osd, vp_w, vp_h, n); @@ -1749,6 +1750,10 @@ static void pass_draw_osd(struct gl_video *p, int draw_flags, double pts, // upscaling static void pass_render_frame(struct gl_video *p) { + bool use_cms = p->use_lut_3d || p->opts.target_prim != MP_CSP_PRIM_AUTO + || p->opts.target_trc != MP_CSP_TRC_AUTO; + p->use_linear = p->opts.linear_scaling || p->opts.sigmoid_upscaling + || use_cms || p->image_params.gamma == MP_CSP_TRC_LINEAR; p->use_indirect = false; // set to true as needed by pass_* pass_read_video(p); pass_convert_yuv(p); @@ -1781,7 +1786,14 @@ static void pass_render_frame(struct gl_video *p) static void pass_draw_to_screen(struct gl_video *p, int fbo) { - pass_colormanage(p); + // Adjust the overall gamma before drawing to screen + if (p->user_gamma != 1) { + gl_sc_uniform_f(p->sc, "user_gamma", p->user_gamma); + GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) + GLSL(color.rgb = pow(color.rgb, vec3(user_gamma));) + } + pass_colormanage(p, p->image_params.primaries, + p->use_linear ? MP_CSP_TRC_LINEAR : p->image_params.gamma); pass_dither(p); int flags = (p->image_params.rotate % 90 ? 0 : p->image_params.rotate / 90) | (p->image.image_flipped ? 4 : 0); -- cgit v1.2.3