2 * Copyright (C) 2020 Thibault Saunier <tsaunier@igalia.com>
3 * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
25 #include <gst/cuda/gstcudautils.h>
26 #include "gstcudaconvertscale.h"
27 #include "cuda-converter.h"
29 GST_DEBUG_CATEGORY_STATIC (gst_cuda_base_convert_debug);
30 #define GST_CAT_DEFAULT gst_cuda_base_convert_debug
32 #define GST_CUDA_CONVET_FORMATS \
33 "{ I420, YV12, NV12, NV21, P010_10LE, P016_LE, I420_10LE, Y444, Y444_16LE, " \
34 "BGRA, RGBA, RGBx, BGRx, ARGB, ABGR, RGB, BGR, BGR10A2_LE, RGB10A2_LE, " \
35 "Y42B, I422_10LE, I422_12LE }"
37 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
40 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
41 (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, GST_CUDA_CONVET_FORMATS))
44 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
47 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
48 (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, GST_CUDA_CONVET_FORMATS))
51 struct _GstCudaBaseConvert
53 GstCudaBaseTransform parent;
55 GstCudaConverter *converter;
62 static void gst_cuda_base_convert_dispose (GObject * object);
63 static GstCaps *gst_cuda_base_convert_transform_caps (GstBaseTransform * trans,
64 GstPadDirection direction, GstCaps * caps, GstCaps * filter);
65 static GstCaps *gst_cuda_base_convert_fixate_caps (GstBaseTransform * trans,
66 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
68 gst_cuda_base_convert_propose_allocation (GstBaseTransform * trans,
69 GstQuery * decide_query, GstQuery * query);
70 static gboolean gst_cuda_base_convert_decide_allocation (GstBaseTransform *
71 trans, GstQuery * query);
72 static gboolean gst_cuda_base_convert_filter_meta (GstBaseTransform * trans,
73 GstQuery * query, GType api, const GstStructure * params);
74 static GstFlowReturn gst_cuda_base_convert_transform (GstBaseTransform * trans,
75 GstBuffer * inbuf, GstBuffer * outbuf);
76 static gboolean gst_cuda_base_convert_set_info (GstCudaBaseTransform * btrans,
77 GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
78 GstVideoInfo * out_info);
83 * A baseclass implementation for cuda convert elements
87 #define gst_cuda_base_convert_parent_class parent_class
88 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstCudaBaseConvert,
89 gst_cuda_base_convert, GST_TYPE_CUDA_BASE_TRANSFORM,
90 GST_DEBUG_CATEGORY_INIT (gst_cuda_base_convert_debug,
91 "cudaconvertscale", 0, "CUDA Base Filter"));
94 gst_cuda_base_convert_class_init (GstCudaBaseConvertClass * klass)
96 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
97 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
98 GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
99 GstCudaBaseTransformClass *btrans_class =
100 GST_CUDA_BASE_TRANSFORM_CLASS (klass);
102 gobject_class->dispose = gst_cuda_base_convert_dispose;
104 gst_element_class_add_static_pad_template (element_class, &sink_template);
105 gst_element_class_add_static_pad_template (element_class, &src_template);
107 trans_class->passthrough_on_same_caps = TRUE;
109 trans_class->transform_caps =
110 GST_DEBUG_FUNCPTR (gst_cuda_base_convert_transform_caps);
111 trans_class->fixate_caps =
112 GST_DEBUG_FUNCPTR (gst_cuda_base_convert_fixate_caps);
113 trans_class->propose_allocation =
114 GST_DEBUG_FUNCPTR (gst_cuda_base_convert_propose_allocation);
115 trans_class->decide_allocation =
116 GST_DEBUG_FUNCPTR (gst_cuda_base_convert_decide_allocation);
117 trans_class->filter_meta =
118 GST_DEBUG_FUNCPTR (gst_cuda_base_convert_filter_meta);
119 trans_class->transform = GST_DEBUG_FUNCPTR (gst_cuda_base_convert_transform);
121 btrans_class->set_info = GST_DEBUG_FUNCPTR (gst_cuda_base_convert_set_info);
123 gst_type_mark_as_plugin_api (GST_TYPE_CUDA_BASE_CONVERT, 0);
127 gst_cuda_base_convert_init (GstCudaBaseConvert * self)
132 gst_cuda_base_convert_dispose (GObject * object)
134 GstCudaBaseConvert *self = GST_CUDA_BASE_CONVERT (object);
136 if (self->converter) {
137 gst_cuda_converter_free (self->converter);
138 self->converter = NULL;
141 G_OBJECT_CLASS (parent_class)->dispose (object);
145 gst_cuda_base_convert_caps_remove_format_info (GstCaps * caps)
151 GstCapsFeatures *feature =
152 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY);
154 res = gst_caps_new_empty ();
156 n = gst_caps_get_size (caps);
157 for (i = 0; i < n; i++) {
158 st = gst_caps_get_structure (caps, i);
159 f = gst_caps_get_features (caps, i);
161 /* If this is already expressed by the existing caps
162 * skip this structure */
163 if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
166 st = gst_structure_copy (st);
167 /* Only remove format info for the cases when we can actually convert */
168 if (!gst_caps_features_is_any (f)
169 && gst_caps_features_is_equal (f, feature)) {
170 gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
174 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
176 gst_caps_features_free (feature);
182 gst_cuda_base_convert_caps_rangify_size_info (GstCaps * caps)
188 GstCapsFeatures *feature =
189 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY);
191 res = gst_caps_new_empty ();
193 n = gst_caps_get_size (caps);
194 for (i = 0; i < n; i++) {
195 st = gst_caps_get_structure (caps, i);
196 f = gst_caps_get_features (caps, i);
198 /* If this is already expressed by the existing caps
199 * skip this structure */
200 if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
203 st = gst_structure_copy (st);
204 /* Only remove format info for the cases when we can actually convert */
205 if (!gst_caps_features_is_any (f)
206 && gst_caps_features_is_equal (f, feature)) {
207 gst_structure_set (st, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
208 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
210 /* if pixel aspect ratio, make a range of it */
211 if (gst_structure_has_field (st, "pixel-aspect-ratio")) {
212 gst_structure_set (st, "pixel-aspect-ratio",
213 GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL);
217 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
219 gst_caps_features_free (feature);
225 gst_cuda_base_convert_caps_remove_format_and_rangify_size_info (GstCaps * caps)
231 GstCapsFeatures *feature =
232 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY);
234 res = gst_caps_new_empty ();
236 n = gst_caps_get_size (caps);
237 for (i = 0; i < n; i++) {
238 st = gst_caps_get_structure (caps, i);
239 f = gst_caps_get_features (caps, i);
241 /* If this is already expressed by the existing caps
242 * skip this structure */
243 if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
246 st = gst_structure_copy (st);
247 /* Only remove format info for the cases when we can actually convert */
248 if (!gst_caps_features_is_any (f)
249 && gst_caps_features_is_equal (f, feature)) {
250 gst_structure_set (st, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
251 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
252 /* if pixel aspect ratio, make a range of it */
253 if (gst_structure_has_field (st, "pixel-aspect-ratio")) {
254 gst_structure_set (st, "pixel-aspect-ratio",
255 GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL);
257 gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
261 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
263 gst_caps_features_free (feature);
269 gst_cuda_base_convert_transform_caps (GstBaseTransform *
270 trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter)
275 /* Get all possible caps that we can transform to */
276 tmp = gst_cuda_base_convert_caps_remove_format_and_rangify_size_info (caps);
279 tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
280 gst_caps_unref (tmp);
286 GST_DEBUG_OBJECT (trans, "transformed %" GST_PTR_FORMAT " into %"
287 GST_PTR_FORMAT, caps, result);
293 * This is an incomplete matrix of in formats and a score for the prefered output
296 * out: RGB24 RGB16 ARGB AYUV YUV444 YUV422 YUV420 YUV411 YUV410 PAL GRAY
298 * RGB24 0 2 1 2 2 3 4 5 6 7 8
299 * RGB16 1 0 1 2 2 3 4 5 6 7 8
300 * ARGB 2 3 0 1 4 5 6 7 8 9 10
301 * AYUV 3 4 1 0 2 5 6 7 8 9 10
302 * YUV444 2 4 3 1 0 5 6 7 8 9 10
303 * YUV422 3 5 4 2 1 0 6 7 8 9 10
304 * YUV420 4 6 5 3 2 1 0 7 8 9 10
305 * YUV411 4 6 5 3 2 1 7 0 8 9 10
306 * YUV410 6 8 7 5 4 3 2 1 0 9 10
307 * PAL 1 3 2 6 4 6 7 8 9 0 10
308 * GRAY 1 4 3 2 1 5 6 7 8 9 0
310 * PAL or GRAY are never prefered, if we can we would convert to PAL instead
312 * less subsampling is prefered and if any, preferably horizontal
313 * We would like to keep the alpha, even if we would need to to colorspace conversion
316 #define SCORE_FORMAT_CHANGE 1
317 #define SCORE_DEPTH_CHANGE 1
318 #define SCORE_ALPHA_CHANGE 1
319 #define SCORE_CHROMA_W_CHANGE 1
320 #define SCORE_CHROMA_H_CHANGE 1
321 #define SCORE_PALETTE_CHANGE 1
323 #define SCORE_COLORSPACE_LOSS 2 /* RGB <-> YUV */
324 #define SCORE_DEPTH_LOSS 4 /* change bit depth */
325 #define SCORE_ALPHA_LOSS 8 /* lose the alpha channel */
326 #define SCORE_CHROMA_W_LOSS 16 /* vertical subsample */
327 #define SCORE_CHROMA_H_LOSS 32 /* horizontal subsample */
328 #define SCORE_PALETTE_LOSS 64 /* convert to palette format */
329 #define SCORE_COLOR_LOSS 128 /* convert to GRAY */
331 #define COLORSPACE_MASK (GST_VIDEO_FORMAT_FLAG_YUV | \
332 GST_VIDEO_FORMAT_FLAG_RGB | GST_VIDEO_FORMAT_FLAG_GRAY)
333 #define ALPHA_MASK (GST_VIDEO_FORMAT_FLAG_ALPHA)
334 #define PALETTE_MASK (GST_VIDEO_FORMAT_FLAG_PALETTE)
336 /* calculate how much loss a conversion would be */
338 score_value (GstBaseTransform * base, const GstVideoFormatInfo * in_info,
339 const GValue * val, gint * min_loss, const GstVideoFormatInfo ** out_info)
342 const GstVideoFormatInfo *t_info;
343 guint in_flags, t_flags;
346 fname = g_value_get_string (val);
347 t_info = gst_video_format_get_info (gst_video_format_from_string (fname));
348 if (!t_info || t_info->format == GST_VIDEO_FORMAT_UNKNOWN)
351 /* accept input format immediately without loss */
352 if (in_info == t_info) {
358 loss = SCORE_FORMAT_CHANGE;
360 in_flags = GST_VIDEO_FORMAT_INFO_FLAGS (in_info);
361 in_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
362 in_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
363 in_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
365 t_flags = GST_VIDEO_FORMAT_INFO_FLAGS (t_info);
366 t_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
367 t_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
368 t_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
370 if ((t_flags & PALETTE_MASK) != (in_flags & PALETTE_MASK)) {
371 loss += SCORE_PALETTE_CHANGE;
372 if (t_flags & PALETTE_MASK)
373 loss += SCORE_PALETTE_LOSS;
376 if ((t_flags & COLORSPACE_MASK) != (in_flags & COLORSPACE_MASK)) {
377 loss += SCORE_COLORSPACE_LOSS;
378 if (t_flags & GST_VIDEO_FORMAT_FLAG_GRAY)
379 loss += SCORE_COLOR_LOSS;
382 if ((t_flags & ALPHA_MASK) != (in_flags & ALPHA_MASK)) {
383 loss += SCORE_ALPHA_CHANGE;
384 if (in_flags & ALPHA_MASK)
385 loss += SCORE_ALPHA_LOSS;
388 if ((in_info->h_sub[1]) != (t_info->h_sub[1])) {
389 loss += SCORE_CHROMA_H_CHANGE;
390 if ((in_info->h_sub[1]) < (t_info->h_sub[1]))
391 loss += SCORE_CHROMA_H_LOSS;
393 if ((in_info->w_sub[1]) != (t_info->w_sub[1])) {
394 loss += SCORE_CHROMA_W_CHANGE;
395 if ((in_info->w_sub[1]) < (t_info->w_sub[1]))
396 loss += SCORE_CHROMA_W_LOSS;
399 if ((in_info->bits) != (t_info->bits)) {
400 loss += SCORE_DEPTH_CHANGE;
401 if ((in_info->bits) > (t_info->bits))
402 loss += SCORE_DEPTH_LOSS + (in_info->bits - t_info->bits);
405 GST_DEBUG_OBJECT (base, "score %s -> %s = %d",
406 GST_VIDEO_FORMAT_INFO_NAME (in_info),
407 GST_VIDEO_FORMAT_INFO_NAME (t_info), loss);
409 if (loss < *min_loss) {
410 GST_DEBUG_OBJECT (base, "found new best %d", loss);
417 gst_cuda_base_convert_fixate_format (GstBaseTransform * trans,
418 GstCaps * caps, GstCaps * result)
420 GstStructure *ins, *outs;
421 const gchar *in_format;
422 const GstVideoFormatInfo *in_info, *out_info = NULL;
423 gint min_loss = G_MAXINT;
426 ins = gst_caps_get_structure (caps, 0);
427 in_format = gst_structure_get_string (ins, "format");
432 GST_DEBUG_OBJECT (trans, "source format %s", in_format);
435 gst_video_format_get_info (gst_video_format_from_string (in_format));
439 outs = gst_caps_get_structure (result, 0);
441 capslen = gst_caps_get_size (result);
442 GST_DEBUG ("iterate %d structures", capslen);
443 for (i = 0; i < capslen; i++) {
445 const GValue *format;
447 tests = gst_caps_get_structure (result, i);
448 format = gst_structure_get_value (tests, "format");
450 /* should not happen */
454 if (GST_VALUE_HOLDS_LIST (format)) {
457 len = gst_value_list_get_size (format);
458 GST_DEBUG_OBJECT (trans, "have %d formats", len);
459 for (j = 0; j < len; j++) {
462 val = gst_value_list_get_value (format, j);
463 if (G_VALUE_HOLDS_STRING (val)) {
464 score_value (trans, in_info, val, &min_loss, &out_info);
469 } else if (G_VALUE_HOLDS_STRING (format)) {
470 score_value (trans, in_info, format, &min_loss, &out_info);
474 gst_structure_set (outs, "format", G_TYPE_STRING,
475 GST_VIDEO_FORMAT_INFO_NAME (out_info), NULL);
479 subsampling_unchanged (GstVideoInfo * in_info, GstVideoInfo * out_info)
482 const GstVideoFormatInfo *in_format, *out_format;
484 if (GST_VIDEO_INFO_N_COMPONENTS (in_info) !=
485 GST_VIDEO_INFO_N_COMPONENTS (out_info))
488 in_format = in_info->finfo;
489 out_format = out_info->finfo;
491 for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (in_info); i++) {
492 if (GST_VIDEO_FORMAT_INFO_W_SUB (in_format,
493 i) != GST_VIDEO_FORMAT_INFO_W_SUB (out_format, i))
495 if (GST_VIDEO_FORMAT_INFO_H_SUB (in_format,
496 i) != GST_VIDEO_FORMAT_INFO_H_SUB (out_format, i))
504 transfer_colorimetry_from_input (GstBaseTransform * trans, GstCaps * in_caps,
507 GstStructure *out_caps_s = gst_caps_get_structure (out_caps, 0);
508 GstStructure *in_caps_s = gst_caps_get_structure (in_caps, 0);
509 gboolean have_colorimetry =
510 gst_structure_has_field (out_caps_s, "colorimetry");
511 gboolean have_chroma_site =
512 gst_structure_has_field (out_caps_s, "chroma-site");
514 /* If the output already has colorimetry and chroma-site, stop,
515 * otherwise try and transfer what we can from the input caps */
516 if (have_colorimetry && have_chroma_site)
520 GstVideoInfo in_info, out_info;
521 const GValue *in_colorimetry =
522 gst_structure_get_value (in_caps_s, "colorimetry");
524 if (!gst_video_info_from_caps (&in_info, in_caps)) {
525 GST_WARNING_OBJECT (trans,
526 "Failed to convert sink pad caps to video info");
529 if (!gst_video_info_from_caps (&out_info, out_caps)) {
530 GST_WARNING_OBJECT (trans,
531 "Failed to convert src pad caps to video info");
535 if (!have_colorimetry && in_colorimetry != NULL) {
536 if ((GST_VIDEO_INFO_IS_YUV (&out_info)
537 && GST_VIDEO_INFO_IS_YUV (&in_info))
538 || (GST_VIDEO_INFO_IS_RGB (&out_info)
539 && GST_VIDEO_INFO_IS_RGB (&in_info))
540 || (GST_VIDEO_INFO_IS_GRAY (&out_info)
541 && GST_VIDEO_INFO_IS_GRAY (&in_info))) {
542 /* Can transfer the colorimetry intact from the input if it has it */
543 gst_structure_set_value (out_caps_s, "colorimetry", in_colorimetry);
545 gchar *colorimetry_str;
547 /* Changing between YUV/RGB - forward primaries and transfer function, but use
548 * default range and matrix.
549 * the primaries is used for conversion between RGB and XYZ (CIE 1931 coordinate).
550 * the transfer function could be another reference (e.g., HDR)
552 out_info.colorimetry.primaries = in_info.colorimetry.primaries;
553 out_info.colorimetry.transfer = in_info.colorimetry.transfer;
556 gst_video_colorimetry_to_string (&out_info.colorimetry);
557 gst_caps_set_simple (out_caps, "colorimetry", G_TYPE_STRING,
558 colorimetry_str, NULL);
559 g_free (colorimetry_str);
563 /* Only YUV output needs chroma-site. If the input was also YUV and had the same chroma
564 * subsampling, transfer the siting. If the sub-sampling is changing, then the planes get
565 * scaled anyway so there's no real reason to prefer the input siting. */
566 if (!have_chroma_site && GST_VIDEO_INFO_IS_YUV (&out_info)) {
567 if (GST_VIDEO_INFO_IS_YUV (&in_info)) {
568 const GValue *in_chroma_site =
569 gst_structure_get_value (in_caps_s, "chroma-site");
570 if (in_chroma_site != NULL
571 && subsampling_unchanged (&in_info, &out_info))
572 gst_structure_set_value (out_caps_s, "chroma-site", in_chroma_site);
579 gst_cuda_base_convert_get_fixed_format (GstBaseTransform * trans,
580 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
584 result = gst_caps_intersect (othercaps, caps);
585 if (gst_caps_is_empty (result)) {
586 gst_caps_unref (result);
587 result = gst_caps_copy (othercaps);
590 gst_cuda_base_convert_fixate_format (trans, caps, result);
592 /* fixate remaining fields */
593 result = gst_caps_fixate (result);
595 if (direction == GST_PAD_SINK) {
596 if (gst_caps_is_subset (caps, result)) {
597 gst_caps_replace (&result, caps);
599 /* Try and preserve input colorimetry / chroma information */
600 transfer_colorimetry_from_input (trans, caps, result);
608 gst_cuda_base_convert_fixate_size (GstBaseTransform * base,
609 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
611 GstStructure *ins, *outs;
612 const GValue *from_par, *to_par;
613 GValue fpar = G_VALUE_INIT, tpar = G_VALUE_INIT;
615 othercaps = gst_caps_truncate (othercaps);
616 othercaps = gst_caps_make_writable (othercaps);
617 ins = gst_caps_get_structure (caps, 0);
618 outs = gst_caps_get_structure (othercaps, 0);
620 from_par = gst_structure_get_value (ins, "pixel-aspect-ratio");
621 to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
623 if (direction == GST_PAD_SINK) {
625 g_value_init (&fpar, GST_TYPE_FRACTION);
626 gst_value_set_fraction (&fpar, 1, 1);
630 g_value_init (&tpar, GST_TYPE_FRACTION_RANGE);
631 gst_value_set_fraction_range_full (&tpar, 1, G_MAXINT, G_MAXINT, 1);
635 gint from_par_n, from_par_d;
638 g_value_init (&fpar, GST_TYPE_FRACTION);
639 gst_value_set_fraction (&fpar, 1, 1);
642 from_par_n = from_par_d = 1;
644 from_par_n = gst_value_get_fraction_numerator (from_par);
645 from_par_d = gst_value_get_fraction_denominator (from_par);
649 gint to_par_n, to_par_d;
651 to_par_n = from_par_n;
652 to_par_d = from_par_d;
654 g_value_init (&tpar, GST_TYPE_FRACTION);
655 gst_value_set_fraction (&tpar, to_par_n, to_par_d);
658 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
659 to_par_n, to_par_d, NULL);
663 /* we have both PAR but they might not be fixated */
665 gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
667 gint from_dar_n, from_dar_d;
670 /* from_par should be fixed */
671 g_return_val_if_fail (gst_value_is_fixed (from_par), othercaps);
673 from_par_n = gst_value_get_fraction_numerator (from_par);
674 from_par_d = gst_value_get_fraction_denominator (from_par);
676 gst_structure_get_int (ins, "width", &from_w);
677 gst_structure_get_int (ins, "height", &from_h);
679 gst_structure_get_int (outs, "width", &w);
680 gst_structure_get_int (outs, "height", &h);
682 /* if both width and height are already fixed, we can't do anything
683 * about it anymore */
687 GST_DEBUG_OBJECT (base, "dimensions already set to %dx%d, not fixating",
689 if (!gst_value_is_fixed (to_par)) {
690 if (gst_video_calculate_display_ratio (&n, &d, from_w, from_h,
691 from_par_n, from_par_d, w, h)) {
692 GST_DEBUG_OBJECT (base, "fixating to_par to %dx%d", n, d);
693 if (gst_structure_has_field (outs, "pixel-aspect-ratio"))
694 gst_structure_fixate_field_nearest_fraction (outs,
695 "pixel-aspect-ratio", n, d);
697 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
704 /* Calculate input DAR */
705 if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d,
706 &from_dar_n, &from_dar_d)) {
707 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
708 ("Error calculating the output scaled size - integer overflow"));
712 GST_DEBUG_OBJECT (base, "Input DAR is %d/%d", from_dar_n, from_dar_d);
714 /* If either width or height are fixed there's not much we
715 * can do either except choosing a height or width and PAR
716 * that matches the DAR as good as possible
720 gint set_w, set_par_n, set_par_d;
722 GST_DEBUG_OBJECT (base, "height is fixed (%d)", h);
724 /* If the PAR is fixed too, there's not much to do
725 * except choosing the width that is nearest to the
726 * width with the same DAR */
727 if (gst_value_is_fixed (to_par)) {
728 to_par_n = gst_value_get_fraction_numerator (to_par);
729 to_par_d = gst_value_get_fraction_denominator (to_par);
731 GST_DEBUG_OBJECT (base, "PAR is fixed %d/%d", to_par_n, to_par_d);
733 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
734 to_par_n, &num, &den)) {
735 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
736 ("Error calculating the output scaled size - integer overflow"));
740 w = (guint) gst_util_uint64_scale_int_round (h, num, den);
741 gst_structure_fixate_field_nearest_int (outs, "width", w);
746 /* The PAR is not fixed and it's quite likely that we can set
747 * an arbitrary PAR. */
749 /* Check if we can keep the input width */
750 tmp = gst_structure_copy (outs);
751 gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
752 gst_structure_get_int (tmp, "width", &set_w);
754 /* Might have failed but try to keep the DAR nonetheless by
755 * adjusting the PAR */
756 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, h, set_w,
757 &to_par_n, &to_par_d)) {
758 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
759 ("Error calculating the output scaled size - integer overflow"));
760 gst_structure_free (tmp);
764 if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
765 gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
766 gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
768 gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
770 gst_structure_free (tmp);
772 /* Check if the adjusted PAR is accepted */
773 if (set_par_n == to_par_n && set_par_d == to_par_d) {
774 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
775 set_par_n != set_par_d)
776 gst_structure_set (outs, "width", G_TYPE_INT, set_w,
777 "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
782 /* Otherwise scale the width to the new PAR and check if the
783 * adjusted with is accepted. If all that fails we can't keep
785 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
786 set_par_n, &num, &den)) {
787 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
788 ("Error calculating the output scaled size - integer overflow"));
792 w = (guint) gst_util_uint64_scale_int_round (h, num, den);
793 gst_structure_fixate_field_nearest_int (outs, "width", w);
794 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
795 set_par_n != set_par_d)
796 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
797 set_par_n, set_par_d, NULL);
802 gint set_h, set_par_n, set_par_d;
804 GST_DEBUG_OBJECT (base, "width is fixed (%d)", w);
806 /* If the PAR is fixed too, there's not much to do
807 * except choosing the height that is nearest to the
808 * height with the same DAR */
809 if (gst_value_is_fixed (to_par)) {
810 to_par_n = gst_value_get_fraction_numerator (to_par);
811 to_par_d = gst_value_get_fraction_denominator (to_par);
813 GST_DEBUG_OBJECT (base, "PAR is fixed %d/%d", to_par_n, to_par_d);
815 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
816 to_par_n, &num, &den)) {
817 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
818 ("Error calculating the output scaled size - integer overflow"));
822 h = (guint) gst_util_uint64_scale_int_round (w, den, num);
823 gst_structure_fixate_field_nearest_int (outs, "height", h);
828 /* The PAR is not fixed and it's quite likely that we can set
829 * an arbitrary PAR. */
831 /* Check if we can keep the input height */
832 tmp = gst_structure_copy (outs);
833 gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
834 gst_structure_get_int (tmp, "height", &set_h);
836 /* Might have failed but try to keep the DAR nonetheless by
837 * adjusting the PAR */
838 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, w,
839 &to_par_n, &to_par_d)) {
840 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
841 ("Error calculating the output scaled size - integer overflow"));
842 gst_structure_free (tmp);
845 if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
846 gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
847 gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
849 gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
851 gst_structure_free (tmp);
853 /* Check if the adjusted PAR is accepted */
854 if (set_par_n == to_par_n && set_par_d == to_par_d) {
855 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
856 set_par_n != set_par_d)
857 gst_structure_set (outs, "height", G_TYPE_INT, set_h,
858 "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
863 /* Otherwise scale the height to the new PAR and check if the
864 * adjusted with is accepted. If all that fails we can't keep
866 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
867 set_par_n, &num, &den)) {
868 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
869 ("Error calculating the output scale sized - integer overflow"));
873 h = (guint) gst_util_uint64_scale_int_round (w, den, num);
874 gst_structure_fixate_field_nearest_int (outs, "height", h);
875 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
876 set_par_n != set_par_d)
877 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
878 set_par_n, set_par_d, NULL);
881 } else if (gst_value_is_fixed (to_par)) {
883 gint set_h, set_w, f_h, f_w;
885 to_par_n = gst_value_get_fraction_numerator (to_par);
886 to_par_d = gst_value_get_fraction_denominator (to_par);
888 /* Calculate scale factor for the PAR change */
889 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n,
890 to_par_d, &num, &den)) {
891 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
892 ("Error calculating the output scaled size - integer overflow"));
896 /* Try to keep the input height (because of interlacing) */
897 tmp = gst_structure_copy (outs);
898 gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
899 gst_structure_get_int (tmp, "height", &set_h);
901 /* This might have failed but try to scale the width
902 * to keep the DAR nonetheless */
903 w = (guint) gst_util_uint64_scale_int_round (set_h, num, den);
904 gst_structure_fixate_field_nearest_int (tmp, "width", w);
905 gst_structure_get_int (tmp, "width", &set_w);
906 gst_structure_free (tmp);
908 /* We kept the DAR and the height is nearest to the original height */
910 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
911 G_TYPE_INT, set_h, NULL);
918 /* If the former failed, try to keep the input width at least */
919 tmp = gst_structure_copy (outs);
920 gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
921 gst_structure_get_int (tmp, "width", &set_w);
923 /* This might have failed but try to scale the width
924 * to keep the DAR nonetheless */
925 h = (guint) gst_util_uint64_scale_int_round (set_w, den, num);
926 gst_structure_fixate_field_nearest_int (tmp, "height", h);
927 gst_structure_get_int (tmp, "height", &set_h);
928 gst_structure_free (tmp);
930 /* We kept the DAR and the width is nearest to the original width */
932 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
933 G_TYPE_INT, set_h, NULL);
937 /* If all this failed, keep the dimensions with the DAR that was closest
938 * to the correct DAR. This changes the DAR but there's not much else to
941 if (set_w * ABS (set_h - h) < ABS (f_w - w) * f_h) {
945 gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT,
950 gint set_h, set_w, set_par_n, set_par_d, tmp2;
952 /* width, height and PAR are not fixed but passthrough is not possible */
954 /* First try to keep the height and width as good as possible
956 tmp = gst_structure_copy (outs);
957 gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
958 gst_structure_get_int (tmp, "height", &set_h);
959 gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
960 gst_structure_get_int (tmp, "width", &set_w);
962 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w,
963 &to_par_n, &to_par_d)) {
964 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
965 ("Error calculating the output scaled size - integer overflow"));
966 gst_structure_free (tmp);
970 if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
971 gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
972 gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
974 gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
976 gst_structure_free (tmp);
978 if (set_par_n == to_par_n && set_par_d == to_par_d) {
979 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
980 G_TYPE_INT, set_h, NULL);
982 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
983 set_par_n != set_par_d)
984 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
985 set_par_n, set_par_d, NULL);
989 /* Otherwise try to scale width to keep the DAR with the set
991 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
992 set_par_n, &num, &den)) {
993 GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
994 ("Error calculating the output scaled size - integer overflow"));
998 w = (guint) gst_util_uint64_scale_int_round (set_h, num, den);
999 tmp = gst_structure_copy (outs);
1000 gst_structure_fixate_field_nearest_int (tmp, "width", w);
1001 gst_structure_get_int (tmp, "width", &tmp2);
1002 gst_structure_free (tmp);
1005 gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height",
1006 G_TYPE_INT, set_h, NULL);
1007 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
1008 set_par_n != set_par_d)
1009 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1010 set_par_n, set_par_d, NULL);
1014 /* ... or try the same with the height */
1015 h = (guint) gst_util_uint64_scale_int_round (set_w, den, num);
1016 tmp = gst_structure_copy (outs);
1017 gst_structure_fixate_field_nearest_int (tmp, "height", h);
1018 gst_structure_get_int (tmp, "height", &tmp2);
1019 gst_structure_free (tmp);
1022 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
1023 G_TYPE_INT, tmp2, NULL);
1024 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
1025 set_par_n != set_par_d)
1026 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1027 set_par_n, set_par_d, NULL);
1031 /* If all fails we can't keep the DAR and take the nearest values
1032 * for everything from the first try */
1033 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
1034 G_TYPE_INT, set_h, NULL);
1035 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
1036 set_par_n != set_par_d)
1037 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1038 set_par_n, set_par_d, NULL);
1043 if (from_par == &fpar)
1044 g_value_unset (&fpar);
1045 if (to_par == &tpar)
1046 g_value_unset (&tpar);
1052 gst_cuda_base_convert_fixate_caps (GstBaseTransform * trans,
1053 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
1055 GstCaps *format = NULL;
1057 GST_DEBUG_OBJECT (trans,
1058 "trying to fixate othercaps %" GST_PTR_FORMAT " based on caps %"
1059 GST_PTR_FORMAT, othercaps, caps);
1061 format = gst_cuda_base_convert_get_fixed_format (trans, direction, caps,
1064 if (gst_caps_is_empty (format)) {
1065 GST_ERROR_OBJECT (trans, "Could not convert formats");
1069 /* convert mode is "all" or "size" here */
1071 gst_cuda_base_convert_fixate_size (trans, direction, caps, othercaps);
1073 if (gst_caps_get_size (othercaps) == 1) {
1075 const gchar *format_fields[] = { "format", "colorimetry", "chroma-site" };
1076 GstStructure *format_struct = gst_caps_get_structure (format, 0);
1077 GstStructure *fixated_struct;
1079 othercaps = gst_caps_make_writable (othercaps);
1080 fixated_struct = gst_caps_get_structure (othercaps, 0);
1082 for (i = 0; i < G_N_ELEMENTS (format_fields); i++) {
1083 if (gst_structure_has_field (format_struct, format_fields[i])) {
1084 gst_structure_set (fixated_struct, format_fields[i], G_TYPE_STRING,
1085 gst_structure_get_string (format_struct, format_fields[i]), NULL);
1087 gst_structure_remove_field (fixated_struct, format_fields[i]);
1091 gst_caps_unref (format);
1093 GST_DEBUG_OBJECT (trans, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
1099 gst_cuda_base_convert_propose_allocation (GstBaseTransform * trans,
1100 GstQuery * decide_query, GstQuery * query)
1102 GstCudaBaseTransform *ctrans = GST_CUDA_BASE_TRANSFORM (trans);
1104 GstBufferPool *pool;
1108 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
1109 decide_query, query))
1112 /* passthrough, we're done */
1113 if (decide_query == NULL)
1116 gst_query_parse_allocation (query, &caps, NULL);
1121 if (!gst_video_info_from_caps (&info, caps))
1124 if (gst_query_get_n_allocation_pools (query) == 0) {
1125 GstStructure *config;
1127 pool = gst_cuda_buffer_pool_new (ctrans->context);
1129 config = gst_buffer_pool_get_config (pool);
1131 gst_buffer_pool_config_add_option (config,
1132 GST_BUFFER_POOL_OPTION_VIDEO_META);
1134 size = GST_VIDEO_INFO_SIZE (&info);
1135 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
1137 if (!gst_buffer_pool_set_config (pool, config)) {
1138 GST_ERROR_OBJECT (ctrans, "failed to set config");
1139 gst_object_unref (pool);
1143 /* Get updated size by cuda buffer pool */
1144 config = gst_buffer_pool_get_config (pool);
1145 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
1146 gst_structure_free (config);
1148 gst_query_add_allocation_pool (query, pool, size, 0, 0);
1150 gst_object_unref (pool);
1153 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1159 gst_cuda_base_convert_decide_allocation (GstBaseTransform * trans,
1162 GstCudaBaseTransform *ctrans = GST_CUDA_BASE_TRANSFORM (trans);
1163 GstCaps *outcaps = NULL;
1164 GstBufferPool *pool = NULL;
1165 guint size, min, max;
1166 GstStructure *config;
1167 gboolean update_pool = FALSE;
1169 gst_query_parse_allocation (query, &outcaps, NULL);
1174 if (gst_query_get_n_allocation_pools (query) > 0) {
1175 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1177 if (!GST_IS_CUDA_BUFFER_POOL (pool)) {
1178 gst_clear_object (&pool);
1180 GstCudaBufferPool *cpool = GST_CUDA_BUFFER_POOL (pool);
1182 if (cpool->context != ctrans->context) {
1183 gst_clear_object (&pool);
1191 gst_video_info_from_caps (&vinfo, outcaps);
1192 size = GST_VIDEO_INFO_SIZE (&vinfo);
1197 GST_DEBUG_OBJECT (ctrans, "create our pool");
1199 pool = gst_cuda_buffer_pool_new (ctrans->context);
1202 config = gst_buffer_pool_get_config (pool);
1203 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1204 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1205 gst_buffer_pool_set_config (pool, config);
1207 /* Get updated size by cuda buffer pool */
1208 config = gst_buffer_pool_get_config (pool);
1209 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
1210 gst_structure_free (config);
1213 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1215 gst_query_add_allocation_pool (query, pool, size, min, max);
1217 gst_object_unref (pool);
1219 return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
1224 gst_cuda_base_convert_set_info (GstCudaBaseTransform * btrans,
1225 GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
1226 GstVideoInfo * out_info)
1228 GstCudaBaseConvert *self = GST_CUDA_BASE_CONVERT (btrans);
1229 gint from_dar_n, from_dar_d, to_dar_n, to_dar_d;
1230 GstVideoInfo tmp_info;
1232 g_clear_pointer (&self->converter, gst_cuda_converter_free);
1234 if (!gst_util_fraction_multiply (in_info->width,
1235 in_info->height, in_info->par_n, in_info->par_d, &from_dar_n,
1237 from_dar_n = from_dar_d = -1;
1240 if (!gst_util_fraction_multiply (out_info->width,
1241 out_info->height, out_info->par_n, out_info->par_d, &to_dar_n,
1243 to_dar_n = to_dar_d = -1;
1246 self->borders_w = self->borders_h = 0;
1247 if (to_dar_n != from_dar_n || to_dar_d != from_dar_d) {
1248 if (self->add_borders) {
1249 gint n, d, to_h, to_w;
1251 if (from_dar_n != -1 && from_dar_d != -1
1252 && gst_util_fraction_multiply (from_dar_n, from_dar_d,
1253 out_info->par_d, out_info->par_n, &n, &d)) {
1254 to_h = gst_util_uint64_scale_int (out_info->width, d, n);
1255 if (to_h <= out_info->height) {
1256 self->borders_h = out_info->height - to_h;
1257 self->borders_w = 0;
1259 to_w = gst_util_uint64_scale_int (out_info->height, n, d);
1260 g_assert (to_w <= out_info->width);
1261 self->borders_h = 0;
1262 self->borders_w = out_info->width - to_w;
1265 GST_WARNING_OBJECT (self, "Can't calculate borders");
1268 GST_WARNING_OBJECT (self, "Can't keep DAR!");
1272 /* if present, these must match */
1273 if (in_info->interlace_mode != out_info->interlace_mode) {
1274 GST_ERROR_OBJECT (self, "input and output formats do not match");
1278 /* if the only thing different in the caps is the transfer function, and
1279 * we're converting between equivalent transfer functions, do passthrough */
1280 tmp_info = *in_info;
1281 tmp_info.colorimetry.transfer = out_info->colorimetry.transfer;
1282 if (gst_video_info_is_equal (&tmp_info, out_info) &&
1283 gst_video_transfer_function_is_equivalent (in_info->colorimetry.transfer,
1284 in_info->finfo->bits, out_info->colorimetry.transfer,
1285 out_info->finfo->bits)) {
1286 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (self), TRUE);
1288 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (self), FALSE);
1290 self->converter = gst_cuda_converter_new (in_info,
1291 out_info, btrans->context);
1292 if (!self->converter) {
1293 GST_ERROR_OBJECT (self, "Couldn't create converter");
1298 GST_DEBUG_OBJECT (self, "%s from=%dx%d (par=%d/%d dar=%d/%d), size %"
1299 G_GSIZE_FORMAT " -> %s to=%dx%d (par=%d/%d dar=%d/%d borders=%d:%d), "
1300 "size %" G_GSIZE_FORMAT,
1301 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
1302 in_info->width, in_info->height, in_info->par_n, in_info->par_d,
1303 from_dar_n, from_dar_d, in_info->size,
1304 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)),
1306 out_info->height, out_info->par_n, out_info->par_d, to_dar_n, to_dar_d,
1307 self->borders_w, self->borders_h, out_info->size);
1313 gst_cuda_base_convert_filter_meta (GstBaseTransform * trans, GstQuery * query,
1314 GType api, const GstStructure * params)
1316 /* This element cannot passthrough the crop meta, because it would convert the
1317 * wrong sub-region of the image, and worst, our output image may not be large
1318 * enough for the crop to be applied later */
1319 if (api == GST_VIDEO_CROP_META_API_TYPE)
1322 /* propose all other metadata upstream */
1326 static GstFlowReturn
1327 gst_cuda_base_convert_transform (GstBaseTransform * trans,
1328 GstBuffer * inbuf, GstBuffer * outbuf)
1330 GstCudaBaseConvert *self = GST_CUDA_BASE_CONVERT (trans);
1331 GstCudaBaseTransform *btrans = GST_CUDA_BASE_TRANSFORM (trans);
1332 GstVideoFrame in_frame, out_frame;
1333 GstFlowReturn ret = GST_FLOW_OK;
1336 if (gst_buffer_n_memory (inbuf) != 1) {
1337 GST_ERROR_OBJECT (self, "Invalid input buffer");
1338 return GST_FLOW_ERROR;
1341 mem = gst_buffer_peek_memory (inbuf, 0);
1342 if (!gst_is_cuda_memory (mem)) {
1343 GST_ERROR_OBJECT (self, "Input buffer is not CUDA");
1344 return GST_FLOW_ERROR;
1347 if (gst_buffer_n_memory (outbuf) != 1) {
1348 GST_ERROR_OBJECT (self, "Invalid output buffer");
1349 return GST_FLOW_ERROR;
1352 mem = gst_buffer_peek_memory (outbuf, 0);
1353 if (!gst_is_cuda_memory (mem)) {
1354 GST_ERROR_OBJECT (self, "Input buffer is not CUDA");
1355 return GST_FLOW_ERROR;
1358 if (!gst_video_frame_map (&in_frame, &btrans->in_info, inbuf,
1359 GST_MAP_READ | GST_MAP_CUDA)) {
1360 GST_ERROR_OBJECT (self, "Failed to map input buffer");
1361 return GST_FLOW_ERROR;
1364 if (!gst_video_frame_map (&out_frame, &btrans->out_info, outbuf,
1365 GST_MAP_WRITE | GST_MAP_CUDA)) {
1366 gst_video_frame_unmap (&in_frame);
1367 GST_ERROR_OBJECT (self, "Failed to map output buffer");
1368 return GST_FLOW_ERROR;
1371 if (!gst_cuda_converter_convert_frame (self->converter, &in_frame, &out_frame,
1372 btrans->cuda_stream)) {
1373 GST_ERROR_OBJECT (self, "Failed to convert frame");
1374 ret = GST_FLOW_ERROR;
1377 gst_video_frame_unmap (&out_frame);
1378 gst_video_frame_unmap (&in_frame);
1384 * SECTION:element-cudaconvertscale
1385 * @title: cudaconvertscale
1386 * @short_description: A CUDA based color conversion and video resizing element
1388 * This element resizes video frames and change color space.
1389 * By default the element will try to negotiate to the same size on the source
1390 * and sinkpad so that no scaling is needed.
1391 * It is therefore safe to insert this element in a pipeline to
1392 * get more robust behaviour without any cost if no scaling is needed.
1394 * ## Example launch line
1396 * gst-launch-1.0 videotestsrc ! cudaupload ! cudaconvertscale ! cudadownload ! autovideosink
1402 struct _GstCudaConvertScale
1404 GstCudaBaseConvert parent;
1407 G_DEFINE_TYPE (GstCudaConvertScale, gst_cuda_convert_scale,
1408 GST_TYPE_CUDA_BASE_CONVERT);
1411 gst_cuda_convert_scale_class_init (GstCudaConvertScaleClass * klass)
1413 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1415 gst_element_class_set_static_metadata (element_class,
1416 "CUDA colorspace converter and scaler",
1417 "Filter/Converter/Video/Scaler/Colorspace/Hardware",
1418 "Resizes video and allow color conversion using CUDA",
1419 "Seungha Yang <seungha@centricular.com>");
1423 gst_cuda_convert_scale_init (GstCudaConvertScale * self)
1428 * SECTION:element-cudaconvert
1429 * @title: cudaconvert
1431 * Convert video frames between supported video formats.
1433 * ## Example launch line
1435 * gst-launch-1.0 videotestsrc ! cudaupload ! cudaconvert ! cudadownload ! autovideosink
1441 struct _GstCudaConvert
1443 GstCudaBaseConvert parent;
1446 static GstCaps *gst_cuda_convert_transform_caps (GstBaseTransform *
1447 trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter);
1448 static GstCaps *gst_cuda_convert_fixate_caps (GstBaseTransform * base,
1449 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
1451 G_DEFINE_TYPE (GstCudaConvert, gst_cuda_convert, GST_TYPE_CUDA_BASE_CONVERT);
1454 gst_cuda_convert_class_init (GstCudaConvertClass * klass)
1456 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1457 GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
1459 gst_element_class_set_static_metadata (element_class,
1460 "CUDA colorspace converter",
1461 "Filter/Converter/Video/Hardware",
1462 "Converts video from one colorspace to another using CUDA",
1463 "Seungha Yang <seungha.yang@navercorp.com>");
1465 trans_class->transform_caps =
1466 GST_DEBUG_FUNCPTR (gst_cuda_convert_transform_caps);
1467 trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_cuda_convert_fixate_caps);
1471 gst_cuda_convert_init (GstCudaConvert * self)
1476 gst_cuda_convert_transform_caps (GstBaseTransform *
1477 trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1479 GstCaps *tmp, *tmp2;
1482 /* Get all possible caps that we can transform to */
1483 tmp = gst_cuda_base_convert_caps_remove_format_info (caps);
1486 tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
1487 gst_caps_unref (tmp);
1493 GST_DEBUG_OBJECT (trans, "transformed %" GST_PTR_FORMAT " into %"
1494 GST_PTR_FORMAT, caps, result);
1500 gst_cuda_convert_fixate_caps (GstBaseTransform * base,
1501 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
1503 GstCaps *format = NULL;
1505 GST_DEBUG_OBJECT (base,
1506 "trying to fixate othercaps %" GST_PTR_FORMAT " based on caps %"
1507 GST_PTR_FORMAT, othercaps, caps);
1509 format = gst_cuda_base_convert_get_fixed_format (base, direction, caps,
1511 gst_caps_unref (othercaps);
1513 if (gst_caps_is_empty (format)) {
1514 GST_ERROR_OBJECT (base, "Could not convert formats");
1516 GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, format);
1523 * SECTION:element-cudascale
1526 * A CUDA based video resizing element
1528 * ## Example launch line
1530 * gst-launch-1.0 videotestsrc ! video/x-raw,width=640,height=480 ! cudaupload ! cudascale ! cudadownload ! video/x-raw,width=1280,height=720 ! fakesink
1532 * This will upload a 640x480 resolution test video to CUDA
1533 * memory space and resize it to 1280x720 resolution. Then a resized CUDA
1534 * frame will be downloaded to system memory space.
1539 struct _GstCudaScale
1541 GstCudaBaseConvert parent;
1544 static GstCaps *gst_cuda_scale_transform_caps (GstBaseTransform *
1545 trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter);
1546 static GstCaps *gst_cuda_scale_fixate_caps (GstBaseTransform * base,
1547 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
1549 G_DEFINE_TYPE (GstCudaScale, gst_cuda_scale, GST_TYPE_CUDA_BASE_CONVERT);
1552 gst_cuda_scale_class_init (GstCudaScaleClass * klass)
1554 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1555 GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
1557 gst_element_class_set_static_metadata (element_class,
1558 "CUDA video scaler",
1559 "Filter/Converter/Video/Scaler/Hardware",
1560 "Resize video using CUDA", "Seungha Yang <seungha.yang@navercorp.com>");
1562 trans_class->transform_caps =
1563 GST_DEBUG_FUNCPTR (gst_cuda_scale_transform_caps);
1564 trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_cuda_scale_fixate_caps);
1568 gst_cuda_scale_init (GstCudaScale * self)
1573 gst_cuda_scale_transform_caps (GstBaseTransform * trans,
1574 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1576 GstCaps *tmp, *tmp2;
1579 /* Get all possible caps that we can transform to */
1580 tmp = gst_cuda_base_convert_caps_rangify_size_info (caps);
1583 tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
1584 gst_caps_unref (tmp);
1590 GST_DEBUG_OBJECT (trans, "transformed %" GST_PTR_FORMAT " into %"
1591 GST_PTR_FORMAT, caps, result);
1597 gst_cuda_scale_fixate_caps (GstBaseTransform * base,
1598 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
1600 GST_DEBUG_OBJECT (base,
1601 "trying to fixate othercaps %" GST_PTR_FORMAT " based on caps %"
1602 GST_PTR_FORMAT, othercaps, caps);
1605 gst_cuda_base_convert_fixate_size (base, direction, caps, othercaps);
1607 GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);