From 61f9a2a4159079d40f47cf4e8daf563f4461f6b6 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Mon, 18 Feb 2019 23:28:50 +0900 Subject: [PATCH] matroskademux: Add support parsing HDR metadata Set SMPTE ST 2086 mastering-display-metadata and content-light-level to caps, if any --- gst/matroska/matroska-demux.c | 153 ++++++++++++++++++++++++++++++++++ gst/matroska/matroska-ids.c | 4 +- gst/matroska/matroska-ids.h | 19 +++++ 3 files changed, 175 insertions(+), 1 deletion(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index b2cd9b5d41..acafe12311 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -463,6 +463,110 @@ gst_matroska_demux_add_stream_headers_to_caps (GstMatroskaDemux * demux, g_value_unset (&buf_val); } +static GstFlowReturn +gst_matroska_demux_parse_mastering_metadata (GstMatroskaDemux * demux, + GstEbmlRead * ebml, GstMatroskaTrackVideoContext * video_context) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstVideoMasteringDisplayInfo minfo; + guint32 id; + gdouble num; + /* Precision defined by HEVC specification */ + const guint chroma_den = 50000; + const guint luma_den = 10000; + + gst_video_mastering_display_info_init (&minfo); + + DEBUG_ELEMENT_START (demux, ebml, "MasteringMetadata"); + + if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) + goto beach; + + while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) { + if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) + goto beach; + + /* all sub elements have float type */ + if ((ret = gst_ebml_read_float (ebml, &id, &num)) != GST_FLOW_OK) + goto beach; + + /* chromaticity should be in [0, 1] range */ + if (id >= GST_MATROSKA_ID_PRIMARYRCHROMATICITYX && + id <= GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY) { + if (num < 0 || num > 1.0) { + GST_WARNING_OBJECT (demux, "0x%x has invalid value %f", id, num); + goto beach; + } + } else if (id == GST_MATROSKA_ID_LUMINANCEMAX || + id == GST_MATROSKA_ID_LUMINANCEMIN) { + /* Note: webM spec said valid range is [0, 999.9999] but + * 1000 cd/m^2 is generally used value on HDR. Just check guint range here. + * See https://www.webmproject.org/docs/container/#LuminanceMax + */ + if (num < 0 || num > (gdouble) (G_MAXUINT32 / luma_den)) { + GST_WARNING_OBJECT (demux, "0x%x has invalid value %f", id, num); + goto beach; + } + } + + switch (id) { + case GST_MATROSKA_ID_PRIMARYRCHROMATICITYX: + minfo.Rx_n = (guint) round (num * chroma_den); + minfo.Rx_d = chroma_den; + break; + case GST_MATROSKA_ID_PRIMARYRCHROMATICITYY: + minfo.Ry_n = (guint) round (num * chroma_den); + minfo.Ry_d = chroma_den; + break; + case GST_MATROSKA_ID_PRIMARYGCHROMATICITYX: + minfo.Gx_n = (guint) round (num * chroma_den); + minfo.Gx_d = chroma_den; + break; + case GST_MATROSKA_ID_PRIMARYGCHROMATICITYY: + minfo.Gy_n = (guint) round (num * chroma_den); + minfo.Gy_d = chroma_den; + break; + case GST_MATROSKA_ID_PRIMARYBCHROMATICITYX: + minfo.Bx_n = (guint) round (num * chroma_den); + minfo.Bx_d = chroma_den; + break; + case GST_MATROSKA_ID_PRIMARYBCHROMATICITYY: + minfo.By_n = (guint) round (num * chroma_den); + minfo.By_d = chroma_den; + break; + case GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX: + minfo.Wx_n = (guint) round (num * chroma_den); + minfo.Wx_d = chroma_den; + break; + case GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY: + minfo.Wy_n = (guint) round (num * chroma_den); + minfo.Wy_d = chroma_den; + break; + case GST_MATROSKA_ID_LUMINANCEMAX: + minfo.max_luma_n = (guint) round (num * luma_den); + minfo.max_luma_d = luma_den; + break; + case GST_MATROSKA_ID_LUMINANCEMIN: + minfo.min_luma_n = (guint) round (num * luma_den); + minfo.min_luma_d = luma_den; + break; + default: + GST_FIXME_OBJECT (demux, + "Unsupported subelement 0x%x in MasteringMetadata", id); + ret = gst_ebml_read_skip (ebml); + break; + } + } + + video_context->mastering_display_info = minfo; + video_context->mastering_display_info_present = TRUE; + +beach: + DEBUG_ELEMENT_STOP (demux, ebml, "MasteringMetadata", ret); + + return ret; +} + static GstFlowReturn gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml, GstMatroskaTrackVideoContext * video_context) @@ -631,6 +735,40 @@ gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml, break; } + case GST_MATROSKA_ID_MASTERINGMETADATA:{ + if ((ret = + gst_matroska_demux_parse_mastering_metadata (demux, ebml, + video_context)) != GST_FLOW_OK) + goto beach; + break; + } + + case GST_MATROSKA_ID_MAXCLL:{ + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + goto beach; + if (num >= G_MAXUINT32) { + GST_WARNING_OBJECT (demux, + "Too large maxCLL value %" G_GUINT64_FORMAT, num); + } else { + video_context->content_light_level.maxCLL_n = num; + video_context->content_light_level.maxCLL_d = 1; + } + break; + } + + case GST_MATROSKA_ID_MAXFALL:{ + if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) + goto beach; + if (num >= G_MAXUINT32) { + GST_WARNING_OBJECT (demux, + "Too large maxFALL value %" G_GUINT64_FORMAT, num); + } else { + video_context->content_light_level.maxFALL_n = num; + video_context->content_light_level.maxFALL_d = 1; + } + break; + } + default: GST_FIXME_OBJECT (demux, "Unsupported subelement 0x%x in Colour", id); ret = gst_ebml_read_skip (ebml); @@ -6429,6 +6567,21 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * g_free (colorimetry); } + if (videocontext->mastering_display_info_present) { + if (!gst_video_mastering_display_info_add_to_caps + (&videocontext->mastering_display_info, caps)) { + GST_WARNING ("couldn't set mastering display info to caps"); + } + } + + if (videocontext->content_light_level.maxCLL_n && + videocontext->content_light_level.maxFALL_n) { + if (!gst_video_content_light_level_add_to_caps + (&videocontext->content_light_level, caps)) { + GST_WARNING ("couldn't set content light level to caps"); + } + } + caps = gst_caps_simplify (caps); } diff --git a/gst/matroska/matroska-ids.c b/gst/matroska/matroska-ids.c index 5716b45874..63f7b4c0ad 100644 --- a/gst/matroska/matroska-ids.c +++ b/gst/matroska/matroska-ids.c @@ -68,7 +68,9 @@ gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context) video_context->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN; video_context->colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN; video_context->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN; - + gst_video_mastering_display_info_init + (&video_context->mastering_display_info); + gst_video_content_light_level_init (&video_context->content_light_level); return TRUE; } diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h index 34a25cd490..ab74ed2897 100644 --- a/gst/matroska/matroska-ids.h +++ b/gst/matroska/matroska-ids.h @@ -145,6 +145,20 @@ #define GST_MATROSKA_ID_VIDEORANGE 0x55B9 #define GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS 0x55BA #define GST_MATROSKA_ID_VIDEOPRIMARIES 0x55BB +#define GST_MATROSKA_ID_MAXCLL 0x55BC +#define GST_MATROSKA_ID_MAXFALL 0x55BD +#define GST_MATROSKA_ID_MASTERINGMETADATA 0x55D0 +/* IDs in the MasteringMetadata */ +#define GST_MATROSKA_ID_PRIMARYRCHROMATICITYX 0x55D1 +#define GST_MATROSKA_ID_PRIMARYRCHROMATICITYY 0x55D2 +#define GST_MATROSKA_ID_PRIMARYGCHROMATICITYX 0x55D3 +#define GST_MATROSKA_ID_PRIMARYGCHROMATICITYY 0x55D4 +#define GST_MATROSKA_ID_PRIMARYBCHROMATICITYX 0x55D5 +#define GST_MATROSKA_ID_PRIMARYBCHROMATICITYY 0x55D6 +#define GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX 0x55D7 +#define GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY 0x55D8 +#define GST_MATROSKA_ID_LUMINANCEMAX 0x55D9 +#define GST_MATROSKA_ID_LUMINANCEMIN 0x55DA /* IDs in the TrackAudio master */ #define GST_MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 @@ -627,6 +641,11 @@ typedef struct _GstMatroskaTrackVideoContext { GstBuffer *dirac_unit; GstVideoColorimetry colorimetry; + + GstVideoMasteringDisplayInfo mastering_display_info; + gboolean mastering_display_info_present; + + GstVideoContentLightLevel content_light_level; } GstMatroskaTrackVideoContext; typedef struct _GstMatroskaTrackAudioContext {