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