summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2016-06-29 09:43:55 +0200
committerwm4 <wm4@nowhere>2016-07-03 19:42:52 +0200
commit5b6cce2b735951f82b707c3d3625f99bc6d6da09 (patch)
tree945223846d8aeb60b3ddfb175e14dd1c3c7bc9ff
parent923e3c7b20f0a238062b0ac538a751c6c363a8cb (diff)
downloadmpv-5b6cce2b735951f82b707c3d3625f99bc6d6da09.tar.bz2
mpv-5b6cce2b735951f82b707c3d3625f99bc6d6da09.tar.xz
vd_lavc: expose mastering display side data reference peak
This greatly improves the result when decoding typical (ST.2084) HDR content, since the job of tone mapping gets significantly easier when you're only mapping from 1000 to 250, rather than 10000 to 250. The difference is so drastic that we can now even reasonably use `hdr-tone-mapping=linear` and get a very perceptually uniform result that is only slightly darker than normal. (To compensate for the extra dynamic range) Due to weird implementation details, this only seems to be present on keyframes (or something like that), so we have to cache the last seen value for the frames in between. Also, in some files the metadata is just completely broken / nonsensical, so I decided to apply a simple heuristic to detect completely broken metadata.
-rw-r--r--video/decode/lavc.h2
-rw-r--r--video/decode/vd_lavc.c25
-rw-r--r--wscript6
3 files changed, 32 insertions, 1 deletions
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index e76dff50bc..993c3ec437 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -26,7 +26,7 @@ typedef struct lavc_ctx {
bool hwdec_notified;
// For HDR side-data caching
- int cached_hdr_peak;
+ double cached_hdr_peak;
struct mp_image **delay_queue;
int num_delay_queue;
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 62fc4ff280..5962f883cd 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -47,6 +47,10 @@
#include "video/csputils.h"
#include "video/sws_utils.h"
+#if HAVE_AVUTIL_MASTERING_METADATA
+#include <libavutil/mastering_display_metadata.h>
+#endif
+
#include "lavc.h"
#if AVPALETTE_SIZE != MP_PALETTE_SIZE
@@ -572,6 +576,26 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame,
vd_ffmpeg_ctx *ctx = vd->priv;
struct MPOpts *opts = ctx->opts;
+#if HAVE_AVUTIL_MASTERING_METADATA
+ // 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 (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;
+ }
+ }
+ }
+#endif
+
*out_params = (struct mp_image_params) {
.imgfmt = pixfmt2imgfmt(frame->format),
.w = frame->width,
@@ -583,6 +607,7 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame,
.levels = avcol_range_to_mp_csp_levels(ctx->avctx->color_range),
.primaries = avcol_pri_to_mp_csp_prim(ctx->avctx->color_primaries),
.gamma = avcol_trc_to_mp_csp_trc(ctx->avctx->color_trc),
+ .sig_peak = ctx->cached_hdr_peak,
},
.chroma_location =
avchroma_location_to_mp(ctx->avctx->chroma_sample_location),
diff --git a/wscript b/wscript
index e29d1ab403..9269d95b54 100644
--- a/wscript
+++ b/wscript
@@ -504,6 +504,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_
'AVCOL_TRC_SMPTEST2084,'
'AVCOL_TRC_ARIB_STD_B67',
use='libav'),
+ }, {
+ 'name': 'avutil-mastering-metadata',
+ 'desc': 'libavutil mastering display metadata struct',
+ 'func': check_statement('libavutil/mastering_display_metadata.h',
+ 'AV_FRAME_DATA_MASTERING_DISPLAY_METADATA',
+ use='libav'),
}
]