1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-21 18:57:35 +00:00

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.
This commit is contained in:
Niklas Haas 2016-06-26 19:28:06 +02:00 committed by wm4
parent 740fdc139f
commit f3b6966d14
7 changed files with 42 additions and 3 deletions

View File

@ -314,6 +314,7 @@ Available filters are:
:prophoto: ProPhoto RGB (ROMM) curve :prophoto: ProPhoto RGB (ROMM) curve
:st2084: SMPTE ST2084 (HDR) curve :st2084: SMPTE ST2084 (HDR) curve
:std-b67: ARIB STD-B67 (Hybrid Log-gamma) curve :std-b67: ARIB STD-B67 (Hybrid Log-gamma) curve
:v-log: Panasonic V-Log transfer curve
``<peak>`` ``<peak>``
Reference peak illumination for the video file. This is mostly Reference peak illumination for the video file. This is mostly

View File

@ -1007,6 +1007,8 @@ Available video output drivers are:
SMPTE ST2084 (HDR) curve, PQ OETF SMPTE ST2084 (HDR) curve, PQ OETF
std-b67 std-b67
ARIB STD-B67 (Hybrid Log-gamma) curve, also known as BBC/NHK HDR 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 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 curve but it will not set any HDMI flags or other signalling that

View File

@ -80,6 +80,7 @@ const struct m_opt_choice_alternatives mp_csp_trc_names[] = {
{"prophoto", MP_CSP_TRC_PRO_PHOTO}, {"prophoto", MP_CSP_TRC_PRO_PHOTO},
{"st2084", MP_CSP_TRC_SMPTE_ST2084}, {"st2084", MP_CSP_TRC_SMPTE_ST2084},
{"std-b67", MP_CSP_TRC_ARIB_STD_B67}, {"std-b67", MP_CSP_TRC_ARIB_STD_B67},
{"v-log", MP_CSP_TRC_V_LOG},
{0} {0}
}; };

View File

@ -81,6 +81,7 @@ enum mp_csp_trc {
MP_CSP_TRC_PRO_PHOTO, MP_CSP_TRC_PRO_PHOTO,
MP_CSP_TRC_SMPTE_ST2084, MP_CSP_TRC_SMPTE_ST2084,
MP_CSP_TRC_ARIB_STD_B67, MP_CSP_TRC_ARIB_STD_B67,
MP_CSP_TRC_V_LOG,
MP_CSP_TRC_COUNT MP_CSP_TRC_COUNT
}; };

View File

@ -611,8 +611,13 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
} }
if (params->colorspace == MP_CSP_AUTO) if (params->colorspace == MP_CSP_AUTO)
params->colorspace = mp_csp_guess_colorspace(params->w, params->h); params->colorspace = mp_csp_guess_colorspace(params->w, params->h);
if (params->colorlevels == MP_CSP_LEVELS_AUTO) if (params->colorlevels == MP_CSP_LEVELS_AUTO) {
params->colorlevels = MP_CSP_LEVELS_TV; 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) { if (params->primaries == MP_CSP_PRIM_AUTO) {
// Guess based on the colormatrix as a first priority // Guess based on the colormatrix as a first priority
if (params->colorspace == MP_CSP_BT_2020_NC || if (params->colorspace == MP_CSP_BT_2020_NC ||

View File

@ -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 // We could pick any value we want here, the difference is just coding
// efficiency. // efficiency.
if (trc_orig == MP_CSP_TRC_SMPTE_ST2084 || 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; 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 // target's reference peak
if (trc_src == MP_CSP_TRC_ARIB_STD_B67) if (trc_src == MP_CSP_TRC_ARIB_STD_B67)
peak_src = 12 * peak_dst; 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, // All operations from here on require linear light as a starting point,

View File

@ -232,6 +232,12 @@ static const float B67_A = 0.17883277,
B67_B = 0.28466892, B67_B = 0.28466892,
B67_C = 0.55991073; 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 // Linearize (expand), given a TRC as input
void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) 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) // assume 1.0 is the maximum brightness, not the reference peak)
GLSL(color.rgb /= vec3(12.0);) GLSL(color.rgb /= vec3(12.0);)
break; 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: default:
abort(); 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", " lessThan(vec3(1.0), color.rgb));\n",
B67_A, B67_B, B67_C); B67_A, B67_B, B67_C);
break; 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: default:
abort(); abort();
} }