diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 1814a7efd2..41226c56ba 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -594,7 +594,6 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track, } if (colour->n_max_cll) { track->color.hdr.max_cll = colour->max_cll; - track->color.sig_peak = track->color.hdr.max_cll / MP_REF_WHITE; MP_DBG(demuxer, "| + MaxCLL: %"PRIu64"\n", colour->max_cll); } if (colour->n_max_fall) { @@ -642,8 +641,6 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track, } if (mastering->n_luminance_max) { track->color.hdr.max_luma = mastering->luminance_max; - if (!track->color.sig_peak) - track->color.sig_peak = track->color.hdr.max_luma / MP_REF_WHITE; MP_DBG(demuxer, "| + LuminanceMax: %f\n", track->color.hdr.max_luma); } } diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c index 6551e3478f..87489ccdf1 100644 --- a/filters/f_decoder_wrapper.c +++ b/filters/f_decoder_wrapper.c @@ -548,11 +548,6 @@ void mp_decoder_wrapper_set_play_dir(struct mp_decoder_wrapper *d, int dir) thread_unlock(p); } -static bool is_valid_peak(float sig_peak) -{ - return !sig_peak || (sig_peak >= 1 && sig_peak <= 100); -} - static void fix_image_params(struct priv *p, struct mp_image_params *params) { @@ -623,12 +618,6 @@ static void fix_image_params(struct priv *p, mp_colorspace_merge(&m.color, &c->color); - // Sanitize the HDR peak. Sadly necessary - if (!is_valid_peak(m.color.sig_peak)) { - MP_WARN(p, "Invalid HDR peak in stream: %f\n", m.color.sig_peak); - m.color.sig_peak = 0.0; - } - // Guess missing colorspace fields from metadata. This guarantees all // fields are at least set to legal values afterwards. mp_image_params_guess_csp(&m); diff --git a/player/command.c b/player/command.c index f61e89be9e..de215a2732 100644 --- a/player/command.c +++ b/player/command.c @@ -2323,7 +2323,7 @@ static int property_imgparams(struct mp_image_params p, int action, void *arg) SUB_PROP_STR(m_opt_choice_str(mp_csp_prim_names, p.color.primaries))}, {"gamma", SUB_PROP_STR(m_opt_choice_str(mp_csp_trc_names, p.color.gamma))}, - {"sig-peak", SUB_PROP_FLOAT(p.color.sig_peak)}, + {"sig-peak", SUB_PROP_FLOAT(p.color.hdr.max_luma * MP_REF_WHITE)}, {"light", SUB_PROP_STR(m_opt_choice_str(mp_csp_light_names, p.color.light))}, {"chroma-location", diff --git a/player/lua/stats.lua b/player/lua/stats.lua index 75e44cd66f..9401a9032c 100644 --- a/player/lua/stats.lua +++ b/player/lua/stats.lua @@ -933,11 +933,6 @@ local function add_video(s) append_fps(s, "container-fps", "estimated-vf-fps") end append_img_params(s, r, ro) - - if not ro["max-cll"] then - ro["max-cll"] = math.floor((ro["sig-peak"] or 0) * 203) - end - append_hdr(s, ro) append_property(s, "packet-video-bitrate", {prefix="Bitrate:", suffix=" kbps"}) append_filters(s, "vf", "Filters:") diff --git a/test/meson.build b/test/meson.build index 5ddcedd10a..59c34549af 100644 --- a/test/meson.build +++ b/test/meson.build @@ -64,6 +64,7 @@ img_utils_files = [ 'video/fmt-conversion.c', 'video/img_format.c', 'video/mp_image.c', + 'video/out/placebo/utils.c', 'video/sws_utils.c' ] if features['zimg'] diff --git a/test/test_utils.c b/test/test_utils.c index ac59c17e8f..b80caf8f71 100644 --- a/test/test_utils.c +++ b/test/test_utils.c @@ -1,5 +1,6 @@ #include +#include "common/msg.h" #include "options/m_option.h" #include "options/path.h" #include "osdep/subprocess.h" @@ -98,7 +99,7 @@ void assert_memcmp_impl(const char *file, int line, } /* Stubs: see test_utils.h */ -struct mp_log *mp_null_log; +struct mp_log *const mp_null_log; const char *mp_help_text; void mp_msg(struct mp_log *log, int lev, const char *format, ...) {}; @@ -106,3 +107,5 @@ int mp_msg_find_level(const char *s) {return 0;}; int mp_msg_level(struct mp_log *log) {return 0;}; void mp_write_console_ansi(void) {}; void mp_set_avdict(AVDictionary **dict, char **kv) {}; +struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent, + const char *name) { return NULL; }; diff --git a/video/csputils.c b/video/csputils.c index b7fe5737cd..59200c5669 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -129,8 +129,6 @@ void mp_colorspace_merge(struct mp_colorspace *orig, struct mp_colorspace *new) orig->primaries = new->primaries; if (!orig->gamma) orig->gamma = new->gamma; - if (!orig->sig_peak) - orig->sig_peak = new->sig_peak; if (!orig->light) orig->light = new->light; pl_hdr_metadata_merge(&orig->hdr, &new->hdr); @@ -913,7 +911,6 @@ bool mp_colorspace_equal(struct mp_colorspace c1, struct mp_colorspace c2) c1.primaries == c2.primaries && c1.gamma == c2.gamma && c1.light == c2.light && - c1.sig_peak == c2.sig_peak && pl_hdr_metadata_equal(&c1.hdr, &c2.hdr); } diff --git a/video/csputils.h b/video/csputils.h index 5b2fe6d63e..3a904cbf38 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -147,7 +147,6 @@ struct mp_colorspace { enum mp_csp_prim primaries; enum mp_csp_trc gamma; enum mp_csp_light light; - float sig_peak; // highest relative value in signal. 0 = unknown/auto (deprecated) struct pl_hdr_metadata hdr; }; diff --git a/video/filter/vf_format.c b/video/filter/vf_format.c index c0ec11d0b8..4997d6f173 100644 --- a/video/filter/vf_format.c +++ b/video/filter/vf_format.c @@ -77,14 +77,12 @@ static void set_params(struct vf_format_opts *p, struct mp_image_params *out, // When changing the gamma function explicitly, also reset stuff // related to the gamma function since that information will almost // surely be false now and have to be re-inferred - out->color.sig_peak = 0.0; + out->color.hdr = (struct pl_hdr_metadata){0}; out->color.light = MP_CSP_LIGHT_AUTO; } } - if (p->sig_peak) { - out->color.sig_peak = p->sig_peak; - out->color.hdr.max_cll = p->sig_peak; - } + if (p->sig_peak) + out->color.hdr = (struct pl_hdr_metadata){ .max_luma = p->sig_peak * MP_REF_WHITE }; if (p->light) out->color.light = p->light; if (p->chroma_location) diff --git a/video/image_writer.c b/video/image_writer.c index 75ac01ec37..96f10c7567 100644 --- a/video/image_writer.c +++ b/video/image_writer.c @@ -637,7 +637,7 @@ static struct mp_image *convert_image(struct mp_image *image, int destfmt, p.color.primaries = MP_CSP_PRIM_BT_709; p.color.gamma = MP_CSP_TRC_AUTO; p.color.light = MP_CSP_LIGHT_DISPLAY; - p.color.sig_peak = 0; + p.color.hdr = (struct pl_hdr_metadata){0}; if (p.color.space != MP_CSP_RGB) { p.color.levels = yuv_levels; p.color.space = MP_CSP_BT_601; diff --git a/video/mp_image.c b/video/mp_image.c index 2b8fbeb033..dff2051d39 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -27,6 +27,7 @@ #include #include #include +#include #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 16, 100) # include @@ -41,6 +42,7 @@ #include "mp_image.h" #include "osdep/threads.h" #include "sws_utils.h" +#include "out/placebo/utils.h" // Determine strides, plane sizes, and total required size for an image // allocation. Returns total size on success, <0 on error. Unused planes @@ -776,8 +778,6 @@ char *mp_image_params_to_str_buf(char *b, size_t bs, m_opt_choice_str(mp_csp_trc_names, p->color.gamma), m_opt_choice_str(mp_csp_levels_names, p->color.levels), m_opt_choice_str(mp_csp_light_names, p->color.light)); - if (p->color.sig_peak) - mp_snprintf_cat(b, bs, " SP=%f", p->color.sig_peak); mp_snprintf_cat(b, bs, " CL=%s", m_opt_choice_str(mp_chroma_names, p->chroma_location)); if (mp_image_crop_valid(p)) { @@ -955,20 +955,20 @@ void mp_image_params_guess_csp(struct mp_image_params *params) params->color.gamma = MP_CSP_TRC_AUTO; } - if (!params->color.sig_peak) { + if (!params->color.hdr.max_luma) { if (params->color.gamma == MP_CSP_TRC_HLG) { - params->color.sig_peak = 1000 / MP_REF_WHITE; // reference display + params->color.hdr.max_luma = 1000; // reference display } else { // If the signal peak is unknown, we're forced to pick the TRC's // nominal range as the signal peak to prevent clipping - params->color.sig_peak = mp_trc_nom_peak(params->color.gamma); + params->color.hdr.max_luma = mp_trc_nom_peak(params->color.gamma) * MP_REF_WHITE; } } if (!mp_trc_is_hdr(params->color.gamma)) { // Some clips have leftover HDR metadata after conversion to SDR, so to // avoid blowing up the tone mapping code, strip/sanitize it - params->color.sig_peak = 1.0; + params->color.hdr = pl_hdr_metadata_empty; } if (params->chroma_location == MP_CHROMA_AUTO) { @@ -1061,20 +1061,14 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *src) if (sd) dst->icc_profile = sd->buf; - // Get the content light metadata if available - sd = av_frame_get_side_data(src, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); - if (sd) { - AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; - dst->params.color.sig_peak = clm->MaxCLL / MP_REF_WHITE; - } - - // Otherwise, try getting the mastering metadata if available - sd = av_frame_get_side_data(src, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); - if (!dst->params.color.sig_peak && sd) { - AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *)sd->data; - if (mdm->has_luminance) - dst->params.color.sig_peak = av_q2d(mdm->max_luminance) / MP_REF_WHITE; - } + AVFrameSideData *mdm = av_frame_get_side_data(src, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + AVFrameSideData *clm = av_frame_get_side_data(src, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + AVFrameSideData *dhp = av_frame_get_side_data(src, AV_FRAME_DATA_DYNAMIC_HDR_PLUS); + pl_map_hdr_metadata(&dst->params.color.hdr, &(struct pl_av_hdr_metadata) { + .mdm = (void *)(mdm ? mdm->data : NULL), + .clm = (void *)(clm ? clm->data : NULL), + .dhp = (void *)(dhp ? dhp->data : NULL), + }); sd = av_frame_get_side_data(src, AV_FRAME_DATA_A53_CC); if (sd) @@ -1189,12 +1183,11 @@ struct AVFrame *mp_image_to_av_frame(struct mp_image *src) new_ref->icc_profile = NULL; } - if (src->params.color.sig_peak) { - AVContentLightMetadata *clm = - av_content_light_metadata_create_side_data(dst); - MP_HANDLE_OOM(clm); - clm->MaxCLL = src->params.color.sig_peak * MP_REF_WHITE; - } + pl_avframe_set_color(dst, (struct pl_color_space){ + .primaries = mp_prim_to_pl(src->params.color.primaries), + .transfer = mp_trc_to_pl(src->params.color.gamma), + .hdr = src->params.color.hdr, + }); { AVFrameSideData *sd = av_frame_new_side_data(dst, diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index 69be403933..1782132ea1 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -609,7 +609,7 @@ struct mp_colorspace gl_video_get_output_colorspace(struct gl_video *p) return (struct mp_colorspace) { .primaries = p->opts.target_prim, .gamma = p->opts.target_trc, - .sig_peak = p->opts.target_peak / MP_REF_WHITE, + .hdr.max_luma = p->opts.target_peak, }; } @@ -2565,8 +2565,8 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, .primaries = p->opts.target_prim == MP_CSP_PRIM_AUTO ? fbo_csp.primaries : p->opts.target_prim, .light = MP_CSP_LIGHT_DISPLAY, - .sig_peak = !p->opts.target_peak ? - fbo_csp.sig_peak : p->opts.target_peak / MP_REF_WHITE, + .hdr.max_luma = !p->opts.target_peak ? + fbo_csp.hdr.max_luma : p->opts.target_peak, }; if (!p->colorspace_override_warned && @@ -2643,10 +2643,10 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, // If there's no specific signal peak known for the output display, infer // it from the chosen transfer function. Also normalize the src peak, in // case it was unknown - if (!dst.sig_peak) - dst.sig_peak = mp_trc_nom_peak(dst.gamma); - if (!src.sig_peak) - src.sig_peak = mp_trc_nom_peak(src.gamma); + if (!dst.hdr.max_luma) + dst.hdr.max_luma = mp_trc_nom_peak(dst.gamma) * MP_REF_WHITE; + if (!src.hdr.max_luma) + src.hdr.max_luma = mp_trc_nom_peak(src.gamma) * MP_REF_WHITE; // Whitelist supported modes switch (p->opts.tone_map.curve) { @@ -2679,7 +2679,7 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, struct gl_tone_map_opts tone_map = p->opts.tone_map; bool detect_peak = tone_map.compute_peak >= 0 && mp_trc_is_hdr(src.gamma) - && src.sig_peak > dst.sig_peak; + && src.hdr.max_luma > dst.hdr.max_luma; if (detect_peak && !p->hdr_peak_ssbo) { struct { diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c index 6c49967238..6c0e8a815e 100644 --- a/video/out/gpu/video_shaders.c +++ b/video/out/gpu/video_shaders.c @@ -848,7 +848,7 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, gl_sc_uniform_vec3(sc, "dst_luma", rgb2xyz[1]); bool need_ootf = src.light != dst.light; - if (src.light == MP_CSP_LIGHT_SCENE_HLG && src.sig_peak != dst.sig_peak) + if (src.light == MP_CSP_LIGHT_SCENE_HLG && src.hdr.max_luma != dst.hdr.max_luma) need_ootf = true; // All operations from here on require linear light as a starting point, @@ -856,7 +856,7 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, // operations needs it bool need_linear = src.gamma != dst.gamma || src.primaries != dst.primaries || - src.sig_peak != dst.sig_peak || + src.hdr.max_luma != dst.hdr.max_luma || need_ootf; if (need_linear && !is_linear) { @@ -869,11 +869,13 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, GLSLF("color.rgb *= vec3(%f);\n", mp_trc_nom_peak(src.gamma)); if (need_ootf) - pass_ootf(sc, src.light, src.sig_peak); + pass_ootf(sc, src.light, src.hdr.max_luma / MP_REF_WHITE); // Tone map to prevent clipping due to excessive brightness - if (src.sig_peak > dst.sig_peak) - pass_tone_map(sc, src.sig_peak, dst.sig_peak, opts); + if (src.hdr.max_luma > dst.hdr.max_luma) { + pass_tone_map(sc, src.hdr.max_luma / MP_REF_WHITE, + dst.hdr.max_luma / MP_REF_WHITE, opts); + } // Adapt to the right colorspace if necessary if (src.primaries != dst.primaries) { @@ -892,18 +894,18 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, color.rgb = mix(color.rgb, vec3(luma), coeff); }) GLSLF("float cmax = 1.0/%f * max(max(color.r, color.g), color.b);\n", - dst.sig_peak); + dst.hdr.max_luma / MP_REF_WHITE); GLSL(if (cmax > 1.0) color.rgb /= cmax;) } } if (need_ootf) - pass_inverse_ootf(sc, dst.light, dst.sig_peak); + pass_inverse_ootf(sc, dst.light, dst.hdr.max_luma / MP_REF_WHITE); // Post-scale the outgoing values from absolute scale to normalized. // For SDR, we normalize to the chosen signal peak. For HDR, we normalize // to the encoding range of the transfer function. - float dst_range = dst.sig_peak; + float dst_range = dst.hdr.max_luma / MP_REF_WHITE; if (mp_trc_is_hdr(dst.gamma)) dst_range = mp_trc_nom_peak(dst.gamma); diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 9db649e785..dac5eec3a3 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -439,30 +439,13 @@ static int plane_data_from_imgfmt(struct pl_plane_data out_data[4], return desc.num_planes; } -static inline void *get_side_data(const struct mp_image *mpi, - enum AVFrameSideDataType type) -{ - for (int i = 0; i num_ff_side_data; i++) { - if (mpi->ff_side_data[i].type == type) - return (void *) mpi->ff_side_data[i].buf->data; - } - - return NULL; -} - static struct pl_color_space get_mpi_csp(struct vo *vo, struct mp_image *mpi) { struct pl_color_space csp = { .primaries = mp_prim_to_pl(mpi->params.color.primaries), .transfer = mp_trc_to_pl(mpi->params.color.gamma), - .hdr.max_luma = mpi->params.color.sig_peak * MP_REF_WHITE, + .hdr = mpi->params.color.hdr, }; - - pl_map_hdr_metadata(&csp.hdr, &(struct pl_av_hdr_metadata) { - .mdm = get_side_data(mpi, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA), - .clm = get_side_data(mpi, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL), - .dhp = get_side_data(mpi, AV_FRAME_DATA_DYNAMIC_HDR_PLUS), - }); return csp; } @@ -1346,7 +1329,7 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args) args->res->params.color.primaries = mp_prim_from_pl(target.color.primaries); args->res->params.color.gamma = mp_trc_from_pl(target.color.transfer); args->res->params.color.levels = mp_levels_from_pl(target.repr.levels); - args->res->params.color.sig_peak = target.color.hdr.max_luma / MP_REF_WHITE; + args->res->params.color.hdr = target.color.hdr; if (args->scaled) args->res->params.p_w = args->res->params.p_h = 1; diff --git a/video/zimg.c b/video/zimg.c index be2953c58c..5ff300caab 100644 --- a/video/zimg.c +++ b/video/zimg.c @@ -548,8 +548,8 @@ static bool mp_zimg_state_init(struct mp_zimg_context *ctx, params.allow_approximate_gamma = 1; // leave at default for SDR, which means 100 cd/m^2 for zimg - if (ctx->dst.color.sig_peak > 0 && mp_trc_is_hdr(ctx->dst.color.gamma)) - params.nominal_peak_luminance = ctx->dst.color.sig_peak * MP_REF_WHITE; + if (ctx->dst.color.hdr.max_luma > 0 && mp_trc_is_hdr(ctx->dst.color.gamma)) + params.nominal_peak_luminance = ctx->dst.color.hdr.max_luma; st->graph = zimg_filter_graph_build(&src_fmt, &dst_fmt, ¶ms); if (!st->graph) {