Coverage Report

Created: 2026-05-28 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/video/video-info.c
Line
Count
Source
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
/**
23
 * SECTION:video-info
24
 * @title: GstVideoInfo
25
 * @short_description: Structures and enumerations to describe raw images
26
 */
27
28
#ifdef HAVE_CONFIG_H
29
#  include "config.h"
30
#endif
31
32
#include <string.h>
33
#include <stdio.h>
34
35
#include "video-info.h"
36
#include "video-tile.h"
37
38
#ifndef GST_DISABLE_GST_DEBUG
39
#define GST_CAT_DEFAULT ensure_debug_category()
40
static GstDebugCategory *
41
ensure_debug_category (void)
42
0
{
43
0
  static gsize cat_gonce = 0;
44
45
0
  if (g_once_init_enter (&cat_gonce)) {
46
0
    gsize cat_done;
47
48
0
    cat_done = (gsize) _gst_debug_category_new ("video-info", 0,
49
0
        "video-info structure");
50
51
0
    g_once_init_leave (&cat_gonce, cat_done);
52
0
  }
53
54
0
  return (GstDebugCategory *) cat_gonce;
55
0
}
56
#else
57
#define ensure_debug_category() /* NOOP */
58
#endif /* GST_DISABLE_GST_DEBUG */
59
60
/**
61
 * gst_video_info_copy:
62
 * @info: a #GstVideoInfo
63
 *
64
 * Copy a GstVideoInfo structure.
65
 *
66
 * Returns: (transfer full): a new #GstVideoInfo. free with gst_video_info_free.
67
 *
68
 * Since: 1.6
69
 */
70
GstVideoInfo *
71
gst_video_info_copy (const GstVideoInfo * info)
72
0
{
73
0
  return g_memdup2 (info, sizeof (GstVideoInfo));
74
0
}
75
76
/**
77
 * gst_video_info_free:
78
 * @info: a #GstVideoInfo
79
 *
80
 * Free a GstVideoInfo structure previously allocated with gst_video_info_new()
81
 * or gst_video_info_copy().
82
 *
83
 * Since: 1.6
84
 */
85
void
86
gst_video_info_free (GstVideoInfo * info)
87
0
{
88
0
  g_free (info);
89
0
}
90
91
0
G_DEFINE_BOXED_TYPE (GstVideoInfo, gst_video_info,
92
0
    (GBoxedCopyFunc) gst_video_info_copy, (GBoxedFreeFunc) gst_video_info_free);
93
0
94
0
/**
95
0
 * gst_video_info_new:
96
0
 *
97
0
 * Allocate a new #GstVideoInfo that is also initialized with
98
0
 * gst_video_info_init().
99
0
 *
100
0
 * Returns: (transfer full): a new #GstVideoInfo. free with gst_video_info_free().
101
0
 *
102
0
 * Since: 1.6
103
0
 */
104
0
GstVideoInfo *
105
0
gst_video_info_new (void)
106
0
{
107
0
  GstVideoInfo *info;
108
109
0
  info = g_new (GstVideoInfo, 1);
110
0
  gst_video_info_init (info);
111
112
0
  return info;
113
0
}
114
115
static gboolean fill_planes (GstVideoInfo * info,
116
    gsize plane_size[GST_VIDEO_MAX_PLANES]);
117
118
/**
119
 * gst_video_info_init:
120
 * @info: (out caller-allocates): a #GstVideoInfo
121
 *
122
 * Initialize @info with default values.
123
 */
124
void
125
gst_video_info_init (GstVideoInfo * info)
126
6
{
127
6
  g_return_if_fail (info != NULL);
128
129
6
  memset (info, 0, sizeof (GstVideoInfo));
130
131
6
  info->finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_UNKNOWN);
132
133
6
  info->views = 1;
134
  /* arrange for sensible defaults, e.g. if turned into caps */
135
6
  info->fps_n = 0;
136
6
  info->fps_d = 1;
137
6
  info->par_n = 1;
138
6
  info->par_d = 1;
139
6
  GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE;
140
6
  GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
141
6
  GST_VIDEO_INFO_FIELD_ORDER (info) = GST_VIDEO_FIELD_ORDER_UNKNOWN;
142
6
}
143
144
#define MAKE_COLORIMETRY(r,m,t,p) {  \
145
  GST_VIDEO_COLOR_RANGE ##r, GST_VIDEO_COLOR_MATRIX_ ##m, \
146
  GST_VIDEO_TRANSFER_ ##t, GST_VIDEO_COLOR_PRIMARIES_ ##p }
147
148
0
#define DEFAULT_YUV_SD  0
149
0
#define DEFAULT_YUV_HD  1
150
0
#define DEFAULT_RGB     2
151
0
#define DEFAULT_GRAY    3
152
3
#define DEFAULT_UNKNOWN 4
153
154
static const GstVideoColorimetry default_color[] = {
155
  MAKE_COLORIMETRY (_16_235, BT601, BT601, SMPTE170M),
156
  MAKE_COLORIMETRY (_16_235, BT709, BT709, BT709),
157
  MAKE_COLORIMETRY (_0_255, RGB, SRGB, BT709),
158
  MAKE_COLORIMETRY (_0_255, BT601, UNKNOWN, UNKNOWN),
159
  MAKE_COLORIMETRY (_UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN),
160
};
161
162
static void
163
set_default_colorimetry (GstVideoInfo * info)
164
3
{
165
3
  const GstVideoFormatInfo *finfo = info->finfo;
166
167
3
  if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)) {
168
0
    if (info->height > 576) {
169
0
      info->colorimetry = default_color[DEFAULT_YUV_HD];
170
0
    } else {
171
0
      info->colorimetry = default_color[DEFAULT_YUV_SD];
172
0
    }
173
3
  } else if (GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo)) {
174
0
    info->colorimetry = default_color[DEFAULT_GRAY];
175
3
  } else if (GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) {
176
0
    info->colorimetry = default_color[DEFAULT_RGB];
177
3
  } else {
178
3
    info->colorimetry = default_color[DEFAULT_UNKNOWN];
179
3
  }
180
3
}
181
182
static gboolean
183
validate_colorimetry (const GstVideoInfo * info)
184
0
{
185
0
  const GstVideoFormatInfo *finfo = info->finfo;
186
187
0
  if ((GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)
188
0
          || GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo))
189
0
      && info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
190
0
    GST_WARNING
191
0
        ("color matrix RGB is only supported with RGB format, %s is not",
192
0
        finfo->name);
193
0
    return FALSE;
194
0
  }
195
196
0
  if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo) &&
197
0
      info->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
198
0
    GST_WARNING ("Need to specify a color matrix when using YUV format (%s)",
199
0
        finfo->name);
200
0
    return FALSE;
201
0
  }
202
203
0
  return TRUE;
204
0
}
205
206
static void
207
set_default_chroma_site (GstVideoInfo * info)
208
3
{
209
3
  const GstVideoFormatInfo *finfo = info->finfo;
210
211
3
  if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)) {
212
0
    if (info->height > 576) {
213
0
      info->chroma_site = GST_VIDEO_CHROMA_SITE_H_COSITED;
214
0
    } else {
215
0
      info->chroma_site = GST_VIDEO_CHROMA_SITE_NONE;
216
0
    }
217
3
  } else {
218
3
    info->chroma_site = GST_VIDEO_CHROMA_SITE_UNKNOWN;
219
3
  }
220
3
}
221
222
static gboolean
223
validate_chroma_site (const GstVideoInfo * info)
224
0
{
225
0
  const GstVideoFormatInfo *finfo = info->finfo;
226
227
0
  if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)) {
228
    // FIXME: Might also want to check here for subsampling?
229
    // - chroma-site only makes sense with subsampled formats?
230
    // - ALT_LINE only makes sense for formats with vertical subsampling, and if
231
    //   also V_COSITED?
232
0
    if ((info->chroma_site & GST_VIDEO_CHROMA_SITE_NONE) &&
233
0
        (info->chroma_site & (GST_VIDEO_CHROMA_SITE_H_COSITED |
234
0
                GST_VIDEO_CHROMA_SITE_V_COSITED))) {
235
0
      GST_WARNING
236
0
          ("No chroma siting together with horizontal or vertical cositing is invalid");
237
0
      return FALSE;
238
0
    }
239
0
  } else if (info->chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN) {
240
0
    GST_WARNING ("chroma-site only makes sense for YUV formats, %s is none",
241
0
        finfo->name);
242
0
    return FALSE;
243
0
  }
244
245
0
  return TRUE;
246
0
}
247
248
static gboolean
249
gst_video_info_set_format_common (GstVideoInfo * info, GstVideoFormat format,
250
    guint width, guint height)
251
0
{
252
0
  g_return_val_if_fail (info != NULL, FALSE);
253
0
  g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
254
255
0
  if (width > G_MAXINT || height > G_MAXINT)
256
0
    return FALSE;
257
258
0
  gst_video_info_init (info);
259
260
0
  info->finfo = gst_video_format_get_info (format);
261
0
  info->width = width;
262
0
  info->height = height;
263
0
  info->views = 1;
264
265
0
  set_default_colorimetry (info);
266
267
0
  return TRUE;
268
0
}
269
270
/**
271
 * gst_video_info_set_format:
272
 * @info: a #GstVideoInfo
273
 * @format: the format
274
 * @width: a width
275
 * @height: a height
276
 *
277
 * Set the default info for a video frame of @format and @width and @height.
278
 *
279
 * Note: This initializes @info first, no values are preserved. This function
280
 * does not set the offsets correctly for interlaced vertically
281
 * subsampled formats.
282
 *
283
 * Returns: %FALSE if the returned video info is invalid, e.g. because the
284
 *   size of a frame can't be represented as a 32 bit integer (Since: 1.12)
285
 */
286
gboolean
287
gst_video_info_set_format (GstVideoInfo * info, GstVideoFormat format,
288
    guint width, guint height)
289
0
{
290
0
  if (!gst_video_info_set_format_common (info, format, width, height))
291
0
    return FALSE;
292
293
0
  return fill_planes (info, NULL);
294
0
}
295
296
/**
297
 * gst_video_info_set_interlaced_format:
298
 * @info: a #GstVideoInfo
299
 * @format: the format
300
 * @mode: a #GstVideoInterlaceMode
301
 * @width: a width
302
 * @height: a height
303
 *
304
 * Same as #gst_video_info_set_format but also allowing to set the interlaced
305
 * mode.
306
 *
307
 * Returns: %FALSE if the returned video info is invalid, e.g. because the
308
 *   size of a frame can't be represented as a 32 bit integer.
309
 *
310
 * Since: 1.16
311
 */
312
gboolean
313
gst_video_info_set_interlaced_format (GstVideoInfo * info,
314
    GstVideoFormat format, GstVideoInterlaceMode mode, guint width,
315
    guint height)
316
0
{
317
0
  if (!gst_video_info_set_format_common (info, format, width, height))
318
0
    return FALSE;
319
320
0
  GST_VIDEO_INFO_INTERLACE_MODE (info) = mode;
321
0
  return fill_planes (info, NULL);
322
0
}
323
324
static const gchar *interlace_mode[] = {
325
  "progressive",
326
  "interleaved",
327
  "mixed",
328
  "fields",
329
  "alternate"
330
};
331
332
/**
333
 * gst_video_interlace_mode_to_string:
334
 * @mode: a #GstVideoInterlaceMode
335
 *
336
 * Convert @mode to its string representation.
337
 *
338
 * Returns: @mode as a string.
339
 *
340
 * Since: 1.6
341
 */
342
const gchar *
343
gst_video_interlace_mode_to_string (GstVideoInterlaceMode mode)
344
0
{
345
0
  if (((guint) mode) >= G_N_ELEMENTS (interlace_mode))
346
0
    return NULL;
347
348
0
  return interlace_mode[mode];
349
0
}
350
351
/**
352
 * gst_video_interlace_mode_from_string:
353
 * @mode: a mode
354
 *
355
 * Convert @mode to a #GstVideoInterlaceMode
356
 *
357
 * Returns: the #GstVideoInterlaceMode of @mode or
358
 *    #GST_VIDEO_INTERLACE_MODE_PROGRESSIVE when @mode is not a valid
359
 *    string representation for a #GstVideoInterlaceMode.
360
 *
361
 * Since: 1.6
362
 */
363
GstVideoInterlaceMode
364
gst_video_interlace_mode_from_string (const gchar * mode)
365
0
{
366
0
  gint i;
367
0
  for (i = 0; i < G_N_ELEMENTS (interlace_mode); i++) {
368
0
    if (g_str_equal (interlace_mode[i], mode))
369
0
      return i;
370
0
  }
371
0
  return GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
372
0
}
373
374
static const gchar *field_order[] = {
375
  "unknown",
376
  "top-field-first",
377
  "bottom-field-first"
378
};
379
380
/**
381
 * gst_video_field_order_to_string:
382
 * @order: a #GstVideoFieldOrder
383
 *
384
 * Convert @order to its string representation.
385
 *
386
 * Returns: @order as a string.
387
 *
388
 * Since: 1.12
389
 */
390
const gchar *
391
gst_video_field_order_to_string (GstVideoFieldOrder order)
392
0
{
393
0
  if (((guint) order) >= G_N_ELEMENTS (field_order))
394
0
    return NULL;
395
396
0
  return field_order[order];
397
0
}
398
399
/**
400
 * gst_video_field_order_from_string:
401
 * @order: a field order
402
 *
403
 * Convert @order to a #GstVideoFieldOrder
404
 *
405
 * Returns: the #GstVideoFieldOrder of @order or
406
 *    #GST_VIDEO_FIELD_ORDER_UNKNOWN when @order is not a valid
407
 *    string representation for a #GstVideoFieldOrder.
408
 *
409
 * Since: 1.12
410
 */
411
GstVideoFieldOrder
412
gst_video_field_order_from_string (const gchar * order)
413
0
{
414
0
  gint i;
415
0
  for (i = 0; i < G_N_ELEMENTS (field_order); i++) {
416
0
    if (g_str_equal (field_order[i], order))
417
0
      return i;
418
0
  }
419
0
  return GST_VIDEO_FIELD_ORDER_UNKNOWN;
420
0
}
421
422
/**
423
 * gst_video_info_from_caps:
424
 * @info: (out caller-allocates): #GstVideoInfo
425
 * @caps: a #GstCaps
426
 *
427
 * Parse @caps and update @info.
428
 *
429
 * Returns: TRUE if @caps could be parsed
430
 */
431
gboolean
432
gst_video_info_from_caps (GstVideoInfo * info, const GstCaps * caps)
433
3
{
434
3
  GstStructure *structure;
435
3
  const gchar *s;
436
3
  GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
437
3
  gint width = 0, height = 0;
438
3
  gint fps_n, fps_d;
439
3
  gint par_n, par_d;
440
3
  guint multiview_flags;
441
442
3
  g_return_val_if_fail (info != NULL, FALSE);
443
3
  g_return_val_if_fail (caps != NULL, FALSE);
444
3
  g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
445
446
3
  GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
447
448
3
  structure = gst_caps_get_structure (caps, 0);
449
450
3
  if (gst_structure_has_name (structure, "video/x-raw")) {
451
0
    if (!(s = gst_structure_get_string (structure, "format")))
452
0
      goto no_format;
453
454
0
    format = gst_video_format_from_string (s);
455
0
    if (format == GST_VIDEO_FORMAT_UNKNOWN)
456
0
      goto unknown_format;
457
458
3
  } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/") ||
459
3
      g_str_has_prefix (gst_structure_get_name (structure), "image/")) {
460
3
    format = GST_VIDEO_FORMAT_ENCODED;
461
3
  } else {
462
0
    goto wrong_name;
463
0
  }
464
465
  /* width and height are mandatory, except for non-raw-formats */
466
3
  if (!gst_structure_get_int (structure, "width", &width) &&
467
0
      format != GST_VIDEO_FORMAT_ENCODED)
468
0
    goto no_width;
469
3
  if (!gst_structure_get_int (structure, "height", &height) &&
470
0
      format != GST_VIDEO_FORMAT_ENCODED)
471
0
    goto no_height;
472
473
3
  gst_video_info_init (info);
474
475
3
  info->finfo = gst_video_format_get_info (format);
476
3
  info->width = width;
477
3
  info->height = height;
478
479
3
  if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
480
3
    if (fps_n == 0) {
481
      /* variable framerate */
482
0
      info->flags |= GST_VIDEO_FLAG_VARIABLE_FPS;
483
      /* see if we have a max-framerate */
484
0
      gst_structure_get_fraction (structure, "max-framerate", &fps_n, &fps_d);
485
0
    }
486
3
    info->fps_n = fps_n;
487
3
    info->fps_d = fps_d;
488
3
  } else {
489
    /* unspecified is variable framerate */
490
0
    info->fps_n = 0;
491
0
    info->fps_d = 1;
492
0
  }
493
494
3
  if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
495
3
          &par_n, &par_d)) {
496
3
    info->par_n = par_n;
497
3
    info->par_d = par_d;
498
3
  } else {
499
0
    info->par_n = 1;
500
0
    info->par_d = 1;
501
0
  }
502
503
3
  if ((s = gst_structure_get_string (structure, "interlace-mode")))
504
0
    info->interlace_mode = gst_video_interlace_mode_from_string (s);
505
3
  else
506
3
    info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
507
508
  /* Interlaced feature is mandatory for raw alternate streams */
509
3
  if (info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE &&
510
0
      format != GST_VIDEO_FORMAT_ENCODED) {
511
0
    GstCapsFeatures *f;
512
513
0
    f = gst_caps_get_features (caps, 0);
514
0
    if (!f
515
0
        || !gst_caps_features_contains (f, GST_CAPS_FEATURE_FORMAT_INTERLACED))
516
0
      goto alternate_no_feature;
517
0
  }
518
519
3
  if (GST_VIDEO_INFO_IS_INTERLACED (info) &&
520
0
      (s = gst_structure_get_string (structure, "field-order"))) {
521
0
    GST_VIDEO_INFO_FIELD_ORDER (info) = gst_video_field_order_from_string (s);
522
3
  } else {
523
3
    GST_VIDEO_INFO_FIELD_ORDER (info) = GST_VIDEO_FIELD_ORDER_UNKNOWN;
524
3
  }
525
526
3
  {
527
3
    if ((s = gst_structure_get_string (structure, "multiview-mode")))
528
0
      GST_VIDEO_INFO_MULTIVIEW_MODE (info) =
529
0
          gst_video_multiview_mode_from_caps_string (s);
530
3
    else
531
3
      GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE;
532
533
3
    if (gst_structure_get_flagset (structure, "multiview-flags",
534
3
            &multiview_flags, NULL))
535
0
      GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = multiview_flags;
536
537
3
    if (!gst_structure_get_int (structure, "views", &info->views))
538
3
      info->views = 1;
539
540
    /* At one point, I tried normalising the half-aspect flag here,
541
     * but it behaves weird for GstVideoInfo operations other than
542
     * directly converting to/from caps - sometimes causing the
543
     * PAR to be doubled/halved too many times */
544
3
  }
545
546
3
  if ((s = gst_structure_get_string (structure, "chroma-site"))) {
547
0
    info->chroma_site = gst_video_chroma_site_from_string (s);
548
0
    if (!validate_chroma_site (info)) {
549
0
      GST_WARNING ("invalid chroma-site, using default");
550
0
      set_default_chroma_site (info);
551
0
    } else if (GST_VIDEO_FORMAT_INFO_IS_YUV (info->finfo)
552
0
        && info->chroma_site == GST_VIDEO_CHROMA_SITE_UNKNOWN) {
553
      /* force a default chroma-site for YUV formats */
554
0
      set_default_chroma_site (info);
555
0
    }
556
3
  } else {
557
3
    set_default_chroma_site (info);
558
3
  }
559
560
3
  if ((s = gst_structure_get_string (structure, "colorimetry"))) {
561
0
    if (!gst_video_colorimetry_from_string (&info->colorimetry, s)) {
562
0
      GST_WARNING ("unparsable colorimetry, using default");
563
0
      set_default_colorimetry (info);
564
0
    } else if (!validate_colorimetry (info)) {
565
0
      GST_WARNING ("invalid colorimetry, using default");
566
0
      set_default_colorimetry (info);
567
0
    } else {
568
      /* force RGB matrix for RGB formats */
569
0
      if (GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo) &&
570
0
          info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
571
0
        GST_WARNING ("invalid matrix %d for RGB format, using RGB",
572
0
            info->colorimetry.matrix);
573
0
        info->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
574
0
      }
575
0
    }
576
3
  } else {
577
3
    GST_DEBUG ("no colorimetry, using default");
578
3
    set_default_colorimetry (info);
579
3
  }
580
581
3
  if (!fill_planes (info, NULL))
582
0
    return FALSE;
583
584
3
  return TRUE;
585
586
  /* ERROR */
587
0
wrong_name:
588
0
  {
589
0
    GST_ERROR ("wrong name '%s', expected video/ or image/",
590
0
        gst_structure_get_name (structure));
591
0
    return FALSE;
592
3
  }
593
0
no_format:
594
0
  {
595
0
    GST_ERROR ("no format given");
596
0
    return FALSE;
597
3
  }
598
0
unknown_format:
599
0
  {
600
0
    GST_ERROR ("unknown format '%s' given", s);
601
0
    return FALSE;
602
3
  }
603
0
no_width:
604
0
  {
605
0
    GST_ERROR ("no width property given");
606
0
    return FALSE;
607
3
  }
608
0
no_height:
609
0
  {
610
0
    GST_ERROR ("no height property given");
611
0
    return FALSE;
612
3
  }
613
0
alternate_no_feature:
614
0
  {
615
0
    GST_ERROR
616
0
        ("caps has 'interlace-mode=alternate' but doesn't have the Interlaced feature");
617
0
    return FALSE;
618
3
  }
619
3
}
620
621
/**
622
 * gst_video_info_new_from_caps:
623
 * @caps: a #GstCaps
624
 *
625
 * Parse @caps to generate a #GstVideoInfo.
626
 *
627
 * Returns: (transfer full) (nullable): A #GstVideoInfo, or %NULL if @caps couldn't be parsed
628
 * Since: 1.20
629
 */
630
GstVideoInfo *
631
gst_video_info_new_from_caps (const GstCaps * caps)
632
0
{
633
0
  GstVideoInfo *ret = gst_video_info_new ();
634
635
0
  if (gst_video_info_from_caps (ret, caps)) {
636
0
    return ret;
637
0
  } else {
638
0
    gst_video_info_free (ret);
639
0
    return NULL;
640
0
  }
641
0
}
642
643
/**
644
 * gst_video_info_is_equal:
645
 * @info: a #GstVideoInfo
646
 * @other: a #GstVideoInfo
647
 *
648
 * Compares two #GstVideoInfo and returns whether they are equal or not
649
 *
650
 * Returns: %TRUE if @info and @other are equal, else %FALSE.
651
 */
652
gboolean
653
gst_video_info_is_equal (const GstVideoInfo * info, const GstVideoInfo * other)
654
0
{
655
0
  gint i;
656
657
0
  if (info == other)
658
0
    return TRUE;
659
0
  if (info->finfo == NULL || other->finfo == NULL)
660
0
    return FALSE;
661
0
  if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_INFO_FORMAT (other))
662
0
    return FALSE;
663
0
  if (GST_VIDEO_INFO_INTERLACE_MODE (info) !=
664
0
      GST_VIDEO_INFO_INTERLACE_MODE (other))
665
0
    return FALSE;
666
0
  if (GST_VIDEO_INFO_FLAGS (info) != GST_VIDEO_INFO_FLAGS (other))
667
0
    return FALSE;
668
0
  if (GST_VIDEO_INFO_WIDTH (info) != GST_VIDEO_INFO_WIDTH (other))
669
0
    return FALSE;
670
0
  if (GST_VIDEO_INFO_HEIGHT (info) != GST_VIDEO_INFO_HEIGHT (other))
671
0
    return FALSE;
672
0
  if (GST_VIDEO_INFO_SIZE (info) != GST_VIDEO_INFO_SIZE (other))
673
0
    return FALSE;
674
0
  if (GST_VIDEO_INFO_PAR_N (info) != GST_VIDEO_INFO_PAR_N (other))
675
0
    return FALSE;
676
0
  if (GST_VIDEO_INFO_PAR_D (info) != GST_VIDEO_INFO_PAR_D (other))
677
0
    return FALSE;
678
0
  if (GST_VIDEO_INFO_FPS_N (info) != GST_VIDEO_INFO_FPS_N (other))
679
0
    return FALSE;
680
0
  if (GST_VIDEO_INFO_FPS_D (info) != GST_VIDEO_INFO_FPS_D (other))
681
0
    return FALSE;
682
0
  if (!gst_video_colorimetry_is_equal (&GST_VIDEO_INFO_COLORIMETRY (info),
683
0
          &GST_VIDEO_INFO_COLORIMETRY (other)))
684
0
    return FALSE;
685
0
  if (GST_VIDEO_INFO_CHROMA_SITE (info) != GST_VIDEO_INFO_CHROMA_SITE (other))
686
0
    return FALSE;
687
0
  if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) !=
688
0
      GST_VIDEO_INFO_MULTIVIEW_MODE (other))
689
0
    return FALSE;
690
0
  if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) !=
691
0
      GST_VIDEO_INFO_MULTIVIEW_FLAGS (other))
692
0
    return FALSE;
693
0
  if (GST_VIDEO_INFO_VIEWS (info) != GST_VIDEO_INFO_VIEWS (other))
694
0
    return FALSE;
695
696
0
  for (i = 0; i < info->finfo->n_planes; i++) {
697
0
    if (info->stride[i] != other->stride[i])
698
0
      return FALSE;
699
0
    if (info->offset[i] != other->offset[i])
700
0
      return FALSE;
701
0
  }
702
703
0
  return TRUE;
704
0
}
705
706
/**
707
 * gst_video_info_to_caps:
708
 * @info: a #GstVideoInfo
709
 *
710
 * Convert the values of @info into a #GstCaps.
711
 *
712
 * Returns: (transfer full): a new #GstCaps containing the info of @info.
713
 */
714
GstCaps *
715
gst_video_info_to_caps (const GstVideoInfo * info)
716
0
{
717
0
  GstCaps *caps;
718
0
  const gchar *format;
719
0
  gchar *color;
720
0
  gint par_n, par_d;
721
0
  GstVideoColorimetry colorimetry;
722
723
0
  g_return_val_if_fail (info != NULL, NULL);
724
0
  g_return_val_if_fail (info->finfo != NULL, NULL);
725
0
  g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
726
727
0
  format = gst_video_format_to_string (info->finfo->format);
728
0
  g_return_val_if_fail (format != NULL, NULL);
729
730
0
  caps = gst_caps_new_static_str_simple ("video/x-raw",
731
0
      "format", G_TYPE_STRING, format,
732
0
      "width", G_TYPE_INT, info->width,
733
0
      "height", G_TYPE_INT, info->height, NULL);
734
735
0
  par_n = info->par_n;
736
0
  par_d = info->par_d;
737
738
0
  gst_caps_set_simple_static_str (caps, "interlace-mode", G_TYPE_STRING,
739
0
      gst_video_interlace_mode_to_string (info->interlace_mode), NULL);
740
741
0
  if ((info->interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ||
742
0
          info->interlace_mode == GST_VIDEO_INTERLACE_MODE_FIELDS ||
743
0
          info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE) &&
744
0
      GST_VIDEO_INFO_FIELD_ORDER (info) != GST_VIDEO_FIELD_ORDER_UNKNOWN) {
745
0
    gst_caps_set_simple_static_str (caps, "field-order", G_TYPE_STRING,
746
0
        gst_video_field_order_to_string (GST_VIDEO_INFO_FIELD_ORDER (info)),
747
0
        NULL);
748
0
  }
749
750
0
  if (info->interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
751
    /* 'alternate' mode must always be accompanied by interlaced caps feature.
752
     */
753
0
    GstCapsFeatures *features;
754
755
0
    features =
756
0
        gst_caps_features_new_static_str (GST_CAPS_FEATURE_FORMAT_INTERLACED,
757
0
        NULL);
758
0
    gst_caps_set_features (caps, 0, features);
759
0
  }
760
761
0
  if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) {
762
0
    const gchar *caps_str = NULL;
763
0
    GstVideoMultiviewFlags multiview_flags =
764
0
        GST_VIDEO_INFO_MULTIVIEW_FLAGS (info);
765
766
    /* If the half-aspect flag is set, applying it into the PAR of the
767
     * resulting caps now seems safe, and helps with automatic behaviour
768
     * in elements that aren't explicitly multiview aware */
769
0
    if (multiview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) {
770
0
      multiview_flags &= ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
771
0
      switch (GST_VIDEO_INFO_MULTIVIEW_MODE (info)) {
772
0
        case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
773
0
        case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX:
774
0
        case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
775
0
        case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
776
0
          par_n *= 2;           /* double the width / half the height */
777
0
          break;
778
0
        case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
779
0
        case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
780
0
          par_d *= 2;           /* half the width / double the height */
781
0
          break;
782
0
        default:
783
0
          break;
784
0
      }
785
0
    }
786
787
0
    caps_str =
788
0
        gst_video_multiview_mode_to_caps_string (GST_VIDEO_INFO_MULTIVIEW_MODE
789
0
        (info));
790
0
    if (caps_str != NULL) {
791
0
      gst_caps_set_simple_static_str (caps, "multiview-mode", G_TYPE_STRING,
792
0
          caps_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
793
0
          multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
794
0
    }
795
0
  }
796
797
0
  gst_caps_set_simple_static_str (caps, "pixel-aspect-ratio",
798
0
      GST_TYPE_FRACTION, par_n, par_d, NULL);
799
800
0
  if (info->chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN) {
801
0
    gchar *chroma_site = gst_video_chroma_site_to_string (info->chroma_site);
802
803
0
    if (!chroma_site) {
804
0
      GST_WARNING ("Couldn't convert chroma-site 0x%x to string",
805
0
          info->chroma_site);
806
0
    } else {
807
0
      gst_caps_set_simple_static_str (caps,
808
0
          "chroma-site", G_TYPE_STRING, chroma_site, NULL);
809
0
      g_free (chroma_site);
810
0
    }
811
0
  }
812
813
  /* make sure we set the RGB matrix for RGB formats */
814
0
  colorimetry = info->colorimetry;
815
0
  if (GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo) &&
816
0
      colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
817
0
    GST_WARNING ("invalid matrix %d for RGB format, using RGB",
818
0
        colorimetry.matrix);
819
0
    colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
820
0
  }
821
0
  if ((color = gst_video_colorimetry_to_string (&colorimetry))) {
822
0
    gst_caps_set_simple_static_str (caps, "colorimetry", G_TYPE_STRING, color,
823
0
        NULL);
824
0
    g_free (color);
825
0
  }
826
827
0
  if (info->views > 1)
828
0
    gst_caps_set_simple_static_str (caps, "views", G_TYPE_INT, info->views,
829
0
        NULL);
830
831
0
  if (info->flags & GST_VIDEO_FLAG_VARIABLE_FPS && info->fps_n != 0) {
832
    /* variable fps with a max-framerate */
833
0
    gst_caps_set_simple_static_str (caps, "framerate", GST_TYPE_FRACTION, 0, 1,
834
0
        "max-framerate", GST_TYPE_FRACTION, info->fps_n, info->fps_d, NULL);
835
0
  } else {
836
    /* no variable fps or no max-framerate */
837
0
    gst_caps_set_simple_static_str (caps, "framerate", GST_TYPE_FRACTION,
838
0
        info->fps_n, info->fps_d, NULL);
839
0
  }
840
841
0
  return caps;
842
0
}
843
844
static gboolean
845
fill_planes (GstVideoInfo * info, gsize plane_size[GST_VIDEO_MAX_PLANES])
846
3
{
847
3
  gsize width, height, cr_h;
848
3
  gint bpp = 0, i;
849
850
3
  width = (gsize) info->width;
851
3
  height = (gsize) GST_VIDEO_INFO_FIELD_HEIGHT (info);
852
853
  /* Sanity check the resulting frame size for overflows */
854
3
  for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (info); i++)
855
3
    bpp += GST_VIDEO_INFO_COMP_DEPTH (info, i);
856
3
  bpp = GST_ROUND_UP_8 (bpp) / 8;
857
3
  if (bpp > 0 && GST_ROUND_UP_128 ((guint64) width) * ((guint64) height) >=
858
0
      G_MAXUINT / bpp) {
859
0
    GST_ERROR ("Frame size %ux%u would overflow", info->width, info->height);
860
0
    return FALSE;
861
0
  }
862
863
3
  switch (info->finfo->format) {
864
0
    case GST_VIDEO_FORMAT_YUY2:
865
0
    case GST_VIDEO_FORMAT_YVYU:
866
0
    case GST_VIDEO_FORMAT_UYVY:
867
0
    case GST_VIDEO_FORMAT_VYUY:
868
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
869
0
      info->offset[0] = 0;
870
0
      info->size = info->stride[0] * height;
871
0
      break;
872
0
    case GST_VIDEO_FORMAT_AYUV:
873
0
    case GST_VIDEO_FORMAT_RGBx:
874
0
    case GST_VIDEO_FORMAT_RGBA:
875
0
    case GST_VIDEO_FORMAT_BGRx:
876
0
    case GST_VIDEO_FORMAT_BGRA:
877
0
    case GST_VIDEO_FORMAT_xRGB:
878
0
    case GST_VIDEO_FORMAT_ARGB:
879
0
    case GST_VIDEO_FORMAT_xBGR:
880
0
    case GST_VIDEO_FORMAT_ABGR:
881
0
    case GST_VIDEO_FORMAT_r210:
882
0
    case GST_VIDEO_FORMAT_Y410:
883
0
    case GST_VIDEO_FORMAT_VUYA:
884
0
    case GST_VIDEO_FORMAT_BGR10A2_LE:
885
0
    case GST_VIDEO_FORMAT_RGB10A2_LE:
886
0
    case GST_VIDEO_FORMAT_BGR10x2_LE:
887
0
    case GST_VIDEO_FORMAT_RGB10x2_LE:
888
0
    case GST_VIDEO_FORMAT_RBGA:
889
0
      info->stride[0] = width * 4;
890
0
      info->offset[0] = 0;
891
0
      info->size = info->stride[0] * height;
892
0
      break;
893
0
    case GST_VIDEO_FORMAT_RGB16:
894
0
    case GST_VIDEO_FORMAT_BGR16:
895
0
    case GST_VIDEO_FORMAT_RGB15:
896
0
    case GST_VIDEO_FORMAT_BGR15:
897
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
898
0
      info->offset[0] = 0;
899
0
      info->size = info->stride[0] * height;
900
0
      break;
901
0
    case GST_VIDEO_FORMAT_RGB:
902
0
    case GST_VIDEO_FORMAT_BGR:
903
0
    case GST_VIDEO_FORMAT_v308:
904
0
    case GST_VIDEO_FORMAT_IYU2:
905
0
      info->stride[0] = GST_ROUND_UP_4 (width * 3);
906
0
      info->offset[0] = 0;
907
0
      info->size = info->stride[0] * height;
908
0
      break;
909
0
    case GST_VIDEO_FORMAT_v210:
910
0
      info->stride[0] = ((width + 47) / 48) * 128;
911
0
      info->offset[0] = 0;
912
0
      info->size = info->stride[0] * height;
913
0
      break;
914
0
    case GST_VIDEO_FORMAT_v216:
915
0
    case GST_VIDEO_FORMAT_Y210:
916
0
    case GST_VIDEO_FORMAT_Y212_BE:
917
0
    case GST_VIDEO_FORMAT_Y212_LE:
918
0
    case GST_VIDEO_FORMAT_Y216_BE:
919
0
    case GST_VIDEO_FORMAT_Y216_LE:
920
0
      info->stride[0] = GST_ROUND_UP_8 (width * 4);
921
0
      info->offset[0] = 0;
922
0
      info->size = info->stride[0] * height;
923
0
      break;
924
0
    case GST_VIDEO_FORMAT_GRAY8:
925
0
      info->stride[0] = GST_ROUND_UP_4 (width);
926
0
      info->offset[0] = 0;
927
0
      info->size = info->stride[0] * height;
928
0
      break;
929
0
    case GST_VIDEO_FORMAT_GRAY16_BE:
930
0
    case GST_VIDEO_FORMAT_GRAY16_LE:
931
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
932
0
      info->offset[0] = 0;
933
0
      info->size = info->stride[0] * height;
934
0
      break;
935
0
    case GST_VIDEO_FORMAT_UYVP:
936
0
      info->stride[0] = GST_ROUND_UP_4 ((GST_ROUND_UP_2 (width) * 5) / 2);
937
0
      info->offset[0] = 0;
938
0
      info->size = info->stride[0] * height;
939
0
      break;
940
0
    case GST_VIDEO_FORMAT_RGB8P:
941
0
      info->stride[0] = GST_ROUND_UP_4 (width);
942
0
      info->stride[1] = 4;
943
0
      info->offset[0] = 0;
944
0
      info->offset[1] = info->stride[0] * height;
945
0
      info->size = info->offset[1] + (4 * 256);
946
0
      break;
947
0
    case GST_VIDEO_FORMAT_IYU1:
948
0
      info->stride[0] = GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) +
949
0
          GST_ROUND_UP_4 (width) / 2);
950
0
      info->offset[0] = 0;
951
0
      info->size = info->stride[0] * height;
952
0
      break;
953
0
    case GST_VIDEO_FORMAT_ARGB64:
954
0
    case GST_VIDEO_FORMAT_ARGB64_BE:
955
0
    case GST_VIDEO_FORMAT_ARGB64_LE:
956
0
    case GST_VIDEO_FORMAT_RGBA64_BE:
957
0
    case GST_VIDEO_FORMAT_RGBA64_LE:
958
0
    case GST_VIDEO_FORMAT_BGRA64_BE:
959
0
    case GST_VIDEO_FORMAT_BGRA64_LE:
960
0
    case GST_VIDEO_FORMAT_ABGR64_BE:
961
0
    case GST_VIDEO_FORMAT_ABGR64_LE:
962
0
    case GST_VIDEO_FORMAT_AYUV64:
963
0
    case GST_VIDEO_FORMAT_Y412_BE:
964
0
    case GST_VIDEO_FORMAT_Y412_LE:
965
0
    case GST_VIDEO_FORMAT_Y416_BE:
966
0
    case GST_VIDEO_FORMAT_Y416_LE:
967
0
      info->stride[0] = width * 8;
968
0
      info->offset[0] = 0;
969
0
      info->size = info->stride[0] * height;
970
0
      break;
971
0
    case GST_VIDEO_FORMAT_I420:
972
0
    case GST_VIDEO_FORMAT_YV12:        /* same as I420, but plane 1+2 swapped */
973
0
      info->stride[0] = GST_ROUND_UP_4 (width);
974
0
      info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2);
975
0
      info->stride[2] = info->stride[1];
976
0
      info->offset[0] = 0;
977
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
978
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
979
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
980
0
        cr_h = GST_ROUND_UP_2 (cr_h);
981
0
      info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
982
0
      info->size = info->offset[2] + info->stride[2] * cr_h;
983
0
      break;
984
0
    case GST_VIDEO_FORMAT_Y41B:
985
0
      info->stride[0] = GST_ROUND_UP_4 (width);
986
0
      info->stride[1] = GST_ROUND_UP_16 (width) / 4;
987
0
      info->stride[2] = info->stride[1];
988
0
      info->offset[0] = 0;
989
0
      info->offset[1] = info->stride[0] * height;
990
0
      info->offset[2] = info->offset[1] + info->stride[1] * height;
991
      /* simplification of ROUNDUP4(w)*h + 2*((ROUNDUP16(w)/4)*h */
992
0
      info->size = (info->stride[0] + (GST_ROUND_UP_16 (width) / 2)) * height;
993
0
      break;
994
0
    case GST_VIDEO_FORMAT_Y42B:
995
0
      info->stride[0] = GST_ROUND_UP_4 (width);
996
0
      info->stride[1] = GST_ROUND_UP_8 (width) / 2;
997
0
      info->stride[2] = info->stride[1];
998
0
      info->offset[0] = 0;
999
0
      info->offset[1] = info->stride[0] * height;
1000
0
      info->offset[2] = info->offset[1] + info->stride[1] * height;
1001
      /* simplification of ROUNDUP4(w)*h + 2*(ROUNDUP8(w)/2)*h */
1002
0
      info->size = (info->stride[0] + GST_ROUND_UP_8 (width)) * height;
1003
0
      break;
1004
0
    case GST_VIDEO_FORMAT_Y444:
1005
0
    case GST_VIDEO_FORMAT_GBR:
1006
0
    case GST_VIDEO_FORMAT_RGBP:
1007
0
    case GST_VIDEO_FORMAT_BGRP:
1008
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1009
0
      info->stride[1] = info->stride[0];
1010
0
      info->stride[2] = info->stride[0];
1011
0
      info->offset[0] = 0;
1012
0
      info->offset[1] = info->stride[0] * height;
1013
0
      info->offset[2] = info->offset[1] * 2;
1014
0
      info->size = info->stride[0] * height * 3;
1015
0
      break;
1016
0
    case GST_VIDEO_FORMAT_GBRA:
1017
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1018
0
      info->stride[1] = info->stride[0];
1019
0
      info->stride[2] = info->stride[0];
1020
0
      info->stride[3] = info->stride[0];
1021
0
      info->offset[0] = 0;
1022
0
      info->offset[1] = info->stride[0] * height;
1023
0
      info->offset[2] = info->offset[1] * 2;
1024
0
      info->offset[3] = info->offset[1] * 3;
1025
0
      info->size = info->stride[0] * height * 4;
1026
0
      break;
1027
0
    case GST_VIDEO_FORMAT_NV12:
1028
0
    case GST_VIDEO_FORMAT_NV21:
1029
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1030
0
      info->stride[1] = info->stride[0];
1031
0
      info->offset[0] = 0;
1032
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1033
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1034
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1035
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1036
0
      info->size = info->offset[1] + info->stride[0] * cr_h;
1037
0
      break;
1038
0
    case GST_VIDEO_FORMAT_AV12:
1039
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1040
0
      info->stride[1] = info->stride[0];
1041
0
      info->stride[2] = info->stride[0];
1042
0
      info->offset[0] = 0;
1043
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1044
0
      info->offset[2] =
1045
0
          info->offset[1] + (info->stride[1] * GST_ROUND_UP_2 (height) / 2);
1046
0
      info->size = info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1047
0
      break;
1048
0
    case GST_VIDEO_FORMAT_NV16:
1049
0
    case GST_VIDEO_FORMAT_NV61:
1050
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1051
0
      info->stride[1] = info->stride[0];
1052
0
      info->offset[0] = 0;
1053
0
      info->offset[1] = info->stride[0] * height;
1054
0
      info->size = info->stride[0] * height * 2;
1055
0
      break;
1056
0
    case GST_VIDEO_FORMAT_NV24:
1057
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1058
0
      info->stride[1] = GST_ROUND_UP_4 (width * 2);
1059
0
      info->offset[0] = 0;
1060
0
      info->offset[1] = info->stride[0] * height;
1061
0
      info->size = info->stride[0] * height + info->stride[1] * height;
1062
0
      break;
1063
0
    case GST_VIDEO_FORMAT_A420:
1064
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1065
0
      info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_2 (width) / 2);
1066
0
      info->stride[2] = info->stride[1];
1067
0
      info->stride[3] = info->stride[0];
1068
0
      info->offset[0] = 0;
1069
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1070
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1071
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1072
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1073
0
      info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1074
0
      info->offset[3] = info->offset[2] + info->stride[2] * cr_h;
1075
0
      info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1076
0
      break;
1077
0
    case GST_VIDEO_FORMAT_A422:
1078
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1079
0
      info->stride[1] = GST_ROUND_UP_8 (width) / 2;
1080
0
      info->stride[2] = info->stride[1];
1081
0
      info->stride[3] = info->stride[0];
1082
0
      info->offset[0] = 0;
1083
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1084
0
      info->offset[2] = info->offset[1] +
1085
0
          info->stride[1] * GST_ROUND_UP_2 (height);
1086
0
      info->offset[3] =
1087
0
          info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1088
0
      info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1089
0
      break;
1090
0
    case GST_VIDEO_FORMAT_A444:
1091
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1092
0
      info->stride[1] = info->stride[0];
1093
0
      info->stride[2] = info->stride[0];
1094
0
      info->stride[3] = info->stride[0];
1095
0
      info->offset[0] = 0;
1096
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1097
0
      info->offset[2] = info->offset[1] +
1098
0
          info->stride[1] * GST_ROUND_UP_2 (height);
1099
0
      info->offset[3] =
1100
0
          info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1101
0
      info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1102
0
      break;
1103
0
    case GST_VIDEO_FORMAT_YUV9:
1104
0
    case GST_VIDEO_FORMAT_YVU9:
1105
0
      info->stride[0] = GST_ROUND_UP_4 (width);
1106
0
      info->stride[1] = GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) / 4);
1107
0
      info->stride[2] = info->stride[1];
1108
0
      info->offset[0] = 0;
1109
0
      info->offset[1] = info->stride[0] * height;
1110
0
      cr_h = GST_ROUND_UP_4 (height) / 4;
1111
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1112
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1113
0
      info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1114
0
      info->size = info->offset[2] + info->stride[2] * cr_h;
1115
0
      break;
1116
0
    case GST_VIDEO_FORMAT_I420_10LE:
1117
0
    case GST_VIDEO_FORMAT_I420_10BE:
1118
0
    case GST_VIDEO_FORMAT_I420_12LE:
1119
0
    case GST_VIDEO_FORMAT_I420_12BE:
1120
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1121
0
      info->stride[1] = GST_ROUND_UP_4 (width);
1122
0
      info->stride[2] = info->stride[1];
1123
0
      info->offset[0] = 0;
1124
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1125
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1126
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1127
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1128
0
      info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1129
0
      info->size = info->offset[2] + info->stride[2] * cr_h;
1130
0
      break;
1131
0
    case GST_VIDEO_FORMAT_I422_10LE:
1132
0
    case GST_VIDEO_FORMAT_I422_10BE:
1133
0
    case GST_VIDEO_FORMAT_I422_12LE:
1134
0
    case GST_VIDEO_FORMAT_I422_12BE:
1135
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1136
0
      info->stride[1] = GST_ROUND_UP_4 (width);
1137
0
      info->stride[2] = info->stride[1];
1138
0
      info->offset[0] = 0;
1139
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1140
0
      info->offset[2] = info->offset[1] +
1141
0
          info->stride[1] * GST_ROUND_UP_2 (height);
1142
0
      info->size = info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1143
0
      break;
1144
0
    case GST_VIDEO_FORMAT_Y444_10LE:
1145
0
    case GST_VIDEO_FORMAT_Y444_10BE:
1146
0
    case GST_VIDEO_FORMAT_Y444_12LE:
1147
0
    case GST_VIDEO_FORMAT_Y444_12BE:
1148
0
    case GST_VIDEO_FORMAT_GBR_10LE:
1149
0
    case GST_VIDEO_FORMAT_GBR_10BE:
1150
0
    case GST_VIDEO_FORMAT_GBR_12LE:
1151
0
    case GST_VIDEO_FORMAT_GBR_12BE:
1152
0
    case GST_VIDEO_FORMAT_GBR_16LE:
1153
0
    case GST_VIDEO_FORMAT_GBR_16BE:
1154
0
    case GST_VIDEO_FORMAT_Y444_16LE:
1155
0
    case GST_VIDEO_FORMAT_Y444_16BE:
1156
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1157
0
      info->stride[1] = info->stride[0];
1158
0
      info->stride[2] = info->stride[0];
1159
0
      info->offset[0] = 0;
1160
0
      info->offset[1] = info->stride[0] * height;
1161
0
      info->offset[2] = info->offset[1] * 2;
1162
0
      info->size = info->stride[0] * height * 3;
1163
0
      break;
1164
0
    case GST_VIDEO_FORMAT_GBRA_10LE:
1165
0
    case GST_VIDEO_FORMAT_GBRA_10BE:
1166
0
    case GST_VIDEO_FORMAT_GBRA_12LE:
1167
0
    case GST_VIDEO_FORMAT_GBRA_12BE:
1168
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1169
0
      info->stride[1] = info->stride[0];
1170
0
      info->stride[2] = info->stride[0];
1171
0
      info->stride[3] = info->stride[0];
1172
0
      info->offset[0] = 0;
1173
0
      info->offset[1] = info->stride[0] * height;
1174
0
      info->offset[2] = info->offset[1] * 2;
1175
0
      info->offset[3] = info->offset[1] * 3;
1176
0
      info->size = info->stride[0] * height * 4;
1177
0
      break;
1178
0
    case GST_VIDEO_FORMAT_NV12_64Z32:
1179
0
      info->stride[0] =
1180
0
          GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_128 (width) / 64,
1181
0
          GST_ROUND_UP_32 (height) / 32);
1182
0
      info->stride[1] =
1183
0
          GST_VIDEO_TILE_MAKE_STRIDE (GST_ROUND_UP_128 (width) / 64,
1184
0
          GST_ROUND_UP_64 (height) / 64);
1185
0
      info->offset[0] = 0;
1186
0
      info->offset[1] = GST_ROUND_UP_128 (width) * GST_ROUND_UP_32 (height);
1187
0
      info->size = info->offset[1] +
1188
0
          GST_ROUND_UP_128 (width) * (GST_ROUND_UP_64 (height) / 2);
1189
0
      break;
1190
0
    case GST_VIDEO_FORMAT_NV12_4L4:
1191
0
    case GST_VIDEO_FORMAT_NV12_32L32:
1192
0
    case GST_VIDEO_FORMAT_NV12_10LE40_4L4:
1193
0
    {
1194
0
      const gsize tile_size = GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, 0);
1195
0
      gint tile_width = GST_VIDEO_FORMAT_INFO_TILE_WIDTH (info->finfo, 0);
1196
0
      gint tile_height = GST_VIDEO_FORMAT_INFO_TILE_HEIGHT (info->finfo, 0);
1197
0
      gint n_tile_x = GST_ROUND_UP_N (info->width, tile_width) / tile_width;
1198
0
      gint n_tile_y = GST_ROUND_UP_N (info->height, tile_height) / tile_height;
1199
1200
0
      info->stride[0] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, n_tile_y);
1201
0
      info->stride[1] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x,
1202
0
          GST_ROUND_UP_2 (n_tile_y) / 2);
1203
0
      info->offset[1] = n_tile_x * n_tile_y * tile_size;
1204
0
      info->size = info->offset[1] +
1205
0
          n_tile_x * GST_ROUND_UP_2 (n_tile_y) / 2 * tile_size;
1206
0
      break;
1207
0
    }
1208
0
    case GST_VIDEO_FORMAT_NV12_16L32S:
1209
0
    {
1210
0
      const gsize y_tile_size =
1211
0
          GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, 0);
1212
0
      const gsize uv_tile_size =
1213
0
          GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, 1);
1214
0
      gint tile_width = GST_VIDEO_FORMAT_INFO_TILE_WIDTH (info->finfo, 0);
1215
0
      gint tile_height = GST_VIDEO_FORMAT_INFO_TILE_HEIGHT (info->finfo, 0);
1216
0
      gint n_tile_x = GST_ROUND_UP_N (info->width, tile_width) / tile_width;
1217
0
      gint n_tile_y = GST_ROUND_UP_N (info->height, tile_height) / tile_height;
1218
1219
0
      info->stride[0] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, n_tile_y);
1220
      /*
1221
       * size of UV plane tiles is subsample, hence have the same number of
1222
       * tiles in both directions.
1223
       */
1224
0
      info->stride[1] = info->stride[0];
1225
0
      info->offset[0] = 0;
1226
0
      info->offset[1] = n_tile_x * n_tile_y * y_tile_size;
1227
0
      info->size = info->offset[1] + n_tile_x * n_tile_y * uv_tile_size;
1228
0
      break;
1229
0
    }
1230
0
    case GST_VIDEO_FORMAT_A420_10LE:
1231
0
    case GST_VIDEO_FORMAT_A420_10BE:
1232
0
    case GST_VIDEO_FORMAT_A420_12LE:
1233
0
    case GST_VIDEO_FORMAT_A420_12BE:
1234
0
    case GST_VIDEO_FORMAT_A420_16LE:
1235
0
    case GST_VIDEO_FORMAT_A420_16BE:
1236
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1237
0
      info->stride[1] = GST_ROUND_UP_4 (width);
1238
0
      info->stride[2] = info->stride[1];
1239
0
      info->stride[3] = info->stride[0];
1240
0
      info->offset[0] = 0;
1241
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1242
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1243
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1244
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1245
0
      info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
1246
0
      info->offset[3] = info->offset[2] + info->stride[2] * cr_h;
1247
0
      info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1248
0
      break;
1249
0
    case GST_VIDEO_FORMAT_A422_10LE:
1250
0
    case GST_VIDEO_FORMAT_A422_10BE:
1251
0
    case GST_VIDEO_FORMAT_A422_12LE:
1252
0
    case GST_VIDEO_FORMAT_A422_12BE:
1253
0
    case GST_VIDEO_FORMAT_A422_16LE:
1254
0
    case GST_VIDEO_FORMAT_A422_16BE:
1255
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1256
0
      info->stride[1] = GST_ROUND_UP_4 (width);
1257
0
      info->stride[2] = info->stride[1];
1258
0
      info->stride[3] = info->stride[0];
1259
0
      info->offset[0] = 0;
1260
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1261
0
      info->offset[2] = info->offset[1] +
1262
0
          info->stride[1] * GST_ROUND_UP_2 (height);
1263
0
      info->offset[3] =
1264
0
          info->offset[2] + info->stride[2] * GST_ROUND_UP_2 (height);
1265
0
      info->size = info->offset[3] + info->stride[0] * GST_ROUND_UP_2 (height);
1266
0
      break;
1267
0
    case GST_VIDEO_FORMAT_A444_10LE:
1268
0
    case GST_VIDEO_FORMAT_A444_10BE:
1269
0
    case GST_VIDEO_FORMAT_A444_12LE:
1270
0
    case GST_VIDEO_FORMAT_A444_12BE:
1271
0
    case GST_VIDEO_FORMAT_A444_16LE:
1272
0
    case GST_VIDEO_FORMAT_A444_16BE:
1273
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1274
0
      info->stride[1] = info->stride[0];
1275
0
      info->stride[2] = info->stride[0];
1276
0
      info->stride[3] = info->stride[0];
1277
0
      info->offset[0] = 0;
1278
0
      info->offset[1] = info->stride[0] * height;
1279
0
      info->offset[2] = info->offset[1] * 2;
1280
0
      info->offset[3] = info->offset[1] * 3;
1281
0
      info->size = info->stride[0] * height * 4;
1282
0
      break;
1283
0
    case GST_VIDEO_FORMAT_P010_10LE:
1284
0
    case GST_VIDEO_FORMAT_P010_10BE:
1285
0
    case GST_VIDEO_FORMAT_P016_LE:
1286
0
    case GST_VIDEO_FORMAT_P016_BE:
1287
0
    case GST_VIDEO_FORMAT_P012_LE:
1288
0
    case GST_VIDEO_FORMAT_P012_BE:
1289
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1290
0
      info->stride[1] = info->stride[0];
1291
0
      info->offset[0] = 0;
1292
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1293
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1294
0
      info->size = info->offset[1] + info->stride[0] * cr_h;
1295
0
      break;
1296
0
    case GST_VIDEO_FORMAT_GRAY10_LE16:
1297
0
      info->stride[0] = GST_ROUND_UP_4 (width * 2);
1298
0
      info->offset[0] = 0;
1299
0
      info->size = info->stride[0] * height;
1300
0
      break;
1301
0
    case GST_VIDEO_FORMAT_GRAY10_LE32:
1302
0
      info->stride[0] = (width + 2) / 3 * 4;
1303
0
      info->offset[0] = 0;
1304
0
      info->size = info->stride[0] * GST_ROUND_UP_2 (height);
1305
0
      break;
1306
0
    case GST_VIDEO_FORMAT_NV12_10LE32:
1307
0
      info->stride[0] = (width + 2) / 3 * 4;
1308
0
      info->stride[1] = info->stride[0];
1309
0
      info->offset[0] = 0;
1310
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1311
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1312
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1313
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1314
0
      info->size = info->offset[1] + info->stride[0] * cr_h;
1315
0
      break;
1316
0
    case GST_VIDEO_FORMAT_NV16_10LE32:
1317
0
      info->stride[0] = (width + 2) / 3 * 4;
1318
0
      info->stride[1] = info->stride[0];
1319
0
      info->offset[0] = 0;
1320
0
      info->offset[1] = info->stride[0] * height;
1321
0
      info->size = info->stride[0] * height * 2;
1322
0
      break;
1323
0
    case GST_VIDEO_FORMAT_NV16_10LE40:
1324
0
      info->stride[0] = ((width * 5 >> 2) + 4) / 5 * 5;
1325
0
      info->stride[1] = info->stride[0];
1326
0
      info->offset[0] = 0;
1327
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1328
0
      info->size = info->offset[1] * 2;
1329
0
      break;
1330
0
    case GST_VIDEO_FORMAT_NV12_10LE40:
1331
0
      info->stride[0] = ((width * 5 >> 2) + 4) / 5 * 5;
1332
0
      info->stride[1] = info->stride[0];
1333
0
      info->offset[0] = 0;
1334
0
      info->offset[1] = info->stride[0] * GST_ROUND_UP_2 (height);
1335
0
      cr_h = GST_ROUND_UP_2 (height) / 2;
1336
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1337
0
        cr_h = GST_ROUND_UP_2 (cr_h);
1338
0
      info->size = info->offset[1] + info->stride[0] * cr_h;
1339
0
      break;
1340
0
    case GST_VIDEO_FORMAT_NV12_8L128:
1341
0
    {
1342
0
      gint tile_size = GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, 0);
1343
0
      gint tile_width = GST_VIDEO_FORMAT_INFO_TILE_WIDTH (info->finfo, 0);
1344
0
      gint tile_height = GST_VIDEO_FORMAT_INFO_TILE_HEIGHT (info->finfo, 0);
1345
0
      gint ALIGN_W = tile_width;
1346
0
      gint ALIGN_H = tile_height;
1347
0
      guint n_tile_x, y_n_tile_y, uv_n_tile_y;
1348
1349
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1350
0
        ALIGN_H *= 2;
1351
1352
0
      n_tile_x = GST_ROUND_UP_N (width, ALIGN_W) / tile_width;
1353
0
      y_n_tile_y = GST_ROUND_UP_N (height, ALIGN_H) / tile_height;
1354
0
      uv_n_tile_y = GST_ROUND_UP_2 (y_n_tile_y) / 2;
1355
1356
0
      info->stride[0] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, y_n_tile_y);
1357
0
      info->stride[1] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, uv_n_tile_y);
1358
0
      info->offset[0] = 0;
1359
0
      info->offset[1] = n_tile_x * y_n_tile_y * tile_size;
1360
0
      info->size = info->offset[1] + n_tile_x * uv_n_tile_y * tile_size;
1361
0
      break;
1362
0
    }
1363
0
    case GST_VIDEO_FORMAT_NV12_10BE_8L128:
1364
0
    {
1365
0
      gint tile_size = GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, 0);
1366
0
      gint tile_stride = GST_VIDEO_FORMAT_INFO_TILE_STRIDE (info->finfo, 0);
1367
0
      gint tile_height = GST_VIDEO_FORMAT_INFO_TILE_HEIGHT (info->finfo, 0);
1368
0
      gint stride = GST_ROUND_UP_8 (width * 10) >> 3;
1369
0
      gint ALIGN_W = tile_stride;
1370
0
      gint ALIGN_H = tile_height;
1371
0
      guint n_tile_x, y_n_tile_y, uv_n_tile_y;
1372
1373
0
      if (GST_VIDEO_INFO_IS_INTERLACED (info))
1374
0
        ALIGN_H *= 2;
1375
1376
0
      n_tile_x = GST_ROUND_UP_N (stride, ALIGN_W) / tile_stride;
1377
0
      y_n_tile_y = GST_ROUND_UP_N (height, ALIGN_H) / tile_height;
1378
0
      uv_n_tile_y = GST_ROUND_UP_2 (y_n_tile_y) / 2;
1379
1380
0
      info->stride[0] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, y_n_tile_y);
1381
0
      info->stride[1] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, uv_n_tile_y);
1382
0
      info->offset[0] = 0;
1383
0
      info->offset[1] = n_tile_x * y_n_tile_y * tile_size;
1384
0
      info->size = info->offset[1] + n_tile_x * uv_n_tile_y * tile_size;
1385
0
      break;
1386
0
    }
1387
0
    case GST_VIDEO_FORMAT_MT2110T:
1388
0
    case GST_VIDEO_FORMAT_MT2110R:
1389
0
    {
1390
0
      const gsize tile_size = GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, 0);
1391
0
      gint n_tile_x = GST_ROUND_UP_16 (info->width) / 16;
1392
0
      gint n_tile_y = GST_ROUND_UP_32 (info->height) / 32;
1393
1394
0
      info->stride[0] = GST_VIDEO_TILE_MAKE_STRIDE (n_tile_x, n_tile_y);
1395
0
      info->stride[1] = info->stride[0];
1396
0
      info->offset[0] = 0;
1397
0
      info->offset[1] = tile_size * n_tile_x * n_tile_y;
1398
0
      info->size = info->offset[1] + info->offset[1] / 2;
1399
0
      break;
1400
0
    }
1401
3
    case GST_VIDEO_FORMAT_ENCODED:
1402
3
    case GST_VIDEO_FORMAT_DMA_DRM:
1403
3
      break;
1404
0
    case GST_VIDEO_FORMAT_UNKNOWN:
1405
0
      GST_ERROR ("invalid format");
1406
0
      g_warning ("invalid format");
1407
0
      return FALSE;
1408
0
      break;
1409
3
  }
1410
1411
3
  if (plane_size) {
1412
0
    for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1413
0
      if (i < GST_VIDEO_INFO_N_PLANES (info)) {
1414
0
        if (GST_VIDEO_FORMAT_INFO_IS_TILED (info->finfo)) {
1415
0
          guint x_tiles = GST_VIDEO_TILE_X_TILES (info->stride[i]);
1416
0
          guint y_tiles = GST_VIDEO_TILE_Y_TILES (info->stride[i]);
1417
0
          plane_size[i] = x_tiles * y_tiles *
1418
0
              GST_VIDEO_FORMAT_INFO_TILE_SIZE (info->finfo, i);
1419
0
        } else {
1420
0
          gint comp[GST_VIDEO_MAX_COMPONENTS];
1421
0
          guint plane_height;
1422
1423
          /* Convert plane index to component index */
1424
0
          gst_video_format_info_component (info->finfo, i, comp);
1425
0
          plane_height =
1426
0
              GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0],
1427
0
              GST_VIDEO_INFO_FIELD_HEIGHT (info));
1428
0
          plane_size[i] = plane_height * GST_VIDEO_INFO_PLANE_STRIDE (info, i);
1429
0
        }
1430
0
      } else {
1431
0
        plane_size[i] = 0;
1432
0
      }
1433
0
    }
1434
0
  }
1435
1436
3
  return TRUE;
1437
3
}
1438
1439
/**
1440
 * gst_video_info_convert:
1441
 * @info: a #GstVideoInfo
1442
 * @src_format: #GstFormat of the @src_value
1443
 * @src_value: value to convert
1444
 * @dest_format: #GstFormat of the @dest_value
1445
 * @dest_value: (out): pointer to destination value
1446
 *
1447
 * Converts among various #GstFormat types.  This function handles
1448
 * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT.  For
1449
 * raw video, GST_FORMAT_DEFAULT corresponds to video frames.  This
1450
 * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
1451
 *
1452
 * Returns: TRUE if the conversion was successful.
1453
 */
1454
gboolean
1455
gst_video_info_convert (const GstVideoInfo * info,
1456
    GstFormat src_format, gint64 src_value,
1457
    GstFormat dest_format, gint64 * dest_value)
1458
0
{
1459
0
  gboolean ret = FALSE;
1460
0
  int fps_n, fps_d;
1461
0
  gsize size;
1462
1463
0
  g_return_val_if_fail (info != NULL, 0);
1464
0
  g_return_val_if_fail (info->finfo != NULL, 0);
1465
0
  g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, 0);
1466
0
  g_return_val_if_fail (info->size > 0, 0);
1467
1468
0
  size = info->size;
1469
0
  fps_n = info->fps_n;
1470
0
  fps_d = info->fps_d;
1471
1472
0
  GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s to %s",
1473
0
      src_value, gst_format_get_name (src_format),
1474
0
      gst_format_get_name (dest_format));
1475
1476
0
  if (src_format == dest_format) {
1477
0
    *dest_value = src_value;
1478
0
    ret = TRUE;
1479
0
    goto done;
1480
0
  }
1481
1482
0
  if (src_value == -1) {
1483
0
    *dest_value = -1;
1484
0
    ret = TRUE;
1485
0
    goto done;
1486
0
  }
1487
1488
  /* bytes to frames */
1489
0
  if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_DEFAULT) {
1490
0
    if (size != 0) {
1491
0
      *dest_value = gst_util_uint64_scale (src_value, 1, size);
1492
0
    } else {
1493
0
      GST_ERROR ("blocksize is 0");
1494
0
      *dest_value = 0;
1495
0
    }
1496
0
    ret = TRUE;
1497
0
    goto done;
1498
0
  }
1499
1500
  /* frames to bytes */
1501
0
  if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_BYTES) {
1502
0
    *dest_value = gst_util_uint64_scale (src_value, size, 1);
1503
0
    ret = TRUE;
1504
0
    goto done;
1505
0
  }
1506
1507
  /* time to frames */
1508
0
  if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_DEFAULT) {
1509
0
    if (fps_d != 0) {
1510
0
      *dest_value = gst_util_uint64_scale (src_value,
1511
0
          fps_n, GST_SECOND * fps_d);
1512
0
    } else {
1513
0
      GST_ERROR ("framerate denominator is 0");
1514
0
      *dest_value = 0;
1515
0
    }
1516
0
    ret = TRUE;
1517
0
    goto done;
1518
0
  }
1519
1520
  /* frames to time */
1521
0
  if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) {
1522
0
    if (fps_n != 0) {
1523
0
      *dest_value = gst_util_uint64_scale (src_value,
1524
0
          GST_SECOND * fps_d, fps_n);
1525
0
    } else {
1526
0
      GST_ERROR ("framerate numerator is 0");
1527
0
      *dest_value = 0;
1528
0
    }
1529
0
    ret = TRUE;
1530
0
    goto done;
1531
0
  }
1532
1533
  /* time to bytes */
1534
0
  if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
1535
0
    if (fps_d != 0) {
1536
0
      *dest_value = gst_util_uint64_scale (src_value,
1537
0
          fps_n * size, GST_SECOND * fps_d);
1538
0
    } else {
1539
0
      GST_ERROR ("framerate denominator is 0");
1540
0
      *dest_value = 0;
1541
0
    }
1542
0
    ret = TRUE;
1543
0
    goto done;
1544
0
  }
1545
1546
  /* bytes to time */
1547
0
  if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) {
1548
0
    if (fps_n != 0 && size != 0) {
1549
0
      *dest_value = gst_util_uint64_scale (src_value,
1550
0
          GST_SECOND * fps_d, fps_n * size);
1551
0
    } else {
1552
0
      GST_ERROR ("framerate denominator and/or blocksize is 0");
1553
0
      *dest_value = 0;
1554
0
    }
1555
0
    ret = TRUE;
1556
0
  }
1557
1558
0
done:
1559
1560
0
  GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, ret, *dest_value);
1561
1562
0
  return ret;
1563
0
}
1564
1565
/**
1566
 * gst_video_info_align_full:
1567
 * @info: a #GstVideoInfo
1568
 * @align: alignment parameters
1569
 * @plane_size: (out) (optional): array used to store the plane sizes
1570
 *
1571
 * Extra padding will be added to the right side when stride alignment padding
1572
 * is required and @align will be updated with the new padding values.
1573
 *
1574
 * This variant of gst_video_info_align() provides the updated size, in bytes,
1575
 * of each video plane after the alignment, including all horizontal and vertical
1576
 * paddings.
1577
 *
1578
 * In case of GST_VIDEO_INTERLACE_MODE_ALTERNATE info, the returned sizes are the
1579
 * ones used to hold a single field, not the full frame.
1580
 *
1581
 * Returns: %FALSE if alignment could not be applied, e.g. because the
1582
 *   size of a frame can't be represented as a 32 bit integer
1583
 *
1584
 * Since: 1.18
1585
 */
1586
gboolean
1587
gst_video_info_align_full (GstVideoInfo * info, GstVideoAlignment * align,
1588
    gsize plane_size[GST_VIDEO_MAX_PLANES])
1589
0
{
1590
0
  const GstVideoFormatInfo *vinfo = info->finfo;
1591
0
  gint width, height;
1592
0
  gint padded_width, padded_height;
1593
0
  gint i, n_planes;
1594
0
  gboolean aligned;
1595
1596
0
  width = GST_VIDEO_INFO_WIDTH (info);
1597
0
  height = GST_VIDEO_INFO_HEIGHT (info);
1598
1599
0
  GST_LOG ("padding %u-%ux%u-%u", align->padding_top,
1600
0
      align->padding_left, align->padding_right, align->padding_bottom);
1601
1602
0
  n_planes = GST_VIDEO_INFO_N_PLANES (info);
1603
1604
0
  if (GST_VIDEO_FORMAT_INFO_HAS_PALETTE (vinfo))
1605
0
    n_planes--;
1606
1607
  /* first make sure the left padding does not cause alignment problems later */
1608
0
  do {
1609
0
    GST_LOG ("left padding %u", align->padding_left);
1610
0
    aligned = TRUE;
1611
0
    for (i = 0; i < n_planes; i++) {
1612
0
      gint comp[GST_VIDEO_MAX_COMPONENTS];
1613
0
      gint hedge;
1614
1615
      /* this is the amount of pixels to add as left padding */
1616
0
      gst_video_format_info_component (vinfo, i, comp);
1617
0
      hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, comp[0],
1618
0
          align->padding_left);
1619
0
      hedge *= GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, comp[0]);
1620
1621
0
      GST_LOG ("plane %d, padding %d, alignment %u", i, hedge,
1622
0
          align->stride_align[i]);
1623
0
      aligned &= (hedge & align->stride_align[i]) == 0;
1624
0
    }
1625
0
    if (aligned)
1626
0
      break;
1627
1628
0
    GST_LOG ("unaligned padding, increasing padding");
1629
    /* increase padded_width */
1630
0
    align->padding_left += align->padding_left & ~(align->padding_left - 1);
1631
0
  } while (!aligned);
1632
1633
  /* add the padding */
1634
0
  padded_width = width + align->padding_left + align->padding_right;
1635
0
  padded_height = height + align->padding_top + align->padding_bottom;
1636
1637
0
  do {
1638
0
    GST_LOG ("padded dimension %u-%u", padded_width, padded_height);
1639
1640
0
    info->width = padded_width;
1641
0
    info->height = padded_height;
1642
1643
0
    if (!fill_planes (info, plane_size))
1644
0
      return FALSE;
1645
1646
    /* check alignment */
1647
0
    aligned = TRUE;
1648
0
    for (i = 0; i < n_planes; i++) {
1649
0
      GST_LOG ("plane %d, stride %d, alignment %u", i, info->stride[i],
1650
0
          align->stride_align[i]);
1651
0
      aligned &= (info->stride[i] & align->stride_align[i]) == 0;
1652
0
    }
1653
0
    if (aligned)
1654
0
      break;
1655
1656
0
    GST_LOG ("unaligned strides, increasing dimension");
1657
    /* increase padded_width */
1658
0
    padded_width += padded_width & ~(padded_width - 1);
1659
0
  } while (!aligned);
1660
1661
0
  align->padding_right = padded_width - width - align->padding_left;
1662
1663
0
  info->width = width;
1664
0
  info->height = height;
1665
1666
0
  for (i = 0; i < n_planes; i++) {
1667
0
    gint comp[GST_VIDEO_MAX_COMPONENTS];
1668
0
    gint vedge, hedge;
1669
1670
0
    gst_video_format_info_component (info->finfo, i, comp);
1671
0
    hedge =
1672
0
        GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, comp[0], align->padding_left);
1673
0
    vedge =
1674
0
        GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo, comp[0], align->padding_top);
1675
1676
0
    GST_DEBUG ("plane %d: comp: %d, hedge %d vedge %d align %d stride %d", i,
1677
0
        comp[0], hedge, vedge, align->stride_align[i], info->stride[i]);
1678
1679
0
    info->offset[i] += (vedge * info->stride[i]) +
1680
0
        (hedge * GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, comp[0]));
1681
0
  }
1682
1683
0
  return TRUE;
1684
0
}
1685
1686
/**
1687
 * gst_video_info_align:
1688
 * @info: a #GstVideoInfo
1689
 * @align: alignment parameters
1690
 *
1691
 * Adjust the offset and stride fields in @info so that the padding and
1692
 * stride alignment in @align is respected.
1693
 *
1694
 * Extra padding will be added to the right side when stride alignment padding
1695
 * is required and @align will be updated with the new padding values.
1696
 *
1697
 * Returns: %FALSE if alignment could not be applied, e.g. because the
1698
 *   size of a frame can't be represented as a 32 bit integer (Since: 1.12)
1699
 */
1700
gboolean
1701
gst_video_info_align (GstVideoInfo * info, GstVideoAlignment * align)
1702
0
{
1703
  return gst_video_info_align_full (info, align, NULL);
1704
0
}