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>
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.
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.
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.
29 #include "video-info.h"
30 #include "video-tile.h"
33 * gst_video_info_copy:
34 * @info: a #GstVideoInfo
36 * Copy a GstVideoInfo structure.
38 * Returns: a new #GstVideoInfo. free with gst_video_info_free.
43 gst_video_info_copy (const GstVideoInfo * info)
45 return g_slice_dup (GstVideoInfo, info);
49 * gst_video_info_free:
50 * @info: a #GstVideoInfo
52 * Free a GstVideoInfo structure previously allocated with gst_video_info_new()
53 * or gst_video_info_copy().
58 gst_video_info_free (GstVideoInfo * info)
60 g_slice_free (GstVideoInfo, info);
63 G_DEFINE_BOXED_TYPE (GstVideoInfo, gst_video_info,
64 (GBoxedCopyFunc) gst_video_info_copy, (GBoxedFreeFunc) gst_video_info_free);
69 * Allocate a new #GstVideoInfo that is also initialized with
70 * gst_video_info_init().
72 * Returns: a new #GstVideoInfo. free with gst_video_info_free().
77 gst_video_info_new (void)
81 info = g_slice_new (GstVideoInfo);
82 gst_video_info_init (info);
87 static int fill_planes (GstVideoInfo * info);
90 * gst_video_info_init:
91 * @info: a #GstVideoInfo
93 * Initialize @info with default values.
96 gst_video_info_init (GstVideoInfo * info)
98 g_return_if_fail (info != NULL);
100 memset (info, 0, sizeof (GstVideoInfo));
102 info->finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_UNKNOWN);
105 /* arrange for sensible defaults, e.g. if turned into caps */
110 GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE;
113 #define MAKE_COLORIMETRY(r,m,t,p) { \
114 GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m, \
115 GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p }
117 #define DEFAULT_YUV_SD 0
118 #define DEFAULT_YUV_HD 1
119 #define DEFAULT_RGB 2
120 #define DEFAULT_GRAY 3
121 #define DEFAULT_UNKNOWN 4
122 #define DEFAULT_YUV_UHD 5
124 static const GstVideoColorimetry default_color[] = {
125 MAKE_COLORIMETRY (_16_235, BT601, BT709, SMPTE170M),
126 MAKE_COLORIMETRY (_16_235, BT709, BT709, BT709),
127 MAKE_COLORIMETRY (_0_255, RGB, SRGB, BT709),
128 MAKE_COLORIMETRY (_0_255, BT601, UNKNOWN, UNKNOWN),
129 MAKE_COLORIMETRY (_UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN),
130 MAKE_COLORIMETRY (_16_235, BT2020, BT2020_12, BT2020),
134 set_default_colorimetry (GstVideoInfo * info)
136 const GstVideoFormatInfo *finfo = info->finfo;
138 if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)) {
139 if (info->height >= 2160) {
140 info->chroma_site = GST_VIDEO_CHROMA_SITE_H_COSITED;
141 info->colorimetry = default_color[DEFAULT_YUV_UHD];
142 } else if (info->height > 576) {
143 info->chroma_site = GST_VIDEO_CHROMA_SITE_H_COSITED;
144 info->colorimetry = default_color[DEFAULT_YUV_HD];
146 info->chroma_site = GST_VIDEO_CHROMA_SITE_NONE;
147 info->colorimetry = default_color[DEFAULT_YUV_SD];
149 } else if (GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo)) {
150 info->colorimetry = default_color[DEFAULT_GRAY];
151 } else if (GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) {
152 info->colorimetry = default_color[DEFAULT_RGB];
154 info->colorimetry = default_color[DEFAULT_UNKNOWN];
159 validate_colorimetry (GstVideoInfo * info)
161 const GstVideoFormatInfo *finfo = info->finfo;
163 if (!GST_VIDEO_FORMAT_INFO_IS_RGB (finfo) &&
164 info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB)
167 if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo) &&
168 info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
175 * gst_video_info_set_format:
176 * @info: a #GstVideoInfo
177 * @format: the format
181 * Set the default info for a video frame of @format and @width and @height.
183 * Note: This initializes @info first, no values are preserved. This function
184 * does not set the offsets correctly for interlaced vertically
185 * subsampled formats.
188 gst_video_info_set_format (GstVideoInfo * info, GstVideoFormat format,
189 guint width, guint height)
191 g_return_if_fail (info != NULL);
192 g_return_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN);
194 gst_video_info_init (info);
196 info->finfo = gst_video_format_get_info (format);
198 info->height = height;
201 set_default_colorimetry (info);
206 static const gchar *interlace_mode[] = {
214 * gst_video_interlace_mode_to_string:
215 * @mode: a #GstVideoInterlaceMode
217 * Convert @mode to its string representation.
219 * Returns: @mode as a string or NULL if @mode in invalid.
224 gst_video_interlace_mode_to_string (GstVideoInterlaceMode mode)
226 if (((guint) mode) >= G_N_ELEMENTS (interlace_mode))
229 return interlace_mode[mode];
233 * gst_video_interlace_mode_from_string:
236 * Convert @mode to a #GstVideoInterlaceMode
238 * Returns: the #GstVideoInterlaceMode of @mode or
239 * #GST_VIDEO_INTERLACE_MODE_PROGRESSIVE when @mode is not a valid
240 * string representation for a #GstVideoInterlaceMode.
244 GstVideoInterlaceMode
245 gst_video_interlace_mode_from_string (const gchar * mode)
248 for (i = 0; i < G_N_ELEMENTS (interlace_mode); i++) {
249 if (g_str_equal (interlace_mode[i], mode))
252 return GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
256 * gst_video_info_from_caps:
257 * @info: a #GstVideoInfo
260 * Parse @caps and update @info.
262 * Returns: TRUE if @caps could be parsed
265 gst_video_info_from_caps (GstVideoInfo * info, const GstCaps * caps)
267 GstStructure *structure;
269 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
270 gint width = 0, height = 0;
274 g_return_val_if_fail (info != NULL, FALSE);
275 g_return_val_if_fail (caps != NULL, FALSE);
276 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
278 GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
280 structure = gst_caps_get_structure (caps, 0);
282 if (gst_structure_has_name (structure, "video/x-raw")) {
283 if (!(s = gst_structure_get_string (structure, "format")))
286 format = gst_video_format_from_string (s);
287 if (format == GST_VIDEO_FORMAT_UNKNOWN)
290 } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/") ||
291 g_str_has_prefix (gst_structure_get_name (structure), "image/")) {
292 format = GST_VIDEO_FORMAT_ENCODED;
297 /* width and height are mandatory, except for non-raw-formats */
298 if (!gst_structure_get_int (structure, "width", &width) &&
299 format != GST_VIDEO_FORMAT_ENCODED)
301 if (!gst_structure_get_int (structure, "height", &height) &&
302 format != GST_VIDEO_FORMAT_ENCODED)
305 gst_video_info_init (info);
307 info->finfo = gst_video_format_get_info (format);
309 info->height = height;
311 if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
313 /* variable framerate */
314 info->flags |= GST_VIDEO_FLAG_VARIABLE_FPS;
315 /* see if we have a max-framerate */
316 gst_structure_get_fraction (structure, "max-framerate", &fps_n, &fps_d);
321 /* unspecified is variable framerate */
326 if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
335 if ((s = gst_structure_get_string (structure, "interlace-mode")))
336 info->interlace_mode = gst_video_interlace_mode_from_string (s);
338 info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
341 if ((s = gst_structure_get_string (structure, "multiview-mode")))
342 GST_VIDEO_INFO_MULTIVIEW_MODE (info) =
343 gst_video_multiview_mode_from_caps_string (s);
345 GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE;
347 gst_structure_get_flagset (structure, "multiview-flags",
348 &GST_VIDEO_INFO_MULTIVIEW_FLAGS (info), NULL);
350 if (!gst_structure_get_int (structure, "views", &info->views))
353 /* At one point, I tried normalising the half-aspect flag here,
354 * but it behaves weird for GstVideoInfo operations other than
355 * directly converting to/from caps - sometimes causing the
356 * PAR to be doubled/halved too many times */
359 if ((s = gst_structure_get_string (structure, "chroma-site")))
360 info->chroma_site = gst_video_chroma_from_string (s);
362 info->chroma_site = GST_VIDEO_CHROMA_SITE_UNKNOWN;
364 if ((s = gst_structure_get_string (structure, "colorimetry"))) {
365 if (!gst_video_colorimetry_from_string (&info->colorimetry, s)) {
366 GST_WARNING ("unparsable colorimetry, using default");
367 set_default_colorimetry (info);
368 } else if (!validate_colorimetry (info)) {
369 GST_WARNING ("invalid colorimetry, using default");
370 set_default_colorimetry (info);
373 GST_DEBUG ("no colorimetry, using default");
374 set_default_colorimetry (info);
384 GST_ERROR ("wrong name '%s', expected video/ or image/",
385 gst_structure_get_name (structure));
390 GST_ERROR ("no format given");
395 GST_ERROR ("unknown format '%s' given", s);
400 GST_ERROR ("no width property given");
405 GST_ERROR ("no height property given");
411 * gst_video_info_is_equal:
412 * @info: a #GstVideoInfo
413 * @other: a #GstVideoInfo
415 * Compares two #GstVideoInfo and returns whether they are equal or not
417 * Returns: %TRUE if @info and @other are equal, else %FALSE.
420 gst_video_info_is_equal (const GstVideoInfo * info, const GstVideoInfo * other)
424 if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_INFO_FORMAT (other))
426 if (GST_VIDEO_INFO_INTERLACE_MODE (info) !=
427 GST_VIDEO_INFO_INTERLACE_MODE (other))
429 if (GST_VIDEO_INFO_FLAGS (info) != GST_VIDEO_INFO_FLAGS (other))
431 if (GST_VIDEO_INFO_WIDTH (info) != GST_VIDEO_INFO_WIDTH (other))
433 if (GST_VIDEO_INFO_HEIGHT (info) != GST_VIDEO_INFO_HEIGHT (other))
435 if (GST_VIDEO_INFO_SIZE (info) != GST_VIDEO_INFO_SIZE (other))
437 if (GST_VIDEO_INFO_PAR_N (info) != GST_VIDEO_INFO_PAR_N (other))
439 if (GST_VIDEO_INFO_PAR_D (info) != GST_VIDEO_INFO_PAR_D (other))
441 if (GST_VIDEO_INFO_FPS_N (info) != GST_VIDEO_INFO_FPS_N (other))
443 if (GST_VIDEO_INFO_FPS_D (info) != GST_VIDEO_INFO_FPS_D (other))
445 if (!gst_video_colorimetry_is_equal (&GST_VIDEO_INFO_COLORIMETRY (info),
446 &GST_VIDEO_INFO_COLORIMETRY (other)))
448 if (GST_VIDEO_INFO_CHROMA_SITE (info) != GST_VIDEO_INFO_CHROMA_SITE (other))
450 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) !=
451 GST_VIDEO_INFO_MULTIVIEW_MODE (other))
453 if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) !=
454 GST_VIDEO_INFO_MULTIVIEW_FLAGS (other))
456 if (GST_VIDEO_INFO_VIEWS (info) != GST_VIDEO_INFO_VIEWS (other))
459 for (i = 0; i < info->finfo->n_planes; i++) {
460 if (info->stride[i] != other->stride[i])
462 if (info->offset[i] != other->offset[i])
470 * gst_video_info_to_caps:
471 * @info: a #GstVideoInfo
473 * Convert the values of @info into a #GstCaps.
475 * Returns: a new #GstCaps containing the info of @info.
478 gst_video_info_to_caps (GstVideoInfo * info)
485 g_return_val_if_fail (info != NULL, NULL);
486 g_return_val_if_fail (info->finfo != NULL, NULL);
487 g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
489 format = gst_video_format_to_string (info->finfo->format);
490 g_return_val_if_fail (format != NULL, NULL);
492 caps = gst_caps_new_simple ("video/x-raw",
493 "format", G_TYPE_STRING, format,
494 "width", G_TYPE_INT, info->width,
495 "height", G_TYPE_INT, info->height, NULL);
500 gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING,
501 gst_video_interlace_mode_to_string (info->interlace_mode), NULL);
503 if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
504 const gchar *caps_str = NULL;
506 /* If the half-aspect flag is set, applying it into the PAR of the
507 * resulting caps now seems safe, and helps with automatic behaviour
508 * in elements that aren't explicitly multiview aware */
509 if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &
510 GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
511 GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &=
512 ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
513 switch (GST_VIDEO_INFO_MULTIVIEW_MODE (info)) {
514 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
515 case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
516 case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
517 case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
518 par_n *= 2; /* double the width / half the height */
520 case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
521 case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
522 par_d *= 2; /* half the width / double the height */
530 gst_video_multiview_mode_to_caps_string (GST_VIDEO_INFO_MULTIVIEW_MODE
532 if (caps_str != NULL) {
533 gst_caps_set_simple (caps, "multiview-mode", G_TYPE_STRING,
534 caps_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
535 GST_VIDEO_INFO_MULTIVIEW_FLAGS (info), GST_FLAG_SET_MASK_EXACT, NULL);
539 gst_caps_set_simple (caps, "pixel-aspect-ratio",
540 GST_TYPE_FRACTION, par_n, par_d, NULL);
542 if (info->chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN)
543 gst_caps_set_simple (caps, "chroma-site", G_TYPE_STRING,
544 gst_video_chroma_to_string (info->chroma_site), NULL);
546 if ((color = gst_video_colorimetry_to_string (&info->colorimetry))) {
547 gst_caps_set_simple (caps, "colorimetry", G_TYPE_STRING, color, NULL);
552 gst_caps_set_simple (caps, "views", G_TYPE_INT, info->views, NULL);
554 if (info->flags & GST_VIDEO_FLAG_VARIABLE_FPS && info->fps_n != 0) {
555 /* variable fps with a max-framerate */
556 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, 0, 1,
557 "max-framerate", GST_TYPE_FRACTION, info->fps_n, info->fps_d, NULL);
559 /* no variable fps or no max-framerate */
560 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
561 info->fps_n, info->fps_d, NULL);
568 fill_planes (GstVideoInfo * info)
570 gsize width, height, cr_h;
572 width = (gsize) info->width;
573 height = (gsize) info->height;
575 switch (info->finfo->format) {
576 case GST_VIDEO_FORMAT_YUY2:
577 case GST_VIDEO_FORMAT_YVYU:
578 case GST_VIDEO_FORMAT_UYVY:
579 info->stride[0] = GST_ROUND_UP_4 (width * 2);
581 info->size = info->stride[0] * height;
583 case GST_VIDEO_FORMAT_AYUV:
584 case GST_VIDEO_FORMAT_RGBx:
585 case GST_VIDEO_FORMAT_RGBA:
586 case GST_VIDEO_FORMAT_BGRx:
587 case GST_VIDEO_FORMAT_BGRA:
588 case GST_VIDEO_FORMAT_xRGB:
589 case GST_VIDEO_FORMAT_ARGB:
590 case GST_VIDEO_FORMAT_xBGR:
591 case GST_VIDEO_FORMAT_ABGR:
592 case GST_VIDEO_FORMAT_r210:
593 info->stride[0] = width * 4;
595 info->size = info->stride[0] * height;
597 case GST_VIDEO_FORMAT_RGB16:
598 case GST_VIDEO_FORMAT_BGR16:
599 case GST_VIDEO_FORMAT_RGB15:
600 case GST_VIDEO_FORMAT_BGR15:
601 info->stride[0] = GST_ROUND_UP_4 (width * 2);
603 info->size = info->stride[0] * height;
605 case GST_VIDEO_FORMAT_RGB:
606 case GST_VIDEO_FORMAT_BGR:
607 case GST_VIDEO_FORMAT_v308:
608 info->stride[0] = GST_ROUND_UP_4 (width * 3);
610 info->size = info->stride[0] * height;
612 case GST_VIDEO_FORMAT_v210:
613 info->stride[0] = ((width + 47) / 48) * 128;
615 info->size = info->stride[0] * height;
617 case GST_VIDEO_FORMAT_v216:
618 info->stride[0] = GST_ROUND_UP_8 (width * 4);
620 info->size = info->stride[0] * height;
622 case GST_VIDEO_FORMAT_GRAY8:
623 info->stride[0] = GST_ROUND_UP_4 (width);
625 info->size = info->stride[0] * height;
627 case GST_VIDEO_FORMAT_GRAY16_BE:
628 case GST_VIDEO_FORMAT_GRAY16_LE:
629 info->stride[0] = GST_ROUND_UP_4 (width * 2);
631 info->size = info->stride[0] * height;
633 case GST_VIDEO_FORMAT_UYVP:
634 info->stride[0] = GST_ROUND_UP_4 ((width * 2 * 5 + 3) / 4);
636 info->size = info->stride[0] * height;
638 case GST_VIDEO_FORMAT_RGB8P:
639 info->stride[0] = GST_ROUND_UP_4 (width);
642 info->offset[1] = info->stride[0] * height;
643 info->size = info->offset[1] + (4 * 256);
645 case GST_VIDEO_FORMAT_IYU1:
646 info->stride[0] = GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) +
647 GST_ROUND_UP_4 (width) / 2);
649 info->size = info->stride[0] * height;
651 case GST_VIDEO_FORMAT_ARGB64:
652 case GST_VIDEO_FORMAT_AYUV64:
653 info->stride[0] = width * 8;
655 info->size = info->stride[0] * height;
657 case GST_VIDEO_FORMAT_I420:
658 case GST_VIDEO_FORMAT_YV12: /* same as I420, but plane 1+2 swapped */
659 info->stride[0] = GST_ROUND_UP_4 (width);
660 info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2);
661 info->stride[2] = info->stride[1];
663 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
664 cr_h = GST_ROUND_UP_2 (height) / 2;
665 if (GST_VIDEO_INFO_IS_INTERLACED (info))
666 cr_h = GST_ROUND_UP_2 (cr_h);
667 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
668 info->size = info->offset[2] + info->stride[2] * cr_h;
669 GST_DEBUG ("%d %d %d", GST_VIDEO_INFO_IS_INTERLACED (info),
670 (int) info->offset[2], (int) info->size);
672 case GST_VIDEO_FORMAT_Y41B:
673 info->stride[0] = GST_ROUND_UP_4 (width);
674 info->stride[1] = GST_ROUND_UP_16 (width) / 4;
675 info->stride[2] = info->stride[1];
677 info->offset[1] = info->stride[0] * height;
678 info->offset[2] = info->offset[1] + info->stride[1] * height;
679 /* simplification of ROUNDUP4(w)*h + 2*((ROUNDUP16(w)/4)*h */
680 info->size = (info->stride[0] + (GST_ROUND_UP_16 (width) / 2)) * height;
682 case GST_VIDEO_FORMAT_Y42B:
683 info->stride[0] = GST_ROUND_UP_4 (width);
684 info->stride[1] = GST_ROUND_UP_8 (width) / 2;
685 info->stride[2] = info->stride[1];
687 info->offset[1] = info->stride[0] * height;
688 info->offset[2] = info->offset[1] + info->stride[1] * height;
689 /* simplification of ROUNDUP4(w)*h + 2*(ROUNDUP8(w)/2)*h */
690 info->size = (info->stride[0] + GST_ROUND_UP_8 (width)) * height;
692 case GST_VIDEO_FORMAT_Y444:
693 case GST_VIDEO_FORMAT_GBR:
694 info->stride[0] = GST_ROUND_UP_4 (width);
695 info->stride[1] = info->stride[0];
696 info->stride[2] = info->stride[0];
698 info->offset[1] = info->stride[0] * height;
699 info->offset[2] = info->offset[1] * 2;
700 info->size = info->stride[0] * height * 3;
702 case GST_VIDEO_FORMAT_NV12:
703 case GST_VIDEO_FORMAT_NV21:
704 info->stride[0] = GST_ROUND_UP_4 (width);
705 info->stride[1] = info->stride[0];
707 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
708 cr_h = GST_ROUND_UP_2 (height) / 2;
709 if (GST_VIDEO_INFO_IS_INTERLACED (info))
710 cr_h = GST_ROUND_UP_2 (cr_h);
711 info->size = info->offset[1] + info->stride[0] * cr_h;
713 case GST_VIDEO_FORMAT_NV16:
714 case GST_VIDEO_FORMAT_NV61:
715 info->stride[0] = GST_ROUND_UP_4 (width);
716 info->stride[1] = info->stride[0];
718 info->offset[1] = info->stride[0] * height;
719 info->size = info->stride[0] * height * 2;
721 case GST_VIDEO_FORMAT_NV24:
722 info->stride[0] = GST_ROUND_UP_4 (width);
723 info->stride[1] = GST_ROUND_UP_4 (width * 2);
725 info->offset[1] = info->stride[0] * height;
726 info->size = info->stride[0] * height + info->stride[1] * height;
728 case GST_VIDEO_FORMAT_A420:
729 info->stride[0] = GST_ROUND_UP_4 (width);
730 info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2);
731 info->stride[2] = info->stride[1];
732 info->stride[3] = info->stride[0];
734 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
735 cr_h = GST_ROUND_UP_2 (height) / 2;
736 if (GST_VIDEO_INFO_IS_INTERLACED (info))
737 cr_h = GST_ROUND_UP_2 (cr_h);
738 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
739 info->offset[3] = info->offset[2] + info->stride[2] * cr_h;
740 info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
742 case GST_VIDEO_FORMAT_YUV9:
743 case GST_VIDEO_FORMAT_YVU9:
744 info->stride[0] = GST_ROUND_UP_4 (width);
745 info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) / 4);
746 info->stride[2] = info->stride[1];
748 info->offset[1] = info->stride[0] * height;
749 cr_h = GST_ROUND_UP_4 (height) / 4;
750 if (GST_VIDEO_INFO_IS_INTERLACED (info))
751 cr_h = GST_ROUND_UP_2 (cr_h);
752 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
753 info->size = info->offset[2] + info->stride[2] * cr_h;
755 case GST_VIDEO_FORMAT_I420_10LE:
756 case GST_VIDEO_FORMAT_I420_10BE:
757 info->stride[0] = GST_ROUND_UP_4 (width * 2);
758 info->stride[1] = GST_ROUND_UP_4 (width);
759 info->stride[2] = info->stride[1];
761 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
762 cr_h = GST_ROUND_UP_2 (height) / 2;
763 if (GST_VIDEO_INFO_IS_INTERLACED (info))
764 cr_h = GST_ROUND_UP_2 (cr_h);
765 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
766 info->size = info->offset[2] + info->stride[2] * cr_h;
768 case GST_VIDEO_FORMAT_I422_10LE:
769 case GST_VIDEO_FORMAT_I422_10BE:
770 info->stride[0] = GST_ROUND_UP_4 (width * 2);
771 info->stride[1] = GST_ROUND_UP_4 (width);
772 info->stride[2] = info->stride[1];
774 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
775 info->offset[2] = info->offset[1] +
776 info->stride[1] * GST_ROUND_UP_2 (height);
777 info->size = info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
779 case GST_VIDEO_FORMAT_Y444_10LE:
780 case GST_VIDEO_FORMAT_Y444_10BE:
781 case GST_VIDEO_FORMAT_GBR_10LE:
782 case GST_VIDEO_FORMAT_GBR_10BE:
783 info->stride[0] = GST_ROUND_UP_4 (width * 2);
784 info->stride[1] = info->stride[0];
785 info->stride[2] = info->stride[0];
787 info->offset[1] = info->stride[0] * height;
788 info->offset[2] = info->offset[1] * 2;
789 info->size = info->stride[0] * height * 3;
791 case GST_VIDEO_FORMAT_NV12_64Z32:
793 GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_128 (width) / 64,
794 GST_ROUND_UP_32 (height) / 32);
796 GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_128 (width) / 64,
797 GST_ROUND_UP_64 (height) / 64);
799 info->offset[1] = GST_ROUND_UP_128 (width) * GST_ROUND_UP_32 (height);
800 info->size = info->offset[1] +
801 GST_ROUND_UP_128 (width) * GST_ROUND_UP_64 (height) / 2;
803 case GST_VIDEO_FORMAT_A420_10LE:
804 case GST_VIDEO_FORMAT_A420_10BE:
805 info->stride[0] = GST_ROUND_UP_4 (width * 2);
806 info->stride[1] = GST_ROUND_UP_4 (width);
807 info->stride[2] = info->stride[1];
808 info->stride[3] = info->stride[0];
810 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
811 cr_h = GST_ROUND_UP_2 (height) / 2;
812 if (GST_VIDEO_INFO_IS_INTERLACED (info))
813 cr_h = GST_ROUND_UP_2 (cr_h);
814 info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
815 info->offset[3] = info->offset[2] + info->stride[2] * cr_h;
816 info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
818 case GST_VIDEO_FORMAT_A422_10LE:
819 case GST_VIDEO_FORMAT_A422_10BE:
820 info->stride[0] = GST_ROUND_UP_4 (width * 2);
821 info->stride[1] = GST_ROUND_UP_4 (width);
822 info->stride[2] = info->stride[1];
823 info->stride[3] = info->stride[0];
825 info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
826 info->offset[2] = info->offset[1] +
827 info->stride[1] * GST_ROUND_UP_2 (height);
829 info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
830 info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
832 case GST_VIDEO_FORMAT_A444_10LE:
833 case GST_VIDEO_FORMAT_A444_10BE:
834 info->stride[0] = GST_ROUND_UP_4 (width * 2);
835 info->stride[1] = info->stride[0];
836 info->stride[2] = info->stride[0];
837 info->stride[3] = info->stride[0];
839 info->offset[1] = info->stride[0] * height;
840 info->offset[2] = info->offset[1] * 2;
841 info->offset[3] = info->offset[1] * 3;
842 info->size = info->stride[0] * height * 4;
845 case GST_VIDEO_FORMAT_ENCODED:
847 case GST_VIDEO_FORMAT_UNKNOWN:
848 GST_ERROR ("invalid format");
849 g_warning ("invalid format");
856 * gst_video_info_convert:
857 * @info: a #GstVideoInfo
858 * @src_format: #GstFormat of the @src_value
859 * @src_value: value to convert
860 * @dest_format: #GstFormat of the @dest_value
861 * @dest_value: pointer to destination value
863 * Converts among various #GstFormat types. This function handles
864 * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT. For
865 * raw video, GST_FORMAT_DEFAULT corresponds to video frames. This
866 * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
868 * Returns: TRUE if the conversion was successful.
871 gst_video_info_convert (GstVideoInfo * info,
872 GstFormat src_format, gint64 src_value,
873 GstFormat dest_format, gint64 * dest_value)
875 gboolean ret = FALSE;
879 g_return_val_if_fail (info != NULL, 0);
880 g_return_val_if_fail (info->finfo != NULL, 0);
881 g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, 0);
882 g_return_val_if_fail (info->size > 0, 0);
888 GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s to %s",
889 src_value, gst_format_get_name (src_format),
890 gst_format_get_name (dest_format));
892 if (src_format == dest_format) {
893 *dest_value = src_value;
898 if (src_value == -1) {
904 /* bytes to frames */
905 if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_DEFAULT) {
907 *dest_value = gst_util_uint64_scale (src_value, 1, size);
909 GST_ERROR ("blocksize is 0");
916 /* frames to bytes */
917 if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_BYTES) {
918 *dest_value = gst_util_uint64_scale (src_value, size, 1);
924 if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_DEFAULT) {
926 *dest_value = gst_util_uint64_scale (src_value,
927 fps_n, GST_SECOND * fps_d);
929 GST_ERROR ("framerate denominator is 0");
937 if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) {
939 *dest_value = gst_util_uint64_scale (src_value,
940 GST_SECOND * fps_d, fps_n);
942 GST_ERROR ("framerate numerator is 0");
950 if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
952 *dest_value = gst_util_uint64_scale (src_value,
953 fps_n * size, GST_SECOND * fps_d);
955 GST_ERROR ("framerate denominator is 0");
963 if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) {
964 if (fps_n != 0 && size != 0) {
965 *dest_value = gst_util_uint64_scale (src_value,
966 GST_SECOND * fps_d, fps_n * size);
968 GST_ERROR ("framerate denominator and/or blocksize is 0");
976 GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, ret, *dest_value);
982 * gst_video_info_align:
983 * @info: a #GstVideoInfo
984 * @align: alignment parameters
986 * Adjust the offset and stride fields in @info so that the padding and
987 * stride alignment in @align is respected.
989 * Extra padding will be added to the right side when stride alignment padding
990 * is required and @align will be updated with the new padding values.
993 gst_video_info_align (GstVideoInfo * info, GstVideoAlignment * align)
995 const GstVideoFormatInfo *vinfo = info->finfo;
997 gint padded_width, padded_height;
1001 width = GST_VIDEO_INFO_WIDTH (info);
1002 height = GST_VIDEO_INFO_HEIGHT (info);
1004 GST_LOG ("padding %u-%ux%u-%u", align->padding_top,
1005 align->padding_left, align->padding_right, align->padding_bottom);
1007 n_planes = GST_VIDEO_INFO_N_PLANES (info);
1009 if (GST_VIDEO_FORMAT_INFO_HAS_PALETTE (vinfo))
1012 /* first make sure the left padding does not cause alignment problems later */
1014 GST_LOG ("left padding %u", align->padding_left);
1016 for (i = 0; i < n_planes; i++) {
1019 /* this is the amout of pixels to add as left padding */
1020 hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, i, align->padding_left);
1021 hedge *= GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, i);
1023 GST_LOG ("plane %d, padding %d, alignment %u", i, hedge,
1024 align->stride_align[i]);
1025 aligned &= (hedge & align->stride_align[i]) == 0;
1030 GST_LOG ("unaligned padding, increasing padding");
1031 /* increase padded_width */
1032 align->padding_left += align->padding_left & ~(align->padding_left - 1);
1035 /* add the padding */
1036 padded_width = width + align->padding_left + align->padding_right;
1037 padded_height = height + align->padding_top + align->padding_bottom;
1040 GST_LOG ("padded dimension %u-%u", padded_width, padded_height);
1042 info->width = padded_width;
1043 info->height = padded_height;
1046 /* check alignment */
1048 for (i = 0; i < n_planes; i++) {
1049 GST_LOG ("plane %d, stride %d, alignment %u", i, info->stride[i],
1050 align->stride_align[i]);
1051 aligned &= (info->stride[i] & align->stride_align[i]) == 0;
1056 GST_LOG ("unaligned strides, increasing dimension");
1057 /* increase padded_width */
1058 padded_width += padded_width & ~(padded_width - 1);
1061 align->padding_right = padded_width - width - align->padding_left;
1063 info->width = width;
1064 info->height = height;
1066 for (i = 0; i < n_planes; i++) {
1067 gint vedge, hedge, comp;
1069 /* Find the component for this plane, FIXME, we assume the plane number and
1070 * component number is the same for now, for scaling the dimensions this is
1071 * currently true for all formats but it might not be when adding new
1072 * formats. We might need to add a plane subsamling in the format info to
1073 * make this more generic or maybe use a plane -> component mapping. */
1077 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, comp, align->padding_left);
1079 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo, comp, align->padding_top);
1081 GST_DEBUG ("plane %d: comp: %d, hedge %d vedge %d align %d stride %d", i,
1082 comp, hedge, vedge, align->stride_align[i], info->stride[i]);
1084 info->offset[i] += (vedge * info->stride[i]) +
1085 (hedge * GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, comp));