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