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