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