mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 02:30:35 +00:00
f76b731cbf
update GST_VIDEO_HDR10_PLUS_MAX_ROWS_MD_APL and GST_VIDEO_HDR10_PLUS_MAX_COLS_MD_APL Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/979>
739 lines
22 KiB
C
739 lines
22 KiB
C
/* GStreamer
|
|
* Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <gst/base/gstbitreader.h>
|
|
|
|
#include "video-hdr.h"
|
|
|
|
#define HDR10_PLUS_MAX_BEZIER_CURVE_ANCHORS 9
|
|
#define HDR10_PLUS_MAX_DIST_MAXRGB_PERCENTILES 9
|
|
|
|
#define N_ELEMENT_MASTERING_DISPLAY_INFO 10
|
|
#define MASTERING_FORMAT \
|
|
"%d:%d:" \
|
|
"%d:%d:" \
|
|
"%d:%d:" \
|
|
"%d:%d:" \
|
|
"%d:%d"
|
|
|
|
#define MASTERING_PRINTF_ARGS(m) \
|
|
(m)->display_primaries[0].x, (m)->display_primaries[0].y, \
|
|
(m)->display_primaries[1].x, (m)->display_primaries[1].y, \
|
|
(m)->display_primaries[2].x, (m)->display_primaries[2].y, \
|
|
(m)->white_point.x, (m)->white_point.y, \
|
|
(m)->max_display_mastering_luminance, \
|
|
(m)->min_display_mastering_luminance
|
|
|
|
/**
|
|
* gst_video_hdr_format_to_string:
|
|
* @format: a #GstVideoHDRFormat
|
|
*
|
|
* Returns: (nullable): a string containing a descriptive name for
|
|
* the #GstVideoHDRFormat if there is one, or %NULL otherwise.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
const gchar *
|
|
gst_video_hdr_format_to_string (GstVideoHDRFormat format)
|
|
{
|
|
switch (format) {
|
|
case GST_VIDEO_HDR_FORMAT_HDR10:
|
|
return "hdr10";
|
|
case GST_VIDEO_HDR_FORMAT_HDR10_PLUS:
|
|
return "hdr10+";
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_video_hdr_format_from_string:
|
|
* @format: (nullable): a #GstVideoHDRFormat
|
|
*
|
|
* Returns: the #GstVideoHDRFormat for @format or GST_VIDEO_HDR_FORMAT_NONE when the
|
|
* string is not a known format.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
GstVideoHDRFormat
|
|
gst_video_hdr_format_from_string (const gchar * format)
|
|
{
|
|
if (!g_strcmp0 (format, "hdr10"))
|
|
return GST_VIDEO_HDR_FORMAT_HDR10;
|
|
else if (!g_strcmp0 (format, "hdr10+"))
|
|
return GST_VIDEO_HDR_FORMAT_HDR10_PLUS;
|
|
|
|
return GST_VIDEO_HDR_FORMAT_NONE;
|
|
}
|
|
|
|
/**
|
|
* gst_video_mastering_display_info_init:
|
|
* @minfo: a #GstVideoMasteringDisplayInfo
|
|
*
|
|
* Initialize @minfo
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
void
|
|
gst_video_mastering_display_info_init (GstVideoMasteringDisplayInfo * minfo)
|
|
{
|
|
g_return_if_fail (minfo != NULL);
|
|
|
|
memset (minfo, 0, sizeof (GstVideoMasteringDisplayInfo));
|
|
}
|
|
|
|
/**
|
|
* gst_video_mastering_display_info_from_string:
|
|
* @minfo: (out): a #GstVideoMasteringDisplayInfo
|
|
* @mastering: a #GstStructure representing #GstVideoMasteringDisplayInfo
|
|
*
|
|
* Extract #GstVideoMasteringDisplayInfo from @mastering
|
|
*
|
|
* Returns: %TRUE if @minfo was filled with @mastering
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_mastering_display_info_from_string (GstVideoMasteringDisplayInfo *
|
|
minfo, const gchar * mastering)
|
|
{
|
|
gboolean ret = FALSE;
|
|
gchar **split;
|
|
gint i;
|
|
gint idx = 0;
|
|
guint64 val;
|
|
|
|
g_return_val_if_fail (minfo != NULL, FALSE);
|
|
g_return_val_if_fail (mastering != NULL, FALSE);
|
|
|
|
split = g_strsplit (mastering, ":", -1);
|
|
|
|
if (g_strv_length (split) != N_ELEMENT_MASTERING_DISPLAY_INFO)
|
|
goto out;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (minfo->display_primaries); i++) {
|
|
if (!g_ascii_string_to_unsigned (split[idx++],
|
|
10, 0, G_MAXUINT16, &val, NULL))
|
|
goto out;
|
|
|
|
minfo->display_primaries[i].x = (guint16) val;
|
|
|
|
if (!g_ascii_string_to_unsigned (split[idx++],
|
|
10, 0, G_MAXUINT16, &val, NULL))
|
|
goto out;
|
|
|
|
minfo->display_primaries[i].y = (guint16) val;
|
|
}
|
|
|
|
if (!g_ascii_string_to_unsigned (split[idx++],
|
|
10, 0, G_MAXUINT16, &val, NULL))
|
|
goto out;
|
|
|
|
minfo->white_point.x = (guint16) val;
|
|
|
|
if (!g_ascii_string_to_unsigned (split[idx++],
|
|
10, 0, G_MAXUINT16, &val, NULL))
|
|
goto out;
|
|
|
|
minfo->white_point.y = (guint16) val;
|
|
|
|
if (!g_ascii_string_to_unsigned (split[idx++],
|
|
10, 0, G_MAXUINT32, &val, NULL))
|
|
goto out;
|
|
|
|
minfo->max_display_mastering_luminance = (guint32) val;
|
|
|
|
if (!g_ascii_string_to_unsigned (split[idx++],
|
|
10, 0, G_MAXUINT32, &val, NULL))
|
|
goto out;
|
|
|
|
minfo->min_display_mastering_luminance = (guint32) val;
|
|
ret = TRUE;
|
|
|
|
out:
|
|
g_strfreev (split);
|
|
if (!ret)
|
|
gst_video_mastering_display_info_init (minfo);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* gst_video_mastering_display_info_to_string:
|
|
* @minfo: a #GstVideoMasteringDisplayInfo
|
|
*
|
|
* Convert @minfo to its string representation
|
|
*
|
|
* Returns: (transfer full): a string representation of @minfo
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gchar *
|
|
gst_video_mastering_display_info_to_string (const GstVideoMasteringDisplayInfo *
|
|
minfo)
|
|
{
|
|
g_return_val_if_fail (minfo != NULL, NULL);
|
|
|
|
return g_strdup_printf (MASTERING_FORMAT, MASTERING_PRINTF_ARGS (minfo));
|
|
}
|
|
|
|
/**
|
|
* gst_video_mastering_display_info_is_equal:
|
|
* @minfo: a #GstVideoMasteringDisplayInfo
|
|
* @other: a #GstVideoMasteringDisplayInfo
|
|
*
|
|
* Checks equality between @minfo and @other.
|
|
*
|
|
* Returns: %TRUE if @minfo and @other are equal.
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_mastering_display_info_is_equal (const GstVideoMasteringDisplayInfo *
|
|
minfo, const GstVideoMasteringDisplayInfo * other)
|
|
{
|
|
gint i;
|
|
|
|
g_return_val_if_fail (minfo != NULL, FALSE);
|
|
g_return_val_if_fail (other != NULL, FALSE);
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (minfo->display_primaries); i++) {
|
|
if (minfo->display_primaries[i].x != other->display_primaries[i].x ||
|
|
minfo->display_primaries[i].y != other->display_primaries[i].y)
|
|
return FALSE;
|
|
}
|
|
|
|
if (minfo->white_point.x != other->white_point.x ||
|
|
minfo->white_point.y != other->white_point.y ||
|
|
minfo->max_display_mastering_luminance !=
|
|
other->max_display_mastering_luminance
|
|
|| minfo->min_display_mastering_luminance !=
|
|
other->min_display_mastering_luminance)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_video_mastering_display_info_from_caps:
|
|
* @minfo: a #GstVideoMasteringDisplayInfo
|
|
* @caps: a #GstCaps
|
|
*
|
|
* Parse @caps and update @minfo
|
|
*
|
|
* Returns: %TRUE if @caps has #GstVideoMasteringDisplayInfo and could be parsed
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_mastering_display_info_from_caps (GstVideoMasteringDisplayInfo *
|
|
minfo, const GstCaps * caps)
|
|
{
|
|
GstStructure *structure;
|
|
const gchar *s;
|
|
|
|
g_return_val_if_fail (minfo != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
|
|
if ((s = gst_structure_get_string (structure,
|
|
"mastering-display-info")) == NULL)
|
|
return FALSE;
|
|
|
|
return gst_video_mastering_display_info_from_string (minfo, s);
|
|
}
|
|
|
|
/**
|
|
* gst_video_mastering_display_info_add_to_caps:
|
|
* @minfo: a #GstVideoMasteringDisplayInfo
|
|
* @caps: a #GstCaps
|
|
*
|
|
* Set string representation of @minfo to @caps
|
|
*
|
|
* Returns: %TRUE if @minfo was successfully set to @caps
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_mastering_display_info_add_to_caps (const GstVideoMasteringDisplayInfo
|
|
* minfo, GstCaps * caps)
|
|
{
|
|
gchar *s;
|
|
|
|
g_return_val_if_fail (minfo != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
|
|
|
|
s = gst_video_mastering_display_info_to_string (minfo);
|
|
if (!s)
|
|
return FALSE;
|
|
|
|
gst_caps_set_simple (caps, "mastering-display-info", G_TYPE_STRING, s, NULL);
|
|
g_free (s);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_video_content_light_level_init:
|
|
* @linfo: a #GstVideoContentLightLevel
|
|
*
|
|
* Initialize @linfo
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
void
|
|
gst_video_content_light_level_init (GstVideoContentLightLevel * linfo)
|
|
{
|
|
g_return_if_fail (linfo != NULL);
|
|
|
|
memset (linfo, 0, sizeof (GstVideoContentLightLevel));
|
|
}
|
|
|
|
/**
|
|
* gst_video_content_light_level_from_string:
|
|
* @linfo: a #GstVideoContentLightLevel
|
|
* @level: a content-light-level string from caps
|
|
*
|
|
* Parse the value of content-light-level caps field and update @minfo
|
|
* with the parsed values.
|
|
*
|
|
* Returns: %TRUE if @linfo points to valid #GstVideoContentLightLevel.
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_content_light_level_from_string (GstVideoContentLightLevel * linfo,
|
|
const gchar * level)
|
|
{
|
|
gboolean ret = FALSE;
|
|
gchar **split;
|
|
guint64 val;
|
|
|
|
g_return_val_if_fail (linfo != NULL, FALSE);
|
|
g_return_val_if_fail (level != NULL, FALSE);
|
|
|
|
split = g_strsplit (level, ":", -1);
|
|
|
|
if (g_strv_length (split) != 2)
|
|
goto out;
|
|
|
|
if (!g_ascii_string_to_unsigned (split[0], 10, 0, G_MAXUINT16, &val, NULL))
|
|
goto out;
|
|
|
|
linfo->max_content_light_level = (guint16) val;
|
|
|
|
if (!g_ascii_string_to_unsigned (split[1], 10, 0, G_MAXUINT16, &val, NULL))
|
|
goto out;
|
|
|
|
linfo->max_frame_average_light_level = (guint16) val;
|
|
|
|
ret = TRUE;
|
|
|
|
out:
|
|
g_strfreev (split);
|
|
if (!ret)
|
|
gst_video_content_light_level_init (linfo);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* gst_video_content_light_level_to_string:
|
|
* @linfo: a #GstVideoContentLightLevel
|
|
*
|
|
* Convert @linfo to its string representation.
|
|
*
|
|
* Returns: (transfer full): a string representation of @linfo.
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gchar *
|
|
gst_video_content_light_level_to_string (const GstVideoContentLightLevel *
|
|
linfo)
|
|
{
|
|
g_return_val_if_fail (linfo != NULL, NULL);
|
|
|
|
return g_strdup_printf ("%d:%d",
|
|
linfo->max_content_light_level, linfo->max_frame_average_light_level);
|
|
}
|
|
|
|
/**
|
|
* gst_video_content_light_level_from_caps:
|
|
* @linfo: a #GstVideoContentLightLevel
|
|
* @caps: a #GstCaps
|
|
*
|
|
* Parse @caps and update @linfo
|
|
*
|
|
* Returns: if @caps has #GstVideoContentLightLevel and could be parsed
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_content_light_level_from_caps (GstVideoContentLightLevel * linfo,
|
|
const GstCaps * caps)
|
|
{
|
|
GstStructure *structure;
|
|
const gchar *s;
|
|
|
|
g_return_val_if_fail (linfo != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
|
|
if ((s = gst_structure_get_string (structure, "content-light-level")) == NULL)
|
|
return FALSE;
|
|
|
|
return gst_video_content_light_level_from_string (linfo, s);
|
|
}
|
|
|
|
/**
|
|
* gst_video_content_light_level_add_to_caps:
|
|
* @linfo: a #GstVideoContentLightLevel
|
|
* @caps: a #GstCaps
|
|
*
|
|
* Parse @caps and update @linfo
|
|
*
|
|
* Returns: %TRUE if @linfo was successfully set to @caps
|
|
*
|
|
* Since: 1.18
|
|
*/
|
|
gboolean
|
|
gst_video_content_light_level_add_to_caps (const GstVideoContentLightLevel *
|
|
linfo, GstCaps * caps)
|
|
{
|
|
gchar *s;
|
|
|
|
g_return_val_if_fail (linfo != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
|
|
|
|
s = gst_video_content_light_level_to_string (linfo);
|
|
gst_caps_set_simple (caps, "content-light-level", G_TYPE_STRING, s, NULL);
|
|
g_free (s);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Dynamic HDR Meta implementation */
|
|
|
|
GType
|
|
gst_video_hdr_meta_api_get_type (void)
|
|
{
|
|
static volatile GType type = 0;
|
|
|
|
if (g_once_init_enter (&type)) {
|
|
static const gchar *tags[] = {
|
|
GST_META_TAG_VIDEO_STR,
|
|
NULL
|
|
};
|
|
GType _type = gst_meta_api_type_register ("GstVideoHDRMetaAPI", tags);
|
|
g_once_init_leave (&type, _type);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static gboolean
|
|
gst_video_hdr_meta_transform (GstBuffer * dest, GstMeta * meta,
|
|
GstBuffer * buffer, GQuark type, gpointer data)
|
|
{
|
|
GstVideoHDRMeta *dmeta, *smeta;
|
|
|
|
/* We always copy over the caption meta */
|
|
smeta = (GstVideoHDRMeta *) meta;
|
|
|
|
GST_DEBUG ("copy HDR metadata");
|
|
dmeta =
|
|
gst_buffer_add_video_hdr_meta (dest, smeta->format, smeta->data,
|
|
smeta->size);
|
|
if (!dmeta)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_video_hdr_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
|
|
{
|
|
GstVideoHDRMeta *emeta = (GstVideoHDRMeta *) meta;
|
|
|
|
emeta->data = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gst_video_hdr_meta_free (GstMeta * meta, GstBuffer * buffer)
|
|
{
|
|
GstVideoHDRMeta *emeta = (GstVideoHDRMeta *) meta;
|
|
|
|
g_free (emeta->data);
|
|
}
|
|
|
|
const GstMetaInfo *
|
|
gst_video_hdr_meta_get_info (void)
|
|
{
|
|
static const GstMetaInfo *meta_info = NULL;
|
|
|
|
if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
|
|
const GstMetaInfo *mi = gst_meta_register (GST_VIDEO_HDR_META_API_TYPE,
|
|
"GstVideoHDRMeta",
|
|
sizeof (GstVideoHDRMeta),
|
|
gst_video_hdr_meta_init,
|
|
gst_video_hdr_meta_free,
|
|
gst_video_hdr_meta_transform);
|
|
g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) mi);
|
|
}
|
|
return meta_info;
|
|
}
|
|
|
|
/**
|
|
* gst_buffer_add_video_hdr_meta:
|
|
* @buffer: a #GstBuffer
|
|
* @format: The type of dynamic HDR contained in the meta.
|
|
* @data: contains the dynamic HDR data
|
|
* @size: The size in bytes of @data
|
|
*
|
|
* Attaches #GstVideoHDRMeta metadata to @buffer with the given
|
|
* parameters.
|
|
*
|
|
* Returns: (transfer none): the #GstVideoHDRMeta on @buffer.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
GstVideoHDRMeta *
|
|
gst_buffer_add_video_hdr_meta (GstBuffer * buffer,
|
|
GstVideoHDRFormat format, const guint8 * data, gsize size)
|
|
{
|
|
GstVideoHDRMeta *meta;
|
|
|
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
|
|
g_return_val_if_fail (data != NULL, NULL);
|
|
|
|
meta = (GstVideoHDRMeta *) gst_buffer_add_meta (buffer,
|
|
GST_VIDEO_HDR_META_INFO, NULL);
|
|
g_assert (meta != NULL);
|
|
|
|
meta->format = format;
|
|
meta->data = g_memdup (data, size);
|
|
meta->size = size;
|
|
|
|
return meta;
|
|
}
|
|
|
|
#define CHECK_HDR10PLUS_REMAINING(br, needed) \
|
|
if (gst_bit_reader_get_remaining (&br) < needed) { \
|
|
GST_DEBUG ("Not enough bits remaining %d, needed %d", gst_bit_reader_get_remaining (&br), needed); \
|
|
return FALSE; \
|
|
}
|
|
|
|
/**
|
|
* gst_video_hdr_parse_hdr10_plus:
|
|
* @data: HDR10+ data
|
|
* @size: size of data
|
|
* @hdr10_plus: (out): #GstVideoHDR10Plus structure to fill in.
|
|
*
|
|
* Parse HDR10+ (SMPTE2094-40) user data and store in @hdr10_plus
|
|
* For more details, see:
|
|
* https://www.atsc.org/wp-content/uploads/2018/02/S34-301r2-A341-Amendment-2094-40-1.pdf
|
|
* and SMPTE ST2094-40
|
|
*
|
|
* Returns: %TRUE if @data was successfully parsed to @hdr10_plus
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gboolean
|
|
gst_video_hdr_parse_hdr10_plus (const guint8 * data, gsize size,
|
|
GstVideoHDR10Plus * hdr10_plus)
|
|
{
|
|
guint16 provider_oriented_code;
|
|
int w, i, j;
|
|
GstBitReader br;
|
|
|
|
/* there must be at least one byte, and not more than GST_VIDEO_HDR10_PLUS_MAX_BYTES bytes */
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
|
|
memset (hdr10_plus, 0, sizeof (GstVideoHDR10Plus));
|
|
gst_bit_reader_init (&br, data, size);
|
|
GST_MEMDUMP ("HDR10+", data, size);
|
|
CHECK_HDR10PLUS_REMAINING (br, 2 + 8 + 8 + 2);
|
|
provider_oriented_code = gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
if (provider_oriented_code != 0x0001)
|
|
return FALSE;
|
|
|
|
|
|
hdr10_plus->application_identifier =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
|
|
hdr10_plus->application_version =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
|
|
hdr10_plus->num_windows = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
|
|
if (hdr10_plus->num_windows != GST_VIDEO_HDR10_PLUS_NUM_WINDOWS)
|
|
return FALSE;
|
|
for (w = 0; w < hdr10_plus->num_windows; w++) {
|
|
CHECK_HDR10PLUS_REMAINING (br,
|
|
16 + 16 + 16 + 16 + 16 + 16 + 8 + 16 + 16 + 16 + 1);
|
|
hdr10_plus->processing_window[w].window_upper_left_corner_x =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].window_upper_left_corner_y =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].window_lower_right_corner_x =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].window_lower_right_corner_y =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].center_of_ellipse_x =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].center_of_ellipse_y =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].rotation_angle =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
|
|
hdr10_plus->processing_window[w].semimajor_axis_internal_ellipse =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].semimajor_axis_external_ellipse =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].semiminor_axis_external_ellipse =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
|
|
hdr10_plus->processing_window[w].overlap_process_option =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
}
|
|
CHECK_HDR10PLUS_REMAINING (br, 27 + 1);
|
|
hdr10_plus->targeted_system_display_maximum_luminance =
|
|
gst_bit_reader_get_bits_uint32_unchecked (&br, 27);
|
|
hdr10_plus->targeted_system_display_actual_peak_luminance_flag =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
if (hdr10_plus->targeted_system_display_actual_peak_luminance_flag) {
|
|
CHECK_HDR10PLUS_REMAINING (br, 5 + 5);
|
|
hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
|
|
hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
|
|
if (hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance >
|
|
GST_VIDEO_HDR10_PLUS_MAX_ROWS_TSD_APL)
|
|
return FALSE;
|
|
if (hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance >
|
|
GST_VIDEO_HDR10_PLUS_MAX_COLS_MD_APL)
|
|
return FALSE;
|
|
CHECK_HDR10PLUS_REMAINING (br,
|
|
hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance *
|
|
hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance * 4);
|
|
for (i = 0;
|
|
i < hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance;
|
|
i++) {
|
|
for (j = 0;
|
|
j <
|
|
hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance;
|
|
j++)
|
|
hdr10_plus->targeted_system_display_actual_peak_luminance[i][j] =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
|
|
}
|
|
for (w = 0; w < hdr10_plus->num_windows; w++) {
|
|
CHECK_HDR10PLUS_REMAINING (br, (17 * 3));
|
|
for (i = 0; i < 3; i++)
|
|
hdr10_plus->processing_window[w].maxscl[i] =
|
|
gst_bit_reader_get_bits_uint32_unchecked (&br, 17);
|
|
CHECK_HDR10PLUS_REMAINING (br, 17 + 4);
|
|
hdr10_plus->processing_window[w].average_maxrgb =
|
|
gst_bit_reader_get_bits_uint32_unchecked (&br, 17);
|
|
hdr10_plus->processing_window[w].num_distribution_maxrgb_percentiles =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
|
|
if (hdr10_plus->processing_window[w].
|
|
num_distribution_maxrgb_percentiles !=
|
|
HDR10_PLUS_MAX_DIST_MAXRGB_PERCENTILES)
|
|
return FALSE;
|
|
CHECK_HDR10PLUS_REMAINING (br,
|
|
hdr10_plus->processing_window[w].num_distribution_maxrgb_percentiles *
|
|
(17 + 7));
|
|
for (i = 0;
|
|
i <
|
|
hdr10_plus->processing_window[w].num_distribution_maxrgb_percentiles;
|
|
i++) {
|
|
hdr10_plus->processing_window[w].distribution_maxrgb_percentages[i] =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 7);
|
|
hdr10_plus->processing_window[w].distribution_maxrgb_percentiles[i] =
|
|
gst_bit_reader_get_bits_uint32_unchecked (&br, 17);
|
|
}
|
|
CHECK_HDR10PLUS_REMAINING (br, 10)
|
|
hdr10_plus->processing_window[w].fraction_bright_pixels =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 10);
|
|
}
|
|
}
|
|
CHECK_HDR10PLUS_REMAINING (br, 1)
|
|
hdr10_plus->mastering_display_actual_peak_luminance_flag =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
if (hdr10_plus->targeted_system_display_actual_peak_luminance_flag) {
|
|
CHECK_HDR10PLUS_REMAINING (br, 5 + 5)
|
|
hdr10_plus->num_rows_mastering_display_actual_peak_luminance =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
|
|
hdr10_plus->num_cols_mastering_display_actual_peak_luminance =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
|
|
if (hdr10_plus->num_rows_mastering_display_actual_peak_luminance >
|
|
GST_VIDEO_HDR10_PLUS_MAX_ROWS_TSD_APL)
|
|
return FALSE;
|
|
if (hdr10_plus->num_cols_mastering_display_actual_peak_luminance >
|
|
GST_VIDEO_HDR10_PLUS_MAX_COLS_MD_APL)
|
|
return FALSE;
|
|
CHECK_HDR10PLUS_REMAINING (br,
|
|
hdr10_plus->num_rows_mastering_display_actual_peak_luminance *
|
|
hdr10_plus->num_cols_mastering_display_actual_peak_luminance * 4)
|
|
for (i = 0;
|
|
i < hdr10_plus->num_rows_mastering_display_actual_peak_luminance; i++) {
|
|
for (j = 0;
|
|
j < hdr10_plus->num_cols_mastering_display_actual_peak_luminance; j++)
|
|
hdr10_plus->mastering_display_actual_peak_luminance[i][j] =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
|
|
}
|
|
for (w = 0; w < hdr10_plus->num_windows; w++) {
|
|
CHECK_HDR10PLUS_REMAINING (br, 1)
|
|
hdr10_plus->processing_window[w].tone_mapping_flag =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
if (hdr10_plus->processing_window[w].tone_mapping_flag) {
|
|
CHECK_HDR10PLUS_REMAINING (br, 12 + 12 + 4)
|
|
hdr10_plus->processing_window[w].knee_point_x =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 12);
|
|
hdr10_plus->processing_window[w].knee_point_y =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 12);
|
|
hdr10_plus->processing_window[w].num_bezier_curve_anchors =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
|
|
if (hdr10_plus->processing_window[w].num_bezier_curve_anchors >
|
|
HDR10_PLUS_MAX_BEZIER_CURVE_ANCHORS)
|
|
return FALSE;
|
|
CHECK_HDR10PLUS_REMAINING (br,
|
|
10 * hdr10_plus->processing_window[w].num_bezier_curve_anchors);
|
|
for (i = 0;
|
|
i < hdr10_plus->processing_window[w].num_bezier_curve_anchors; i++)
|
|
hdr10_plus->processing_window[w].bezier_curve_anchors[i] =
|
|
gst_bit_reader_get_bits_uint16_unchecked (&br, 10);
|
|
}
|
|
CHECK_HDR10PLUS_REMAINING (br, 1);
|
|
hdr10_plus->processing_window[w].color_saturation_mapping_flag =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
if (hdr10_plus->processing_window[w].color_saturation_mapping_flag) {
|
|
CHECK_HDR10PLUS_REMAINING (br, 6);
|
|
hdr10_plus->processing_window[w].color_saturation_weight =
|
|
gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|