diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index b4e4438f78..7f60da9385 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -311,6 +311,7 @@ Available filters are: :gamma2.8: Pure power curve (gamma 2.8) :prophoto: ProPhoto RGB (ROMM) curve :st2084: SMPTE ST2084 (HDR) curve + :std-b67: ARIB STD-B67 (Hybrid Log-gamma) curve ```` Reference peak illumination for the video file. This is mostly diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index bdc317fc8f..a4d42e48c3 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -1003,6 +1003,8 @@ Available video output drivers are: ProPhoto RGB (ROMM) st2084 SMPTE ST2084 (HDR) curve, PQ OETF + std-b67 + ARIB STD-B67 (Hybrid Log-gamma) curve, also known as BBC/NHK HDR ``target-brightness=<1..100000>`` Specifies the display's approximate brightness in cd/m^2. When playing diff --git a/video/csputils.c b/video/csputils.c index ffa1f82a6d..e9e6772ac8 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -78,6 +78,7 @@ const struct m_opt_choice_alternatives mp_csp_trc_names[] = { {"gamma2.8", MP_CSP_TRC_GAMMA28}, {"prophoto", MP_CSP_TRC_PRO_PHOTO}, {"st2084", MP_CSP_TRC_SMPTE_ST2084}, + {"std-b67", MP_CSP_TRC_ARIB_STD_B67}, {0} }; @@ -171,8 +172,9 @@ enum mp_csp_trc avcol_trc_to_mp_csp_trc(int avtrc) case AVCOL_TRC_LINEAR: return MP_CSP_TRC_LINEAR; case AVCOL_TRC_GAMMA22: return MP_CSP_TRC_GAMMA22; case AVCOL_TRC_GAMMA28: return MP_CSP_TRC_GAMMA28; -#if HAVE_AVUTIL_ST2084 +#if HAVE_AVUTIL_HDR case AVCOL_TRC_SMPTEST2084: return MP_CSP_TRC_SMPTE_ST2084; + case AVCOL_TRC_ARIB_STD_B67: return MP_CSP_TRC_ARIB_STD_B67; #endif default: return MP_CSP_TRC_AUTO; } @@ -222,8 +224,9 @@ int mp_csp_trc_to_avcol_trc(enum mp_csp_trc trc) case MP_CSP_TRC_LINEAR: return AVCOL_TRC_LINEAR; case MP_CSP_TRC_GAMMA22: return AVCOL_TRC_GAMMA22; case MP_CSP_TRC_GAMMA28: return AVCOL_TRC_GAMMA28; -#if HAVE_AVUTIL_ST2084 +#if HAVE_AVUTIL_HDR case MP_CSP_TRC_SMPTE_ST2084: return AVCOL_TRC_SMPTEST2084; + case MP_CSP_TRC_ARIB_STD_B67: return AVCOL_TRC_ARIB_STD_B67; #endif default: return AVCOL_TRC_UNSPECIFIED; } diff --git a/video/csputils.h b/video/csputils.h index 19dd88f145..f64c42e6c8 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -79,6 +79,7 @@ enum mp_csp_trc { MP_CSP_TRC_GAMMA28, MP_CSP_TRC_PRO_PHOTO, MP_CSP_TRC_SMPTE_ST2084, + MP_CSP_TRC_ARIB_STD_B67, MP_CSP_TRC_COUNT }; diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 4387208ead..6fd92ddb29 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -2172,12 +2172,15 @@ static void pass_colormanage(struct gl_video *p, float peak_src, enum mp_csp_prim prim_orig = p->image_params.primaries; enum mp_csp_trc trc_orig = p->image_params.gamma; - // One exception: SMPTE ST.2084 is not implemented by LittleCMS - // for technical limitation reasons, so we use a gamma 2.2 input curve - // here instead. We could pick any value we want here, the difference - // is just coding efficiency. - if (trc_orig == MP_CSP_TRC_SMPTE_ST2084) + // One exception: HDR is not implemented by LittleCMS for technical + // limitation reasons, so we use a gamma 2.2 input curve here instead. + // 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_GAMMA22; + } if (gl_video_get_lut3d(p, prim_orig, trc_orig)) { prim_dst = prim_orig; @@ -2216,6 +2219,11 @@ static void pass_colormanage(struct gl_video *p, float peak_src, // If the source has no information known, it's display-referred // (and should be treated relative to the specified desired peak_dst) peak_src = peak_dst; + + // Exception: ARIB STD-B67's nominal peak is exactly 12 times the + // target's reference peak + if (trc_src == MP_CSP_TRC_ARIB_STD_B67) + peak_src = 12 * 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 1f37f4fed1..4a15b6ceed 100644 --- a/video/out/opengl/video_shaders.c +++ b/video/out/opengl/video_shaders.c @@ -227,6 +227,11 @@ static const float HDR_M1 = 2610./4096 * 1./4, HDR_C2 = 2413./4096 * 32, HDR_C3 = 2392./4096 * 32; +// Common constants for ARIB STD-B67 (Hybrid Log-gamma) +static const float B67_A = 0.17883277, + B67_B = 0.28466892, + B67_C = 0.55991073; + // Linearize (expand), given a TRC as input void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) { @@ -265,6 +270,17 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) HDR_C1, HDR_C2, HDR_C3); GLSLF("color.rgb = pow(color.rgb, vec3(1.0/%f));\n", HDR_M1); break; + case MP_CSP_TRC_ARIB_STD_B67: + GLSLF("color.rgb = mix(vec3(4.0) * color.rgb * color.rgb,\n" + " exp((color.rgb - vec3(%f)) / vec3(%f)) + vec3(%f),\n" + " lessThan(vec3(0.5), color.rgb));\n", + B67_C, B67_A, B67_B); + // Since the ARIB function's signal value of 1.0 corresponds to + // a peak of 12.0, we need to renormalize to prevent GL textures + // from clipping. (In general, mpv's internal conversions always + // assume 1.0 is the maximum brightness, not the reference peak) + GLSL(color.rgb /= vec3(12.0);) + break; default: abort(); } @@ -308,6 +324,13 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) HDR_C1, HDR_C2, HDR_C3); GLSLF("color.rgb = pow(color.rgb, vec3(%f));\n", HDR_M2); break; + case MP_CSP_TRC_ARIB_STD_B67: + GLSL(color.rgb *= vec3(12.0);) + GLSLF("color.rgb = mix(vec3(0.5) * sqrt(color.rgb),\n" + " vec3(%f) * log(color.rgb - vec3(%f)) + vec3(%f),\n" + " lessThan(vec3(1.0), color.rgb));\n", + B67_A, B67_B, B67_C); + break; default: abort(); } diff --git a/wscript b/wscript index 1915f7cd67..e29d1ab403 100644 --- a/wscript +++ b/wscript @@ -498,10 +498,11 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ '(void)offsetof(AVFrame, hw_frames_ctx)', use='libav'), }, { - 'name': 'avutil-st2084', - 'desc': 'libavutil AVCOL_TRC_SMPTEST2084', + 'name': 'avutil-hdr', + 'desc': 'libavutil HDR TRCs', 'func': check_statement('libavutil/pixfmt.h', - 'AVCOL_TRC_SMPTEST2084', + 'AVCOL_TRC_SMPTEST2084,' + 'AVCOL_TRC_ARIB_STD_B67', use='libav'), } ]