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