1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Library <2002> Ronald Bultje <rbultje@ronald.bitfreak.net>
4 * Copyright (C) 2007 David A. Schleef <ds@schleef.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 /**
23 * SECTION:video-info
24 * @title: GstVideoInfo
25 * @short_description: Structures and enumerations to describe raw images
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "video-info.h"
36 #include "video-tile.h"
37
38 #ifndef GST_DISABLE_GST_DEBUG
39 #define GST_CAT_DEFAULT ensure_debug_category()
40 static GstDebugCategory *
ensure_debug_category(void)41 ensure_debug_category (void)
42 {
43 static gsize cat_gonce = 0;
44
45 if (g_once_init_enter (&cat_gonce)) {
46 gsize cat_done;
47
48 cat_done = (gsize) _gst_debug_category_new ("video-info", 0,
49 "video-info structure");
50
51 g_once_init_leave (&cat_gonce, cat_done);
52 }
53
54 return (GstDebugCategory *) cat_gonce;
55 }
56 #else
57 #define ensure_debug_category() /* NOOP */
58 #endif /* GST_DISABLE_GST_DEBUG */
59
60 /**
61 * gst_video_info_copy:
62 * @info: a #GstVideoInfo
63 *
64 * Copy a GstVideoInfo structure.
65 *
66 * Returns: a new #GstVideoInfo. free with gst_video_info_free.
67 *
68 * Since: 1.6
69 */
70 GstVideoInfo *
gst_video_info_copy(const GstVideoInfo * info)71 gst_video_info_copy (const GstVideoInfo * info)
72 {
73 return g_slice_dup (GstVideoInfo, info);
74 }
75
76 /**
77 * gst_video_info_free:
78 * @info: a #GstVideoInfo
79 *
80 * Free a GstVideoInfo structure previously allocated with gst_video_info_new()
81 * or gst_video_info_copy().
82 *
83 * Since: 1.6
84 */
85 void
gst_video_info_free(GstVideoInfo * info)86 gst_video_info_free (GstVideoInfo * info)
87 {
88 g_slice_free (GstVideoInfo, info);
89 }
90
91 G_DEFINE_BOXED_TYPE (GstVideoInfo, gst_video_info,
92 (GBoxedCopyFunc) gst_video_info_copy, (GBoxedFreeFunc) gst_video_info_free);
93
94 /**
95 * gst_video_info_new:
96 *
97 * Allocate a new #GstVideoInfo that is also initialized with
98 * gst_video_info_init().
99 *
100 * Returns: a new #GstVideoInfo. free with gst_video_info_free().
101 *
102 * Since: 1.6
103 */
104 GstVideoInfo *
gst_video_info_new(void)105 gst_video_info_new (void)
106 {
107 GstVideoInfo *info;
108
109 info = g_slice_new (GstVideoInfo);
110 gst_video_info_init (info);
111
112 return info;
113 }
114
115 static gboolean fill_planes (GstVideoInfo * info,
116 gsize plane_size[GST_VIDEO_MAX_PLANES]);
117
118 /**
119 * gst_video_info_init:
120 * @info: (out caller-allocates): a #GstVideoInfo
121 *
122 * Initialize @info with default values.
123 */
124 void
gst_video_info_init(GstVideoInfo * info)125 gst_video_info_init (GstVideoInfo * info)
126 {
127 g_return_if_fail (info != NULL);
128
129 memset (info, 0, sizeof (GstVideoInfo));
130
131 info->finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_UNKNOWN);
132
133 info->views = 1;
134 /* arrange for sensible defaults, e.g. if turned into caps */
135 info->fps_n = 0;
136 info->fps_d = 1;
137 info->par_n = 1;
138 info->par_d = 1;
139 GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE;
140 GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
141 GST_VIDEO_INFO_FIELD_ORDER (info) = GST_VIDEO_FIELD_ORDER_UNKNOWN;
142 }
143
144 #define MAKE_COLORIMETRY(r,m,t,p) { \
145 GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m, \
146 GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p }
147
148 #define DEFAULT_YUV_SD 0
149 #define DEFAULT_YUV_HD 1
150 #define DEFAULT_RGB 2
151 #define DEFAULT_GRAY 3
152 #define DEFAULT_UNKNOWN 4
153
154 static const GstVideoColorimetry default_color[] = {
155 MAKE_COLORIMETRY (_16_235, BT601, BT601, SMPTE170M),
156 MAKE_COLORIMETRY (_16_235, BT709, BT709, BT709),
157 MAKE_COLORIMETRY (_0_255, RGB, SRGB, BT709),
158 MAKE_COLORIMETRY (_0_255, BT601, UNKNOWN, UNKNOWN),
159 MAKE_COLORIMETRY (_UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN),
160 };
161
162 static void
set_default_colorimetry(GstVideoInfo * info)163 set_default_colorimetry (GstVideoInfo * info)
164 {
165 const GstVideoFormatInfo *finfo = info->finfo;
166
167 if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)) {
168 if (info->height > 576) {
169 info->chroma_site = GST_VIDEO_CHROMA_SITE_H_COSITED;
170 info->colorimetry = default_color[DEFAULT_YUV_HD];
171 } else {
172 info->chroma_site = GST_VIDEO_CHROMA_SITE_NONE;
173 info->colorimetry = default_color[DEFAULT_YUV_SD];
174 }
175 } else if (GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo)) {
176 info->colorimetry = default_color[DEFAULT_GRAY];
177 } else if (GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) {
178 info->colorimetry = default_color[DEFAULT_RGB];
179 } else {
180 info->colorimetry = default_color[DEFAULT_UNKNOWN];
181 }
182 }
183
184 static gboolean
validate_colorimetry(GstVideoInfo * info)185 validate_colorimetry (GstVideoInfo * info)
186 {
187 const GstVideoFormatInfo *finfo = info->finfo;
188
189 if (!GST_VIDEO_FORMAT_INFO_IS_RGB (finfo) &&
190 info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
191 GST_WARNING
192 ("color matrix RGB is only supported with RGB format, %s is not",
193 finfo->name);
194 return FALSE;
195 }
196
197 if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo) &&
198 info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
199 GST_WARNING ("Need to specify a color matrix when using YUV format (%s)",
200 finfo->name);
201 return FALSE;
202 }
203
204 return TRUE;
205 }
206
207 static gboolean
gst_video_info_set_format_common(GstVideoInfo * info,GstVideoFormat format,guint width,guint height)208 gst_video_info_set_format_common (GstVideoInfo * info, GstVideoFormat format,
209 guint width, guint height)
210 {
211 g_return_val_if_fail (info != NULL, FALSE);
212 g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
213
214 if (width > G_MAXINT || height > G_MAXINT)
215 return FALSE;
216
217 gst_video_info_init (info);
218
219 info->finfo = gst_video_format_get_info (format);
220 info->width = width;
221 info->height = height;
222 info->views = 1;
223
224 set_default_colorimetry (info);
225
226 return TRUE;
227 }
228
229 /**
230 * gst_video_info_set_format:
231 * @info: a #GstVideoInfo
232 * @format: the format
233 * @width: a width
234 * @height: a height
235 *
236 * Set the default info for a video frame of @format and @width and @height.
237 *
238 * Note: This initializes @info first, no values are preserved. This function
239 * does not set the offsets correctly for interlaced vertically
240 * subsampled formats.
241 *
242 * Returns: %FALSE if the returned video info is invalid, e.g. because the
243 * size of a frame can't be represented as a 32 bit integer (Since: 1.12)
244 */
245 gboolean
gst_video_info_set_format(GstVideoInfo * info,GstVideoFormat format,guint width,guint height)246 gst_video_info_set_format (GstVideoInfo * info, GstVideoFormat format,
247 guint width, guint height)
248 {
249 if (!gst_video_info_set_format_common (info, format, width, height))
250 return FALSE;
251
252 return fill_planes (info, NULL);
253 }
254
255 /**
256 * gst_video_info_set_interlaced_format:
257 * @info: a #GstVideoInfo
258 * @format: the format
259 * @mode: a #GstVideoInterlaceMode
260 * @width: a width
261 * @height: a height
262 *
263 * Same as #gst_video_info_set_format but also allowing to set the interlaced
264 * mode.
265 *
266 * Returns: %FALSE if the returned video info is invalid, e.g. because the
267 * size of a frame can't be represented as a 32 bit integer.
268 *
269 * Since: 1.16
270 */
271 gboolean
gst_video_info_set_interlaced_format(GstVideoInfo * info,GstVideoFormat format,GstVideoInterlaceMode mode,guint width,guint height)272 gst_video_info_set_interlaced_format (GstVideoInfo * info,
273 GstVideoFormat format, GstVideoInterlaceMode mode, guint width,
274 guint height)
275 {
276 if (!gst_video_info_set_format_common (info, format, width, height))
277 return FALSE;
278
279 GST_VIDEO_INFO_INTERLACE_MODE (info) = mode;
280 return fill_planes (info, NULL);
281 }
282
283 static const gchar *interlace_mode[] = {
284 "progressive",
285 "interleaved",
286 "mixed",
287 "fields",
288 "alternate"
289 };
290
291 /**
292 * gst_video_interlace_mode_to_string:
293 * @mode: a #GstVideoInterlaceMode
294 *
295 * Convert @mode to its string representation.
296 *
297 * Returns: @mode as a string or NULL if @mode in invalid.
298 *
299 * Since: 1.6
300 */
301 const gchar *
gst_video_interlace_mode_to_string(GstVideoInterlaceMode mode)302 gst_video_interlace_mode_to_string (GstVideoInterlaceMode mode)
303 {
304 if (((guint) mode) >= G_N_ELEMENTS (interlace_mode))
305 return NULL;
306
307 return interlace_mode[mode];
308 }
309
310 /**
311 * gst_video_interlace_mode_from_string:
312 * @mode: a mode
313 *
314 * Convert @mode to a #GstVideoInterlaceMode
315 *
316 * Returns: the #GstVideoInterlaceMode of @mode or
317 * #GST_VIDEO_INTERLACE_MODE_PROGRESSIVE when @mode is not a valid
318 * string representation for a #GstVideoInterlaceMode.
319 *
320 * Since: 1.6
321 */
322 GstVideoInterlaceMode
gst_video_interlace_mode_from_string(const gchar * mode)323 gst_video_interlace_mode_from_string (const gchar * mode)
324 {
325 gint i;
326 for (i = 0; i < G_N_ELEMENTS (interlace_mode); i++) {
327 if (g_str_equal (interlace_mode[i], mode))
328 return i;
329 }
330 return GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
331 }
332
333 static const gchar *field_order[] = {
334 "unknown",
335 "top-field-first",
336 "bottom-field-first"
337 };
338
339 /**
340 * gst_video_field_order_to_string:
341 * @order: a #GstVideoFieldOrder
342 *
343 * Convert @order to its string representation.
344 *
345 * Returns: @order as a string or NULL if @order in invalid.
346 *
347 * Since: 1.12
348 */
349 const gchar *
gst_video_field_order_to_string(GstVideoFieldOrder order)350 gst_video_field_order_to_string (GstVideoFieldOrder order)
351 {
352 if (((guint) order) >= G_N_ELEMENTS (field_order))
353 return NULL;
354
355 return field_order[order];
356 }
357
358 /**
359 * gst_video_field_order_from_string:
360 * @order: a field order
361 *
362 * Convert @order to a #GstVideoFieldOrder
363 *
364 * Returns: the #GstVideoFieldOrder of @order or
365 * #GST_VIDEO_FIELD_ORDER_UNKNOWN when @order is not a valid
366 * string representation for a #GstVideoFieldOrder.
367 *
368 * Since: 1.12
369 */
370 GstVideoFieldOrder
gst_video_field_order_from_string(const gchar * order)371 gst_video_field_order_from_string (const gchar * order)
372 {
373 gint i;
374 for (i = 0; i < G_N_ELEMENTS (field_order); i++) {
375 if (g_str_equal (field_order[i], order))
376 return i;
377 }
378 return GST_VIDEO_FIELD_ORDER_UNKNOWN;
379 }
380
381 /**
382 * gst_video_info_from_caps:
383 * @info: (out caller-allocates): #GstVideoInfo
384 * @caps: a #GstCaps
385 *
386 * Parse @caps and update @info.
387 *
388 * Returns: TRUE if @caps could be parsed
389 */
390 gboolean
gst_video_info_from_caps(GstVideoInfo * info,const GstCaps * caps)391 gst_video_info_from_caps (GstVideoInfo * info, const GstCaps * caps)
392 {
393 GstStructure *structure;
394 const gchar *s;
395 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
396 gint width = 0, height = 0;
397 gint fps_n, fps_d;
398 gint par_n, par_d;
399 guint multiview_flags;
400
401 g_return_val_if_fail (info != NULL, FALSE);
402 g_return_val_if_fail (caps != NULL, FALSE);
403 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
404
405 GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
406
407 structure = gst_caps_get_structure (caps, 0);
408
409 if (gst_structure_has_name (structure, "video/x-raw")) {
410 if (!(s = gst_structure_get_string (structure, "format")))
411 goto no_format;
412
413 format = gst_video_format_from_string (s);
414 if (format == GST_VIDEO_FORMAT_UNKNOWN)
415 goto unknown_format;
416
417 } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/") ||
418 g_str_has_prefix (gst_structure_get_name (structure), "image/")) {
419 format = GST_VIDEO_FORMAT_ENCODED;
420 } else {
421 goto wrong_name;
422 }
423
424 /* width and height are mandatory, except for non-raw-formats */
425 if (!gst_structure_get_int (structure, "width", &width) &&
426 format != GST_VIDEO_FORMAT_ENCODED)
427 goto no_width;
428 if (!gst_structure_get_int (structure, "height", &height) &&
429 format != GST_VIDEO_FORMAT_ENCODED)
430 goto no_height;
431
432 gst_video_info_init (info);
433
434 info->finfo = gst_video_format_get_info (format);
435 info->width = width;
436 info->height = height;
437
438 if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
439 if (fps_n == 0) {
440 /* variable framerate */
441 info->flags |= GST_VIDEO_FLAG_VARIABLE_FPS;
442 /* see if we have a max-framerate */
443 gst_structure_get_fraction (structure, "max-framerate", &fps_n, &fps_d);
444 }
445 info->fps_n = fps_n;
446 info->fps_d = fps_d;
447 } else {
448 /* unspecified is variable framerate */
449 info->fps_n = 0;
450 info->fps_d = 1;
451 }
452
453 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
454 &par_n, &par_d)) {
455 info->par_n = par_n;
456 info->par_d = par_d;
457 } else {
458 info->par_n = 1;
459 info->par_d = 1;
460 }
461
462 if ((s = gst_structure_get_string (structure, "interlace-mode")))
463 info->interlace_mode = gst_video_interlace_mode_from_string (s);
464 else
465 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
466
467 /* Interlaced feature is mandatory for raw alternate streams */
468 if (info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE &&
469 format != GST_VIDEO_FORMAT_ENCODED) {
470 GstCapsFeatures *f;
471
472 f = gst_caps_get_features (caps, 0);
473 if (!f
474 || !gst_caps_features_contains (f, GST_CAPS_FEATURE_FORMAT_INTERLACED))
475 goto alternate_no_feature;
476 }
477
478 if (GST_VIDEO_INFO_IS_INTERLACED (info) &&
479 (s = gst_structure_get_string (structure, "field-order"))) {
480 GST_VIDEO_INFO_FIELD_ORDER (info) = gst_video_field_order_from_string (s);
481 } else {
482 GST_VIDEO_INFO_FIELD_ORDER (info) = GST_VIDEO_FIELD_ORDER_UNKNOWN;
483 }
484
485 {
486 if ((s = gst_structure_get_string (structure, "multiview-mode")))
487 GST_VIDEO_INFO_MULTIVIEW_MODE (info) =
488 gst_video_multiview_mode_from_caps_string (s);
489 else
490 GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE;
491
492 if (gst_structure_get_flagset (structure, "multiview-flags",
493 &multiview_flags, NULL))
494 GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = multiview_flags;
495
496 if (!gst_structure_get_int (structure, "views", &info->views))
497 info->views = 1;
498
499 /* At one point, I tried normalising the half-aspect flag here,
500 * but it behaves weird for GstVideoInfo operations other than
501 * directly converting to/from caps - sometimes causing the
502 * PAR to be doubled/halved too many times */
503 }
504
505 if ((s = gst_structure_get_string (structure, "chroma-site")))
506 info->chroma_site = gst_video_chroma_site_from_string (s);
507 else
508 info->chroma_site = GST_VIDEO_CHROMA_SITE_UNKNOWN;
509
510 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
511 if (!gst_video_colorimetry_from_string (&info->colorimetry, s)) {
512 GST_WARNING ("unparsable colorimetry, using default");
513 set_default_colorimetry (info);
514 } else if (!validate_colorimetry (info)) {
515 GST_WARNING ("invalid colorimetry, using default");
516 set_default_colorimetry (info);
517 } else {
518 /* force RGB matrix for RGB formats */
519 if (GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo) &&
520 info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
521 GST_WARNING ("invalid matrix %d for RGB format, using RGB",
522 info->colorimetry.matrix);
523 info->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
524 }
525 }
526 } else {
527 GST_DEBUG ("no colorimetry, using default");
528 set_default_colorimetry (info);
529 }
530
531 if (!fill_planes (info, NULL))
532 return FALSE;
533
534 return TRUE;
535
536 /* ERROR */
537 wrong_name:
538 {
539 GST_ERROR ("wrong name '%s', expected video/ or image/",
540 gst_structure_get_name (structure));
541 return FALSE;
542 }
543 no_format:
544 {
545 GST_ERROR ("no format given");
546 return FALSE;
547 }
548 unknown_format:
549 {
550 GST_ERROR ("unknown format '%s' given", s);
551 return FALSE;
552 }
553 no_width:
554 {
555 GST_ERROR ("no width property given");
556 return FALSE;
557 }
558 no_height:
559 {
560 GST_ERROR ("no height property given");
561 return FALSE;
562 }
563 alternate_no_feature:
564 {
565 GST_ERROR
566 ("caps has 'interlace-mode=alternate' but doesn't have the Interlaced feature");
567 return FALSE;
568 }
569 }
570
571 /**
572 * gst_video_info_new_from_caps:
573 * @caps: a #GstCaps
574 *
575 * Parse @caps to generate a #GstVideoInfo.
576 *
577 * Returns: A #GstVideoInfo, or %NULL if @caps couldn't be parsed
578 * Since: 1.20
579 */
580 GstVideoInfo *
gst_video_info_new_from_caps(const GstCaps * caps)581 gst_video_info_new_from_caps (const GstCaps * caps)
582 {
583 GstVideoInfo *ret = gst_video_info_new ();
584
585 if (gst_video_info_from_caps (ret, caps)) {
586 return ret;
587 } else {
588 gst_video_info_free (ret);
589 return NULL;
590 }
591 }
592
593 /**
594 * gst_video_info_is_equal:
595 * @info: a #GstVideoInfo
596 * @other: a #GstVideoInfo
597 *
598 * Compares two #GstVideoInfo and returns whether they are equal or not
599 *
600 * Returns: %TRUE if @info and @other are equal, else %FALSE.
601 */
602 gboolean
gst_video_info_is_equal(const GstVideoInfo * info,const GstVideoInfo * other)603 gst_video_info_is_equal (const GstVideoInfo * info, const GstVideoInfo * other)
604 {
605 gint i;
606
607 if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_INFO_FORMAT (other))
608 return FALSE;
609 if (GST_VIDEO_INFO_INTERLACE_MODE (info) !=
610 GST_VIDEO_INFO_INTERLACE_MODE (other))
611 return FALSE;
612 if (GST_VIDEO_INFO_FLAGS (info) != GST_VIDEO_INFO_FLAGS (other))
613 return FALSE;
614 if (GST_VIDEO_INFO_WIDTH (info) != GST_VIDEO_INFO_WIDTH (other))
615 return FALSE;
616 if (GST_VIDEO_INFO_HEIGHT (info) != GST_VIDEO_INFO_HEIGHT (other))
617 return FALSE;
618 if (GST_VIDEO_INFO_SIZE (info) != GST_VIDEO_INFO_SIZE (other))
619 return FALSE;
620 if (GST_VIDEO_INFO_PAR_N (info) != GST_VIDEO_INFO_PAR_N (other))
621 return FALSE;
622 if (GST_VIDEO_INFO_PAR_D (info) != GST_VIDEO_INFO_PAR_D (other))
623 return FALSE;
624 if (GST_VIDEO_INFO_FPS_N (info) != GST_VIDEO_INFO_FPS_N (other))
625 return FALSE;
626 if (GST_VIDEO_INFO_FPS_D (info) != GST_VIDEO_INFO_FPS_D (other))
627 return FALSE;
628 if (!gst_video_colorimetry_is_equal (&GST_VIDEO_INFO_COLORIMETRY (info),
629 &GST_VIDEO_INFO_COLORIMETRY (other)))
630 return FALSE;
631 if (GST_VIDEO_INFO_CHROMA_SITE (info) != GST_VIDEO_INFO_CHROMA_SITE (other))
632 return FALSE;
633 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) !=
634 GST_VIDEO_INFO_MULTIVIEW_MODE (other))
635 return FALSE;
636 if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) !=
637 GST_VIDEO_INFO_MULTIVIEW_FLAGS (other))
638 return FALSE;
639 if (GST_VIDEO_INFO_VIEWS (info) != GST_VIDEO_INFO_VIEWS (other))
640 return FALSE;
641
642 for (i = 0; i < info->finfo->n_planes; i++) {
643 if (info->stride[i] != other->stride[i])
644 return FALSE;
645 if (info->offset[i] != other->offset[i])
646 return FALSE;
647 }
648
649 return TRUE;
650 }
651
652 /**
653 * gst_video_info_to_caps:
654 * @info: a #GstVideoInfo
655 *
656 * Convert the values of @info into a #GstCaps.
657 *
658 * Returns: a new #GstCaps containing the info of @info.
659 */
660 GstCaps *
gst_video_info_to_caps(const GstVideoInfo * info)661 gst_video_info_to_caps (const GstVideoInfo * info)
662 {
663 GstCaps *caps;
664 const gchar *format;
665 gchar *color;
666 gint par_n, par_d;
667 GstVideoColorimetry colorimetry;
668
669 g_return_val_if_fail (info != NULL, NULL);
670 g_return_val_if_fail (info->finfo != NULL, NULL);
671 g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
672
673 format = gst_video_format_to_string (info->finfo->format);
674 g_return_val_if_fail (format != NULL, NULL);
675
676 caps = gst_caps_new_simple ("video/x-raw",
677 "format", G_TYPE_STRING, format,
678 "width", G_TYPE_INT, info->width,
679 "height", G_TYPE_INT, info->height, NULL);
680
681 par_n = info->par_n;
682 par_d = info->par_d;
683
684 gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING,
685 gst_video_interlace_mode_to_string (info->interlace_mode), NULL);
686
687 if ((info->interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ||
688 info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE) &&
689 GST_VIDEO_INFO_FIELD_ORDER (info) != GST_VIDEO_FIELD_ORDER_UNKNOWN) {
690 gst_caps_set_simple (caps, "field-order", G_TYPE_STRING,
691 gst_video_field_order_to_string (GST_VIDEO_INFO_FIELD_ORDER (info)),
692 NULL);
693 }
694
695 if (info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
696 /* 'alternate' mode must always be accompanied by interlaced caps feature.
697 */
698 GstCapsFeatures *features;
699
700 features = gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL);
701 gst_caps_set_features (caps, 0, features);
702 }
703
704 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
705 const gchar *caps_str = NULL;
706 GstVideoMultiviewFlags multiview_flags =
707 GST_VIDEO_INFO_MULTIVIEW_FLAGS (info);
708
709 /* If the half-aspect flag is set, applying it into the PAR of the
710 * resulting caps now seems safe, and helps with automatic behaviour
711 * in elements that aren't explicitly multiview aware */
712 if (multiview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
713 multiview_flags &= ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
714 switch (GST_VIDEO_INFO_MULTIVIEW_MODE (info)) {
715 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
716 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
717 case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
718 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
719 par_n *= 2; /* double the width / half the height */
720 break;
721 case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
722 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
723 par_d *= 2; /* half the width / double the height */
724 break;
725 default:
726 break;
727 }
728 }
729
730 caps_str =
731 gst_video_multiview_mode_to_caps_string (GST_VIDEO_INFO_MULTIVIEW_MODE
732 (info));
733 if (caps_str != NULL) {
734 gst_caps_set_simple (caps, "multiview-mode", G_TYPE_STRING,
735 caps_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
736 multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
737 }
738 }
739
740 gst_caps_set_simple (caps, "pixel-aspect-ratio",
741 GST_TYPE_FRACTION, par_n, par_d, NULL);
742
743 if (info->chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN) {
744 gchar *chroma_site = gst_video_chroma_site_to_string (info->chroma_site);
745
746 if (!chroma_site) {
747 GST_WARNING ("Couldn't convert chroma-site 0x%x to string",
748 info->chroma_site);
749 } else {
750 gst_caps_set_simple (caps,
751 "chroma-site", G_TYPE_STRING, chroma_site, NULL);
752 g_free (chroma_site);
753 }
754 }
755
756 /* make sure we set the RGB matrix for RGB formats */
757 colorimetry = info->colorimetry;
758 if (GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo) &&
759 colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
760 GST_WARNING ("invalid matrix %d for RGB format, using RGB",
761 colorimetry.matrix);
762 colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
763 }
764 if ((color = gst_video_colorimetry_to_string (&colorimetry))) {
765 gst_caps_set_simple (caps, "colorimetry", G_TYPE_STRING, color, NULL);
766 g_free (color);
767 }
768
769 if (info->views > 1)
770 gst_caps_set_simple (caps, "views", G_TYPE_INT, info->views, NULL);
771
772 if (info->flags & GST_VIDEO_FLAG_VARIABLE_FPS && info->fps_n != 0) {
773 /* variable fps with a max-framerate */
774 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, 0, 1,
775 "max-framerate", GST_TYPE_FRACTION, info->fps_n, info->fps_d, NULL);
776 } else {
777 /* no variable fps or no max-framerate */
778 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
779 info->fps_n, info->fps_d, NULL);
780 }
781
782 return caps;
783 }
784
785 static gboolean
fill_planes(GstVideoInfo * info,gsize plane_size[GST_VIDEO_MAX_PLANES])786 fill_planes (GstVideoInfo * info, gsize plane_size[GST_VIDEO_MAX_PLANES])
787 {
788 gsize width, height, cr_h;
789 gint bpp = 0, i;
790
791 width = (gsize) info->width;
792 height = (gsize) GST_VIDEO_INFO_FIELD_HEIGHT (info);
793
794 /* Sanity check the resulting frame size for overflows */
795 for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (info); i++)
796 bpp += GST_VIDEO_INFO_COMP_DEPTH (info, i);
797 bpp = GST_ROUND_UP_8 (bpp) / 8;
798 if (bpp > 0 && GST_ROUND_UP_128 ((guint64) width) * ((guint64) height) >=
799 G_MAXUINT / bpp) {
800 GST_ERROR ("Frame size %ux%u would overflow", info->width, info->height);
801 return FALSE;
802 }
803
804 switch (info->finfo->format) {
805 case GST_VIDEO_FORMAT_YUY2:
806 case GST_VIDEO_FORMAT_YVYU:
807 case GST_VIDEO_FORMAT_UYVY:
808 case GST_VIDEO_FORMAT_VYUY:
809 info->stride[0] = GST_ROUND_UP_4 (width * 2);
810 info->offset[0] = 0;
811 info->size = info->stride[0] * height;
812 break;
813 case GST_VIDEO_FORMAT_AYUV:
814 case GST_VIDEO_FORMAT_RGBx:
815 case GST_VIDEO_FORMAT_RGBA:
816 case GST_VIDEO_FORMAT_BGRx:
817 case GST_VIDEO_FORMAT_BGRA:
818 case GST_VIDEO_FORMAT_xRGB:
819 case GST_VIDEO_FORMAT_ARGB:
820 case GST_VIDEO_FORMAT_xBGR:
821 case GST_VIDEO_FORMAT_ABGR:
822 case GST_VIDEO_FORMAT_r210:
823 case GST_VIDEO_FORMAT_Y410:
824 case GST_VIDEO_FORMAT_VUYA:
825 case GST_VIDEO_FORMAT_BGR10A2_LE:
826 case GST_VIDEO_FORMAT_RGB10A2_LE:
827 info->stride[0] = width * 4;
828 info->offset[0] = 0;
829 info->size = info->stride[0] * height;
830 break;
831 case GST_VIDEO_FORMAT_RGB16:
832 case GST_VIDEO_FORMAT_BGR16:
833 case GST_VIDEO_FORMAT_RGB15:
834 case GST_VIDEO_FORMAT_BGR15:
835 info->stride[0] = GST_ROUND_UP_4 (width * 2);
836 info->offset[0] = 0;
837 info->size = info->stride[0] * height;
838 break;
839 case GST_VIDEO_FORMAT_RGB:
840 case GST_VIDEO_FORMAT_BGR:
841 case GST_VIDEO_FORMAT_v308:
842 case GST_VIDEO_FORMAT_IYU2:
843 info->stride[0] = GST_ROUND_UP_4 (width * 3);
844 info->offset[0] = 0;
845 info->size = info->stride[0] * height;
846 break;
847 case GST_VIDEO_FORMAT_v210:
848 info->stride[0] = ((width + 47) / 48) * 128;
849 info->offset[0] = 0;
850 info->size = info->stride[0] * height;
851 break;
852 case GST_VIDEO_FORMAT_v216:
853 case GST_VIDEO_FORMAT_Y210:
854 case GST_VIDEO_FORMAT_Y212_BE:
855 case GST_VIDEO_FORMAT_Y212_LE:
856 info->stride[0] = GST_ROUND_UP_8 (width * 4);
857 info->offset[0] = 0;
858 info->size = info->stride[0] * height;
859 break;
860 case GST_VIDEO_FORMAT_GRAY8:
861 info->stride[0] = GST_ROUND_UP_4 (width);
862 info->offset[0] = 0;
863 info->size = info->stride[0] * height;
864 break;
865 case GST_VIDEO_FORMAT_GRAY16_BE:
866 case GST_VIDEO_FORMAT_GRAY16_LE:
867 info->stride[0] = GST_ROUND_UP_4 (width * 2);
868 info->offset[0] = 0;
869 info->size = info->stride[0] * height;
870 break;
871 case GST_VIDEO_FORMAT_UYVP:
872 info->stride[0] = GST_ROUND_UP_4 ((width * 2 * 5 + 3) / 4);
873 info->offset[0] = 0;
874 info->size = info->stride[0] * height;
875 break;
876 case GST_VIDEO_FORMAT_RGB8P:
877 info->stride[0] = GST_ROUND_UP_4 (width);
878 info->stride[1] = 4;
879 info->offset[0] = 0;
880 info->offset[1] = info->stride[0] * height;
881 info->size = info->offset[1] + (4 * 256);
882 break;
883 case GST_VIDEO_FORMAT_IYU1:
884 info->stride[0] = GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) +
885 GST_ROUND_UP_4 (width) / 2);
886 info->offset[0] = 0;
887 info->size = info->stride[0] * height;
888 break;
889 case GST_VIDEO_FORMAT_ARGB64:
890 case GST_VIDEO_FORMAT_ARGB64_BE:
891 case GST_VIDEO_FORMAT_ARGB64_LE:
892 case GST_VIDEO_FORMAT_RGBA64_BE:
893 case GST_VIDEO_FORMAT_RGBA64_LE:
894 case GST_VIDEO_FORMAT_BGRA64_BE:
895 case GST_VIDEO_FORMAT_BGRA64_LE:
896 case GST_VIDEO_FORMAT_ABGR64_BE:
897 case GST_VIDEO_FORMAT_ABGR64_LE:
898 case GST_VIDEO_FORMAT_AYUV64:
899 case GST_VIDEO_FORMAT_Y412_BE:
900 case GST_VIDEO_FORMAT_Y412_LE:
901 info->stride[0] = width * 8;
902 info->offset[0] = 0;
903 info->size = info->stride[0] * height;
904 break;
905 case GST_VIDEO_FORMAT_I420:
906 case GST_VIDEO_FORMAT_YV12: /* same as I420, but plane 1+2 swapped */
907 info->stride[0] = GST_ROUND_UP_4 (width);
908 info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2);
909 info->stride[2] = info->stride[1];
910 info->offset[0] = 0;
911 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
912 cr_h = GST_ROUND_UP_2 (height) / 2;
913 if (GST_VIDEO_INFO_IS_INTERLACED (info))
914 cr_h = GST_ROUND_UP_2 (cr_h);
915 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
916 info->size = info->offset[2] + info->stride[2] * cr_h;
917 break;
918 case GST_VIDEO_FORMAT_Y41B:
919 info->stride[0] = GST_ROUND_UP_4 (width);
920 info->stride[1] = GST_ROUND_UP_16 (width) / 4;
921 info->stride[2] = info->stride[1];
922 info->offset[0] = 0;
923 info->offset[1] = info->stride[0] * height;
924 info->offset[2] = info->offset[1] + info->stride[1] * height;
925 /* simplification of ROUNDUP4(w)*h + 2*((ROUNDUP16(w)/4)*h */
926 info->size = (info->stride[0] + (GST_ROUND_UP_16 (width) / 2)) * height;
927 break;
928 case GST_VIDEO_FORMAT_Y42B:
929 info->stride[0] = GST_ROUND_UP_4 (width);
930 info->stride[1] = GST_ROUND_UP_8 (width) / 2;
931 info->stride[2] = info->stride[1];
932 info->offset[0] = 0;
933 info->offset[1] = info->stride[0] * height;
934 info->offset[2] = info->offset[1] + info->stride[1] * height;
935 /* simplification of ROUNDUP4(w)*h + 2*(ROUNDUP8(w)/2)*h */
936 info->size = (info->stride[0] + GST_ROUND_UP_8 (width)) * height;
937 break;
938 case GST_VIDEO_FORMAT_Y444:
939 case GST_VIDEO_FORMAT_GBR:
940 case GST_VIDEO_FORMAT_RGBP:
941 case GST_VIDEO_FORMAT_BGRP:
942 info->stride[0] = GST_ROUND_UP_4 (width);
943 info->stride[1] = info->stride[0];
944 info->stride[2] = info->stride[0];
945 info->offset[0] = 0;
946 info->offset[1] = info->stride[0] * height;
947 info->offset[2] = info->offset[1] * 2;
948 info->size = info->stride[0] * height * 3;
949 break;
950 case GST_VIDEO_FORMAT_GBRA:
951 info->stride[0] = GST_ROUND_UP_4 (width);
952 info->stride[1] = info->stride[0];
953 info->stride[2] = info->stride[0];
954 info->stride[3] = info->stride[0];
955 info->offset[0] = 0;
956 info->offset[1] = info->stride[0] * height;
957 info->offset[2] = info->offset[1] * 2;
958 info->offset[3] = info->offset[1] * 3;
959 info->size = info->stride[0] * height * 4;
960 break;
961 case GST_VIDEO_FORMAT_NV12:
962 case GST_VIDEO_FORMAT_NV21:
963 info->stride[0] = GST_ROUND_UP_4 (width);
964 info->stride[1] = info->stride[0];
965 info->offset[0] = 0;
966 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
967 cr_h = GST_ROUND_UP_2 (height) / 2;
968 if (GST_VIDEO_INFO_IS_INTERLACED (info))
969 cr_h = GST_ROUND_UP_2 (cr_h);
970 info->size = info->offset[1] + info->stride[0] * cr_h;
971 break;
972 case GST_VIDEO_FORMAT_AV12:
973 info->stride[0] = GST_ROUND_UP_4 (width);
974 info->stride[1] = info->stride[0];
975 info->stride[2] = info->stride[0];
976 info->offset[0] = 0;
977 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
978 info->offset[2] =
979 info->offset[1] + (info->stride[1] * GST_ROUND_UP_2 (height) / 2);
980 info->size = info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
981 break;
982 case GST_VIDEO_FORMAT_NV16:
983 case GST_VIDEO_FORMAT_NV61:
984 info->stride[0] = GST_ROUND_UP_4 (width);
985 info->stride[1] = info->stride[0];
986 info->offset[0] = 0;
987 info->offset[1] = info->stride[0] * height;
988 info->size = info->stride[0] * height * 2;
989 break;
990 case GST_VIDEO_FORMAT_NV24:
991 info->stride[0] = GST_ROUND_UP_4 (width);
992 info->stride[1] = GST_ROUND_UP_4 (width * 2);
993 info->offset[0] = 0;
994 info->offset[1] = info->stride[0] * height;
995 info->size = info->stride[0] * height + info->stride[1] * height;
996 break;
997 case GST_VIDEO_FORMAT_A420:
998 info->stride[0] = GST_ROUND_UP_4 (width);
999 info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2);
1000 info->stride[2] = info->stride[1];
1001 info->stride[3] = info->stride[0];
1002 info->offset[0] = 0;
1003 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1004 cr_h = GST_ROUND_UP_2 (height) / 2;
1005 if (GST_VIDEO_INFO_IS_INTERLACED (info))
1006 cr_h = GST_ROUND_UP_2 (cr_h);
1007 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1008 info->offset[3] = info->offset[2] + info->stride[2] * cr_h;
1009 info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1010 break;
1011 case GST_VIDEO_FORMAT_YUV9:
1012 case GST_VIDEO_FORMAT_YVU9:
1013 info->stride[0] = GST_ROUND_UP_4 (width);
1014 info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) / 4);
1015 info->stride[2] = info->stride[1];
1016 info->offset[0] = 0;
1017 info->offset[1] = info->stride[0] * height;
1018 cr_h = GST_ROUND_UP_4 (height) / 4;
1019 if (GST_VIDEO_INFO_IS_INTERLACED (info))
1020 cr_h = GST_ROUND_UP_2 (cr_h);
1021 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1022 info->size = info->offset[2] + info->stride[2] * cr_h;
1023 break;
1024 case GST_VIDEO_FORMAT_I420_10LE:
1025 case GST_VIDEO_FORMAT_I420_10BE:
1026 case GST_VIDEO_FORMAT_I420_12LE:
1027 case GST_VIDEO_FORMAT_I420_12BE:
1028 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1029 info->stride[1] = GST_ROUND_UP_4 (width);
1030 info->stride[2] = info->stride[1];
1031 info->offset[0] = 0;
1032 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1033 cr_h = GST_ROUND_UP_2 (height) / 2;
1034 if (GST_VIDEO_INFO_IS_INTERLACED (info))
1035 cr_h = GST_ROUND_UP_2 (cr_h);
1036 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1037 info->size = info->offset[2] + info->stride[2] * cr_h;
1038 break;
1039 case GST_VIDEO_FORMAT_I422_10LE:
1040 case GST_VIDEO_FORMAT_I422_10BE:
1041 case GST_VIDEO_FORMAT_I422_12LE:
1042 case GST_VIDEO_FORMAT_I422_12BE:
1043 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1044 info->stride[1] = GST_ROUND_UP_4 (width);
1045 info->stride[2] = info->stride[1];
1046 info->offset[0] = 0;
1047 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1048 info->offset[2] = info->offset[1] +
1049 info->stride[1] * GST_ROUND_UP_2 (height);
1050 info->size = info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1051 break;
1052 case GST_VIDEO_FORMAT_Y444_10LE:
1053 case GST_VIDEO_FORMAT_Y444_10BE:
1054 case GST_VIDEO_FORMAT_Y444_12LE:
1055 case GST_VIDEO_FORMAT_Y444_12BE:
1056 case GST_VIDEO_FORMAT_GBR_10LE:
1057 case GST_VIDEO_FORMAT_GBR_10BE:
1058 case GST_VIDEO_FORMAT_GBR_12LE:
1059 case GST_VIDEO_FORMAT_GBR_12BE:
1060 case GST_VIDEO_FORMAT_Y444_16LE:
1061 case GST_VIDEO_FORMAT_Y444_16BE:
1062 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1063 info->stride[1] = info->stride[0];
1064 info->stride[2] = info->stride[0];
1065 info->offset[0] = 0;
1066 info->offset[1] = info->stride[0] * height;
1067 info->offset[2] = info->offset[1] * 2;
1068 info->size = info->stride[0] * height * 3;
1069 break;
1070 case GST_VIDEO_FORMAT_GBRA_10LE:
1071 case GST_VIDEO_FORMAT_GBRA_10BE:
1072 case GST_VIDEO_FORMAT_GBRA_12LE:
1073 case GST_VIDEO_FORMAT_GBRA_12BE:
1074 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1075 info->stride[1] = info->stride[0];
1076 info->stride[2] = info->stride[0];
1077 info->stride[3] = info->stride[0];
1078 info->offset[0] = 0;
1079 info->offset[1] = info->stride[0] * height;
1080 info->offset[2] = info->offset[1] * 2;
1081 info->offset[3] = info->offset[1] * 3;
1082 info->size = info->stride[0] * height * 4;
1083 break;
1084 case GST_VIDEO_FORMAT_NV12_64Z32:
1085 info->stride[0] =
1086 GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_128 (width) / 64,
1087 GST_ROUND_UP_32 (height) / 32);
1088 info->stride[1] =
1089 GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_128 (width) / 64,
1090 GST_ROUND_UP_64 (height) / 64);
1091 info->offset[0] = 0;
1092 info->offset[1] = GST_ROUND_UP_128 (width) * GST_ROUND_UP_32 (height);
1093 info->size = info->offset[1] +
1094 GST_ROUND_UP_128 (width) * (GST_ROUND_UP_64 (height) / 2);
1095 break;
1096 case GST_VIDEO_FORMAT_NV12_4L4:
1097 case GST_VIDEO_FORMAT_NV12_32L32:
1098 {
1099 gint ws = GST_VIDEO_FORMAT_INFO_TILE_WS (info->finfo);
1100 gint hs = GST_VIDEO_FORMAT_INFO_TILE_HS (info->finfo);
1101 info->stride[0] =
1102 GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_N (width, 1 << ws) >> ws,
1103 GST_ROUND_UP_N (height, 1 << hs) >> hs);
1104 info->stride[1] =
1105 GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_N (width, 1 << ws) >> ws,
1106 GST_ROUND_UP_N (height, 1 << (hs + 1)) >> (hs + 1));
1107 info->offset[0] = 0;
1108 info->offset[1] =
1109 GST_ROUND_UP_N (width, 1 << ws) * GST_ROUND_UP_N (height, 1 << hs);
1110 info->size = info->offset[1] +
1111 GST_ROUND_UP_N (width, 1 << ws) *
1112 (GST_ROUND_UP_N (height, 1 << (hs + 1)) / 2);
1113 break;
1114 }
1115 case GST_VIDEO_FORMAT_A420_10LE:
1116 case GST_VIDEO_FORMAT_A420_10BE:
1117 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1118 info->stride[1] = GST_ROUND_UP_4 (width);
1119 info->stride[2] = info->stride[1];
1120 info->stride[3] = info->stride[0];
1121 info->offset[0] = 0;
1122 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1123 cr_h = GST_ROUND_UP_2 (height) / 2;
1124 if (GST_VIDEO_INFO_IS_INTERLACED (info))
1125 cr_h = GST_ROUND_UP_2 (cr_h);
1126 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1127 info->offset[3] = info->offset[2] + info->stride[2] * cr_h;
1128 info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1129 break;
1130 case GST_VIDEO_FORMAT_A422_10LE:
1131 case GST_VIDEO_FORMAT_A422_10BE:
1132 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1133 info->stride[1] = GST_ROUND_UP_4 (width);
1134 info->stride[2] = info->stride[1];
1135 info->stride[3] = info->stride[0];
1136 info->offset[0] = 0;
1137 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1138 info->offset[2] = info->offset[1] +
1139 info->stride[1] * GST_ROUND_UP_2 (height);
1140 info->offset[3] =
1141 info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1142 info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1143 break;
1144 case GST_VIDEO_FORMAT_A444_10LE:
1145 case GST_VIDEO_FORMAT_A444_10BE:
1146 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1147 info->stride[1] = info->stride[0];
1148 info->stride[2] = info->stride[0];
1149 info->stride[3] = info->stride[0];
1150 info->offset[0] = 0;
1151 info->offset[1] = info->stride[0] * height;
1152 info->offset[2] = info->offset[1] * 2;
1153 info->offset[3] = info->offset[1] * 3;
1154 info->size = info->stride[0] * height * 4;
1155 break;
1156 case GST_VIDEO_FORMAT_P010_10LE:
1157 case GST_VIDEO_FORMAT_P010_10BE:
1158 case GST_VIDEO_FORMAT_P016_LE:
1159 case GST_VIDEO_FORMAT_P016_BE:
1160 case GST_VIDEO_FORMAT_P012_LE:
1161 case GST_VIDEO_FORMAT_P012_BE:
1162 info->stride[0] = GST_ROUND_UP_4 (width * 2);
1163 info->stride[1] = info->stride[0];
1164 info->offset[0] = 0;
1165 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1166 cr_h = GST_ROUND_UP_2 (height) / 2;
1167 info->size = info->offset[1] + info->stride[0] * cr_h;
1168 break;
1169 case GST_VIDEO_FORMAT_GRAY10_LE32:
1170 info->stride[0] = (width + 2) / 3 * 4;
1171 info->offset[0] = 0;
1172 info->size = info->stride[0] * GST_ROUND_UP_2 (height);
1173 break;
1174 case GST_VIDEO_FORMAT_NV12_10LE32:
1175 info->stride[0] = (width + 2) / 3 * 4;
1176 info->stride[1] = info->stride[0];
1177 info->offset[0] = 0;
1178 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1179 cr_h = GST_ROUND_UP_2 (height) / 2;
1180 if (GST_VIDEO_INFO_IS_INTERLACED (info))
1181 cr_h = GST_ROUND_UP_2 (cr_h);
1182 info->size = info->offset[1] + info->stride[0] * cr_h;
1183 break;
1184 case GST_VIDEO_FORMAT_NV16_10LE32:
1185 info->stride[0] = (width + 2) / 3 * 4;
1186 info->stride[1] = info->stride[0];
1187 info->offset[0] = 0;
1188 info->offset[1] = info->stride[0] * height;
1189 info->size = info->stride[0] * height * 2;
1190 break;
1191 case GST_VIDEO_FORMAT_NV12_10LE40:
1192 info->stride[0] = ((width * 5 >> 2) + 4) / 5 * 5;
1193 info->stride[1] = info->stride[0];
1194 info->offset[0] = 0;
1195 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1196 cr_h = GST_ROUND_UP_2 (height) / 2;
1197 if (GST_VIDEO_INFO_IS_INTERLACED (info))
1198 cr_h = GST_ROUND_UP_2 (cr_h);
1199 info->size = info->offset[1] + info->stride[0] * cr_h;
1200 break;
1201
1202 case GST_VIDEO_FORMAT_ENCODED:
1203 break;
1204 case GST_VIDEO_FORMAT_UNKNOWN:
1205 GST_ERROR ("invalid format");
1206 g_warning ("invalid format");
1207 return FALSE;
1208 break;
1209 }
1210
1211 if (plane_size) {
1212 for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1213 if (i < GST_VIDEO_INFO_N_PLANES (info)) {
1214 gint comp[GST_VIDEO_MAX_COMPONENTS];
1215 guint plane_height;
1216
1217 /* Convert plane index to component index */
1218 gst_video_format_info_component (info->finfo, i, comp);
1219 plane_height =
1220 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0],
1221 GST_VIDEO_INFO_FIELD_HEIGHT (info));
1222 plane_size[i] = plane_height * GST_VIDEO_INFO_PLANE_STRIDE (info, i);
1223 } else {
1224 plane_size[i] = 0;
1225 }
1226 }
1227 }
1228
1229 return TRUE;
1230 }
1231
1232 /**
1233 * gst_video_info_convert:
1234 * @info: a #GstVideoInfo
1235 * @src_format: #GstFormat of the @src_value
1236 * @src_value: value to convert
1237 * @dest_format: #GstFormat of the @dest_value
1238 * @dest_value: (out): pointer to destination value
1239 *
1240 * Converts among various #GstFormat types. This function handles
1241 * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT. For
1242 * raw video, GST_FORMAT_DEFAULT corresponds to video frames. This
1243 * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
1244 *
1245 * Returns: TRUE if the conversion was successful.
1246 */
1247 gboolean
gst_video_info_convert(const GstVideoInfo * info,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)1248 gst_video_info_convert (const GstVideoInfo * info,
1249 GstFormat src_format, gint64 src_value,
1250 GstFormat dest_format, gint64 * dest_value)
1251 {
1252 gboolean ret = FALSE;
1253 int fps_n, fps_d;
1254 gsize size;
1255
1256 g_return_val_if_fail (info != NULL, 0);
1257 g_return_val_if_fail (info->finfo != NULL, 0);
1258 g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, 0);
1259 g_return_val_if_fail (info->size > 0, 0);
1260
1261 size = info->size;
1262 fps_n = info->fps_n;
1263 fps_d = info->fps_d;
1264
1265 GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s to %s",
1266 src_value, gst_format_get_name (src_format),
1267 gst_format_get_name (dest_format));
1268
1269 if (src_format == dest_format) {
1270 *dest_value = src_value;
1271 ret = TRUE;
1272 goto done;
1273 }
1274
1275 if (src_value == -1) {
1276 *dest_value = -1;
1277 ret = TRUE;
1278 goto done;
1279 }
1280
1281 /* bytes to frames */
1282 if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_DEFAULT) {
1283 if (size != 0) {
1284 *dest_value = gst_util_uint64_scale (src_value, 1, size);
1285 } else {
1286 GST_ERROR ("blocksize is 0");
1287 *dest_value = 0;
1288 }
1289 ret = TRUE;
1290 goto done;
1291 }
1292
1293 /* frames to bytes */
1294 if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_BYTES) {
1295 *dest_value = gst_util_uint64_scale (src_value, size, 1);
1296 ret = TRUE;
1297 goto done;
1298 }
1299
1300 /* time to frames */
1301 if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_DEFAULT) {
1302 if (fps_d != 0) {
1303 *dest_value = gst_util_uint64_scale (src_value,
1304 fps_n, GST_SECOND * fps_d);
1305 } else {
1306 GST_ERROR ("framerate denominator is 0");
1307 *dest_value = 0;
1308 }
1309 ret = TRUE;
1310 goto done;
1311 }
1312
1313 /* frames to time */
1314 if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) {
1315 if (fps_n != 0) {
1316 *dest_value = gst_util_uint64_scale (src_value,
1317 GST_SECOND * fps_d, fps_n);
1318 } else {
1319 GST_ERROR ("framerate numerator is 0");
1320 *dest_value = 0;
1321 }
1322 ret = TRUE;
1323 goto done;
1324 }
1325
1326 /* time to bytes */
1327 if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
1328 if (fps_d != 0) {
1329 *dest_value = gst_util_uint64_scale (src_value,
1330 fps_n * size, GST_SECOND * fps_d);
1331 } else {
1332 GST_ERROR ("framerate denominator is 0");
1333 *dest_value = 0;
1334 }
1335 ret = TRUE;
1336 goto done;
1337 }
1338
1339 /* bytes to time */
1340 if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) {
1341 if (fps_n != 0 && size != 0) {
1342 *dest_value = gst_util_uint64_scale (src_value,
1343 GST_SECOND * fps_d, fps_n * size);
1344 } else {
1345 GST_ERROR ("framerate denominator and/or blocksize is 0");
1346 *dest_value = 0;
1347 }
1348 ret = TRUE;
1349 }
1350
1351 done:
1352
1353 GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, ret, *dest_value);
1354
1355 return ret;
1356 }
1357
1358 /**
1359 * gst_video_info_align_full:
1360 * @info: a #GstVideoInfo
1361 * @align: alignment parameters
1362 * @plane_size: (out) (allow-none): array used to store the plane sizes
1363 *
1364 * Extra padding will be added to the right side when stride alignment padding
1365 * is required and @align will be updated with the new padding values.
1366 *
1367 * This variant of gst_video_info_align() provides the updated size, in bytes,
1368 * of each video plane after the alignment, including all horizontal and vertical
1369 * paddings.
1370 *
1371 * In case of GST_VIDEO_INTERLACE_MODE_ALTERNATE info, the returned sizes are the
1372 * ones used to hold a single field, not the full frame.
1373 *
1374 * Returns: %FALSE if alignment could not be applied, e.g. because the
1375 * size of a frame can't be represented as a 32 bit integer
1376 *
1377 * Since: 1.18
1378 */
1379 gboolean
gst_video_info_align_full(GstVideoInfo * info,GstVideoAlignment * align,gsize plane_size[GST_VIDEO_MAX_PLANES])1380 gst_video_info_align_full (GstVideoInfo * info, GstVideoAlignment * align,
1381 gsize plane_size[GST_VIDEO_MAX_PLANES])
1382 {
1383 const GstVideoFormatInfo *vinfo = info->finfo;
1384 gint width, height;
1385 gint padded_width, padded_height;
1386 gint i, n_planes;
1387 gboolean aligned;
1388
1389 width = GST_VIDEO_INFO_WIDTH (info);
1390 height = GST_VIDEO_INFO_HEIGHT (info);
1391
1392 GST_LOG ("padding %u-%ux%u-%u", align->padding_top,
1393 align->padding_left, align->padding_right, align->padding_bottom);
1394
1395 n_planes = GST_VIDEO_INFO_N_PLANES (info);
1396
1397 if (GST_VIDEO_FORMAT_INFO_HAS_PALETTE (vinfo))
1398 n_planes--;
1399
1400 /* first make sure the left padding does not cause alignment problems later */
1401 do {
1402 GST_LOG ("left padding %u", align->padding_left);
1403 aligned = TRUE;
1404 for (i = 0; i < n_planes; i++) {
1405 gint comp[GST_VIDEO_MAX_COMPONENTS];
1406 gint hedge;
1407
1408 /* this is the amount of pixels to add as left padding */
1409 gst_video_format_info_component (vinfo, i, comp);
1410 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, comp[0],
1411 align->padding_left);
1412 hedge *= GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, comp[0]);
1413
1414 GST_LOG ("plane %d, padding %d, alignment %u", i, hedge,
1415 align->stride_align[i]);
1416 aligned &= (hedge & align->stride_align[i]) == 0;
1417 }
1418 if (aligned)
1419 break;
1420
1421 GST_LOG ("unaligned padding, increasing padding");
1422 /* increase padded_width */
1423 align->padding_left += align->padding_left & ~(align->padding_left - 1);
1424 } while (!aligned);
1425
1426 /* add the padding */
1427 padded_width = width + align->padding_left + align->padding_right;
1428 padded_height = height + align->padding_top + align->padding_bottom;
1429
1430 do {
1431 GST_LOG ("padded dimension %u-%u", padded_width, padded_height);
1432
1433 info->width = padded_width;
1434 info->height = padded_height;
1435
1436 if (!fill_planes (info, plane_size))
1437 return FALSE;
1438
1439 /* check alignment */
1440 aligned = TRUE;
1441 for (i = 0; i < n_planes; i++) {
1442 GST_LOG ("plane %d, stride %d, alignment %u", i, info->stride[i],
1443 align->stride_align[i]);
1444 aligned &= (info->stride[i] & align->stride_align[i]) == 0;
1445 }
1446 if (aligned)
1447 break;
1448
1449 GST_LOG ("unaligned strides, increasing dimension");
1450 /* increase padded_width */
1451 padded_width += padded_width & ~(padded_width - 1);
1452 } while (!aligned);
1453
1454 align->padding_right = padded_width - width - align->padding_left;
1455
1456 info->width = width;
1457 info->height = height;
1458
1459 for (i = 0; i < n_planes; i++) {
1460 gint comp[GST_VIDEO_MAX_COMPONENTS];
1461 gint vedge, hedge;
1462
1463 gst_video_format_info_component (info->finfo, i, comp);
1464 hedge =
1465 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, comp[0], align->padding_left);
1466 vedge =
1467 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo, comp[0], align->padding_top);
1468
1469 GST_DEBUG ("plane %d: comp: %d, hedge %d vedge %d align %d stride %d", i,
1470 comp[0], hedge, vedge, align->stride_align[i], info->stride[i]);
1471
1472 info->offset[i] += (vedge * info->stride[i]) +
1473 (hedge * GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, comp[0]));
1474 }
1475
1476 return TRUE;
1477 }
1478
1479 /**
1480 * gst_video_info_align:
1481 * @info: a #GstVideoInfo
1482 * @align: alignment parameters
1483 *
1484 * Adjust the offset and stride fields in @info so that the padding and
1485 * stride alignment in @align is respected.
1486 *
1487 * Extra padding will be added to the right side when stride alignment padding
1488 * is required and @align will be updated with the new padding values.
1489 *
1490 * Returns: %FALSE if alignment could not be applied, e.g. because the
1491 * size of a frame can't be represented as a 32 bit integer (Since: 1.12)
1492 */
1493 gboolean
gst_video_info_align(GstVideoInfo * info,GstVideoAlignment * align)1494 gst_video_info_align (GstVideoInfo * info, GstVideoAlignment * align)
1495 {
1496 return gst_video_info_align_full (info, align, NULL);
1497 }
1498