mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-29 11:40:38 +00:00
1dee0f05a7
This commit modifies GstVideoMasteringDisplayInfo and GstVideoContentLightLevel structs so that each value is to be more like hdr_metadata_infoframe struct of linux drm header and DXGI_HDR_METADATA_HDR10 struct of Windows. So each value is no more fraction but normalized one as per CTA 861.G spec. Also the unit of each value will be consistent with H.264, H.265 specifications, hdr_metadata_infoframe struct for linux and DXGI_HDR_METADATA_HDR10 struct for Windows.
408 lines
10 KiB
C
408 lines
10 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 "video-hdr.h"
|
|
|
|
#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
|
|
|
|
/* g_ascii_string_to_unsigned is available since 2.54. Get rid of this wrapper
|
|
* when we bump the version in 1.18 */
|
|
#if !GLIB_CHECK_VERSION(2,54,0)
|
|
#define g_ascii_string_to_unsigned vidoe_hdr_ascii_string_to_unsigned
|
|
static gboolean
|
|
vidoe_hdr_ascii_string_to_unsigned (const gchar * str, guint base, guint64 min,
|
|
guint64 max, guint64 * out_num, GError ** error)
|
|
{
|
|
gchar *endptr = NULL;
|
|
*out_num = g_ascii_strtoull (str, &endptr, base);
|
|
if (errno)
|
|
return FALSE;
|
|
if (endptr == str)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* 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;
|
|
}
|