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