2 * Copyright (C) 2017 Ericsson AB. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <gst/cuda/gstcudautils.h>
33 #include <gst/cuda/gstcudabufferpool.h>
35 #include "gstcuvidloader.h"
40 GST_DEBUG_CATEGORY_EXTERN (gst_nvdec_debug);
41 #define GST_CAT_DEFAULT gst_nvdec_debug
43 #define DEFAULT_MAX_DISPLAY_DELAY -1
48 PROP_MAX_DISPLAY_DELAY,
52 #ifdef HAVE_NVCODEC_GST_GL
53 #define SUPPORTED_GL_APIS (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)
56 gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
57 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
61 gst_nvdec_copy_device_to_memory (GstNvDec * nvdec,
62 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
64 #ifdef HAVE_NVCODEC_GST_GL
65 typedef struct _GstNvDecRegisterResourceData
68 GstCudaGraphicsResource *resource;
71 } GstNvDecRegisterResourceData;
74 register_cuda_resource (GstGLContext * context,
75 GstNvDecRegisterResourceData * data)
77 GstMemory *mem = data->mem;
78 GstCudaGraphicsResource *resource = data->resource;
79 GstNvDec *nvdec = data->nvdec;
80 GstMapInfo map_info = GST_MAP_INFO_INIT;
81 GstGLBuffer *gl_buf_obj;
85 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
86 GST_WARNING_OBJECT (nvdec, "failed to push CUDA context");
90 if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) {
91 GstGLMemoryPBO *gl_mem = (GstGLMemoryPBO *) data->mem;
92 gl_buf_obj = gl_mem->pbo;
94 GST_LOG_OBJECT (nvdec,
95 "register glbuffer %d to CUDA resource", gl_buf_obj->id);
97 /* register resource without read/write only flags, since
98 * downstream CUDA elements (e.g., nvenc) might want to access
99 * this resource later. Instead, use map flags during map/unmap */
100 if (gst_cuda_graphics_resource_register_gl_buffer (resource,
101 gl_buf_obj->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) {
104 GST_WARNING_OBJECT (nvdec, "failed to register memory");
107 gst_memory_unmap (mem, &map_info);
109 GST_WARNING_OBJECT (nvdec, "failed to map memory");
112 if (!gst_cuda_context_pop (NULL))
113 GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
116 static GstCudaGraphicsResource *
117 ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
120 GstCudaGraphicsResource *cgr_info;
121 GstNvDecRegisterResourceData data;
123 if (!gst_is_gl_memory_pbo (mem)) {
124 GST_WARNING_OBJECT (nvdec, "memory is not GL PBO memory, %s",
125 mem->allocator->mem_type);
129 quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
131 cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
133 cgr_info = gst_cuda_graphics_resource_new (nvdec->cuda_ctx,
134 GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context),
135 GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER);
137 data.resource = cgr_info;
139 gst_gl_context_thread_add ((GstGLContext *) cgr_info->graphics_context,
140 (GstGLContextThreadFunc) register_cuda_resource, &data);
142 GST_WARNING_OBJECT (nvdec, "could not register resource");
143 gst_cuda_graphics_resource_free (cgr_info);
148 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
149 (GDestroyNotify) gst_cuda_graphics_resource_free);
154 #endif /* HAVE_NVCODEC_GST_GL */
156 static gboolean gst_nvdec_open (GstVideoDecoder * decoder);
157 static gboolean gst_nvdec_start (GstVideoDecoder * decoder);
158 static gboolean gst_nvdec_stop (GstVideoDecoder * decoder);
159 static gboolean gst_nvdec_close (GstVideoDecoder * decoder);
160 static gboolean gst_nvdec_set_format (GstVideoDecoder * decoder,
161 GstVideoCodecState * state);
162 static GstFlowReturn gst_nvdec_handle_frame (GstVideoDecoder * decoder,
163 GstVideoCodecFrame * frame);
164 static gboolean gst_nvdec_decide_allocation (GstVideoDecoder * decoder,
166 static void gst_nvdec_set_context (GstElement * element, GstContext * context);
167 static gboolean gst_nvdec_src_query (GstVideoDecoder * decoder,
169 static gboolean gst_nvdec_flush (GstVideoDecoder * decoder);
170 static GstFlowReturn gst_nvdec_drain (GstVideoDecoder * decoder);
171 static GstFlowReturn gst_nvdec_finish (GstVideoDecoder * decoder);
172 static gboolean gst_nvdec_negotiate (GstVideoDecoder * decoder);
173 #ifdef HAVE_NVCODEC_GST_GL
174 static gboolean gst_nvdec_ensure_gl_context (GstNvDec * nvdec);
177 #define gst_nvdec_parent_class parent_class
178 G_DEFINE_ABSTRACT_TYPE (GstNvDec, gst_nvdec, GST_TYPE_VIDEO_DECODER);
181 gst_nv_dec_set_property (GObject * object, guint prop_id, const GValue * value,
184 GstNvDec *nvdec = GST_NVDEC (object);
187 case PROP_MAX_DISPLAY_DELAY:
188 nvdec->max_display_delay = g_value_get_int (value);
191 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197 gst_nv_dec_get_property (GObject * object, guint prop_id, GValue * value,
200 GstNvDec *nvdec = GST_NVDEC (object);
201 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
204 case PROP_MAX_DISPLAY_DELAY:
205 g_value_set_int (value, nvdec->max_display_delay);
207 case PROP_CUDA_DEVICE_ID:
208 g_value_set_uint (value, klass->cuda_device_id);
211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
217 gst_nvdec_class_init (GstNvDecClass * klass)
219 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
220 GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
221 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
223 gobject_class->set_property = gst_nv_dec_set_property;
224 gobject_class->get_property = gst_nv_dec_get_property;
226 video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_nvdec_open);
227 video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_nvdec_start);
228 video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_nvdec_stop);
229 video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_nvdec_close);
230 video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_nvdec_set_format);
231 video_decoder_class->handle_frame =
232 GST_DEBUG_FUNCPTR (gst_nvdec_handle_frame);
233 video_decoder_class->decide_allocation =
234 GST_DEBUG_FUNCPTR (gst_nvdec_decide_allocation);
235 video_decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_nvdec_src_query);
236 video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_nvdec_drain);
237 video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_nvdec_flush);
238 video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_nvdec_finish);
239 video_decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_nvdec_negotiate);
241 element_class->set_context = GST_DEBUG_FUNCPTR (gst_nvdec_set_context);
242 gst_type_mark_as_plugin_api (GST_TYPE_NVDEC, 0);
245 * GstNvDec:max-display-delay:
249 g_object_class_install_property (gobject_class, PROP_MAX_DISPLAY_DELAY,
250 g_param_spec_int ("max-display-delay", "Max Display Delay",
251 "Improves pipelining of decode with display, 0 means no delay "
253 -1, G_MAXINT, DEFAULT_MAX_DISPLAY_DELAY,
254 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
257 * GstNvDec:cuda-device-id:
259 * Assigned CUDA device id
263 g_object_class_install_property (gobject_class, PROP_CUDA_DEVICE_ID,
264 g_param_spec_uint ("cuda-device-id", "CUDA device id",
265 "Assigned CUDA device id", 0, G_MAXINT, 0,
266 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
270 gst_nvdec_init (GstNvDec * nvdec)
272 nvdec->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY;
273 gst_video_decoder_set_packetized (GST_VIDEO_DECODER (nvdec), TRUE);
274 gst_video_decoder_set_needs_format (GST_VIDEO_DECODER (nvdec), TRUE);
277 static cudaVideoSurfaceFormat
278 get_cuda_surface_format_from_gst (GstVideoFormat format)
281 case GST_VIDEO_FORMAT_NV12:
282 return cudaVideoSurfaceFormat_NV12;
283 case GST_VIDEO_FORMAT_P010_10LE:
284 case GST_VIDEO_FORMAT_P010_10BE:
285 case GST_VIDEO_FORMAT_P016_LE:
286 case GST_VIDEO_FORMAT_P016_BE:
287 return cudaVideoSurfaceFormat_P016;
288 case GST_VIDEO_FORMAT_Y444:
289 return cudaVideoSurfaceFormat_YUV444;
290 case GST_VIDEO_FORMAT_Y444_16LE:
291 case GST_VIDEO_FORMAT_Y444_16BE:
292 return cudaVideoSurfaceFormat_YUV444_16Bit;
294 g_assert_not_reached ();
298 return cudaVideoSurfaceFormat_NV12;
302 calculate_num_decode_surface (cudaVideoCodec codec, guint width, guint height)
305 case cudaVideoCodec_VP9:
307 case cudaVideoCodec_H264:
308 case cudaVideoCodec_H264_SVC:
309 case cudaVideoCodec_H264_MVC:
311 case cudaVideoCodec_HEVC:{
314 const gint MaxDpbPicBuf = 6;
315 gint PicSizeInSamplesY;
318 MaxLumaPS = 35651584;
319 PicSizeInSamplesY = width * height;
320 if (PicSizeInSamplesY <= (MaxLumaPS >> 2))
321 max_dpb_size = MaxDpbPicBuf * 4;
322 else if (PicSizeInSamplesY <= (MaxLumaPS >> 1))
323 max_dpb_size = MaxDpbPicBuf * 2;
324 else if (PicSizeInSamplesY <= ((3 * MaxLumaPS) >> 2))
325 max_dpb_size = (MaxDpbPicBuf * 4) / 3;
327 max_dpb_size = MaxDpbPicBuf;
329 max_dpb_size = MIN (max_dpb_size, 16);
331 return max_dpb_size + 4;
341 gst_nvdec_get_max_display_delay (GstNvDec * nvdec)
343 return nvdec->max_display_delay >= 0 ? nvdec->max_display_delay :
344 (nvdec->is_live ? 0 : 4);
348 gst_nvdec_get_latency (GstNvDec * nvdec)
352 if (!nvdec->input_state)
354 fps_n = GST_VIDEO_INFO_FPS_N (&nvdec->input_state->info);
355 fps_d = GST_VIDEO_INFO_FPS_D (&nvdec->input_state->info);
357 /* We assume 25 fps if the input framerate is invalid */
358 if (fps_n < 1 || fps_d < 1) {
363 return gst_util_uint64_scale_int ((nvdec->num_decode_surface +
364 gst_nvdec_get_max_display_delay (nvdec)) * GST_SECOND, fps_d, fps_n);
367 /* 0: fail, 1: succeeded, > 1: override dpb size of parser
368 * (set by CUVIDPARSERPARAMS::ulMaxNumDecodeSurfaces while creating parser) */
370 parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
373 CUVIDDECODECREATEINFO create_info = { 0, };
374 GstVideoFormat out_format;
375 GstVideoInfo *in_info = &nvdec->input_state->info;
376 GstVideoInfo *out_info = &nvdec->out_info;
377 GstVideoInfo prev_out_info = *out_info;
378 GstCudaContext *ctx = nvdec->cuda_ctx;
379 GstStructure *in_s = NULL;
380 gboolean updata = FALSE;
381 guint major_api_ver = 0;
382 guint64 curr_latency, old_latency;
384 old_latency = gst_nvdec_get_latency (nvdec);
385 width = format->display_area.right - format->display_area.left;
386 height = format->display_area.bottom - format->display_area.top;
388 switch (format->chroma_format) {
389 case cudaVideoChromaFormat_444:
390 if (format->bit_depth_luma_minus8 == 0) {
391 out_format = GST_VIDEO_FORMAT_Y444;
392 } else if (format->bit_depth_luma_minus8 == 2 ||
393 format->bit_depth_luma_minus8 == 4) {
394 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
395 out_format = GST_VIDEO_FORMAT_Y444_16LE;
397 out_format = GST_VIDEO_FORMAT_Y444_16BE;
400 GST_ERROR_OBJECT (nvdec, "Unknown 4:4:4 format bitdepth %d",
401 format->bit_depth_luma_minus8 + 8);
403 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
407 case cudaVideoChromaFormat_420:
408 if (format->bit_depth_luma_minus8 == 0) {
409 out_format = GST_VIDEO_FORMAT_NV12;
410 } else if (format->bit_depth_luma_minus8 == 2) {
411 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
412 out_format = GST_VIDEO_FORMAT_P010_10LE;
414 out_format = GST_VIDEO_FORMAT_P010_10BE;
416 } else if (format->bit_depth_luma_minus8 == 4) {
417 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
418 out_format = GST_VIDEO_FORMAT_P016_LE;
420 out_format = GST_VIDEO_FORMAT_P016_BE;
423 GST_ERROR_OBJECT (nvdec, "Unknown 4:2:0 format bitdepth %d",
424 format->bit_depth_luma_minus8 + 8);
426 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
431 GST_ERROR_OBJECT (nvdec, "unhandled chroma format %d, bitdepth %d",
432 format->chroma_format, format->bit_depth_luma_minus8 + 8);
434 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
438 GST_DEBUG_OBJECT (nvdec,
439 "out format: %s", gst_video_format_to_string (out_format));
441 GST_DEBUG_OBJECT (nvdec, "width: %u, height: %u", width, height);
443 gst_video_info_set_format (out_info, out_format, width, height);
444 GST_VIDEO_INFO_FPS_N (out_info) = GST_VIDEO_INFO_FPS_N (in_info);
445 GST_VIDEO_INFO_FPS_D (out_info) = GST_VIDEO_INFO_FPS_D (in_info);
447 if (GST_VIDEO_INFO_FPS_N (out_info) < 1 ||
448 GST_VIDEO_INFO_FPS_D (out_info) < 1) {
449 GST_VIDEO_INFO_FPS_N (out_info) = format->frame_rate.numerator;
450 GST_VIDEO_INFO_FPS_D (out_info) = MAX (1, format->frame_rate.denominator);
453 GST_LOG_OBJECT (nvdec,
454 "Reading colorimetry information full-range %d matrix %d transfer %d primaries %d",
455 format->video_signal_description.video_full_range_flag,
456 format->video_signal_description.matrix_coefficients,
457 format->video_signal_description.transfer_characteristics,
458 format->video_signal_description.color_primaries);
460 if (nvdec->input_state->caps)
461 in_s = gst_caps_get_structure (nvdec->input_state->caps, 0);
463 /* Set colorimetry when upstream did not provide it */
464 if (in_s && !gst_structure_has_field (in_s, "colorimetry")) {
465 GstVideoColorimetry colorimetry = { 0, };
467 if (format->video_signal_description.video_full_range_flag)
468 colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
470 colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
472 colorimetry.primaries =
473 gst_video_color_primaries_from_iso
474 (format->video_signal_description.color_primaries);
476 colorimetry.transfer =
477 gst_video_transfer_function_from_iso
478 (format->video_signal_description.transfer_characteristics);
481 gst_video_color_matrix_from_iso
482 (format->video_signal_description.matrix_coefficients);
484 /* Use a colorimetry having at least one valid colorimetry entry,
485 * because we don't know whether the returned
486 * colorimetry (by nvdec) was actually parsed information or not.
487 * Otherwise let GstVideoInfo handle it with default colorimetry */
488 if (colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN ||
489 colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN ||
490 colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
491 GST_DEBUG_OBJECT (nvdec,
492 "Found valid colorimetry, update output colorimetry");
493 out_info->colorimetry = colorimetry;
496 out_info->colorimetry = in_info->colorimetry;
499 if (format->progressive_sequence) {
500 out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
502 /* nvdec doesn't seem to deal with interlacing with hevc so rely
503 * on upstream's value */
504 if (format->codec == cudaVideoCodec_HEVC) {
505 out_info->interlace_mode = in_info->interlace_mode;
508 out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
511 if (gst_cuvid_get_api_version (&major_api_ver, NULL) && major_api_ver >= 9) {
512 /* min_num_decode_surfaces was introduced in nvcodec sdk 9.0 header */
513 nvdec->num_decode_surface = format->min_num_decode_surfaces;
515 GST_DEBUG_OBJECT (nvdec,
516 "Num decode surface: %d", nvdec->num_decode_surface);
518 nvdec->num_decode_surface =
519 calculate_num_decode_surface (format->codec, width, height);
521 GST_DEBUG_OBJECT (nvdec,
522 "Calculated num decode surface: %d", nvdec->num_decode_surface);
525 /* Update the latency if it has changed */
526 curr_latency = gst_nvdec_get_latency (nvdec);
527 if (old_latency != curr_latency)
528 gst_video_decoder_set_latency (GST_VIDEO_DECODER (nvdec), curr_latency,
531 if (!nvdec->decoder || !gst_video_info_is_equal (out_info, &prev_out_info)) {
534 if (!gst_cuda_context_push (ctx)) {
535 GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
539 if (nvdec->decoder) {
540 GST_DEBUG_OBJECT (nvdec, "destroying decoder");
541 if (!gst_cuda_result (CuvidDestroyDecoder (nvdec->decoder))) {
542 GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
545 nvdec->decoder = NULL;
548 GST_DEBUG_OBJECT (nvdec, "creating decoder");
549 create_info.ulWidth = format->coded_width;
550 create_info.ulHeight = format->coded_height;
551 create_info.ulNumDecodeSurfaces = nvdec->num_decode_surface;
552 create_info.CodecType = format->codec;
553 create_info.ChromaFormat = format->chroma_format;
554 create_info.ulCreationFlags = cudaVideoCreate_Default;
555 create_info.display_area.left = format->display_area.left;
556 create_info.display_area.top = format->display_area.top;
557 create_info.display_area.right = format->display_area.right;
558 create_info.display_area.bottom = format->display_area.bottom;
559 create_info.OutputFormat = get_cuda_surface_format_from_gst (out_format);
560 create_info.bitDepthMinus8 = format->bit_depth_luma_minus8;
561 create_info.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
562 create_info.ulTargetWidth = width;
563 create_info.ulTargetHeight = height;
564 create_info.ulNumOutputSurfaces = 1;
565 create_info.target_rect.left = 0;
566 create_info.target_rect.top = 0;
567 create_info.target_rect.right = width;
568 create_info.target_rect.bottom = height;
571 || !gst_cuda_result (CuvidCreateDecoder (&nvdec->decoder,
573 GST_ERROR_OBJECT (nvdec, "failed to create decoder");
577 if (!gst_cuda_context_pop (NULL)) {
578 GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
583 if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (nvdec)) || updata) {
584 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (nvdec))) {
585 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
590 return nvdec->num_decode_surface;
593 nvdec->last_ret = GST_FLOW_ERROR;
598 gst_nvdec_negotiate (GstVideoDecoder * decoder)
600 GstNvDec *nvdec = GST_NVDEC (decoder);
601 GstVideoCodecState *state;
603 GstVideoInfo *out_info = &nvdec->out_info;
606 GST_DEBUG_OBJECT (nvdec, "negotiate");
608 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (nvdec),
609 GST_VIDEO_INFO_FORMAT (out_info), GST_VIDEO_INFO_WIDTH (out_info),
610 GST_VIDEO_INFO_HEIGHT (out_info), nvdec->input_state);
611 vinfo = &state->info;
613 /* update output info with CUvidparser provided one */
614 vinfo->interlace_mode = out_info->interlace_mode;
615 vinfo->fps_n = out_info->fps_n;
616 vinfo->fps_d = out_info->fps_d;
618 state->caps = gst_video_info_to_caps (&state->info);
619 nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
623 caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (nvdec));
624 GST_DEBUG_OBJECT (nvdec, "Allowed caps %" GST_PTR_FORMAT, caps);
626 if (!caps || gst_caps_is_any (caps)) {
627 GST_DEBUG_OBJECT (nvdec,
628 "cannot determine output format, use system memory");
630 GstCapsFeatures *features;
631 guint size = gst_caps_get_size (caps);
633 gboolean have_cuda = FALSE;
634 gboolean have_gl = FALSE;
636 for (i = 0; i < size; i++) {
637 features = gst_caps_get_features (caps, i);
638 if (features && gst_caps_features_contains (features,
639 GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) {
640 GST_DEBUG_OBJECT (nvdec, "found CUDA memory feature");
644 #ifdef HAVE_NVCODEC_GST_GL
645 if (nvdec->gl_display &&
646 features && gst_caps_features_contains (features,
647 GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
648 GST_DEBUG_OBJECT (nvdec, "found GL memory feature");
655 nvdec->mem_type = GST_NVDEC_MEM_TYPE_CUDA;
657 nvdec->mem_type = GST_NVDEC_MEM_TYPE_GL;
659 gst_clear_caps (&caps);
662 #ifdef HAVE_NVCODEC_GST_GL
663 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL &&
664 !gst_nvdec_ensure_gl_context (nvdec)) {
665 GST_WARNING_OBJECT (nvdec,
666 "OpenGL context is not CUDA-compatible, fallback to system memory");
667 nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
671 switch (nvdec->mem_type) {
672 case GST_NVDEC_MEM_TYPE_CUDA:
673 GST_DEBUG_OBJECT (nvdec, "use cuda memory");
674 gst_caps_set_features (state->caps, 0,
675 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, NULL));
677 #ifdef HAVE_NVCODEC_GST_GL
678 case GST_NVDEC_MEM_TYPE_GL:
679 GST_DEBUG_OBJECT (nvdec, "use gl memory");
680 gst_caps_set_features (state->caps, 0,
681 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, NULL));
682 gst_caps_set_simple (state->caps, "texture-target", G_TYPE_STRING,
687 GST_DEBUG_OBJECT (nvdec, "use system memory");
691 if (nvdec->output_state)
692 gst_video_codec_state_unref (nvdec->output_state);
694 nvdec->output_state = state;
696 ret = GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
699 GST_ERROR_OBJECT (nvdec, "failed to negotiate with downstream");
700 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
706 static gboolean CUDAAPI
707 parser_decode_callback (GstNvDec * nvdec, CUVIDPICPARAMS * params)
709 GList *iter, *pending_frames;
710 GstCudaContext *ctx = nvdec->cuda_ctx;
712 GST_LOG_OBJECT (nvdec, "picture index: %u", params->CurrPicIdx);
714 if (!gst_cuda_context_push (ctx)) {
715 GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
719 if (!gst_cuda_result (CuvidDecodePicture (nvdec->decoder, params))) {
720 GST_ERROR_OBJECT (nvdec, "failed to decode picture");
724 if (!gst_cuda_context_pop (NULL)) {
725 GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
729 pending_frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (nvdec));
731 /* NOTE: this decode callback could be invoked multiple times for
732 * one cuvidParseVideoData() call. Most likely it can be related to "decode only"
733 * frame of VPX codec but no document available.
734 * In that case, the last decoded frame seems to be displayed */
736 for (iter = pending_frames; iter; iter = g_list_next (iter)) {
738 GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
739 gboolean set_data = FALSE;
741 id = GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data (frame));
742 if (G_UNLIKELY (nvdec->state == GST_NVDEC_STATE_DECODE)) {
744 GST_LOG_OBJECT (nvdec, "reset the last user data");
752 gst_video_codec_frame_set_user_data (frame,
753 GUINT_TO_POINTER (params->CurrPicIdx + 1), NULL);
758 nvdec->state = GST_NVDEC_STATE_DECODE;
760 g_list_free_full (pending_frames,
761 (GDestroyNotify) gst_video_codec_frame_unref);
766 nvdec->last_ret = GST_FLOW_ERROR;
770 static gboolean CUDAAPI
771 parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
773 GList *iter, *pending_frames;
774 GstVideoCodecFrame *frame = NULL;
775 GstBuffer *output_buffer = NULL;
776 GstFlowReturn ret = GST_FLOW_OK;
777 gboolean copy_ret = FALSE;
779 GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
781 pending_frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (nvdec));
782 for (iter = pending_frames; iter; iter = g_list_next (iter)) {
784 GstVideoCodecFrame *tmp = (GstVideoCodecFrame *) iter->data;
786 id = GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data (tmp));
787 if (id == dispinfo->picture_index + 1) {
788 frame = gst_video_codec_frame_ref (tmp);
792 g_list_free_full (pending_frames,
793 (GDestroyNotify) gst_video_codec_frame_unref);
795 if (G_UNLIKELY (frame == NULL)) {
796 GST_WARNING_OBJECT (nvdec, "no frame for picture index %u",
797 dispinfo->picture_index);
800 gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (nvdec));
802 if (!output_buffer) {
803 GST_ERROR_OBJECT (nvdec, "Couldn't allocate output buffer");
804 nvdec->last_ret = GST_FLOW_ERROR;
808 GST_BUFFER_PTS (output_buffer) = dispinfo->timestamp;
809 GST_BUFFER_DTS (output_buffer) = GST_CLOCK_TIME_NONE;
810 /* assume buffer duration from framerate */
811 if (nvdec->out_info.fps_n > 0 && nvdec->out_info.fps_d > 0) {
812 GST_BUFFER_DURATION (output_buffer) =
813 gst_util_uint64_scale (GST_SECOND,
814 GST_VIDEO_INFO_FPS_D (&nvdec->out_info),
815 GST_VIDEO_INFO_FPS_N (&nvdec->out_info));
817 GST_BUFFER_DURATION (output_buffer) = GST_CLOCK_TIME_NONE;
820 ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (nvdec),
823 if (ret != GST_FLOW_OK) {
824 GST_WARNING_OBJECT (nvdec, "failed to allocate output frame");
825 nvdec->last_ret = ret;
829 output_buffer = frame->output_buffer;
831 if (dispinfo->timestamp != frame->pts) {
832 GST_INFO_OBJECT (nvdec,
833 "timestamp mismatch, diff: %" GST_STIME_FORMAT,
834 GST_STIME_ARGS (GST_CLOCK_DIFF (dispinfo->timestamp, frame->pts)));
838 #ifdef HAVE_NVCODEC_GST_GL
839 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL) {
840 copy_ret = gst_nvdec_copy_device_to_gl (nvdec, dispinfo, output_buffer);
842 /* FIXME: This is the case where OpenGL context of downstream glbufferpool
843 * belongs to non-nvidia (or different device).
844 * There should be enhancement to ensure nvdec has compatible OpenGL context
847 GST_WARNING_OBJECT (nvdec,
848 "Couldn't copy frame to GL memory, fallback to system memory");
849 nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
856 copy_ret = gst_nvdec_copy_device_to_memory (nvdec, dispinfo, output_buffer);
860 GST_ERROR_OBJECT (nvdec, "failed to copy decoded picture to output buffer");
861 nvdec->last_ret = GST_FLOW_ERROR;
864 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (nvdec), frame);
866 gst_buffer_unref (output_buffer);
871 if (!dispinfo->progressive_frame) {
872 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
874 if (dispinfo->top_field_first) {
875 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
878 if (dispinfo->repeat_first_field == -1) {
879 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_ONEFIELD);
881 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_RFF);
886 ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (nvdec), frame);
888 ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (nvdec), output_buffer);
891 if (ret != GST_FLOW_OK) {
892 GST_DEBUG_OBJECT (nvdec, "failed to finish frame %s",
893 gst_flow_get_name (ret));
894 nvdec->last_ret = ret;
902 gst_nvdec_open (GstVideoDecoder * decoder)
904 GstNvDec *nvdec = GST_NVDEC (decoder);
905 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
908 GST_DEBUG_OBJECT (nvdec, "creating CUDA context");
910 if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (decoder),
911 klass->cuda_device_id, &nvdec->cuda_ctx)) {
912 GST_ERROR_OBJECT (nvdec, "failed to create CUDA context");
916 if (gst_cuda_context_push (nvdec->cuda_ctx)) {
917 cuda_ret = CuStreamCreate (&nvdec->cuda_stream, CU_STREAM_DEFAULT);
918 if (!gst_cuda_result (cuda_ret)) {
919 GST_WARNING_OBJECT (nvdec,
920 "Could not create CUDA stream, will use default stream");
921 nvdec->cuda_stream = NULL;
923 gst_cuda_context_pop (NULL);
925 #if HAVE_NVCODEC_GST_GL
926 gst_gl_ensure_element_data (GST_ELEMENT (nvdec),
927 &nvdec->gl_display, &nvdec->other_gl_context);
928 if (nvdec->gl_display)
929 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvdec->gl_display),
937 gst_nvdec_start (GstVideoDecoder * decoder)
939 GstNvDec *nvdec = GST_NVDEC (decoder);
940 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
942 nvdec->state = GST_NVDEC_STATE_INIT;
943 nvdec->last_ret = GST_FLOW_OK;
944 gst_video_info_init (&nvdec->out_info);
946 if (klass->codec_type == cudaVideoCodec_H264)
947 nvdec->h264_parser = gst_h264_nal_parser_new ();
948 else if (klass->codec_type == cudaVideoCodec_HEVC)
949 nvdec->h265_parser = gst_h265_parser_new ();
955 maybe_destroy_decoder_and_parser (GstNvDec * nvdec)
959 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
960 GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
964 if (nvdec->decoder) {
965 GST_DEBUG_OBJECT (nvdec, "destroying decoder");
966 ret = gst_cuda_result (CuvidDestroyDecoder (nvdec->decoder));
967 nvdec->decoder = NULL;
970 GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
974 GST_DEBUG_OBJECT (nvdec, "destroying parser");
975 if (!gst_cuda_result (CuvidDestroyVideoParser (nvdec->parser))) {
976 GST_ERROR_OBJECT (nvdec, "failed to destroy parser");
979 nvdec->parser = NULL;
982 if (!gst_cuda_context_pop (NULL)) {
983 GST_WARNING_OBJECT (nvdec, "failed to pop CUDA context");
990 gst_nvdec_clear_codec_data (GstNvDec * self)
992 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (self);
995 if (klass->codec_type == cudaVideoCodec_HEVC) {
996 for (i = 0; i < G_N_ELEMENTS (self->vps_nals); i++) {
997 gst_clear_buffer (&self->vps_nals[i]);
1001 if (klass->codec_type == cudaVideoCodec_HEVC ||
1002 klass->codec_type == cudaVideoCodec_H264) {
1003 for (i = 0; i < G_N_ELEMENTS (self->sps_nals); i++) {
1004 gst_clear_buffer (&self->sps_nals[i]);
1007 for (i = 0; i < G_N_ELEMENTS (self->pps_nals); i++) {
1008 gst_clear_buffer (&self->pps_nals[i]);
1012 gst_clear_buffer (&self->codec_data);
1014 self->need_codec_data = TRUE;
1018 gst_nvdec_stop (GstVideoDecoder * decoder)
1020 GstNvDec *nvdec = GST_NVDEC (decoder);
1022 GST_DEBUG_OBJECT (nvdec, "stop");
1024 if (!maybe_destroy_decoder_and_parser (nvdec))
1027 #ifdef HAVE_NVCODEC_GST_GL
1028 gst_clear_object (&nvdec->gl_context);
1029 gst_clear_object (&nvdec->other_gl_context);
1030 gst_clear_object (&nvdec->gl_display);
1033 g_clear_pointer (&nvdec->input_state, gst_video_codec_state_unref);
1034 g_clear_pointer (&nvdec->output_state, gst_video_codec_state_unref);
1036 g_clear_pointer (&nvdec->h264_parser, gst_h264_nal_parser_free);
1037 g_clear_pointer (&nvdec->h265_parser, gst_h265_parser_free);
1039 gst_nvdec_clear_codec_data (nvdec);
1045 gst_nvdec_close (GstVideoDecoder * decoder)
1047 GstNvDec *nvdec = GST_NVDEC (decoder);
1049 if (nvdec->cuda_ctx && nvdec->cuda_stream) {
1050 if (gst_cuda_context_push (nvdec->cuda_ctx)) {
1051 gst_cuda_result (CuStreamDestroy (nvdec->cuda_stream));
1052 gst_cuda_context_pop (NULL);
1056 gst_clear_object (&nvdec->cuda_ctx);
1057 nvdec->cuda_stream = NULL;
1063 gst_nvdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
1065 GstNvDec *nvdec = GST_NVDEC (decoder);
1066 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (decoder);
1067 CUVIDPARSERPARAMS parser_params = { 0, };
1069 gboolean ret = TRUE;
1071 GST_DEBUG_OBJECT (nvdec, "set format");
1073 if (nvdec->input_state)
1074 gst_video_codec_state_unref (nvdec->input_state);
1076 nvdec->input_state = gst_video_codec_state_ref (state);
1078 if (!maybe_destroy_decoder_and_parser (nvdec))
1081 /* Check if pipeline is live */
1082 nvdec->is_live = FALSE;
1083 query = gst_query_new_latency ();
1084 if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (decoder), query))
1085 gst_query_parse_latency (query, &nvdec->is_live, NULL, NULL);
1086 gst_query_unref (query);
1088 parser_params.CodecType = klass->codec_type;
1089 /* ulMaxNumDecodeSurfaces will be updated by the return value of
1090 * SequenceCallback */
1091 parser_params.ulMaxNumDecodeSurfaces = 1;
1092 parser_params.ulErrorThreshold = 100;
1093 parser_params.ulMaxDisplayDelay = gst_nvdec_get_max_display_delay (nvdec);
1094 parser_params.ulClockRate = GST_SECOND;
1095 parser_params.pUserData = nvdec;
1096 parser_params.pfnSequenceCallback =
1097 (PFNVIDSEQUENCECALLBACK) parser_sequence_callback;
1098 parser_params.pfnDecodePicture =
1099 (PFNVIDDECODECALLBACK) parser_decode_callback;
1100 parser_params.pfnDisplayPicture =
1101 (PFNVIDDISPLAYCALLBACK) parser_display_callback;
1103 gst_cuda_context_push (nvdec->cuda_ctx);
1104 GST_DEBUG_OBJECT (nvdec, "creating parser");
1105 if (!gst_cuda_result (CuvidCreateVideoParser (&nvdec->parser,
1107 GST_ERROR_OBJECT (nvdec, "failed to create parser");
1111 gst_cuda_context_pop (NULL);
1113 /* store codec data */
1114 gst_nvdec_clear_codec_data (nvdec);
1116 if (ret && nvdec->input_state->caps) {
1119 str = gst_caps_get_structure (nvdec->input_state->caps, 0);
1121 if (klass->codec_type == cudaVideoCodec_MPEG4) {
1122 const GValue *codec_data_value;
1123 codec_data_value = gst_structure_get_value (str, "codec_data");
1124 if (codec_data_value && GST_VALUE_HOLDS_BUFFER (codec_data_value)) {
1125 GstBuffer *codec_data = gst_value_get_buffer (codec_data_value);
1126 gst_buffer_replace (&nvdec->codec_data, codec_data);
1130 /* For all CODEC we get complete picture ... */
1131 nvdec->recv_complete_picture = TRUE;
1133 /* Except for JPEG, for which it depends on the caps */
1134 if (klass->codec_type == cudaVideoCodec_JPEG) {
1136 if (gst_structure_get_boolean (str, "parsed", &parsed))
1137 nvdec->recv_complete_picture = parsed;
1139 nvdec->recv_complete_picture = FALSE;
1146 #ifdef HAVE_NVCODEC_GST_GL
1150 CUVIDPARSERDISPINFO *dispinfo;
1152 GstBuffer *output_buffer;
1153 } GstNvDecCopyToGLData;
1156 copy_video_frame_to_gl_textures (GstGLContext * context,
1157 GstNvDecCopyToGLData * data)
1159 GstNvDec *nvdec = data->nvdec;
1160 CUVIDPARSERDISPINFO *dispinfo = data->dispinfo;
1161 GstCudaGraphicsResource **resources;
1162 guint num_resources;
1163 CUVIDPROCPARAMS proc_params = { 0, };
1166 CUDA_MEMCPY2D mcpy2d = { 0, };
1167 GstVideoInfo *info = &nvdec->output_state->info;
1169 GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
1171 proc_params.progressive_frame = dispinfo->progressive_frame;
1172 proc_params.top_field_first = dispinfo->top_field_first;
1173 proc_params.unpaired_field = dispinfo->repeat_first_field == -1;
1174 proc_params.output_stream = nvdec->cuda_stream;
1178 num_resources = gst_buffer_n_memory (data->output_buffer);
1179 resources = g_newa (GstCudaGraphicsResource *, num_resources);
1181 for (i = 0; i < num_resources; i++) {
1184 mem = gst_buffer_peek_memory (data->output_buffer, i);
1185 resources[i] = ensure_cuda_graphics_resource (mem, nvdec);
1186 if (!resources[i]) {
1187 GST_WARNING_OBJECT (nvdec, "could not register %dth memory", i);
1193 /* Need PBO -> texture */
1194 GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
1197 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
1198 GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
1203 if (!gst_cuda_result (CuvidMapVideoFrame (nvdec->decoder,
1204 dispinfo->picture_index, &dptr, &pitch, &proc_params))) {
1205 GST_WARNING_OBJECT (nvdec, "failed to map CUDA video frame");
1207 goto unlock_cuda_context;
1210 mcpy2d.srcMemoryType = CU_MEMORYTYPE_DEVICE;
1211 mcpy2d.srcPitch = pitch;
1212 mcpy2d.dstMemoryType = CU_MEMORYTYPE_DEVICE;
1214 for (i = 0; i < num_resources; i++) {
1215 CUdeviceptr cuda_ptr;
1217 CUgraphicsResource cuda_resource =
1218 gst_cuda_graphics_resource_map (resources[i], nvdec->cuda_stream,
1219 CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1221 if (!cuda_resource) {
1222 GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
1224 goto unmap_video_frame;
1227 if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&cuda_ptr, &size,
1229 GST_WARNING_OBJECT (nvdec, "failed to map CUDA resource");
1234 mcpy2d.dstPitch = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
1235 mcpy2d.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (info, i)
1236 * GST_VIDEO_INFO_COMP_PSTRIDE (info, i);
1238 mcpy2d.srcDevice = dptr + (i * pitch * GST_VIDEO_INFO_HEIGHT (info));
1239 mcpy2d.dstDevice = cuda_ptr;
1240 mcpy2d.Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
1242 if (!gst_cuda_result (CuMemcpy2DAsync (&mcpy2d, nvdec->cuda_stream))) {
1243 GST_WARNING_OBJECT (nvdec, "memcpy to mapped array failed");
1248 gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
1251 for (i = 0; i < num_resources; i++) {
1252 gst_cuda_graphics_resource_unmap (resources[i], nvdec->cuda_stream);
1255 if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
1256 GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
1258 unlock_cuda_context:
1259 if (!gst_cuda_context_pop (NULL))
1260 GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
1264 gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
1265 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
1267 GstNvDecCopyToGLData data = { 0, };
1270 data.dispinfo = dispinfo;
1271 data.output_buffer = output_buffer;
1273 gst_gl_context_thread_add (nvdec->gl_context,
1274 (GstGLContextThreadFunc) copy_video_frame_to_gl_textures, &data);
1281 gst_nvdec_copy_device_to_memory (GstNvDec * nvdec,
1282 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
1284 CUVIDPROCPARAMS params = { 0, };
1285 CUDA_MEMCPY2D copy_params = { 0, };
1288 GstVideoFrame video_frame;
1289 GstVideoInfo *info = &nvdec->output_state->info;
1292 gboolean use_device_copy = FALSE;
1293 GstMapFlags map_flags = GST_MAP_WRITE;
1295 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_CUDA &&
1296 (mem = gst_buffer_peek_memory (output_buffer, 0)) &&
1297 gst_is_cuda_memory (mem)) {
1298 map_flags |= GST_MAP_CUDA;
1299 use_device_copy = TRUE;
1302 if (!gst_video_frame_map (&video_frame, info, output_buffer, map_flags)) {
1303 GST_ERROR_OBJECT (nvdec, "frame map failure");
1307 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
1308 gst_video_frame_unmap (&video_frame);
1309 GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
1313 params.progressive_frame = dispinfo->progressive_frame;
1314 params.second_field = dispinfo->repeat_first_field + 1;
1315 params.top_field_first = dispinfo->top_field_first;
1316 params.unpaired_field = dispinfo->repeat_first_field < 0;
1317 params.output_stream = nvdec->cuda_stream;
1319 if (!gst_cuda_result (CuvidMapVideoFrame (nvdec->decoder,
1320 dispinfo->picture_index, &dptr, &pitch, ¶ms))) {
1321 GST_ERROR_OBJECT (nvdec, "failed to map video frame");
1322 gst_cuda_context_pop (NULL);
1326 copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
1327 copy_params.srcPitch = pitch;
1328 copy_params.dstMemoryType =
1329 use_device_copy ? CU_MEMORYTYPE_DEVICE : CU_MEMORYTYPE_HOST;
1331 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1332 copy_params.srcDevice = dptr + (i * pitch * GST_VIDEO_INFO_HEIGHT (info));
1333 if (use_device_copy) {
1334 copy_params.dstDevice =
1335 (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (&video_frame, i);
1337 copy_params.dstHost = GST_VIDEO_FRAME_PLANE_DATA (&video_frame, i);
1339 copy_params.dstPitch = GST_VIDEO_FRAME_PLANE_STRIDE (&video_frame, i);
1340 copy_params.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (info, i)
1341 * GST_VIDEO_INFO_COMP_PSTRIDE (info, i);
1342 copy_params.Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
1344 if (!gst_cuda_result (CuMemcpy2DAsync (©_params, nvdec->cuda_stream))) {
1345 GST_ERROR_OBJECT (nvdec, "failed to copy %dth plane", i);
1346 CuvidUnmapVideoFrame (nvdec->decoder, dptr);
1347 gst_video_frame_unmap (&video_frame);
1348 gst_cuda_context_pop (NULL);
1353 gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
1355 gst_video_frame_unmap (&video_frame);
1357 if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
1358 GST_WARNING_OBJECT (nvdec, "failed to unmap video frame");
1360 if (!gst_cuda_context_pop (NULL))
1361 GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
1367 gst_nvdec_store_h264_nal (GstNvDec * self, guint id,
1368 GstH264NalUnitType nal_type, GstH264NalUnit * nalu)
1370 GstBuffer *buf, **store;
1371 guint size = nalu->size, store_size;
1372 static const guint8 start_code[] = { 0, 0, 1 };
1374 if (nal_type == GST_H264_NAL_SPS || nal_type == GST_H264_NAL_SUBSET_SPS) {
1375 store_size = GST_H264_MAX_SPS_COUNT;
1376 store = self->sps_nals;
1377 GST_DEBUG_OBJECT (self, "storing sps %u", id);
1378 } else if (nal_type == GST_H264_NAL_PPS) {
1379 store_size = GST_H264_MAX_PPS_COUNT;
1380 store = self->pps_nals;
1381 GST_DEBUG_OBJECT (self, "storing pps %u", id);
1386 if (id >= store_size) {
1387 GST_DEBUG_OBJECT (self, "unable to store nal, id out-of-range %d", id);
1391 buf = gst_buffer_new_allocate (NULL, size + sizeof (start_code), NULL);
1392 gst_buffer_fill (buf, 0, start_code, sizeof (start_code));
1393 gst_buffer_fill (buf, sizeof (start_code), nalu->data + nalu->offset, size);
1396 gst_buffer_unref (store[id]);
1402 gst_nvdec_handle_h264_buffer (GstNvDec * self, GstBuffer * buffer)
1404 GstH264NalParser *parser = self->h264_parser;
1405 GstH264NalUnit nalu;
1406 GstH264ParserResult pres;
1408 gboolean have_sps = FALSE;
1409 gboolean have_pps = FALSE;
1413 if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
1414 GST_WARNING_OBJECT (self, "Failed to map input buffer");
1415 return gst_buffer_ref (buffer);
1418 memset (&nalu, 0, sizeof (GstH264NalUnit));
1421 pres = gst_h264_parser_identify_nalu (parser,
1422 map.data, nalu.offset + nalu.size, map.size, &nalu);
1424 if (pres == GST_H264_PARSER_NO_NAL_END)
1425 pres = GST_H264_PARSER_OK;
1427 switch (nalu.type) {
1428 case GST_H264_NAL_SPS:
1429 case GST_H264_NAL_SUBSET_SPS:{
1432 if (nalu.type == GST_H264_NAL_SPS) {
1433 pres = gst_h264_parser_parse_sps (parser, &nalu, &sps);
1435 pres = gst_h264_parser_parse_subset_sps (parser, &nalu, &sps);
1438 if (pres != GST_H264_PARSER_OK)
1442 gst_nvdec_store_h264_nal (self, sps.id, nalu.type, &nalu);
1443 gst_h264_sps_clear (&sps);
1446 case GST_H264_NAL_PPS:{
1449 pres = gst_h264_parser_parse_pps (parser, &nalu, &pps);
1450 if (pres != GST_H264_PARSER_OK)
1454 gst_nvdec_store_h264_nal (self, pps.id, nalu.type, &nalu);
1455 gst_h264_pps_clear (&pps);
1461 } while (pres == GST_H264_PARSER_OK);
1463 gst_buffer_unmap (buffer, &map);
1465 if (!self->need_codec_data || (have_sps && have_pps)) {
1466 self->need_codec_data = FALSE;
1467 return gst_buffer_ref (buffer);
1470 new_buf = gst_buffer_new ();
1472 for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
1473 if (!self->sps_nals[i])
1477 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->sps_nals[i]));
1482 for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
1483 if (!self->pps_nals[i])
1487 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->pps_nals[i]));
1491 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (buffer));
1493 if (have_sps && have_pps)
1494 self->need_codec_data = FALSE;
1500 gst_nvdec_store_h265_nal (GstNvDec * self, guint id,
1501 GstH265NalUnitType nal_type, GstH265NalUnit * nalu)
1503 GstBuffer *buf, **store;
1504 guint size = nalu->size, store_size;
1505 static const guint8 start_code[] = { 0, 0, 1 };
1507 if (nal_type == GST_H265_NAL_VPS) {
1508 store_size = GST_H265_MAX_VPS_COUNT;
1509 store = self->vps_nals;
1510 GST_DEBUG_OBJECT (self, "storing vps %u", id);
1511 } else if (nal_type == GST_H265_NAL_SPS) {
1512 store_size = GST_H265_MAX_SPS_COUNT;
1513 store = self->sps_nals;
1514 GST_DEBUG_OBJECT (self, "storing sps %u", id);
1515 } else if (nal_type == GST_H265_NAL_PPS) {
1516 store_size = GST_H265_MAX_PPS_COUNT;
1517 store = self->pps_nals;
1518 GST_DEBUG_OBJECT (self, "storing pps %u", id);
1523 if (id >= store_size) {
1524 GST_DEBUG_OBJECT (self, "unable to store nal, id out-of-range %d", id);
1528 buf = gst_buffer_new_allocate (NULL, size + sizeof (start_code), NULL);
1529 gst_buffer_fill (buf, 0, start_code, sizeof (start_code));
1530 gst_buffer_fill (buf, sizeof (start_code), nalu->data + nalu->offset, size);
1533 gst_buffer_unref (store[id]);
1539 gst_nvdec_handle_h265_buffer (GstNvDec * self, GstBuffer * buffer)
1541 GstH265Parser *parser = self->h265_parser;
1542 GstH265NalUnit nalu;
1543 GstH265ParserResult pres;
1545 gboolean have_vps = FALSE;
1546 gboolean have_sps = FALSE;
1547 gboolean have_pps = FALSE;
1551 if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
1552 GST_WARNING_OBJECT (self, "Failed to map input buffer");
1553 return gst_buffer_ref (buffer);
1556 memset (&nalu, 0, sizeof (GstH265NalUnit));
1559 pres = gst_h265_parser_identify_nalu (parser,
1560 map.data, nalu.offset + nalu.size, map.size, &nalu);
1562 if (pres == GST_H265_PARSER_NO_NAL_END)
1563 pres = GST_H265_PARSER_OK;
1565 switch (nalu.type) {
1566 case GST_H265_NAL_VPS:{
1569 pres = gst_h265_parser_parse_vps (parser, &nalu, &vps);
1570 if (pres != GST_H265_PARSER_OK)
1574 gst_nvdec_store_h265_nal (self, vps.id, nalu.type, &nalu);
1577 case GST_H265_NAL_SPS:{
1580 pres = gst_h265_parser_parse_sps (parser, &nalu, &sps, FALSE);
1581 if (pres != GST_H265_PARSER_OK)
1585 gst_nvdec_store_h265_nal (self, sps.id, nalu.type, &nalu);
1588 case GST_H265_NAL_PPS:{
1591 pres = gst_h265_parser_parse_pps (parser, &nalu, &pps);
1592 if (pres != GST_H265_PARSER_OK)
1596 gst_nvdec_store_h265_nal (self, pps.id, nalu.type, &nalu);
1602 } while (pres == GST_H265_PARSER_OK);
1604 gst_buffer_unmap (buffer, &map);
1606 if (!self->need_codec_data || (have_sps && have_pps)) {
1607 self->need_codec_data = FALSE;
1608 return gst_buffer_ref (buffer);
1611 new_buf = gst_buffer_new ();
1613 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1614 if (!self->vps_nals[i])
1617 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->vps_nals[i]));
1622 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1623 if (!self->sps_nals[i])
1627 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->sps_nals[i]));
1632 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
1633 if (!self->pps_nals[i])
1637 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->pps_nals[i]));
1641 if (have_sps && have_pps)
1642 self->need_codec_data = FALSE;
1644 return gst_buffer_append (new_buf, gst_buffer_ref (buffer));
1648 gst_nvdec_process_input (GstNvDec * self, GstBuffer * inbuf)
1650 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (self);
1651 gboolean parse_nal = FALSE;
1653 if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT) ||
1654 self->need_codec_data) {
1658 if (klass->codec_type == cudaVideoCodec_MPEG4 &&
1659 self->codec_data && GST_BUFFER_IS_DISCONT (inbuf)) {
1660 return gst_buffer_append (gst_buffer_ref (self->codec_data),
1661 gst_buffer_ref (inbuf));
1662 } else if (klass->codec_type == cudaVideoCodec_H264 && parse_nal) {
1663 return gst_nvdec_handle_h264_buffer (self, inbuf);
1664 } else if (klass->codec_type == cudaVideoCodec_HEVC && parse_nal) {
1665 return gst_nvdec_handle_h265_buffer (self, inbuf);
1668 return gst_buffer_ref (inbuf);
1671 static GstFlowReturn
1672 gst_nvdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
1674 GstNvDec *nvdec = GST_NVDEC (decoder);
1675 GstMapInfo map_info = GST_MAP_INFO_INIT;
1676 CUVIDSOURCEDATAPACKET packet = { 0, };
1677 GstBuffer *in_buffer;
1679 GST_LOG_OBJECT (nvdec, "handle frame");
1681 /* initialize with zero to keep track of frames */
1682 gst_video_codec_frame_set_user_data (frame, GUINT_TO_POINTER (0), NULL);
1684 in_buffer = gst_nvdec_process_input (nvdec, frame->input_buffer);
1686 if (!gst_buffer_map (in_buffer, &map_info, GST_MAP_READ)) {
1687 GST_ERROR_OBJECT (nvdec, "failed to map input buffer");
1688 gst_buffer_unref (in_buffer);
1689 gst_video_codec_frame_unref (frame);
1690 return GST_FLOW_ERROR;
1693 packet.payload_size = (gulong) map_info.size;
1694 packet.payload = map_info.data;
1695 packet.timestamp = frame->pts;
1696 packet.flags |= CUVID_PKT_TIMESTAMP;
1698 if (nvdec->recv_complete_picture)
1699 packet.flags |= CUVID_PKT_ENDOFPICTURE;
1701 nvdec->state = GST_NVDEC_STATE_PARSE;
1702 nvdec->last_ret = GST_FLOW_OK;
1704 if (!gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1705 GST_WARNING_OBJECT (nvdec, "parser failed");
1707 gst_buffer_unmap (in_buffer, &map_info);
1708 gst_buffer_unref (in_buffer);
1709 gst_video_codec_frame_unref (frame);
1711 return nvdec->last_ret;
1715 gst_nvdec_flush (GstVideoDecoder * decoder)
1717 GstNvDec *nvdec = GST_NVDEC (decoder);
1718 CUVIDSOURCEDATAPACKET packet = { 0, };
1720 GST_DEBUG_OBJECT (nvdec, "flush");
1722 packet.payload_size = 0;
1723 packet.payload = NULL;
1724 packet.flags = CUVID_PKT_ENDOFSTREAM;
1726 nvdec->state = GST_NVDEC_STATE_PARSE;
1727 nvdec->last_ret = GST_FLOW_OK;
1730 && !gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1731 GST_WARNING_OBJECT (nvdec, "parser failed");
1733 nvdec->need_codec_data = TRUE;
1738 static GstFlowReturn
1739 gst_nvdec_drain (GstVideoDecoder * decoder)
1741 GstNvDec *nvdec = GST_NVDEC (decoder);
1742 CUVIDSOURCEDATAPACKET packet = { 0, };
1744 GST_DEBUG_OBJECT (nvdec, "draining decoder");
1746 packet.payload_size = 0;
1747 packet.payload = NULL;
1748 packet.flags = CUVID_PKT_ENDOFSTREAM;
1750 nvdec->state = GST_NVDEC_STATE_PARSE;
1751 nvdec->last_ret = GST_FLOW_OK;
1754 && !gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1755 GST_WARNING_OBJECT (nvdec, "parser failed");
1757 nvdec->need_codec_data = TRUE;
1759 return nvdec->last_ret;
1762 static GstFlowReturn
1763 gst_nvdec_finish (GstVideoDecoder * decoder)
1765 GST_DEBUG_OBJECT (decoder, "finish");
1767 return gst_nvdec_drain (decoder);
1770 #ifdef HAVE_NVCODEC_GST_GL
1772 gst_nvdec_check_cuda_device_from_context (GstGLContext * context,
1775 guint device_count = 0;
1776 CUdevice device_list[1] = { 0, };
1781 cuda_ret = CuGLGetDevices (&device_count,
1782 device_list, 1, CU_GL_DEVICE_LIST_ALL);
1784 if (!gst_cuda_result (cuda_ret) || device_count == 0)
1793 gst_nvdec_ensure_gl_context (GstNvDec * nvdec)
1797 if (!nvdec->gl_display) {
1798 GST_DEBUG_OBJECT (nvdec, "No available OpenGL display");
1802 if (!gst_gl_query_local_gl_context (GST_ELEMENT (nvdec), GST_PAD_SRC,
1803 &nvdec->gl_context)) {
1804 GST_INFO_OBJECT (nvdec, "failed to query local OpenGL context");
1805 if (nvdec->gl_context)
1806 gst_object_unref (nvdec->gl_context);
1808 gst_gl_display_get_gl_context_for_thread (nvdec->gl_display, NULL);
1809 if (!nvdec->gl_context
1810 || !gst_gl_display_add_context (nvdec->gl_display, nvdec->gl_context)) {
1811 if (nvdec->gl_context)
1812 gst_object_unref (nvdec->gl_context);
1813 if (!gst_gl_display_create_context (nvdec->gl_display,
1814 nvdec->other_gl_context, &nvdec->gl_context, NULL)) {
1815 GST_ERROR_OBJECT (nvdec, "failed to create OpenGL context");
1818 if (!gst_gl_display_add_context (nvdec->gl_display, nvdec->gl_context)) {
1819 GST_ERROR_OBJECT (nvdec,
1820 "failed to add the OpenGL context to the display");
1826 if (!gst_gl_context_check_gl_version (nvdec->gl_context,
1827 SUPPORTED_GL_APIS, 3, 0)) {
1828 GST_WARNING_OBJECT (nvdec, "OpenGL context could not support PBO download");
1832 gst_gl_context_thread_add (nvdec->gl_context,
1833 (GstGLContextThreadFunc) gst_nvdec_check_cuda_device_from_context, &ret);
1836 GST_WARNING_OBJECT (nvdec, "Current OpenGL context is not CUDA-compatible");
1844 gst_nvdec_ensure_gl_pool (GstNvDec * nvdec, GstQuery * query)
1847 GstBufferPool *pool = NULL;
1848 guint n, size, min, max;
1849 GstVideoInfo vinfo = { 0, };
1850 GstStructure *config;
1852 GST_DEBUG_OBJECT (nvdec, "decide allocation");
1854 gst_query_parse_allocation (query, &outcaps, NULL);
1855 n = gst_query_get_n_allocation_pools (query);
1857 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1859 if (pool && !GST_IS_GL_BUFFER_POOL (pool)) {
1860 gst_object_unref (pool);
1865 GST_DEBUG_OBJECT (nvdec, "no downstream pool, create our pool");
1866 pool = gst_gl_buffer_pool_new (nvdec->gl_context);
1869 gst_video_info_from_caps (&vinfo, outcaps);
1870 size = (guint) vinfo.size;
1874 config = gst_buffer_pool_get_config (pool);
1875 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1876 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1877 gst_buffer_pool_set_config (pool, config);
1879 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1881 gst_query_add_allocation_pool (query, pool, size, min, max);
1882 gst_object_unref (pool);
1889 gst_nvdec_ensure_cuda_pool (GstNvDec * nvdec, GstQuery * query)
1892 GstBufferPool *pool = NULL;
1893 guint n, size, min, max;
1894 GstVideoInfo vinfo = { 0, };
1895 GstStructure *config;
1897 gst_query_parse_allocation (query, &outcaps, NULL);
1898 n = gst_query_get_n_allocation_pools (query);
1900 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1902 if (!GST_IS_CUDA_BUFFER_POOL (pool)) {
1903 gst_clear_object (&pool);
1905 GstCudaBufferPool *cpool = GST_CUDA_BUFFER_POOL (pool);
1907 if (cpool->context != nvdec->cuda_ctx)
1908 gst_clear_object (&pool);
1914 GST_DEBUG_OBJECT (nvdec, "no downstream pool, create our pool");
1915 pool = gst_cuda_buffer_pool_new (nvdec->cuda_ctx);
1918 gst_video_info_from_caps (&vinfo, outcaps);
1919 size = (guint) vinfo.size;
1923 config = gst_buffer_pool_get_config (pool);
1924 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1925 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1926 gst_buffer_pool_set_config (pool, config);
1928 /* Get updated size by cuda buffer pool */
1929 config = gst_buffer_pool_get_config (pool);
1930 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
1931 gst_structure_free (config);
1934 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1936 gst_query_add_allocation_pool (query, pool, size, min, max);
1937 gst_object_unref (pool);
1943 gst_nvdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1945 GstNvDec *nvdec = GST_NVDEC (decoder);
1947 GST_DEBUG_OBJECT (nvdec, "decide allocation");
1949 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_SYSTEM)
1952 #ifdef HAVE_NVCODEC_GST_GL
1953 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL) {
1954 if (!gst_nvdec_ensure_gl_pool (nvdec, query))
1958 if (!gst_nvdec_ensure_cuda_pool (nvdec, query)) {
1963 return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->decide_allocation
1968 gst_nvdec_src_query (GstVideoDecoder * decoder, GstQuery * query)
1970 GstNvDec *nvdec = GST_NVDEC (decoder);
1972 switch (GST_QUERY_TYPE (query)) {
1973 case GST_QUERY_CONTEXT:
1974 if (gst_cuda_handle_context_query (GST_ELEMENT (decoder),
1975 query, nvdec->cuda_ctx)) {
1978 #ifdef HAVE_NVCODEC_GST_GL
1979 if (gst_gl_handle_context_query (GST_ELEMENT (decoder), query,
1980 nvdec->gl_display, nvdec->gl_context, nvdec->other_gl_context)) {
1981 if (nvdec->gl_display)
1982 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvdec->gl_display),
1992 return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->src_query (decoder,
1997 gst_nvdec_set_context (GstElement * element, GstContext * context)
1999 GstNvDec *nvdec = GST_NVDEC (element);
2000 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
2002 GST_DEBUG_OBJECT (nvdec, "set context %s",
2003 gst_context_get_context_type (context));
2005 if (gst_cuda_handle_set_context (element,
2006 context, klass->cuda_device_id, &nvdec->cuda_ctx)) {
2009 #ifdef HAVE_NVCODEC_GST_GL
2010 gst_gl_handle_set_context (element, context, &nvdec->gl_display,
2011 &nvdec->other_gl_context);
2015 GST_ELEMENT_CLASS (gst_nvdec_parent_class)->set_context (element, context);
2022 cudaVideoCodec codec_type;
2024 guint cuda_device_id;
2025 gboolean is_default;
2026 } GstNvDecClassData;
2029 gst_nvdec_subclass_init (gpointer g_class, gpointer data)
2031 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
2032 GstNvDecClass *nvdec_class = GST_NVDEC_CLASS (g_class);
2033 GstNvDecClassData *cdata = data;
2036 if (cdata->is_default) {
2037 long_name = g_strdup_printf ("NVDEC %s Video Decoder", cdata->codec);
2039 long_name = g_strdup_printf ("NVDEC %s Video Decoder with device %d",
2040 cdata->codec, cdata->cuda_device_id);
2043 gst_element_class_set_metadata (element_class, long_name,
2044 "Codec/Decoder/Video/Hardware", "NVDEC video decoder",
2045 "Ericsson AB, http://www.ericsson.com, "
2046 "Seungha Yang <seungha.yang@navercorp.com>");
2049 gst_element_class_add_pad_template (element_class,
2050 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
2052 gst_element_class_add_pad_template (element_class,
2053 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
2056 nvdec_class->codec_type = cdata->codec_type;
2057 nvdec_class->cuda_device_id = cdata->cuda_device_id;
2059 gst_caps_unref (cdata->sink_caps);
2060 gst_caps_unref (cdata->src_caps);
2061 g_free (cdata->codec);
2066 gst_nvdec_subclass_register (GstPlugin * plugin, GType type,
2067 cudaVideoCodec codec_type, const gchar * codec, guint device_id, guint rank,
2068 GstCaps * sink_caps, GstCaps * src_caps)
2070 GTypeQuery type_query;
2071 GTypeInfo type_info = { 0, };
2074 GstNvDecClassData *cdata;
2075 gboolean is_default = TRUE;
2078 cdata = g_new0 (GstNvDecClassData, 1);
2079 cdata->sink_caps = gst_caps_ref (sink_caps);
2080 cdata->src_caps = gst_caps_ref (src_caps);
2081 cdata->codec_type = codec_type;
2082 cdata->codec = g_strdup (codec);
2083 cdata->cuda_device_id = device_id;
2085 g_type_query (type, &type_query);
2086 memset (&type_info, 0, sizeof (type_info));
2087 type_info.class_size = type_query.class_size;
2088 type_info.instance_size = type_query.instance_size;
2089 type_info.class_init = gst_nvdec_subclass_init;
2090 type_info.class_data = cdata;
2092 type_name = g_strdup_printf ("nv%sdec", codec);
2093 while (g_type_from_name (type_name)) {
2096 type_name = g_strdup_printf ("nv%sdevice%ddec", codec, index);
2100 cdata->is_default = is_default;
2101 subtype = g_type_register_static (type, type_name, &type_info, 0);
2103 /* make lower rank than default device */
2104 if (rank > 0 && !is_default)
2107 if (!gst_element_register (plugin, type_name, rank, subtype))
2108 GST_WARNING ("Failed to register plugin '%s'", type_name);
2114 gst_nvdec_plugin_init (GstPlugin * plugin, guint device_index,
2115 cudaVideoCodec codec, const gchar * codec_name, GstCaps * sink_template,
2116 GstCaps * src_template)
2118 gst_nvdec_subclass_register (plugin, GST_TYPE_NVDEC, codec,
2119 codec_name, device_index, GST_RANK_PRIMARY, sink_template, src_template);