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