mirror of
https://github.com/mpv-player/mpv
synced 2024-12-22 06:42:03 +00:00
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.
This commit is contained in:
parent
c335e84230
commit
deb9370779
@ -568,7 +568,12 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track,
|
||||
MP_VERBOSE(demuxer, "| + Levels: %s\n",
|
||||
m_opt_choice_str(mp_csp_levels_names, track->color.levels));
|
||||
}
|
||||
if (colour->n_mastering_metadata) {
|
||||
if (colour->n_max_cll) {
|
||||
track->color.sig_peak = colour->max_cll / MP_REF_WHITE;
|
||||
MP_VERBOSE(demuxer, "| + MaxCLL: %lu\n", colour->max_cll);
|
||||
}
|
||||
// if MaxCLL is unavailable, try falling back to the mastering metadata
|
||||
if (!track->color.sig_peak && colour->n_mastering_metadata) {
|
||||
struct ebml_mastering_metadata *mastering = &colour->mastering_metadata;
|
||||
|
||||
if (mastering->n_luminance_max) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
|
||||
params->color.sig_peak = clm->MaxCLL / MP_REF_WHITE;
|
||||
}
|
||||
#endif
|
||||
|
||||
params->color.sig_peak = ctx->cached_hdr_peak / MP_REF_WHITE;
|
||||
#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)
|
||||
params->color.sig_peak = av_q2d(mdm->max_luminance) / MP_REF_WHITE;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
6
wscript
6
wscript
@ -449,6 +449,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_
|
||||
'func': check_statement('libavutil/imgutils.h',
|
||||
'av_image_copy_uc_from(0,0,0,0,0,0,0)',
|
||||
use='libav'),
|
||||
}, {
|
||||
'name': 'avutil-content-light-level',
|
||||
'desc': 'libavutil content light level struct',
|
||||
'func': check_statement('libavutil/frame.h',
|
||||
'AV_FRAME_DATA_CONTENT_LIGHT_LEVEL',
|
||||
use='libav'),
|
||||
},
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user