From 4470eaf5e5caefc5c68440babb9b4e5b23c4627a Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sun, 7 Nov 2021 23:47:55 +0100 Subject: vo_gpu_next: implement HDR passthrough Completely untested, since Linux still can't into HDR in 2021. Somebody please make sure it works. Technically covers #8219, since gpu-context=drm can be combined with vo=gpu-next. --- DOCS/interface-changes.rst | 1 + DOCS/man/options.rst | 5 ++++ video/out/vo_gpu_next.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 6aa6fd907d..e8ad97cd55 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -31,6 +31,7 @@ Interface changes `--allow-delayed-peak-detect`, `--builtin-scalers`, `--interpolation-preserve` `--lut`, `--lut-type`, `--image-lut`, `--image-lut-type` and `--target-lut` along with it. + - add `--target-colorspace-hint` --- mpv 0.34.0 --- - deprecate selecting by card number with `--drm-connector`, add `--drm-device` which can be used instead diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 254321d6ce..d03ec08f0d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6172,6 +6172,11 @@ them. Fully replaces the color decoding. A LUT of this type should ingest the image's native colorspace and output normalized non-linear RGB. +``--target-colorspace-hint``` + Automatically configure the output colorspace of the display to pass + through the input values of the stream (e.g. for HDR passthrough), if + possible. Requires a supporting driver and ``--vo=gpu-next``. + ``--target-prim=`` Specifies the primaries of the display. Video colors will be adapted to this colorspace when ICC color management is not being used. Valid values diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 64ff4eb1da..c260af8865 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -127,6 +127,7 @@ struct priv { int delayed_peak; int inter_preserve; + int target_hint; }; static void update_render_options(struct priv *p); @@ -486,6 +487,57 @@ static void discard_frame(const struct pl_source_frame *src) talloc_free(mpi); } +static struct pl_swapchain_colors get_csp_hint(struct vo *vo, struct mp_image *mpi) +{ + struct priv *p = vo->priv; + const struct gl_video_opts *opts = p->opts_cache->opts; + + struct pl_swapchain_colors hint = { + .primaries = mp_prim_to_pl(mpi->params.color.primaries), + .transfer = mp_trc_to_pl(mpi->params.color.gamma), + }; + + // Respect target color space overrides + if (opts->target_prim) + hint.primaries = mp_prim_to_pl(opts->target_prim); + if (opts->target_trc) + hint.transfer = mp_prim_to_pl(opts->target_trc); + + for (int i = 0; i < mpi->num_ff_side_data; i++) { + void *data = mpi->ff_side_data[i].buf->data; + switch (mpi->ff_side_data[i].type) { + case AV_FRAME_DATA_CONTENT_LIGHT_LEVEL: { + const AVContentLightMetadata *clm = data; + hint.hdr.max_cll = clm->MaxCLL; + hint.hdr.max_fall = clm->MaxFALL; + break; + } + case AV_FRAME_DATA_MASTERING_DISPLAY_METADATA: { + const AVMasteringDisplayMetadata *mdm = data; + if (mdm->has_luminance) { + hint.hdr.min_luma = av_q2d(mdm->min_luminance); + hint.hdr.max_luma = av_q2d(mdm->max_luminance); + } + + if (mdm->has_primaries) { + hint.hdr.prim.red.x = av_q2d(mdm->display_primaries[0][0]); + hint.hdr.prim.red.y = av_q2d(mdm->display_primaries[0][1]); + hint.hdr.prim.green.x = av_q2d(mdm->display_primaries[1][0]); + hint.hdr.prim.green.y = av_q2d(mdm->display_primaries[1][1]); + hint.hdr.prim.blue.x = av_q2d(mdm->display_primaries[2][0]); + hint.hdr.prim.blue.y = av_q2d(mdm->display_primaries[2][1]); + hint.hdr.prim.white.x = av_q2d(mdm->white_point[0]); + hint.hdr.prim.white.y = av_q2d(mdm->white_point[1]); + } + break; + } + default: break; + } + } + + return hint; +} + static void info_callback(void *priv, const struct pl_render_info *info) { struct vo *vo = priv; @@ -580,6 +632,13 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (!should_draw) return; + if (p->target_hint && frame->current) { + struct pl_swapchain_colors hint = get_csp_hint(vo, frame->current); + pl_swapchain_colorspace_hint(p->sw, &hint); + } else if (!p->target_hint) { + pl_swapchain_colorspace_hint(p->sw, NULL); + } + struct pl_swapchain_frame swframe; if (!pl_swapchain_start_frame(p->sw, &swframe)) { // Advance the queue state to the current PTS to discard unused frames @@ -1275,6 +1334,7 @@ const struct vo_driver video_out_gpu_next = { {"image-lut", OPT_STRING(image_lut.opt), .flags = M_OPT_FILE}, {"image-lut-type", OPT_CHOICE_C(image_lut.type, lut_types)}, {"target-lut", OPT_STRING(target_lut.opt), .flags = M_OPT_FILE}, + {"target-colorspace-hint", OPT_FLAG(target_hint)}, // No `target-lut-type` because we don't support non-RGB targets {0} }, -- cgit v1.2.3