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