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