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