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