From f3b6966d14e8cb34477474b85c83beb46e542e70 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sun, 26 Jun 2016 19:28:06 +0200 Subject: vo_opengl: implement the Panasonic V-Log function User request and not that hard. Closes #3157. Note that FFmpeg doesn't support this and there's no signalling in HEVC etc., so the only way users can access it is by using vf_format manually. Mind: This encoding uses full range values, not TV range. --- DOCS/man/vf.rst | 1 + DOCS/man/vo.rst | 2 ++ video/csputils.c | 1 + video/csputils.h | 1 + video/mp_image.c | 9 +++++++-- video/out/opengl/video.c | 7 ++++++- video/out/opengl/video_shaders.c | 24 ++++++++++++++++++++++++ 7 files changed, 42 insertions(+), 3 deletions(-) diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index f068f26dff..e6438b984b 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -314,6 +314,7 @@ Available filters are: :prophoto: ProPhoto RGB (ROMM) curve :st2084: SMPTE ST2084 (HDR) curve :std-b67: ARIB STD-B67 (Hybrid Log-gamma) curve + :v-log: Panasonic V-Log transfer curve ```` Reference peak illumination for the video file. This is mostly diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index db6fa1d0fc..d9d4bb4d91 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -1007,6 +1007,8 @@ Available video output drivers are: SMPTE ST2084 (HDR) curve, PQ OETF std-b67 ARIB STD-B67 (Hybrid Log-gamma) curve, also known as BBC/NHK HDR + v-log + Panasonic V-Log (VARICAM) curve NOTE: When using HDR output formats, mpv will encode to the specified curve but it will not set any HDMI flags or other signalling that diff --git a/video/csputils.c b/video/csputils.c index b85b1f28f2..65b26acb3a 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -80,6 +80,7 @@ const struct m_opt_choice_alternatives mp_csp_trc_names[] = { {"prophoto", MP_CSP_TRC_PRO_PHOTO}, {"st2084", MP_CSP_TRC_SMPTE_ST2084}, {"std-b67", MP_CSP_TRC_ARIB_STD_B67}, + {"v-log", MP_CSP_TRC_V_LOG}, {0} }; diff --git a/video/csputils.h b/video/csputils.h index 100e3c13d9..90c5483a05 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -81,6 +81,7 @@ enum mp_csp_trc { MP_CSP_TRC_PRO_PHOTO, MP_CSP_TRC_SMPTE_ST2084, MP_CSP_TRC_ARIB_STD_B67, + MP_CSP_TRC_V_LOG, MP_CSP_TRC_COUNT }; diff --git a/video/mp_image.c b/video/mp_image.c index d5b97481e8..0b46f947bc 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -611,8 +611,13 @@ void mp_image_params_guess_csp(struct mp_image_params *params) } if (params->colorspace == MP_CSP_AUTO) params->colorspace = mp_csp_guess_colorspace(params->w, params->h); - if (params->colorlevels == MP_CSP_LEVELS_AUTO) - params->colorlevels = MP_CSP_LEVELS_TV; + if (params->colorlevels == MP_CSP_LEVELS_AUTO) { + if (params->gamma == MP_CSP_TRC_V_LOG) { + params->colorlevels = MP_CSP_LEVELS_PC; + } else { + params->colorlevels = MP_CSP_LEVELS_TV; + } + } if (params->primaries == MP_CSP_PRIM_AUTO) { // Guess based on the colormatrix as a first priority if (params->colorspace == MP_CSP_BT_2020_NC || diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 6fd92ddb29..a870fe0e4f 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -2177,7 +2177,8 @@ static void pass_colormanage(struct gl_video *p, float peak_src, // We could pick any value we want here, the difference is just coding // efficiency. if (trc_orig == MP_CSP_TRC_SMPTE_ST2084 || - trc_orig == MP_CSP_TRC_ARIB_STD_B67) + trc_orig == MP_CSP_TRC_ARIB_STD_B67 || + trc_orig == MP_CSP_TRC_V_LOG) { trc_orig = MP_CSP_TRC_GAMMA22; } @@ -2224,6 +2225,10 @@ static void pass_colormanage(struct gl_video *p, float peak_src, // target's reference peak if (trc_src == MP_CSP_TRC_ARIB_STD_B67) peak_src = 12 * peak_dst; + + // Similar deal for V-Log + if (trc_src == MP_CSP_TRC_V_LOG) + peak_src = 46.0855 * peak_dst; } // All operations from here on require linear light as a starting point, diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c index 4a15b6ceed..7b736f1d5d 100644 --- a/video/out/opengl/video_shaders.c +++ b/video/out/opengl/video_shaders.c @@ -232,6 +232,12 @@ static const float B67_A = 0.17883277, B67_B = 0.28466892, B67_C = 0.55991073; +// Common constants for Panasonic V-Log +static const float VLOG_B = 0.00873, + VLOG_C = 0.241514, + VLOG_D = 0.598206, + VLOG_R = 46.085527; // nominal peak + // Linearize (expand), given a TRC as input void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) { @@ -281,6 +287,16 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) // assume 1.0 is the maximum brightness, not the reference peak) GLSL(color.rgb /= vec3(12.0);) break; + case MP_CSP_TRC_V_LOG: + GLSLF("color.rgb = mix((color.rgb - vec3(0.125)) / vec3(5.6), \n" + " pow(vec3(10.0), (color.rgb - vec3(%f)) / vec3(%f)) \n" + " - vec3(%f), \n" + " lessThanEqual(vec3(0.181), color.rgb)); \n", + VLOG_D, VLOG_C, VLOG_B); + // Same deal as with the B67 function, renormalize to texture range + GLSLF("color.rgb /= vec3(%f);\n", VLOG_R); + GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) + break; default: abort(); } @@ -331,6 +347,14 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) " lessThan(vec3(1.0), color.rgb));\n", B67_A, B67_B, B67_C); break; + case MP_CSP_TRC_V_LOG: + GLSLF("color.rgb *= vec3(%f);\n", VLOG_R); + GLSLF("color.rgb = mix(vec3(5.6) * color.rgb + vec3(0.125), \n" + " vec3(%f) * log(color.rgb + vec3(%f)) \n" + " + vec3(%f), \n" + " lessThanEqual(vec3(0.01), color.rgb)); \n", + VLOG_C / M_LN10, VLOG_B, VLOG_D); + break; default: abort(); } -- cgit v1.2.3