gstreamer/gst-libs/gst/video/video-hdr.c
Matthew Waters 98249a57db gst: don't use volatile to mean atomic
volatile is not sufficient to provide atomic guarantees and real atomics
should be used instead.  GCC 11 has started warning about using volatile
with atomic operations.

https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719

Discovered in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/868

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1073>
2021-03-19 04:20:19 +00:00

763 lines
23 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_is_equal:
* @linfo: a #GstVideoContentLightLevel
* @other: a #GstVideoContentLightLevel
*
* Checks equality between @linfo and @other.
*
* Returns: %TRUE if @linfo and @other are equal.
*
* Since: 1.20
*/
gboolean
gst_video_content_light_level_is_equal (const GstVideoContentLightLevel * linfo,
const GstVideoContentLightLevel * other)
{
g_return_val_if_fail (linfo != NULL, FALSE);
g_return_val_if_fail (other != NULL, FALSE);
return (linfo->max_content_light_level == other->max_content_light_level &&
linfo->max_frame_average_light_level ==
other->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 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;
}