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.
33 #include "gstcudautils.h"
34 #include "gstcudabufferpool.h"
38 GST_DEBUG_CATEGORY_EXTERN (gst_nvdec_debug);
39 #define GST_CAT_DEFAULT gst_nvdec_debug
41 #define DEFAULT_MAX_DISPLAY_DELAY -1
46 PROP_MAX_DISPLAY_DELAY,
49 #ifdef HAVE_NVCODEC_GST_GL
50 #define SUPPORTED_GL_APIS (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)
53 gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
54 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
58 gst_nvdec_copy_device_to_memory (GstNvDec * nvdec,
59 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
61 #ifdef HAVE_NVCODEC_GST_GL
62 typedef struct _GstNvDecRegisterResourceData
65 GstCudaGraphicsResource *resource;
68 } GstNvDecRegisterResourceData;
71 register_cuda_resource (GstGLContext * context,
72 GstNvDecRegisterResourceData * data)
74 GstMemory *mem = data->mem;
75 GstCudaGraphicsResource *resource = data->resource;
76 GstNvDec *nvdec = data->nvdec;
77 GstMapInfo map_info = GST_MAP_INFO_INIT;
78 GstGLBuffer *gl_buf_obj;
82 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
83 GST_WARNING_OBJECT (nvdec, "failed to push CUDA context");
87 if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) {
88 GstGLMemoryPBO *gl_mem = (GstGLMemoryPBO *) data->mem;
89 gl_buf_obj = gl_mem->pbo;
91 GST_LOG_OBJECT (nvdec,
92 "register glbuffer %d to CUDA resource", gl_buf_obj->id);
94 /* register resource without read/write only flags, since
95 * downstream CUDA elements (e.g., nvenc) might want to access
96 * this resource later. Instead, use map flags during map/unmap */
97 if (gst_cuda_graphics_resource_register_gl_buffer (resource,
98 gl_buf_obj->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) {
101 GST_WARNING_OBJECT (nvdec, "failed to register memory");
104 gst_memory_unmap (mem, &map_info);
106 GST_WARNING_OBJECT (nvdec, "failed to map memory");
109 if (!gst_cuda_context_pop (NULL))
110 GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
113 static GstCudaGraphicsResource *
114 ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
117 GstCudaGraphicsResource *cgr_info;
118 GstNvDecRegisterResourceData data;
120 if (!gst_is_gl_memory_pbo (mem)) {
121 GST_WARNING_OBJECT (nvdec, "memory is not GL PBO memory, %s",
122 mem->allocator->mem_type);
126 quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
128 cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
130 cgr_info = gst_cuda_graphics_resource_new (nvdec->cuda_ctx,
131 GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context),
132 GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER);
134 data.resource = cgr_info;
136 gst_gl_context_thread_add ((GstGLContext *) cgr_info->graphics_context,
137 (GstGLContextThreadFunc) register_cuda_resource, &data);
139 GST_WARNING_OBJECT (nvdec, "could not register resource");
140 gst_cuda_graphics_resource_free (cgr_info);
145 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
146 (GDestroyNotify) gst_cuda_graphics_resource_free);
151 #endif /* HAVE_NVCODEC_GST_GL */
153 static gboolean gst_nvdec_open (GstVideoDecoder * decoder);
154 static gboolean gst_nvdec_start (GstVideoDecoder * decoder);
155 static gboolean gst_nvdec_stop (GstVideoDecoder * decoder);
156 static gboolean gst_nvdec_close (GstVideoDecoder * decoder);
157 static gboolean gst_nvdec_set_format (GstVideoDecoder * decoder,
158 GstVideoCodecState * state);
159 static GstFlowReturn gst_nvdec_handle_frame (GstVideoDecoder * decoder,
160 GstVideoCodecFrame * frame);
161 static gboolean gst_nvdec_decide_allocation (GstVideoDecoder * decoder,
163 static void gst_nvdec_set_context (GstElement * element, GstContext * context);
164 static gboolean gst_nvdec_src_query (GstVideoDecoder * decoder,
166 static gboolean gst_nvdec_flush (GstVideoDecoder * decoder);
167 static GstFlowReturn gst_nvdec_drain (GstVideoDecoder * decoder);
168 static GstFlowReturn gst_nvdec_finish (GstVideoDecoder * decoder);
169 static gboolean gst_nvdec_negotiate (GstVideoDecoder * decoder);
170 #ifdef HAVE_NVCODEC_GST_GL
171 static gboolean gst_nvdec_ensure_gl_context (GstNvDec * nvdec);
174 #define gst_nvdec_parent_class parent_class
175 G_DEFINE_ABSTRACT_TYPE (GstNvDec, gst_nvdec, GST_TYPE_VIDEO_DECODER);
178 gst_nv_dec_set_property (GObject * object, guint prop_id, const GValue * value,
181 GstNvDec *nvdec = GST_NVDEC (object);
184 case PROP_MAX_DISPLAY_DELAY:
185 nvdec->max_display_delay = g_value_get_int (value);
188 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
194 gst_nv_dec_get_property (GObject * object, guint prop_id, GValue * value,
197 GstNvDec *nvdec = GST_NVDEC (object);
200 case PROP_MAX_DISPLAY_DELAY:
201 g_value_set_int (value, nvdec->max_display_delay);
204 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210 gst_nvdec_class_init (GstNvDecClass * klass)
212 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
213 GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
214 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
216 gobject_class->set_property = gst_nv_dec_set_property;
217 gobject_class->get_property = gst_nv_dec_get_property;
219 video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_nvdec_open);
220 video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_nvdec_start);
221 video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_nvdec_stop);
222 video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_nvdec_close);
223 video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_nvdec_set_format);
224 video_decoder_class->handle_frame =
225 GST_DEBUG_FUNCPTR (gst_nvdec_handle_frame);
226 video_decoder_class->decide_allocation =
227 GST_DEBUG_FUNCPTR (gst_nvdec_decide_allocation);
228 video_decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_nvdec_src_query);
229 video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_nvdec_drain);
230 video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_nvdec_flush);
231 video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_nvdec_finish);
232 video_decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_nvdec_negotiate);
234 element_class->set_context = GST_DEBUG_FUNCPTR (gst_nvdec_set_context);
235 gst_type_mark_as_plugin_api (GST_TYPE_NVDEC, 0);
238 * GstNvDec:max-display-delay:
242 g_object_class_install_property (gobject_class, PROP_MAX_DISPLAY_DELAY,
243 g_param_spec_int ("max-display-delay", "Max Display Delay",
244 "Improves pipelining of decode with display, 0 means no delay "
246 -1, G_MAXINT, DEFAULT_MAX_DISPLAY_DELAY,
247 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
251 gst_nvdec_init (GstNvDec * nvdec)
253 nvdec->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY;
254 gst_video_decoder_set_packetized (GST_VIDEO_DECODER (nvdec), TRUE);
255 gst_video_decoder_set_needs_format (GST_VIDEO_DECODER (nvdec), TRUE);
258 static cudaVideoSurfaceFormat
259 get_cuda_surface_format_from_gst (GstVideoFormat format)
262 case GST_VIDEO_FORMAT_NV12:
263 return cudaVideoSurfaceFormat_NV12;
264 case GST_VIDEO_FORMAT_P010_10LE:
265 case GST_VIDEO_FORMAT_P010_10BE:
266 case GST_VIDEO_FORMAT_P016_LE:
267 case GST_VIDEO_FORMAT_P016_BE:
268 return cudaVideoSurfaceFormat_P016;
269 case GST_VIDEO_FORMAT_Y444:
270 return cudaVideoSurfaceFormat_YUV444;
271 case GST_VIDEO_FORMAT_Y444_16LE:
272 case GST_VIDEO_FORMAT_Y444_16BE:
273 return cudaVideoSurfaceFormat_YUV444_16Bit;
275 g_assert_not_reached ();
279 return cudaVideoSurfaceFormat_NV12;
283 calculate_num_decode_surface (cudaVideoCodec codec, guint width, guint height)
286 case cudaVideoCodec_VP9:
288 case cudaVideoCodec_H264:
289 case cudaVideoCodec_H264_SVC:
290 case cudaVideoCodec_H264_MVC:
292 case cudaVideoCodec_HEVC:{
295 const gint MaxDpbPicBuf = 6;
296 gint PicSizeInSamplesY;
299 MaxLumaPS = 35651584;
300 PicSizeInSamplesY = width * height;
301 if (PicSizeInSamplesY <= (MaxLumaPS >> 2))
302 max_dpb_size = MaxDpbPicBuf * 4;
303 else if (PicSizeInSamplesY <= (MaxLumaPS >> 1))
304 max_dpb_size = MaxDpbPicBuf * 2;
305 else if (PicSizeInSamplesY <= ((3 * MaxLumaPS) >> 2))
306 max_dpb_size = (MaxDpbPicBuf * 4) / 3;
308 max_dpb_size = MaxDpbPicBuf;
310 max_dpb_size = MIN (max_dpb_size, 16);
312 return max_dpb_size + 4;
322 gst_nvdec_get_max_display_delay (GstNvDec * nvdec)
324 return nvdec->max_display_delay >= 0 ? nvdec->max_display_delay :
325 (nvdec->is_live ? 0 : 4);
329 gst_nvdec_get_latency (GstNvDec * nvdec)
333 if (!nvdec->input_state)
335 fps_n = GST_VIDEO_INFO_FPS_N (&nvdec->input_state->info);
336 fps_d = GST_VIDEO_INFO_FPS_D (&nvdec->input_state->info);
338 /* We assume 25 fps if the input framerate is invalid */
339 if (fps_n < 1 || fps_d < 1) {
344 return gst_util_uint64_scale_int ((nvdec->num_decode_surface +
345 gst_nvdec_get_max_display_delay (nvdec)) * GST_SECOND, fps_d, fps_n);
348 /* 0: fail, 1: succeeded, > 1: override dpb size of parser
349 * (set by CUVIDPARSERPARAMS::ulMaxNumDecodeSurfaces while creating parser) */
351 parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
354 CUVIDDECODECREATEINFO create_info = { 0, };
355 GstVideoFormat out_format;
356 GstVideoInfo *in_info = &nvdec->input_state->info;
357 GstVideoInfo *out_info = &nvdec->out_info;
358 GstVideoInfo prev_out_info = *out_info;
359 GstCudaContext *ctx = nvdec->cuda_ctx;
360 GstStructure *in_s = NULL;
361 gboolean updata = FALSE;
362 guint major_api_ver = 0;
363 guint64 curr_latency, old_latency;
365 old_latency = gst_nvdec_get_latency (nvdec);
366 width = format->display_area.right - format->display_area.left;
367 height = format->display_area.bottom - format->display_area.top;
369 switch (format->chroma_format) {
370 case cudaVideoChromaFormat_444:
371 if (format->bit_depth_luma_minus8 == 0) {
372 out_format = GST_VIDEO_FORMAT_Y444;
373 } else if (format->bit_depth_luma_minus8 == 2 ||
374 format->bit_depth_luma_minus8 == 4) {
375 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
376 out_format = GST_VIDEO_FORMAT_Y444_16LE;
378 out_format = GST_VIDEO_FORMAT_Y444_16BE;
381 GST_ERROR_OBJECT (nvdec, "Unknown 4:4:4 format bitdepth %d",
382 format->bit_depth_luma_minus8 + 8);
384 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
388 case cudaVideoChromaFormat_420:
389 if (format->bit_depth_luma_minus8 == 0) {
390 out_format = GST_VIDEO_FORMAT_NV12;
391 } else if (format->bit_depth_luma_minus8 == 2) {
392 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
393 out_format = GST_VIDEO_FORMAT_P010_10LE;
395 out_format = GST_VIDEO_FORMAT_P010_10BE;
397 } else if (format->bit_depth_luma_minus8 == 4) {
398 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
399 out_format = GST_VIDEO_FORMAT_P016_LE;
401 out_format = GST_VIDEO_FORMAT_P016_BE;
404 GST_ERROR_OBJECT (nvdec, "Unknown 4:2:0 format bitdepth %d",
405 format->bit_depth_luma_minus8 + 8);
407 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
412 GST_ERROR_OBJECT (nvdec, "unhandled chroma format %d, bitdepth %d",
413 format->chroma_format, format->bit_depth_luma_minus8 + 8);
415 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
419 GST_DEBUG_OBJECT (nvdec,
420 "out format: %s", gst_video_format_to_string (out_format));
422 GST_DEBUG_OBJECT (nvdec, "width: %u, height: %u", width, height);
424 gst_video_info_set_format (out_info, out_format, width, height);
425 GST_VIDEO_INFO_FPS_N (out_info) = GST_VIDEO_INFO_FPS_N (in_info);
426 GST_VIDEO_INFO_FPS_D (out_info) = GST_VIDEO_INFO_FPS_D (in_info);
428 if (GST_VIDEO_INFO_FPS_N (out_info) < 1 ||
429 GST_VIDEO_INFO_FPS_D (out_info) < 1) {
430 GST_VIDEO_INFO_FPS_N (out_info) = format->frame_rate.numerator;
431 GST_VIDEO_INFO_FPS_D (out_info) = MAX (1, format->frame_rate.denominator);
434 GST_LOG_OBJECT (nvdec,
435 "Reading colorimetry information full-range %d matrix %d transfer %d primaries %d",
436 format->video_signal_description.video_full_range_flag,
437 format->video_signal_description.matrix_coefficients,
438 format->video_signal_description.transfer_characteristics,
439 format->video_signal_description.color_primaries);
441 if (nvdec->input_state->caps)
442 in_s = gst_caps_get_structure (nvdec->input_state->caps, 0);
444 /* Set colorimetry when upstream did not provide it */
445 if (in_s && !gst_structure_has_field (in_s, "colorimetry")) {
446 GstVideoColorimetry colorimetry = { 0, };
448 if (format->video_signal_description.video_full_range_flag)
449 colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
451 colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
453 colorimetry.primaries =
454 gst_video_color_primaries_from_iso
455 (format->video_signal_description.color_primaries);
457 colorimetry.transfer =
458 gst_video_transfer_function_from_iso
459 (format->video_signal_description.transfer_characteristics);
462 gst_video_color_matrix_from_iso
463 (format->video_signal_description.matrix_coefficients);
465 /* Use a colorimetry having at least one valid colorimetry entry,
466 * because we don't know whether the returned
467 * colorimetry (by nvdec) was actually parsed information or not.
468 * Otherwise let GstVideoInfo handle it with default colorimetry */
469 if (colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN ||
470 colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN ||
471 colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
472 GST_DEBUG_OBJECT (nvdec,
473 "Found valid colorimetry, update output colorimetry");
474 out_info->colorimetry = colorimetry;
477 out_info->colorimetry = in_info->colorimetry;
480 if (format->progressive_sequence) {
481 out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
483 /* nvdec doesn't seem to deal with interlacing with hevc so rely
484 * on upstream's value */
485 if (format->codec == cudaVideoCodec_HEVC) {
486 out_info->interlace_mode = in_info->interlace_mode;
489 out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
492 if (gst_cuvid_get_api_version (&major_api_ver, NULL) && major_api_ver >= 9) {
493 /* min_num_decode_surfaces was introduced in nvcodec sdk 9.0 header */
494 nvdec->num_decode_surface = format->min_num_decode_surfaces;
496 GST_DEBUG_OBJECT (nvdec,
497 "Num decode surface: %d", nvdec->num_decode_surface);
499 nvdec->num_decode_surface =
500 calculate_num_decode_surface (format->codec, width, height);
502 GST_DEBUG_OBJECT (nvdec,
503 "Calculated num decode surface: %d", nvdec->num_decode_surface);
506 /* Update the latency if it has changed */
507 curr_latency = gst_nvdec_get_latency (nvdec);
508 if (old_latency != curr_latency)
509 gst_video_decoder_set_latency (GST_VIDEO_DECODER (nvdec), curr_latency,
512 if (!nvdec->decoder || !gst_video_info_is_equal (out_info, &prev_out_info)) {
515 if (!gst_cuda_context_push (ctx)) {
516 GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
520 if (nvdec->decoder) {
521 GST_DEBUG_OBJECT (nvdec, "destroying decoder");
522 if (!gst_cuda_result (CuvidDestroyDecoder (nvdec->decoder))) {
523 GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
526 nvdec->decoder = NULL;
529 GST_DEBUG_OBJECT (nvdec, "creating decoder");
530 create_info.ulWidth = width;
531 create_info.ulHeight = height;
532 create_info.ulNumDecodeSurfaces = nvdec->num_decode_surface;
533 create_info.CodecType = format->codec;
534 create_info.ChromaFormat = format->chroma_format;
535 create_info.ulCreationFlags = cudaVideoCreate_Default;
536 create_info.display_area.left = format->display_area.left;
537 create_info.display_area.top = format->display_area.top;
538 create_info.display_area.right = format->display_area.right;
539 create_info.display_area.bottom = format->display_area.bottom;
540 create_info.OutputFormat = get_cuda_surface_format_from_gst (out_format);
541 create_info.bitDepthMinus8 = format->bit_depth_luma_minus8;
542 create_info.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
543 create_info.ulTargetWidth = width;
544 create_info.ulTargetHeight = height;
545 create_info.ulNumOutputSurfaces = 1;
546 create_info.target_rect.left = 0;
547 create_info.target_rect.top = 0;
548 create_info.target_rect.right = width;
549 create_info.target_rect.bottom = height;
552 || !gst_cuda_result (CuvidCreateDecoder (&nvdec->decoder,
554 GST_ERROR_OBJECT (nvdec, "failed to create decoder");
558 if (!gst_cuda_context_pop (NULL)) {
559 GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
564 if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (nvdec)) || updata) {
565 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (nvdec))) {
566 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
571 return nvdec->num_decode_surface;
574 nvdec->last_ret = GST_FLOW_ERROR;
579 gst_nvdec_negotiate (GstVideoDecoder * decoder)
581 GstNvDec *nvdec = GST_NVDEC (decoder);
582 GstVideoCodecState *state;
584 GstVideoInfo *out_info = &nvdec->out_info;
587 GST_DEBUG_OBJECT (nvdec, "negotiate");
589 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (nvdec),
590 GST_VIDEO_INFO_FORMAT (out_info), GST_VIDEO_INFO_WIDTH (out_info),
591 GST_VIDEO_INFO_HEIGHT (out_info), nvdec->input_state);
592 vinfo = &state->info;
594 /* update output info with CUvidparser provided one */
595 vinfo->interlace_mode = out_info->interlace_mode;
596 vinfo->fps_n = out_info->fps_n;
597 vinfo->fps_d = out_info->fps_d;
599 state->caps = gst_video_info_to_caps (&state->info);
600 nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
604 caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (nvdec));
605 GST_DEBUG_OBJECT (nvdec, "Allowed caps %" GST_PTR_FORMAT, caps);
607 if (!caps || gst_caps_is_any (caps)) {
608 GST_DEBUG_OBJECT (nvdec,
609 "cannot determine output format, use system memory");
611 GstCapsFeatures *features;
612 guint size = gst_caps_get_size (caps);
614 gboolean have_cuda = FALSE;
615 gboolean have_gl = FALSE;
617 for (i = 0; i < size; i++) {
618 features = gst_caps_get_features (caps, i);
619 if (features && gst_caps_features_contains (features,
620 GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) {
621 GST_DEBUG_OBJECT (nvdec, "found CUDA memory feature");
625 #ifdef HAVE_NVCODEC_GST_GL
626 if (nvdec->gl_display &&
627 features && gst_caps_features_contains (features,
628 GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
629 GST_DEBUG_OBJECT (nvdec, "found GL memory feature");
636 nvdec->mem_type = GST_NVDEC_MEM_TYPE_CUDA;
638 nvdec->mem_type = GST_NVDEC_MEM_TYPE_GL;
640 gst_clear_caps (&caps);
643 #ifdef HAVE_NVCODEC_GST_GL
644 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL &&
645 !gst_nvdec_ensure_gl_context (nvdec)) {
646 GST_WARNING_OBJECT (nvdec,
647 "OpenGL context is not CUDA-compatible, fallback to system memory");
648 nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
652 switch (nvdec->mem_type) {
653 case GST_NVDEC_MEM_TYPE_CUDA:
654 GST_DEBUG_OBJECT (nvdec, "use cuda memory");
655 gst_caps_set_features (state->caps, 0,
656 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, NULL));
658 #ifdef HAVE_NVCODEC_GST_GL
659 case GST_NVDEC_MEM_TYPE_GL:
660 GST_DEBUG_OBJECT (nvdec, "use gl memory");
661 gst_caps_set_features (state->caps, 0,
662 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, NULL));
663 gst_caps_set_simple (state->caps, "texture-target", G_TYPE_STRING,
668 GST_DEBUG_OBJECT (nvdec, "use system memory");
672 if (nvdec->output_state)
673 gst_video_codec_state_unref (nvdec->output_state);
675 nvdec->output_state = state;
677 ret = GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
680 GST_ERROR_OBJECT (nvdec, "failed to negotiate with downstream");
681 nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
687 static gboolean CUDAAPI
688 parser_decode_callback (GstNvDec * nvdec, CUVIDPICPARAMS * params)
690 GList *iter, *pending_frames;
691 GstCudaContext *ctx = nvdec->cuda_ctx;
693 GST_LOG_OBJECT (nvdec, "picture index: %u", params->CurrPicIdx);
695 if (!gst_cuda_context_push (ctx)) {
696 GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
700 if (!gst_cuda_result (CuvidDecodePicture (nvdec->decoder, params))) {
701 GST_ERROR_OBJECT (nvdec, "failed to decode picture");
705 if (!gst_cuda_context_pop (NULL)) {
706 GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
710 pending_frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (nvdec));
712 /* NOTE: this decode callback could be invoked multiple times for
713 * one cuvidParseVideoData() call. Most likely it can be related to "decode only"
714 * frame of VPX codec but no document available.
715 * In that case, the last decoded frame seems to be displayed */
717 for (iter = pending_frames; iter; iter = g_list_next (iter)) {
719 GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
720 gboolean set_data = FALSE;
722 id = GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data (frame));
723 if (G_UNLIKELY (nvdec->state == GST_NVDEC_STATE_DECODE)) {
725 GST_LOG_OBJECT (nvdec, "reset the last user data");
733 gst_video_codec_frame_set_user_data (frame,
734 GUINT_TO_POINTER (params->CurrPicIdx + 1), NULL);
739 nvdec->state = GST_NVDEC_STATE_DECODE;
741 g_list_free_full (pending_frames,
742 (GDestroyNotify) gst_video_codec_frame_unref);
747 nvdec->last_ret = GST_FLOW_ERROR;
751 static gboolean CUDAAPI
752 parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
754 GList *iter, *pending_frames;
755 GstVideoCodecFrame *frame = NULL;
756 GstBuffer *output_buffer = NULL;
757 GstFlowReturn ret = GST_FLOW_OK;
758 gboolean copy_ret = FALSE;
760 GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
762 pending_frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (nvdec));
763 for (iter = pending_frames; iter; iter = g_list_next (iter)) {
765 GstVideoCodecFrame *tmp = (GstVideoCodecFrame *) iter->data;
767 id = GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data (tmp));
768 if (id == dispinfo->picture_index + 1) {
769 frame = gst_video_codec_frame_ref (tmp);
773 g_list_free_full (pending_frames,
774 (GDestroyNotify) gst_video_codec_frame_unref);
776 if (G_UNLIKELY (frame == NULL)) {
777 GST_WARNING_OBJECT (nvdec, "no frame for picture index %u",
778 dispinfo->picture_index);
781 gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (nvdec));
783 if (!output_buffer) {
784 GST_ERROR_OBJECT (nvdec, "Couldn't allocate output buffer");
785 nvdec->last_ret = GST_FLOW_ERROR;
789 GST_BUFFER_PTS (output_buffer) = dispinfo->timestamp;
790 GST_BUFFER_DTS (output_buffer) = GST_CLOCK_TIME_NONE;
791 /* assume buffer duration from framerate */
792 GST_BUFFER_DURATION (output_buffer) =
793 gst_util_uint64_scale (GST_SECOND,
794 GST_VIDEO_INFO_FPS_D (&nvdec->out_info),
795 GST_VIDEO_INFO_FPS_N (&nvdec->out_info));
797 ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (nvdec),
800 if (ret != GST_FLOW_OK) {
801 GST_WARNING_OBJECT (nvdec, "failed to allocate output frame");
802 nvdec->last_ret = ret;
806 output_buffer = frame->output_buffer;
808 if (dispinfo->timestamp != frame->pts) {
809 GST_INFO_OBJECT (nvdec,
810 "timestamp mismatch, diff: %" GST_STIME_FORMAT,
811 GST_STIME_ARGS (GST_CLOCK_DIFF (dispinfo->timestamp, frame->pts)));
815 #ifdef HAVE_NVCODEC_GST_GL
816 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL) {
817 copy_ret = gst_nvdec_copy_device_to_gl (nvdec, dispinfo, output_buffer);
819 /* FIXME: This is the case where OpenGL context of downstream glbufferpool
820 * belongs to non-nvidia (or different device).
821 * There should be enhancement to ensure nvdec has compatible OpenGL context
824 GST_WARNING_OBJECT (nvdec,
825 "Couldn't copy frame to GL memory, fallback to system memory");
826 nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
833 copy_ret = gst_nvdec_copy_device_to_memory (nvdec, dispinfo, output_buffer);
837 GST_ERROR_OBJECT (nvdec, "failed to copy decoded picture to output buffer");
838 nvdec->last_ret = GST_FLOW_ERROR;
841 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (nvdec), frame);
843 gst_buffer_unref (output_buffer);
848 if (!dispinfo->progressive_frame) {
849 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
851 if (dispinfo->top_field_first) {
852 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
855 if (dispinfo->repeat_first_field == -1) {
856 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_ONEFIELD);
858 GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_RFF);
863 ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (nvdec), frame);
865 ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (nvdec), output_buffer);
868 if (ret != GST_FLOW_OK) {
869 GST_DEBUG_OBJECT (nvdec, "failed to finish frame %s",
870 gst_flow_get_name (ret));
871 nvdec->last_ret = ret;
879 gst_nvdec_open (GstVideoDecoder * decoder)
881 GstNvDec *nvdec = GST_NVDEC (decoder);
882 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
885 GST_DEBUG_OBJECT (nvdec, "creating CUDA context");
887 if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (decoder),
888 klass->cuda_device_id, &nvdec->cuda_ctx)) {
889 GST_ERROR_OBJECT (nvdec, "failed to create CUDA context");
893 if (gst_cuda_context_push (nvdec->cuda_ctx)) {
894 cuda_ret = CuStreamCreate (&nvdec->cuda_stream, CU_STREAM_DEFAULT);
895 if (!gst_cuda_result (cuda_ret)) {
896 GST_WARNING_OBJECT (nvdec,
897 "Could not create CUDA stream, will use default stream");
898 nvdec->cuda_stream = NULL;
900 gst_cuda_context_pop (NULL);
902 #if HAVE_NVCODEC_GST_GL
903 gst_gl_ensure_element_data (GST_ELEMENT (nvdec),
904 &nvdec->gl_display, &nvdec->other_gl_context);
905 if (nvdec->gl_display)
906 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvdec->gl_display),
914 gst_nvdec_start (GstVideoDecoder * decoder)
916 GstNvDec *nvdec = GST_NVDEC (decoder);
917 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
919 nvdec->state = GST_NVDEC_STATE_INIT;
920 nvdec->last_ret = GST_FLOW_OK;
921 gst_video_info_init (&nvdec->out_info);
923 if (klass->codec_type == cudaVideoCodec_H264)
924 nvdec->h264_parser = gst_h264_nal_parser_new ();
925 else if (klass->codec_type == cudaVideoCodec_HEVC)
926 nvdec->h265_parser = gst_h265_parser_new ();
932 maybe_destroy_decoder_and_parser (GstNvDec * nvdec)
936 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
937 GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
941 if (nvdec->decoder) {
942 GST_DEBUG_OBJECT (nvdec, "destroying decoder");
943 ret = gst_cuda_result (CuvidDestroyDecoder (nvdec->decoder));
944 nvdec->decoder = NULL;
947 GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
951 GST_DEBUG_OBJECT (nvdec, "destroying parser");
952 if (!gst_cuda_result (CuvidDestroyVideoParser (nvdec->parser))) {
953 GST_ERROR_OBJECT (nvdec, "failed to destroy parser");
956 nvdec->parser = NULL;
959 if (!gst_cuda_context_pop (NULL)) {
960 GST_WARNING_OBJECT (nvdec, "failed to pop CUDA context");
967 gst_nvdec_clear_codec_data (GstNvDec * self)
969 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (self);
972 if (klass->codec_type == cudaVideoCodec_HEVC) {
973 for (i = 0; i < G_N_ELEMENTS (self->vps_nals); i++) {
974 gst_clear_buffer (&self->vps_nals[i]);
978 if (klass->codec_type == cudaVideoCodec_HEVC ||
979 klass->codec_type == cudaVideoCodec_H264) {
980 for (i = 0; i < G_N_ELEMENTS (self->sps_nals); i++) {
981 gst_clear_buffer (&self->sps_nals[i]);
984 for (i = 0; i < G_N_ELEMENTS (self->pps_nals); i++) {
985 gst_clear_buffer (&self->pps_nals[i]);
989 gst_clear_buffer (&self->codec_data);
991 self->need_codec_data = TRUE;
995 gst_nvdec_stop (GstVideoDecoder * decoder)
997 GstNvDec *nvdec = GST_NVDEC (decoder);
999 GST_DEBUG_OBJECT (nvdec, "stop");
1001 if (!maybe_destroy_decoder_and_parser (nvdec))
1004 #ifdef HAVE_NVCODEC_GST_GL
1005 gst_clear_object (&nvdec->gl_context);
1006 gst_clear_object (&nvdec->other_gl_context);
1007 gst_clear_object (&nvdec->gl_display);
1010 g_clear_pointer (&nvdec->input_state, gst_video_codec_state_unref);
1011 g_clear_pointer (&nvdec->output_state, gst_video_codec_state_unref);
1013 g_clear_pointer (&nvdec->h264_parser, gst_h264_nal_parser_free);
1014 g_clear_pointer (&nvdec->h265_parser, gst_h265_parser_free);
1016 gst_nvdec_clear_codec_data (nvdec);
1022 gst_nvdec_close (GstVideoDecoder * decoder)
1024 GstNvDec *nvdec = GST_NVDEC (decoder);
1026 if (nvdec->cuda_ctx && nvdec->cuda_stream) {
1027 if (gst_cuda_context_push (nvdec->cuda_ctx)) {
1028 gst_cuda_result (CuStreamDestroy (nvdec->cuda_stream));
1029 gst_cuda_context_pop (NULL);
1033 gst_clear_object (&nvdec->cuda_ctx);
1034 nvdec->cuda_stream = NULL;
1040 gst_nvdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
1042 GstNvDec *nvdec = GST_NVDEC (decoder);
1043 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (decoder);
1044 CUVIDPARSERPARAMS parser_params = { 0, };
1046 gboolean ret = TRUE;
1048 GST_DEBUG_OBJECT (nvdec, "set format");
1050 if (nvdec->input_state)
1051 gst_video_codec_state_unref (nvdec->input_state);
1053 nvdec->input_state = gst_video_codec_state_ref (state);
1055 if (!maybe_destroy_decoder_and_parser (nvdec))
1058 /* Check if pipeline is live */
1059 nvdec->is_live = FALSE;
1060 query = gst_query_new_latency ();
1061 if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (decoder), query))
1062 gst_query_parse_latency (query, &nvdec->is_live, NULL, NULL);
1063 gst_query_unref (query);
1065 parser_params.CodecType = klass->codec_type;
1066 /* ulMaxNumDecodeSurfaces will be updated by the return value of
1067 * SequenceCallback */
1068 parser_params.ulMaxNumDecodeSurfaces = 1;
1069 parser_params.ulErrorThreshold = 100;
1070 parser_params.ulMaxDisplayDelay = gst_nvdec_get_max_display_delay (nvdec);
1071 parser_params.ulClockRate = GST_SECOND;
1072 parser_params.pUserData = nvdec;
1073 parser_params.pfnSequenceCallback =
1074 (PFNVIDSEQUENCECALLBACK) parser_sequence_callback;
1075 parser_params.pfnDecodePicture =
1076 (PFNVIDDECODECALLBACK) parser_decode_callback;
1077 parser_params.pfnDisplayPicture =
1078 (PFNVIDDISPLAYCALLBACK) parser_display_callback;
1080 gst_cuda_context_push (nvdec->cuda_ctx);
1081 GST_DEBUG_OBJECT (nvdec, "creating parser");
1082 if (!gst_cuda_result (CuvidCreateVideoParser (&nvdec->parser,
1084 GST_ERROR_OBJECT (nvdec, "failed to create parser");
1088 gst_cuda_context_pop (NULL);
1090 /* store codec data */
1091 gst_nvdec_clear_codec_data (nvdec);
1093 if (ret && nvdec->input_state->caps) {
1096 str = gst_caps_get_structure (nvdec->input_state->caps, 0);
1098 if (klass->codec_type == cudaVideoCodec_MPEG4) {
1099 const GValue *codec_data_value;
1100 codec_data_value = gst_structure_get_value (str, "codec_data");
1101 if (codec_data_value && GST_VALUE_HOLDS_BUFFER (codec_data_value)) {
1102 GstBuffer *codec_data = gst_value_get_buffer (codec_data_value);
1103 gst_buffer_replace (&nvdec->codec_data, codec_data);
1107 /* For all CODEC we get complete picture ... */
1108 nvdec->recv_complete_picture = TRUE;
1110 /* Except for JPEG, for which it depends on the caps */
1111 if (klass->codec_type == cudaVideoCodec_JPEG) {
1113 if (gst_structure_get_boolean (str, "parsed", &parsed))
1114 nvdec->recv_complete_picture = parsed;
1116 nvdec->recv_complete_picture = FALSE;
1123 #ifdef HAVE_NVCODEC_GST_GL
1127 CUVIDPARSERDISPINFO *dispinfo;
1129 GstBuffer *output_buffer;
1130 } GstNvDecCopyToGLData;
1133 copy_video_frame_to_gl_textures (GstGLContext * context,
1134 GstNvDecCopyToGLData * data)
1136 GstNvDec *nvdec = data->nvdec;
1137 CUVIDPARSERDISPINFO *dispinfo = data->dispinfo;
1138 GstCudaGraphicsResource **resources;
1139 guint num_resources;
1140 CUVIDPROCPARAMS proc_params = { 0, };
1143 CUDA_MEMCPY2D mcpy2d = { 0, };
1144 GstVideoInfo *info = &nvdec->output_state->info;
1146 GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
1148 proc_params.progressive_frame = dispinfo->progressive_frame;
1149 proc_params.top_field_first = dispinfo->top_field_first;
1150 proc_params.unpaired_field = dispinfo->repeat_first_field == -1;
1154 num_resources = gst_buffer_n_memory (data->output_buffer);
1155 resources = g_newa (GstCudaGraphicsResource *, num_resources);
1157 for (i = 0; i < num_resources; i++) {
1160 mem = gst_buffer_peek_memory (data->output_buffer, i);
1161 resources[i] = ensure_cuda_graphics_resource (mem, nvdec);
1162 if (!resources[i]) {
1163 GST_WARNING_OBJECT (nvdec, "could not register %dth memory", i);
1169 /* Need PBO -> texture */
1170 GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
1173 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
1174 GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
1179 if (!gst_cuda_result (CuvidMapVideoFrame (nvdec->decoder,
1180 dispinfo->picture_index, &dptr, &pitch, &proc_params))) {
1181 GST_WARNING_OBJECT (nvdec, "failed to map CUDA video frame");
1183 goto unlock_cuda_context;
1186 mcpy2d.srcMemoryType = CU_MEMORYTYPE_DEVICE;
1187 mcpy2d.srcPitch = pitch;
1188 mcpy2d.dstMemoryType = CU_MEMORYTYPE_DEVICE;
1190 for (i = 0; i < num_resources; i++) {
1191 CUdeviceptr cuda_ptr;
1193 CUgraphicsResource cuda_resource =
1194 gst_cuda_graphics_resource_map (resources[i], nvdec->cuda_stream,
1195 CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1197 if (!cuda_resource) {
1198 GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
1200 goto unmap_video_frame;
1203 if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&cuda_ptr, &size,
1205 GST_WARNING_OBJECT (nvdec, "failed to map CUDA resource");
1210 mcpy2d.dstPitch = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
1211 mcpy2d.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (info, i)
1212 * GST_VIDEO_INFO_COMP_PSTRIDE (info, i);
1214 mcpy2d.srcDevice = dptr + (i * pitch * GST_VIDEO_INFO_HEIGHT (info));
1215 mcpy2d.dstDevice = cuda_ptr;
1216 mcpy2d.Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
1218 if (!gst_cuda_result (CuMemcpy2DAsync (&mcpy2d, nvdec->cuda_stream))) {
1219 GST_WARNING_OBJECT (nvdec, "memcpy to mapped array failed");
1224 gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
1227 for (i = 0; i < num_resources; i++) {
1228 gst_cuda_graphics_resource_unmap (resources[i], nvdec->cuda_stream);
1231 if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
1232 GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
1234 unlock_cuda_context:
1235 if (!gst_cuda_context_pop (NULL))
1236 GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
1240 gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
1241 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
1243 GstNvDecCopyToGLData data = { 0, };
1246 data.dispinfo = dispinfo;
1247 data.output_buffer = output_buffer;
1249 gst_gl_context_thread_add (nvdec->gl_context,
1250 (GstGLContextThreadFunc) copy_video_frame_to_gl_textures, &data);
1257 gst_nvdec_copy_device_to_memory (GstNvDec * nvdec,
1258 CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
1260 CUVIDPROCPARAMS params = { 0, };
1261 CUDA_MEMCPY2D copy_params = { 0, };
1264 GstVideoFrame video_frame;
1265 GstVideoInfo *info = &nvdec->output_state->info;
1268 gboolean use_device_copy = FALSE;
1269 GstMapFlags map_flags = GST_MAP_WRITE;
1271 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_CUDA &&
1272 (mem = gst_buffer_peek_memory (output_buffer, 0)) &&
1273 gst_is_cuda_memory (mem)) {
1274 map_flags |= GST_MAP_CUDA;
1275 use_device_copy = TRUE;
1278 if (!gst_video_frame_map (&video_frame, info, output_buffer, map_flags)) {
1279 GST_ERROR_OBJECT (nvdec, "frame map failure");
1283 if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
1284 gst_video_frame_unmap (&video_frame);
1285 GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
1289 params.progressive_frame = dispinfo->progressive_frame;
1290 params.second_field = dispinfo->repeat_first_field + 1;
1291 params.top_field_first = dispinfo->top_field_first;
1292 params.unpaired_field = dispinfo->repeat_first_field < 0;
1294 if (!gst_cuda_result (CuvidMapVideoFrame (nvdec->decoder,
1295 dispinfo->picture_index, &dptr, &pitch, ¶ms))) {
1296 GST_ERROR_OBJECT (nvdec, "failed to map video frame");
1297 gst_cuda_context_pop (NULL);
1301 copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
1302 copy_params.srcPitch = pitch;
1303 copy_params.dstMemoryType =
1304 use_device_copy ? CU_MEMORYTYPE_DEVICE : CU_MEMORYTYPE_HOST;
1306 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1307 copy_params.srcDevice = dptr + (i * pitch * GST_VIDEO_INFO_HEIGHT (info));
1308 if (use_device_copy) {
1309 copy_params.dstDevice =
1310 (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (&video_frame, i);
1312 copy_params.dstHost = GST_VIDEO_FRAME_PLANE_DATA (&video_frame, i);
1314 copy_params.dstPitch = GST_VIDEO_FRAME_PLANE_STRIDE (&video_frame, i);
1315 copy_params.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (info, i)
1316 * GST_VIDEO_INFO_COMP_PSTRIDE (info, i);
1317 copy_params.Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
1319 if (!gst_cuda_result (CuMemcpy2DAsync (©_params, nvdec->cuda_stream))) {
1320 GST_ERROR_OBJECT (nvdec, "failed to copy %dth plane", i);
1321 CuvidUnmapVideoFrame (nvdec->decoder, dptr);
1322 gst_video_frame_unmap (&video_frame);
1323 gst_cuda_context_pop (NULL);
1328 gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
1330 gst_video_frame_unmap (&video_frame);
1332 if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
1333 GST_WARNING_OBJECT (nvdec, "failed to unmap video frame");
1335 if (!gst_cuda_context_pop (NULL))
1336 GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
1342 gst_nvdec_store_h264_nal (GstNvDec * self, guint id,
1343 GstH264NalUnitType nal_type, GstH264NalUnit * nalu)
1345 GstBuffer *buf, **store;
1346 guint size = nalu->size, store_size;
1347 static const guint8 start_code[] = { 0, 0, 1 };
1349 if (nal_type == GST_H264_NAL_SPS || nal_type == GST_H264_NAL_SUBSET_SPS) {
1350 store_size = GST_H264_MAX_SPS_COUNT;
1351 store = self->sps_nals;
1352 GST_DEBUG_OBJECT (self, "storing sps %u", id);
1353 } else if (nal_type == GST_H264_NAL_PPS) {
1354 store_size = GST_H264_MAX_PPS_COUNT;
1355 store = self->pps_nals;
1356 GST_DEBUG_OBJECT (self, "storing pps %u", id);
1361 if (id >= store_size) {
1362 GST_DEBUG_OBJECT (self, "unable to store nal, id out-of-range %d", id);
1366 buf = gst_buffer_new_allocate (NULL, size + sizeof (start_code), NULL);
1367 gst_buffer_fill (buf, 0, start_code, sizeof (start_code));
1368 gst_buffer_fill (buf, sizeof (start_code), nalu->data + nalu->offset, size);
1371 gst_buffer_unref (store[id]);
1377 gst_nvdec_handle_h264_buffer (GstNvDec * self, GstBuffer * buffer)
1379 GstH264NalParser *parser = self->h264_parser;
1380 GstH264NalUnit nalu;
1381 GstH264ParserResult pres;
1383 gboolean have_sps = FALSE;
1384 gboolean have_pps = FALSE;
1388 if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
1389 GST_WARNING_OBJECT (self, "Failed to map input buffer");
1390 return gst_buffer_ref (buffer);
1393 memset (&nalu, 0, sizeof (GstH264NalUnit));
1396 pres = gst_h264_parser_identify_nalu (parser,
1397 map.data, nalu.offset + nalu.size, map.size, &nalu);
1399 if (pres == GST_H264_PARSER_NO_NAL_END)
1400 pres = GST_H264_PARSER_OK;
1402 switch (nalu.type) {
1403 case GST_H264_NAL_SPS:
1404 case GST_H264_NAL_SUBSET_SPS:{
1407 if (nalu.type == GST_H264_NAL_SPS) {
1408 pres = gst_h264_parser_parse_sps (parser, &nalu, &sps);
1410 pres = gst_h264_parser_parse_subset_sps (parser, &nalu, &sps);
1413 if (pres != GST_H264_PARSER_OK)
1417 gst_nvdec_store_h264_nal (self, sps.id, nalu.type, &nalu);
1418 gst_h264_sps_clear (&sps);
1421 case GST_H264_NAL_PPS:{
1424 pres = gst_h264_parser_parse_pps (parser, &nalu, &pps);
1425 if (pres != GST_H264_PARSER_OK)
1429 gst_nvdec_store_h264_nal (self, pps.id, nalu.type, &nalu);
1430 gst_h264_pps_clear (&pps);
1436 } while (pres == GST_H264_PARSER_OK);
1438 gst_buffer_unmap (buffer, &map);
1440 if (!self->need_codec_data || (have_sps && have_pps)) {
1441 self->need_codec_data = FALSE;
1442 return gst_buffer_ref (buffer);
1445 new_buf = gst_buffer_new ();
1447 for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
1448 if (!self->sps_nals[i])
1452 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->sps_nals[i]));
1457 for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
1458 if (!self->pps_nals[i])
1462 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->pps_nals[i]));
1466 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (buffer));
1468 if (have_sps && have_pps)
1469 self->need_codec_data = FALSE;
1475 gst_nvdec_store_h265_nal (GstNvDec * self, guint id,
1476 GstH265NalUnitType nal_type, GstH265NalUnit * nalu)
1478 GstBuffer *buf, **store;
1479 guint size = nalu->size, store_size;
1480 static const guint8 start_code[] = { 0, 0, 1 };
1482 if (nal_type == GST_H265_NAL_VPS) {
1483 store_size = GST_H265_MAX_VPS_COUNT;
1484 store = self->vps_nals;
1485 GST_DEBUG_OBJECT (self, "storing vps %u", id);
1486 } else if (nal_type == GST_H265_NAL_SPS) {
1487 store_size = GST_H265_MAX_SPS_COUNT;
1488 store = self->sps_nals;
1489 GST_DEBUG_OBJECT (self, "storing sps %u", id);
1490 } else if (nal_type == GST_H265_NAL_PPS) {
1491 store_size = GST_H265_MAX_PPS_COUNT;
1492 store = self->pps_nals;
1493 GST_DEBUG_OBJECT (self, "storing pps %u", id);
1498 if (id >= store_size) {
1499 GST_DEBUG_OBJECT (self, "unable to store nal, id out-of-range %d", id);
1503 buf = gst_buffer_new_allocate (NULL, size + sizeof (start_code), NULL);
1504 gst_buffer_fill (buf, 0, start_code, sizeof (start_code));
1505 gst_buffer_fill (buf, sizeof (start_code), nalu->data + nalu->offset, size);
1508 gst_buffer_unref (store[id]);
1514 gst_nvdec_handle_h265_buffer (GstNvDec * self, GstBuffer * buffer)
1516 GstH265Parser *parser = self->h265_parser;
1517 GstH265NalUnit nalu;
1518 GstH265ParserResult pres;
1520 gboolean have_vps = FALSE;
1521 gboolean have_sps = FALSE;
1522 gboolean have_pps = FALSE;
1526 if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
1527 GST_WARNING_OBJECT (self, "Failed to map input buffer");
1528 return gst_buffer_ref (buffer);
1531 memset (&nalu, 0, sizeof (GstH265NalUnit));
1534 pres = gst_h265_parser_identify_nalu (parser,
1535 map.data, nalu.offset + nalu.size, map.size, &nalu);
1537 if (pres == GST_H265_PARSER_NO_NAL_END)
1538 pres = GST_H265_PARSER_OK;
1540 switch (nalu.type) {
1541 case GST_H265_NAL_VPS:{
1544 pres = gst_h265_parser_parse_vps (parser, &nalu, &vps);
1545 if (pres != GST_H265_PARSER_OK)
1549 gst_nvdec_store_h265_nal (self, vps.id, nalu.type, &nalu);
1552 case GST_H265_NAL_SPS:{
1555 pres = gst_h265_parser_parse_sps (parser, &nalu, &sps, FALSE);
1556 if (pres != GST_H265_PARSER_OK)
1560 gst_nvdec_store_h265_nal (self, sps.id, nalu.type, &nalu);
1563 case GST_H265_NAL_PPS:{
1566 pres = gst_h265_parser_parse_pps (parser, &nalu, &pps);
1567 if (pres != GST_H265_PARSER_OK)
1571 gst_nvdec_store_h265_nal (self, pps.id, nalu.type, &nalu);
1577 } while (pres == GST_H265_PARSER_OK);
1579 gst_buffer_unmap (buffer, &map);
1581 if (!self->need_codec_data || (have_sps && have_pps)) {
1582 self->need_codec_data = FALSE;
1583 return gst_buffer_ref (buffer);
1586 new_buf = gst_buffer_new ();
1588 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1589 if (!self->vps_nals[i])
1592 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->vps_nals[i]));
1597 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1598 if (!self->sps_nals[i])
1602 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->sps_nals[i]));
1607 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
1608 if (!self->pps_nals[i])
1612 new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->pps_nals[i]));
1616 if (have_sps && have_pps)
1617 self->need_codec_data = FALSE;
1619 return gst_buffer_append (new_buf, gst_buffer_ref (buffer));
1623 gst_nvdec_process_input (GstNvDec * self, GstBuffer * inbuf)
1625 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (self);
1626 gboolean parse_nal = FALSE;
1628 if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT) ||
1629 self->need_codec_data) {
1633 if (klass->codec_type == cudaVideoCodec_MPEG4 &&
1634 self->codec_data && GST_BUFFER_IS_DISCONT (inbuf)) {
1635 return gst_buffer_append (gst_buffer_ref (self->codec_data),
1636 gst_buffer_ref (inbuf));
1637 } else if (klass->codec_type == cudaVideoCodec_H264 && parse_nal) {
1638 return gst_nvdec_handle_h264_buffer (self, inbuf);
1639 } else if (klass->codec_type == cudaVideoCodec_HEVC && parse_nal) {
1640 return gst_nvdec_handle_h265_buffer (self, inbuf);
1643 return gst_buffer_ref (inbuf);
1646 static GstFlowReturn
1647 gst_nvdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
1649 GstNvDec *nvdec = GST_NVDEC (decoder);
1650 GstMapInfo map_info = GST_MAP_INFO_INIT;
1651 CUVIDSOURCEDATAPACKET packet = { 0, };
1652 GstBuffer *in_buffer;
1654 GST_LOG_OBJECT (nvdec, "handle frame");
1656 /* initialize with zero to keep track of frames */
1657 gst_video_codec_frame_set_user_data (frame, GUINT_TO_POINTER (0), NULL);
1659 in_buffer = gst_nvdec_process_input (nvdec, frame->input_buffer);
1661 if (!gst_buffer_map (in_buffer, &map_info, GST_MAP_READ)) {
1662 GST_ERROR_OBJECT (nvdec, "failed to map input buffer");
1663 gst_buffer_unref (in_buffer);
1664 gst_video_codec_frame_unref (frame);
1665 return GST_FLOW_ERROR;
1668 packet.payload_size = (gulong) map_info.size;
1669 packet.payload = map_info.data;
1670 packet.timestamp = frame->pts;
1671 packet.flags |= CUVID_PKT_TIMESTAMP;
1673 if (nvdec->recv_complete_picture)
1674 packet.flags |= CUVID_PKT_ENDOFPICTURE;
1676 nvdec->state = GST_NVDEC_STATE_PARSE;
1677 nvdec->last_ret = GST_FLOW_OK;
1679 if (!gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1680 GST_WARNING_OBJECT (nvdec, "parser failed");
1682 gst_buffer_unmap (in_buffer, &map_info);
1683 gst_buffer_unref (in_buffer);
1684 gst_video_codec_frame_unref (frame);
1686 return nvdec->last_ret;
1690 gst_nvdec_flush (GstVideoDecoder * decoder)
1692 GstNvDec *nvdec = GST_NVDEC (decoder);
1693 CUVIDSOURCEDATAPACKET packet = { 0, };
1695 GST_DEBUG_OBJECT (nvdec, "flush");
1697 packet.payload_size = 0;
1698 packet.payload = NULL;
1699 packet.flags = CUVID_PKT_ENDOFSTREAM;
1701 nvdec->state = GST_NVDEC_STATE_PARSE;
1702 nvdec->last_ret = GST_FLOW_OK;
1705 && !gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1706 GST_WARNING_OBJECT (nvdec, "parser failed");
1708 nvdec->need_codec_data = TRUE;
1713 static GstFlowReturn
1714 gst_nvdec_drain (GstVideoDecoder * decoder)
1716 GstNvDec *nvdec = GST_NVDEC (decoder);
1717 CUVIDSOURCEDATAPACKET packet = { 0, };
1719 GST_DEBUG_OBJECT (nvdec, "draining decoder");
1721 packet.payload_size = 0;
1722 packet.payload = NULL;
1723 packet.flags = CUVID_PKT_ENDOFSTREAM;
1725 nvdec->state = GST_NVDEC_STATE_PARSE;
1726 nvdec->last_ret = GST_FLOW_OK;
1729 && !gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1730 GST_WARNING_OBJECT (nvdec, "parser failed");
1732 nvdec->need_codec_data = TRUE;
1734 return nvdec->last_ret;
1737 static GstFlowReturn
1738 gst_nvdec_finish (GstVideoDecoder * decoder)
1740 GST_DEBUG_OBJECT (decoder, "finish");
1742 return gst_nvdec_drain (decoder);
1745 #ifdef HAVE_NVCODEC_GST_GL
1747 gst_nvdec_check_cuda_device_from_context (GstGLContext * context,
1750 guint device_count = 0;
1751 CUdevice device_list[1] = { 0, };
1756 cuda_ret = CuGLGetDevices (&device_count,
1757 device_list, 1, CU_GL_DEVICE_LIST_ALL);
1759 if (!gst_cuda_result (cuda_ret) || device_count == 0)
1768 gst_nvdec_ensure_gl_context (GstNvDec * nvdec)
1772 if (!nvdec->gl_display) {
1773 GST_DEBUG_OBJECT (nvdec, "No available OpenGL display");
1777 if (!gst_gl_query_local_gl_context (GST_ELEMENT (nvdec), GST_PAD_SRC,
1778 &nvdec->gl_context)) {
1779 GST_INFO_OBJECT (nvdec, "failed to query local OpenGL context");
1780 if (nvdec->gl_context)
1781 gst_object_unref (nvdec->gl_context);
1783 gst_gl_display_get_gl_context_for_thread (nvdec->gl_display, NULL);
1784 if (!nvdec->gl_context
1785 || !gst_gl_display_add_context (nvdec->gl_display, nvdec->gl_context)) {
1786 if (nvdec->gl_context)
1787 gst_object_unref (nvdec->gl_context);
1788 if (!gst_gl_display_create_context (nvdec->gl_display,
1789 nvdec->other_gl_context, &nvdec->gl_context, NULL)) {
1790 GST_ERROR_OBJECT (nvdec, "failed to create OpenGL context");
1793 if (!gst_gl_display_add_context (nvdec->gl_display, nvdec->gl_context)) {
1794 GST_ERROR_OBJECT (nvdec,
1795 "failed to add the OpenGL context to the display");
1801 if (!gst_gl_context_check_gl_version (nvdec->gl_context,
1802 SUPPORTED_GL_APIS, 3, 0)) {
1803 GST_WARNING_OBJECT (nvdec, "OpenGL context could not support PBO download");
1807 gst_gl_context_thread_add (nvdec->gl_context,
1808 (GstGLContextThreadFunc) gst_nvdec_check_cuda_device_from_context, &ret);
1811 GST_WARNING_OBJECT (nvdec, "Current OpenGL context is not CUDA-compatible");
1819 gst_nvdec_ensure_gl_pool (GstNvDec * nvdec, GstQuery * query)
1822 GstBufferPool *pool = NULL;
1823 guint n, size, min, max;
1824 GstVideoInfo vinfo = { 0, };
1825 GstStructure *config;
1827 GST_DEBUG_OBJECT (nvdec, "decide allocation");
1829 gst_query_parse_allocation (query, &outcaps, NULL);
1830 n = gst_query_get_n_allocation_pools (query);
1832 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1834 if (pool && !GST_IS_GL_BUFFER_POOL (pool)) {
1835 gst_object_unref (pool);
1840 GST_DEBUG_OBJECT (nvdec, "no downstream pool, create our pool");
1841 pool = gst_gl_buffer_pool_new (nvdec->gl_context);
1844 gst_video_info_from_caps (&vinfo, outcaps);
1845 size = (guint) vinfo.size;
1849 config = gst_buffer_pool_get_config (pool);
1850 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1851 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1852 gst_buffer_pool_set_config (pool, config);
1854 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1856 gst_query_add_allocation_pool (query, pool, size, min, max);
1857 gst_object_unref (pool);
1864 gst_nvdec_ensure_cuda_pool (GstNvDec * nvdec, GstQuery * query)
1867 GstBufferPool *pool = NULL;
1868 guint n, size, min, max;
1869 GstVideoInfo vinfo = { 0, };
1870 GstStructure *config;
1872 gst_query_parse_allocation (query, &outcaps, NULL);
1873 n = gst_query_get_n_allocation_pools (query);
1875 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1877 if (!GST_IS_CUDA_BUFFER_POOL (pool)) {
1878 gst_clear_object (&pool);
1880 GstCudaBufferPool *cpool = GST_CUDA_BUFFER_POOL (pool);
1882 if (cpool->context != nvdec->cuda_ctx)
1883 gst_clear_object (&pool);
1889 GST_DEBUG_OBJECT (nvdec, "no downstream pool, create our pool");
1890 pool = gst_cuda_buffer_pool_new (nvdec->cuda_ctx);
1893 gst_video_info_from_caps (&vinfo, outcaps);
1894 size = (guint) vinfo.size;
1898 config = gst_buffer_pool_get_config (pool);
1899 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1900 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1901 gst_buffer_pool_set_config (pool, config);
1903 /* Get updated size by cuda buffer pool */
1904 config = gst_buffer_pool_get_config (pool);
1905 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
1906 gst_structure_free (config);
1909 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1911 gst_query_add_allocation_pool (query, pool, size, min, max);
1912 gst_object_unref (pool);
1918 gst_nvdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1920 GstNvDec *nvdec = GST_NVDEC (decoder);
1922 GST_DEBUG_OBJECT (nvdec, "decide allocation");
1924 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_SYSTEM)
1927 #ifdef HAVE_NVCODEC_GST_GL
1928 if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL) {
1929 if (!gst_nvdec_ensure_gl_pool (nvdec, query))
1933 if (!gst_nvdec_ensure_cuda_pool (nvdec, query)) {
1938 return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->decide_allocation
1943 gst_nvdec_src_query (GstVideoDecoder * decoder, GstQuery * query)
1945 GstNvDec *nvdec = GST_NVDEC (decoder);
1947 switch (GST_QUERY_TYPE (query)) {
1948 case GST_QUERY_CONTEXT:
1949 if (gst_cuda_handle_context_query (GST_ELEMENT (decoder),
1950 query, nvdec->cuda_ctx)) {
1953 #ifdef HAVE_NVCODEC_GST_GL
1954 if (gst_gl_handle_context_query (GST_ELEMENT (decoder), query,
1955 nvdec->gl_display, nvdec->gl_context, nvdec->other_gl_context)) {
1956 if (nvdec->gl_display)
1957 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvdec->gl_display),
1967 return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->src_query (decoder,
1972 gst_nvdec_set_context (GstElement * element, GstContext * context)
1974 GstNvDec *nvdec = GST_NVDEC (element);
1975 GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
1977 GST_DEBUG_OBJECT (nvdec, "set context %s",
1978 gst_context_get_context_type (context));
1980 if (gst_cuda_handle_set_context (element,
1981 context, klass->cuda_device_id, &nvdec->cuda_ctx)) {
1984 #ifdef HAVE_NVCODEC_GST_GL
1985 gst_gl_handle_set_context (element, context, &nvdec->gl_display,
1986 &nvdec->other_gl_context);
1990 GST_ELEMENT_CLASS (gst_nvdec_parent_class)->set_context (element, context);
1997 cudaVideoCodec codec_type;
1999 guint cuda_device_id;
2000 gboolean is_default;
2001 } GstNvDecClassData;
2004 gst_nvdec_subclass_init (gpointer g_class, gpointer data)
2006 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
2007 GstNvDecClass *nvdec_class = GST_NVDEC_CLASS (g_class);
2008 GstNvDecClassData *cdata = data;
2011 if (cdata->is_default) {
2012 long_name = g_strdup_printf ("NVDEC %s Video Decoder", cdata->codec);
2014 long_name = g_strdup_printf ("NVDEC %s Video Decoder with device %d",
2015 cdata->codec, cdata->cuda_device_id);
2018 gst_element_class_set_metadata (element_class, long_name,
2019 "Codec/Decoder/Video/Hardware", "NVDEC video decoder",
2020 "Ericsson AB, http://www.ericsson.com, "
2021 "Seungha Yang <seungha.yang@navercorp.com>");
2024 gst_element_class_add_pad_template (element_class,
2025 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
2027 gst_element_class_add_pad_template (element_class,
2028 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
2031 nvdec_class->codec_type = cdata->codec_type;
2032 nvdec_class->cuda_device_id = cdata->cuda_device_id;
2034 gst_caps_unref (cdata->sink_caps);
2035 gst_caps_unref (cdata->src_caps);
2036 g_free (cdata->codec);
2041 gst_nvdec_subclass_register (GstPlugin * plugin, GType type,
2042 cudaVideoCodec codec_type, const gchar * codec, guint device_id, guint rank,
2043 GstCaps * sink_caps, GstCaps * src_caps)
2045 GTypeQuery type_query;
2046 GTypeInfo type_info = { 0, };
2049 GstNvDecClassData *cdata;
2050 gboolean is_default = TRUE;
2052 cdata = g_new0 (GstNvDecClassData, 1);
2053 cdata->sink_caps = gst_caps_ref (sink_caps);
2054 cdata->src_caps = gst_caps_ref (src_caps);
2055 cdata->codec_type = codec_type;
2056 cdata->codec = g_strdup (codec);
2057 cdata->cuda_device_id = device_id;
2059 g_type_query (type, &type_query);
2060 memset (&type_info, 0, sizeof (type_info));
2061 type_info.class_size = type_query.class_size;
2062 type_info.instance_size = type_query.instance_size;
2063 type_info.class_init = gst_nvdec_subclass_init;
2064 type_info.class_data = cdata;
2066 type_name = g_strdup_printf ("nv%sdec", codec);
2068 if (g_type_from_name (type_name) != 0) {
2070 type_name = g_strdup_printf ("nv%sdevice%ddec", codec, device_id);
2074 cdata->is_default = is_default;
2075 subtype = g_type_register_static (type, type_name, &type_info, 0);
2077 /* make lower rank than default device */
2078 if (rank > 0 && !is_default)
2081 if (!gst_element_register (plugin, type_name, rank, subtype))
2082 GST_WARNING ("Failed to register plugin '%s'", type_name);
2088 gst_nvdec_plugin_init (GstPlugin * plugin, guint device_index,
2089 cudaVideoCodec codec, const gchar * codec_name, GstCaps * sink_template,
2090 GstCaps * src_template)
2092 gst_nvdec_subclass_register (plugin, GST_TYPE_NVDEC, codec,
2093 codec_name, device_index, GST_RANK_PRIMARY, sink_template, src_template);