• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include <string.h>
25 
26 #include "video-hdr.h"
27 
28 #define N_ELEMENT_MASTERING_DISPLAY_INFO 10
29 #define MASTERING_FORMAT \
30   "%d:%d:" \
31   "%d:%d:" \
32   "%d:%d:" \
33   "%d:%d:" \
34   "%d:%d"
35 
36 #define MASTERING_PRINTF_ARGS(m) \
37   (m)->display_primaries[0].x, (m)->display_primaries[0].y, \
38   (m)->display_primaries[1].x, (m)->display_primaries[1].y, \
39   (m)->display_primaries[2].x, (m)->display_primaries[2].y, \
40   (m)->white_point.x, (m)->white_point.y, \
41   (m)->max_display_mastering_luminance, \
42   (m)->min_display_mastering_luminance
43 
44 /**
45  * gst_video_mastering_display_info_init:
46  * @minfo: a #GstVideoMasteringDisplayInfo
47  *
48  * Initialize @minfo
49  *
50  * Since: 1.18
51  */
52 void
gst_video_mastering_display_info_init(GstVideoMasteringDisplayInfo * minfo)53 gst_video_mastering_display_info_init (GstVideoMasteringDisplayInfo * minfo)
54 {
55   g_return_if_fail (minfo != NULL);
56 
57   memset (minfo, 0, sizeof (GstVideoMasteringDisplayInfo));
58 }
59 
60 /**
61  * gst_video_mastering_display_info_from_string:
62  * @minfo: (out): a #GstVideoMasteringDisplayInfo
63  * @mastering: a #GstStructure representing #GstVideoMasteringDisplayInfo
64  *
65  * Extract #GstVideoMasteringDisplayInfo from @mastering
66  *
67  * Returns: %TRUE if @minfo was filled with @mastering
68  *
69  * Since: 1.18
70  */
71 gboolean
gst_video_mastering_display_info_from_string(GstVideoMasteringDisplayInfo * minfo,const gchar * mastering)72 gst_video_mastering_display_info_from_string (GstVideoMasteringDisplayInfo *
73     minfo, const gchar * mastering)
74 {
75   gboolean ret = FALSE;
76   gchar **split;
77   gint i;
78   gint idx = 0;
79   guint64 val;
80 
81   g_return_val_if_fail (minfo != NULL, FALSE);
82   g_return_val_if_fail (mastering != NULL, FALSE);
83 
84   split = g_strsplit (mastering, ":", -1);
85 
86   if (g_strv_length (split) != N_ELEMENT_MASTERING_DISPLAY_INFO)
87     goto out;
88 
89   for (i = 0; i < G_N_ELEMENTS (minfo->display_primaries); i++) {
90     if (!g_ascii_string_to_unsigned (split[idx++],
91             10, 0, G_MAXUINT16, &val, NULL))
92       goto out;
93 
94     minfo->display_primaries[i].x = (guint16) val;
95 
96     if (!g_ascii_string_to_unsigned (split[idx++],
97             10, 0, G_MAXUINT16, &val, NULL))
98       goto out;
99 
100     minfo->display_primaries[i].y = (guint16) val;
101   }
102 
103   if (!g_ascii_string_to_unsigned (split[idx++],
104           10, 0, G_MAXUINT16, &val, NULL))
105     goto out;
106 
107   minfo->white_point.x = (guint16) val;
108 
109   if (!g_ascii_string_to_unsigned (split[idx++],
110           10, 0, G_MAXUINT16, &val, NULL))
111     goto out;
112 
113   minfo->white_point.y = (guint16) val;
114 
115   if (!g_ascii_string_to_unsigned (split[idx++],
116           10, 0, G_MAXUINT32, &val, NULL))
117     goto out;
118 
119   minfo->max_display_mastering_luminance = (guint32) val;
120 
121   if (!g_ascii_string_to_unsigned (split[idx++],
122           10, 0, G_MAXUINT32, &val, NULL))
123     goto out;
124 
125   minfo->min_display_mastering_luminance = (guint32) val;
126   ret = TRUE;
127 
128 out:
129   g_strfreev (split);
130   if (!ret)
131     gst_video_mastering_display_info_init (minfo);
132 
133   return ret;
134 }
135 
136 /**
137  * gst_video_mastering_display_info_to_string:
138  * @minfo: a #GstVideoMasteringDisplayInfo
139  *
140  * Convert @minfo to its string representation
141  *
142  * Returns: (transfer full): a string representation of @minfo
143  *
144  * Since: 1.18
145  */
146 gchar *
gst_video_mastering_display_info_to_string(const GstVideoMasteringDisplayInfo * minfo)147 gst_video_mastering_display_info_to_string (const GstVideoMasteringDisplayInfo *
148     minfo)
149 {
150   g_return_val_if_fail (minfo != NULL, NULL);
151 
152   return g_strdup_printf (MASTERING_FORMAT, MASTERING_PRINTF_ARGS (minfo));
153 }
154 
155 /**
156  * gst_video_mastering_display_info_is_equal:
157  * @minfo: a #GstVideoMasteringDisplayInfo
158  * @other: a #GstVideoMasteringDisplayInfo
159  *
160  * Checks equality between @minfo and @other.
161  *
162  * Returns: %TRUE if @minfo and @other are equal.
163  *
164  * Since: 1.18
165  */
166 gboolean
gst_video_mastering_display_info_is_equal(const GstVideoMasteringDisplayInfo * minfo,const GstVideoMasteringDisplayInfo * other)167 gst_video_mastering_display_info_is_equal (const GstVideoMasteringDisplayInfo *
168     minfo, const GstVideoMasteringDisplayInfo * other)
169 {
170   gint i;
171 
172   g_return_val_if_fail (minfo != NULL, FALSE);
173   g_return_val_if_fail (other != NULL, FALSE);
174 
175   for (i = 0; i < G_N_ELEMENTS (minfo->display_primaries); i++) {
176     if (minfo->display_primaries[i].x != other->display_primaries[i].x ||
177         minfo->display_primaries[i].y != other->display_primaries[i].y)
178       return FALSE;
179   }
180 
181   if (minfo->white_point.x != other->white_point.x ||
182       minfo->white_point.y != other->white_point.y ||
183       minfo->max_display_mastering_luminance !=
184       other->max_display_mastering_luminance
185       || minfo->min_display_mastering_luminance !=
186       other->min_display_mastering_luminance)
187     return FALSE;
188 
189   return TRUE;
190 }
191 
192 /**
193  * gst_video_mastering_display_info_from_caps:
194  * @minfo: a #GstVideoMasteringDisplayInfo
195  * @caps: a #GstCaps
196  *
197  * Parse @caps and update @minfo
198  *
199  * Returns: %TRUE if @caps has #GstVideoMasteringDisplayInfo and could be parsed
200  *
201  * Since: 1.18
202  */
203 gboolean
gst_video_mastering_display_info_from_caps(GstVideoMasteringDisplayInfo * minfo,const GstCaps * caps)204 gst_video_mastering_display_info_from_caps (GstVideoMasteringDisplayInfo *
205     minfo, const GstCaps * caps)
206 {
207   GstStructure *structure;
208   const gchar *s;
209 
210   g_return_val_if_fail (minfo != NULL, FALSE);
211   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
212 
213   structure = gst_caps_get_structure (caps, 0);
214 
215   if ((s = gst_structure_get_string (structure,
216               "mastering-display-info")) == NULL)
217     return FALSE;
218 
219   return gst_video_mastering_display_info_from_string (minfo, s);
220 }
221 
222 /**
223  * gst_video_mastering_display_info_add_to_caps:
224  * @minfo: a #GstVideoMasteringDisplayInfo
225  * @caps: a #GstCaps
226  *
227  * Set string representation of @minfo to @caps
228  *
229  * Returns: %TRUE if @minfo was successfully set to @caps
230  *
231  * Since: 1.18
232  */
233 gboolean
gst_video_mastering_display_info_add_to_caps(const GstVideoMasteringDisplayInfo * minfo,GstCaps * caps)234 gst_video_mastering_display_info_add_to_caps (const GstVideoMasteringDisplayInfo
235     * minfo, GstCaps * caps)
236 {
237   gchar *s;
238 
239   g_return_val_if_fail (minfo != NULL, FALSE);
240   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
241   g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
242 
243   s = gst_video_mastering_display_info_to_string (minfo);
244   if (!s)
245     return FALSE;
246 
247   gst_caps_set_simple (caps, "mastering-display-info", G_TYPE_STRING, s, NULL);
248   g_free (s);
249 
250   return TRUE;
251 }
252 
253 /**
254  * gst_video_content_light_level_init:
255  * @linfo: a #GstVideoContentLightLevel
256  *
257  * Initialize @linfo
258  *
259  * Since: 1.18
260  */
261 void
gst_video_content_light_level_init(GstVideoContentLightLevel * linfo)262 gst_video_content_light_level_init (GstVideoContentLightLevel * linfo)
263 {
264   g_return_if_fail (linfo != NULL);
265 
266   memset (linfo, 0, sizeof (GstVideoContentLightLevel));
267 }
268 
269 /**
270  * gst_video_content_light_level_from_string:
271  * @linfo: a #GstVideoContentLightLevel
272  * @level: a content-light-level string from caps
273  *
274  * Parse the value of content-light-level caps field and update @minfo
275  * with the parsed values.
276  *
277  * Returns: %TRUE if @linfo points to valid #GstVideoContentLightLevel.
278  *
279  * Since: 1.18
280  */
281 gboolean
gst_video_content_light_level_from_string(GstVideoContentLightLevel * linfo,const gchar * level)282 gst_video_content_light_level_from_string (GstVideoContentLightLevel * linfo,
283     const gchar * level)
284 {
285   gboolean ret = FALSE;
286   gchar **split;
287   guint64 val;
288 
289   g_return_val_if_fail (linfo != NULL, FALSE);
290   g_return_val_if_fail (level != NULL, FALSE);
291 
292   split = g_strsplit (level, ":", -1);
293 
294   if (g_strv_length (split) != 2)
295     goto out;
296 
297   if (!g_ascii_string_to_unsigned (split[0], 10, 0, G_MAXUINT16, &val, NULL))
298     goto out;
299 
300   linfo->max_content_light_level = (guint16) val;
301 
302   if (!g_ascii_string_to_unsigned (split[1], 10, 0, G_MAXUINT16, &val, NULL))
303     goto out;
304 
305   linfo->max_frame_average_light_level = (guint16) val;
306 
307   ret = TRUE;
308 
309 out:
310   g_strfreev (split);
311   if (!ret)
312     gst_video_content_light_level_init (linfo);
313 
314   return ret;
315 }
316 
317 /**
318  * gst_video_content_light_level_to_string:
319  * @linfo: a #GstVideoContentLightLevel
320  *
321  * Convert @linfo to its string representation.
322  *
323  * Returns: (transfer full): a string representation of @linfo.
324  *
325  * Since: 1.18
326  */
327 gchar *
gst_video_content_light_level_to_string(const GstVideoContentLightLevel * linfo)328 gst_video_content_light_level_to_string (const GstVideoContentLightLevel *
329     linfo)
330 {
331   g_return_val_if_fail (linfo != NULL, NULL);
332 
333   return g_strdup_printf ("%d:%d",
334       linfo->max_content_light_level, linfo->max_frame_average_light_level);
335 }
336 
337 /**
338  * gst_video_content_light_level_is_equal:
339  * @linfo: a #GstVideoContentLightLevel
340  * @other: a #GstVideoContentLightLevel
341  *
342  * Checks equality between @linfo and @other.
343  *
344  * Returns: %TRUE if @linfo and @other are equal.
345  *
346  * Since: 1.20
347  */
348 gboolean
gst_video_content_light_level_is_equal(const GstVideoContentLightLevel * linfo,const GstVideoContentLightLevel * other)349 gst_video_content_light_level_is_equal (const GstVideoContentLightLevel * linfo,
350     const GstVideoContentLightLevel * other)
351 {
352   g_return_val_if_fail (linfo != NULL, FALSE);
353   g_return_val_if_fail (other != NULL, FALSE);
354 
355   return (linfo->max_content_light_level == other->max_content_light_level &&
356       linfo->max_frame_average_light_level ==
357       other->max_frame_average_light_level);
358 }
359 
360 /**
361  * gst_video_content_light_level_from_caps:
362  * @linfo: a #GstVideoContentLightLevel
363  * @caps: a #GstCaps
364  *
365  * Parse @caps and update @linfo
366  *
367  * Returns: if @caps has #GstVideoContentLightLevel and could be parsed
368  *
369  * Since: 1.18
370  */
371 gboolean
gst_video_content_light_level_from_caps(GstVideoContentLightLevel * linfo,const GstCaps * caps)372 gst_video_content_light_level_from_caps (GstVideoContentLightLevel * linfo,
373     const GstCaps * caps)
374 {
375   GstStructure *structure;
376   const gchar *s;
377 
378   g_return_val_if_fail (linfo != NULL, FALSE);
379   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
380 
381   structure = gst_caps_get_structure (caps, 0);
382 
383   if ((s = gst_structure_get_string (structure, "content-light-level")) == NULL)
384     return FALSE;
385 
386   return gst_video_content_light_level_from_string (linfo, s);
387 }
388 
389 /**
390  * gst_video_content_light_level_add_to_caps:
391  * @linfo: a #GstVideoContentLightLevel
392  * @caps: a #GstCaps
393  *
394  * Parse @caps and update @linfo
395  *
396  * Returns: %TRUE if @linfo was successfully set to @caps
397  *
398  * Since: 1.18
399  */
400 gboolean
gst_video_content_light_level_add_to_caps(const GstVideoContentLightLevel * linfo,GstCaps * caps)401 gst_video_content_light_level_add_to_caps (const GstVideoContentLightLevel *
402     linfo, GstCaps * caps)
403 {
404   gchar *s;
405 
406   g_return_val_if_fail (linfo != NULL, FALSE);
407   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
408   g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
409 
410   s = gst_video_content_light_level_to_string (linfo);
411   gst_caps_set_simple (caps, "content-light-level", G_TYPE_STRING, s, NULL);
412   g_free (s);
413 
414   return TRUE;
415 }
416