From 8d9b30695b1ef130f40a8fa4497cb0cbd2250072 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Mon, 18 Feb 2019 20:53:58 +0900 Subject: [PATCH] avviddec: Extract HDR information if any Convert mastering display information (a.k.a HDR static metadata) and content light level information provided by FFMPEG to Gstreamer. --- ext/libav/gstavviddec.c | 112 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c index e600b2162f..33fcd8e3bb 100644 --- a/ext/libav/gstavviddec.c +++ b/ext/libav/gstavviddec.c @@ -26,6 +26,7 @@ #include #include +#include #include "gstav.h" #include "gstavcodecmap.h" @@ -1069,6 +1070,60 @@ stereo_av_to_gst (enum AVStereo3DType type) return GST_VIDEO_MULTIVIEW_MODE_NONE; } +static gboolean +mastering_display_metadata_av_to_gst (AVMasteringDisplayMetadata * av, + GstVideoMasteringDisplayInfo * gst) +{ + /* Use only complete mastering meta */ + if (!av->has_primaries || !av->has_luminance) + return FALSE; + + gst->Wx_n = av->white_point[0].num; + gst->Wx_d = av->white_point[0].den; + + gst->Wy_n = av->white_point[1].num; + gst->Wy_d = av->white_point[1].den; + + gst->Rx_n = av->display_primaries[0][0].num; + gst->Rx_d = av->display_primaries[0][0].den; + + gst->Ry_n = av->display_primaries[0][1].num; + gst->Ry_d = av->display_primaries[0][1].den; + + gst->Gx_n = av->display_primaries[1][0].num; + gst->Gx_d = av->display_primaries[1][0].den; + + gst->Gy_n = av->display_primaries[1][1].num; + gst->Gy_d = av->display_primaries[1][1].den; + + gst->Bx_n = av->display_primaries[2][0].num; + gst->Bx_d = av->display_primaries[2][0].den; + + gst->By_n = av->display_primaries[2][1].num; + gst->By_d = av->display_primaries[2][1].den; + + gst->max_luma_n = av->max_luminance.num; + gst->max_luma_d = av->max_luminance.den; + + gst->min_luma_n = av->min_luminance.num; + gst->min_luma_d = av->min_luminance.den; + + return TRUE; +} + +static gboolean +content_light_metadata_av_to_gst (AVContentLightMetadata * av, + GstVideoContentLightLevel * gst) +{ + gst->maxCLL_n = av->MaxCLL; + gst->maxCLL_d = 1; + + gst->maxFALL_n = av->MaxFALL; + gst->maxFALL_d = 1; + + return TRUE; +} + static gboolean gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context, AVFrame * picture) @@ -1270,6 +1325,63 @@ gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec, GST_VIDEO_INFO_MULTIVIEW_MODE (out_info) = ffmpegdec->cur_multiview_mode; GST_VIDEO_INFO_MULTIVIEW_FLAGS (out_info) = ffmpegdec->cur_multiview_flags; + /* To passing HDR information to caps directly */ + if (output_state->caps == NULL) { + output_state->caps = gst_video_info_to_caps (out_info); + } else { + output_state->caps = gst_caps_make_writable (output_state->caps); + } + + if (!gst_structure_has_field (in_s, "mastering-display-info")) { + AVFrameSideData *sd = av_frame_get_side_data (picture, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + GstVideoMasteringDisplayInfo mastering; + + if (sd + && mastering_display_metadata_av_to_gst ((AVMasteringDisplayMetadata *) + sd->data, &mastering)) { + GST_LOG_OBJECT (ffmpegdec, "update mastering display info"); + GST_LOG_OBJECT (ffmpegdec, "\tRed (%u/%u, %u/%u)", mastering.Rx_n, + mastering.Rx_d, mastering.Ry_n, mastering.Ry_d); + GST_LOG_OBJECT (ffmpegdec, "\tGreen(%u/%u, %u/%u)", mastering.Gx_n, + mastering.Gx_d, mastering.Gy_n, mastering.Gy_d); + GST_LOG_OBJECT (ffmpegdec, "\tBlue (%u/%u, %u/%u)", mastering.Bx_n, + mastering.Bx_d, mastering.By_n, mastering.By_d); + GST_LOG_OBJECT (ffmpegdec, "\tWhite(%u/%u, %u/%u)", mastering.Wx_n, + mastering.Wx_d, mastering.Wy_n, mastering.Wy_d); + GST_LOG_OBJECT (ffmpegdec, + "\tmax_luminance:(%u/%u), min_luminance:(%u/%u)", + mastering.max_luma_n, mastering.max_luma_d, mastering.min_luma_n, + mastering.min_luma_d); + + if (!gst_video_mastering_display_info_add_to_caps (&mastering, + output_state->caps)) { + GST_WARNING_OBJECT (ffmpegdec, + "Couldn't set mastering display info to caps"); + } + } + } + + if (!gst_structure_has_field (in_s, "content-light-level")) { + AVFrameSideData *sd = av_frame_get_side_data (picture, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + GstVideoContentLightLevel level; + + if (sd && content_light_metadata_av_to_gst ((AVContentLightMetadata *) + sd->data, &level)) { + GST_LOG_OBJECT (ffmpegdec, "update content light level"); + GST_LOG_OBJECT (ffmpegdec, + "\tmaxCLL:(%u/%u), maxFALL:(%u/%u)", level.maxCLL_n, level.maxCLL_d, + level.maxFALL_n, level.maxFALL_d); + + if (!gst_video_content_light_level_add_to_caps (&level, + output_state->caps)) { + GST_WARNING_OBJECT (ffmpegdec, + "Couldn't set content light level to caps"); + } + } + } + if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (ffmpegdec))) goto negotiate_failed;