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