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