• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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