From deb93707791092e608b1e5f8f1d1773b0057ce59 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sat, 10 Jun 2017 14:02:55 +0200 Subject: vd: use ST.2086 / HDR10 MaxCLL in addition to mastering metadata MaxCLL is the more authoritative source for the metadata we are interested in. The use of mastering metadata is sort of a hack anyway, since there's no clearly-defined relationship between the mastering peak brightness and the actual content. (Unlike MaxCLL, which is an explicit relationship) Also move the parameter fixing to `fix_image_params` I don't know if the avutil check is strictly necessary but I've included it anyway to be on the safe side. --- video/decode/dec_video.c | 15 ++++++++++++++- video/decode/lavc.h | 2 +- video/decode/vd_lavc.c | 37 +++++++++++++++++++++---------------- 3 files changed, 36 insertions(+), 18 deletions(-) (limited to 'video') diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c index bd20dbe312..f7ca6cc477 100644 --- a/video/decode/dec_video.c +++ b/video/decode/dec_video.c @@ -188,6 +188,11 @@ bool video_init_best_codec(struct dec_video *d_video) return !!d_video->vd_driver; } +static bool is_valid_peak(float sig_peak) +{ + return !sig_peak || (sig_peak >= 1 && sig_peak <= 100); +} + static void fix_image_params(struct dec_video *d_video, struct mp_image_params *params) { @@ -258,8 +263,16 @@ static void fix_image_params(struct dec_video *d_video, } p.stereo_out = opts->video_stereo_mode; - // Detect colorspace from resolution. mp_colorspace_merge(&p.color, &c->color); + + // Sanitize the HDR peak. Sadly necessary + if (!is_valid_peak(p.color.sig_peak)) { + MP_WARN(d_video, "Invalid HDR peak in stream: %f\n", p.color.sig_peak); + p.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(&p); d_video->last_format = *params; diff --git a/video/decode/lavc.h b/video/decode/lavc.h index f58ee8bc1e..e567a49b4e 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -39,7 +39,7 @@ typedef struct lavc_ctx { int framedrop_flags; // For HDR side-data caching - double cached_hdr_peak; + float cached_sig_peak; bool hw_probing; struct demux_packet **sent_packets; diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index aae6937476..226fd30bd3 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -721,28 +721,33 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, struct mp_image_params *params) { vd_ffmpeg_ctx *ctx = vd->priv; + AVFrameSideData *sd; -#if LIBAVCODEC_VERSION_MICRO >= 100 - // Get the reference peak (for HDR) if available. This is cached into ctx - // when it's found, since it's not available on every frame (and seems to - // be only available for keyframes) - AVFrameSideData *sd = av_frame_get_side_data(frame, - AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); +#if HAVE_AVUTIL_CONTENT_LIGHT_LEVEL + // Get the content light metadata if available + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); if (sd) { + AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; + params->color.sig_peak = clm->MaxCLL / MP_REF_WHITE; + } +#endif + +#if LIBAVCODEC_VERSION_MICRO >= 100 + // Otherwise, try getting the mastering metadata if available + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (!params->color.sig_peak && sd) { AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *)sd->data; - if (mdm->has_luminance) { - double peak = av_q2d(mdm->max_luminance); - if (!isnormal(peak) || peak < 10 || peak > 100000) { - // Invalid data, ignore it. Sadly necessary - MP_WARN(vd, "Invalid HDR reference peak in stream: %f\n", peak); - } else { - ctx->cached_hdr_peak = peak; - } - } + if (mdm->has_luminance) + params->color.sig_peak = av_q2d(mdm->max_luminance) / MP_REF_WHITE; } #endif - params->color.sig_peak = ctx->cached_hdr_peak / MP_REF_WHITE; + if (params->color.sig_peak) { + ctx->cached_sig_peak = params->color.sig_peak; + } else { + params->color.sig_peak = ctx->cached_sig_peak; + } + params->rotate = vd->codec->rotate; params->stereo_in = vd->codec->stereo_mode; } -- cgit v1.2.3