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