matroskademux: Add support parsing HDR metadata

Set SMPTE ST 2086 mastering-display-metadata and
content-light-level to caps, if any
This commit is contained in:
Seungha Yang 2019-02-18 23:28:50 +09:00
parent 53fedc43ae
commit 61f9a2a415
3 changed files with 175 additions and 1 deletions

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 {