gstreamer/gst-libs/gst/video/video-hdr.c
Seungha Yang 1dee0f05a7 video-hdr: Rework for GstVideoMasteringDisplayInfo and GstVideoContentLightLevel struct
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.
2020-04-01 11:11:15 +00:00

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