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