rtsp-server:wfd: Fix build error for gcc upgrade
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / nvcodec / gstnvdec.c
1 /*
2  * Copyright (C) 2017 Ericsson AB. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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
13  *    distribution.
14  *
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <gst/cuda/gstcudautils.h>
33 #include <gst/cuda/gstcudabufferpool.h>
34
35 #include "gstcuvidloader.h"
36 #include "gstnvdec.h"
37
38 #include <string.h>
39
40 GST_DEBUG_CATEGORY_EXTERN (gst_nvdec_debug);
41 #define GST_CAT_DEFAULT gst_nvdec_debug
42
43 #define DEFAULT_MAX_DISPLAY_DELAY -1
44
45 enum
46 {
47   PROP_0,
48   PROP_MAX_DISPLAY_DELAY,
49   PROP_CUDA_DEVICE_ID,
50 };
51
52 #ifdef HAVE_NVCODEC_GST_GL
53 #define SUPPORTED_GL_APIS (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)
54
55 static gboolean
56 gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
57     CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
58 #endif
59
60 static gboolean
61 gst_nvdec_copy_device_to_memory (GstNvDec * nvdec,
62     CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
63
64 #ifdef HAVE_NVCODEC_GST_GL
65 typedef struct _GstNvDecRegisterResourceData
66 {
67   GstMemory *mem;
68   GstCudaGraphicsResource *resource;
69   GstNvDec *nvdec;
70   gboolean ret;
71 } GstNvDecRegisterResourceData;
72
73 static void
74 register_cuda_resource (GstGLContext * context,
75     GstNvDecRegisterResourceData * data)
76 {
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;
82
83   data->ret = FALSE;
84
85   if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
86     GST_WARNING_OBJECT (nvdec, "failed to push CUDA context");
87     return;
88   }
89
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;
93
94     GST_LOG_OBJECT (nvdec,
95         "register glbuffer %d to CUDA resource", gl_buf_obj->id);
96
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)) {
102       data->ret = TRUE;
103     } else {
104       GST_WARNING_OBJECT (nvdec, "failed to register memory");
105     }
106
107     gst_memory_unmap (mem, &map_info);
108   } else {
109     GST_WARNING_OBJECT (nvdec, "failed to map memory");
110   }
111
112   if (!gst_cuda_context_pop (NULL))
113     GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
114 }
115
116 static GstCudaGraphicsResource *
117 ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
118 {
119   GQuark quark;
120   GstCudaGraphicsResource *cgr_info;
121   GstNvDecRegisterResourceData data;
122
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);
126     return NULL;
127   }
128
129   quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
130
131   cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
132   if (!cgr_info) {
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);
136     data.mem = mem;
137     data.resource = cgr_info;
138     data.nvdec = nvdec;
139     gst_gl_context_thread_add ((GstGLContext *) cgr_info->graphics_context,
140         (GstGLContextThreadFunc) register_cuda_resource, &data);
141     if (!data.ret) {
142       GST_WARNING_OBJECT (nvdec, "could not register resource");
143       gst_cuda_graphics_resource_free (cgr_info);
144
145       return NULL;
146     }
147
148     gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
149         (GDestroyNotify) gst_cuda_graphics_resource_free);
150   }
151
152   return cgr_info;
153 }
154 #endif /* HAVE_NVCODEC_GST_GL */
155
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,
165     GstQuery * query);
166 static void gst_nvdec_set_context (GstElement * element, GstContext * context);
167 static gboolean gst_nvdec_src_query (GstVideoDecoder * decoder,
168     GstQuery * query);
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);
175 #endif
176
177 #define gst_nvdec_parent_class parent_class
178 G_DEFINE_ABSTRACT_TYPE (GstNvDec, gst_nvdec, GST_TYPE_VIDEO_DECODER);
179
180 static void
181 gst_nv_dec_set_property (GObject * object, guint prop_id, const GValue * value,
182     GParamSpec * pspec)
183 {
184   GstNvDec *nvdec = GST_NVDEC (object);
185
186   switch (prop_id) {
187     case PROP_MAX_DISPLAY_DELAY:
188       nvdec->max_display_delay = g_value_get_int (value);
189       break;
190     default:
191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192       break;
193   }
194 }
195
196 static void
197 gst_nv_dec_get_property (GObject * object, guint prop_id, GValue * value,
198     GParamSpec * pspec)
199 {
200   GstNvDec *nvdec = GST_NVDEC (object);
201   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
202
203   switch (prop_id) {
204     case PROP_MAX_DISPLAY_DELAY:
205       g_value_set_int (value, nvdec->max_display_delay);
206       break;
207     case PROP_CUDA_DEVICE_ID:
208       g_value_set_uint (value, klass->cuda_device_id);
209       break;
210     default:
211       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
212       break;
213   }
214 }
215
216 static void
217 gst_nvdec_class_init (GstNvDecClass * klass)
218 {
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);
222
223   gobject_class->set_property = gst_nv_dec_set_property;
224   gobject_class->get_property = gst_nv_dec_get_property;
225
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);
240
241   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nvdec_set_context);
242   gst_type_mark_as_plugin_api (GST_TYPE_NVDEC, 0);
243
244   /**
245    * GstNvDec:max-display-delay:
246    *
247    * Since: 1.20
248    */
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 "
252           "(auto = -1)",
253           -1, G_MAXINT, DEFAULT_MAX_DISPLAY_DELAY,
254           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
255
256   /**
257    * GstNvDec:cuda-device-id:
258    *
259    * Assigned CUDA device id
260    *
261    * Since: 1.22
262    */
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));
267 }
268
269 static void
270 gst_nvdec_init (GstNvDec * nvdec)
271 {
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);
275 }
276
277 static cudaVideoSurfaceFormat
278 get_cuda_surface_format_from_gst (GstVideoFormat format)
279 {
280   switch (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;
293     default:
294       g_assert_not_reached ();
295       break;
296   }
297
298   return cudaVideoSurfaceFormat_NV12;
299 }
300
301 static guint
302 calculate_num_decode_surface (cudaVideoCodec codec, guint width, guint height)
303 {
304   switch (codec) {
305     case cudaVideoCodec_VP9:
306       return 12;
307     case cudaVideoCodec_H264:
308     case cudaVideoCodec_H264_SVC:
309     case cudaVideoCodec_H264_MVC:
310       return 20;
311     case cudaVideoCodec_HEVC:{
312       gint max_dpb_size;
313       gint MaxLumaPS;
314       const gint MaxDpbPicBuf = 6;
315       gint PicSizeInSamplesY;
316
317       /* A.4.1 */
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;
326       else
327         max_dpb_size = MaxDpbPicBuf;
328
329       max_dpb_size = MIN (max_dpb_size, 16);
330
331       return max_dpb_size + 4;
332     }
333     default:
334       break;
335   }
336
337   return 8;
338 }
339
340 static guint
341 gst_nvdec_get_max_display_delay (GstNvDec * nvdec)
342 {
343   return nvdec->max_display_delay >= 0 ? nvdec->max_display_delay :
344       (nvdec->is_live ? 0 : 4);
345 }
346
347 static gint64
348 gst_nvdec_get_latency (GstNvDec * nvdec)
349 {
350   gint fps_n, fps_d;
351
352   if (!nvdec->input_state)
353     return 0;
354   fps_n = GST_VIDEO_INFO_FPS_N (&nvdec->input_state->info);
355   fps_d = GST_VIDEO_INFO_FPS_D (&nvdec->input_state->info);
356
357   /* We assume 25 fps if the input framerate is invalid */
358   if (fps_n < 1 || fps_d < 1) {
359     fps_n = 25;
360     fps_d = 1;
361   }
362
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);
365 }
366
367 /* 0: fail, 1: succeeded, > 1: override dpb size of parser
368  * (set by CUVIDPARSERPARAMS::ulMaxNumDecodeSurfaces while creating parser) */
369 static gint CUDAAPI
370 parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
371 {
372   guint width, height;
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;
383
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;
387
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;
396 #else
397         out_format = GST_VIDEO_FORMAT_Y444_16BE;
398 #endif
399       } else {
400         GST_ERROR_OBJECT (nvdec, "Unknown 4:4:4 format bitdepth %d",
401             format->bit_depth_luma_minus8 + 8);
402
403         nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
404         return 0;
405       }
406       break;
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;
413 #else
414         out_format = GST_VIDEO_FORMAT_P010_10BE;
415 #endif
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;
419 #else
420         out_format = GST_VIDEO_FORMAT_P016_BE;
421 #endif
422       } else {
423         GST_ERROR_OBJECT (nvdec, "Unknown 4:2:0 format bitdepth %d",
424             format->bit_depth_luma_minus8 + 8);
425
426         nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
427         return 0;
428       }
429       break;
430     default:
431       GST_ERROR_OBJECT (nvdec, "unhandled chroma format %d, bitdepth %d",
432           format->chroma_format, format->bit_depth_luma_minus8 + 8);
433
434       nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
435       return 0;
436   }
437
438   GST_DEBUG_OBJECT (nvdec,
439       "out format: %s", gst_video_format_to_string (out_format));
440
441   GST_DEBUG_OBJECT (nvdec, "width: %u, height: %u", width, height);
442
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);
446
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);
451   }
452
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);
459
460   if (nvdec->input_state->caps)
461     in_s = gst_caps_get_structure (nvdec->input_state->caps, 0);
462
463   /* Set colorimetry when upstream did not provide it */
464   if (in_s && !gst_structure_has_field (in_s, "colorimetry")) {
465     GstVideoColorimetry colorimetry = { 0, };
466
467     if (format->video_signal_description.video_full_range_flag)
468       colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
469     else
470       colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
471
472     colorimetry.primaries =
473         gst_video_color_primaries_from_iso
474         (format->video_signal_description.color_primaries);
475
476     colorimetry.transfer =
477         gst_video_transfer_function_from_iso
478         (format->video_signal_description.transfer_characteristics);
479
480     colorimetry.matrix =
481         gst_video_color_matrix_from_iso
482         (format->video_signal_description.matrix_coefficients);
483
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;
494     }
495   } else {
496     out_info->colorimetry = in_info->colorimetry;
497   }
498
499   if (format->progressive_sequence) {
500     out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
501
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;
506     }
507   } else {
508     out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
509   }
510
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;
514
515     GST_DEBUG_OBJECT (nvdec,
516         "Num decode surface: %d", nvdec->num_decode_surface);
517   } else {
518     nvdec->num_decode_surface =
519         calculate_num_decode_surface (format->codec, width, height);
520
521     GST_DEBUG_OBJECT (nvdec,
522         "Calculated num decode surface: %d", nvdec->num_decode_surface);
523   }
524
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,
529         curr_latency);
530
531   if (!nvdec->decoder || !gst_video_info_is_equal (out_info, &prev_out_info)) {
532     updata = TRUE;
533
534     if (!gst_cuda_context_push (ctx)) {
535       GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
536       goto error;
537     }
538
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");
543         goto error;
544       } else
545         nvdec->decoder = NULL;
546     }
547
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;
569
570     if (nvdec->decoder
571         || !gst_cuda_result (CuvidCreateDecoder (&nvdec->decoder,
572                 &create_info))) {
573       GST_ERROR_OBJECT (nvdec, "failed to create decoder");
574       goto error;
575     }
576
577     if (!gst_cuda_context_pop (NULL)) {
578       GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
579       goto error;
580     }
581   }
582
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;
586       return 0;
587     }
588   }
589
590   return nvdec->num_decode_surface;
591
592 error:
593   nvdec->last_ret = GST_FLOW_ERROR;
594   return 0;
595 }
596
597 static gboolean
598 gst_nvdec_negotiate (GstVideoDecoder * decoder)
599 {
600   GstNvDec *nvdec = GST_NVDEC (decoder);
601   GstVideoCodecState *state;
602   GstVideoInfo *vinfo;
603   GstVideoInfo *out_info = &nvdec->out_info;
604   gboolean ret;
605
606   GST_DEBUG_OBJECT (nvdec, "negotiate");
607
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;
612
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;
617
618   state->caps = gst_video_info_to_caps (&state->info);
619   nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
620
621   {
622     GstCaps *caps;
623     caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (nvdec));
624     GST_DEBUG_OBJECT (nvdec, "Allowed caps %" GST_PTR_FORMAT, caps);
625
626     if (!caps || gst_caps_is_any (caps)) {
627       GST_DEBUG_OBJECT (nvdec,
628           "cannot determine output format, use system memory");
629     } else {
630       GstCapsFeatures *features;
631       guint size = gst_caps_get_size (caps);
632       guint i;
633       gboolean have_cuda = FALSE;
634       gboolean have_gl = FALSE;
635
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");
641           have_cuda = TRUE;
642           break;
643         }
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");
649           have_gl = TRUE;
650         }
651 #endif
652       }
653
654       if (have_cuda)
655         nvdec->mem_type = GST_NVDEC_MEM_TYPE_CUDA;
656       else if (have_gl)
657         nvdec->mem_type = GST_NVDEC_MEM_TYPE_GL;
658     }
659     gst_clear_caps (&caps);
660   }
661
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;
668   }
669 #endif
670
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));
676       break;
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,
683           "2D", NULL);
684       break;
685 #endif
686     default:
687       GST_DEBUG_OBJECT (nvdec, "use system memory");
688       break;
689   }
690
691   if (nvdec->output_state)
692     gst_video_codec_state_unref (nvdec->output_state);
693
694   nvdec->output_state = state;
695
696   ret = GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
697
698   if (!ret) {
699     GST_ERROR_OBJECT (nvdec, "failed to negotiate with downstream");
700     nvdec->last_ret = GST_FLOW_NOT_NEGOTIATED;
701   }
702
703   return ret;
704 }
705
706 static gboolean CUDAAPI
707 parser_decode_callback (GstNvDec * nvdec, CUVIDPICPARAMS * params)
708 {
709   GList *iter, *pending_frames;
710   GstCudaContext *ctx = nvdec->cuda_ctx;
711
712   GST_LOG_OBJECT (nvdec, "picture index: %u", params->CurrPicIdx);
713
714   if (!gst_cuda_context_push (ctx)) {
715     GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
716     goto error;
717   }
718
719   if (!gst_cuda_result (CuvidDecodePicture (nvdec->decoder, params))) {
720     GST_ERROR_OBJECT (nvdec, "failed to decode picture");
721     goto error;
722   }
723
724   if (!gst_cuda_context_pop (NULL)) {
725     GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
726     goto error;
727   }
728
729   pending_frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (nvdec));
730
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 */
735
736   for (iter = pending_frames; iter; iter = g_list_next (iter)) {
737     guint id;
738     GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
739     gboolean set_data = FALSE;
740
741     id = GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data (frame));
742     if (G_UNLIKELY (nvdec->state == GST_NVDEC_STATE_DECODE)) {
743       if (id) {
744         GST_LOG_OBJECT (nvdec, "reset the last user data");
745         set_data = TRUE;
746       }
747     } else if (!id) {
748       set_data = TRUE;
749     }
750
751     if (set_data) {
752       gst_video_codec_frame_set_user_data (frame,
753           GUINT_TO_POINTER (params->CurrPicIdx + 1), NULL);
754       break;
755     }
756   }
757
758   nvdec->state = GST_NVDEC_STATE_DECODE;
759
760   g_list_free_full (pending_frames,
761       (GDestroyNotify) gst_video_codec_frame_unref);
762
763   return TRUE;
764
765 error:
766   nvdec->last_ret = GST_FLOW_ERROR;
767   return FALSE;
768 }
769
770 static gboolean CUDAAPI
771 parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
772 {
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;
778
779   GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
780
781   pending_frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (nvdec));
782   for (iter = pending_frames; iter; iter = g_list_next (iter)) {
783     guint id;
784     GstVideoCodecFrame *tmp = (GstVideoCodecFrame *) iter->data;
785
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);
789       break;
790     }
791   }
792   g_list_free_full (pending_frames,
793       (GDestroyNotify) gst_video_codec_frame_unref);
794
795   if (G_UNLIKELY (frame == NULL)) {
796     GST_WARNING_OBJECT (nvdec, "no frame for picture index %u",
797         dispinfo->picture_index);
798
799     output_buffer =
800         gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (nvdec));
801
802     if (!output_buffer) {
803       GST_ERROR_OBJECT (nvdec, "Couldn't allocate output buffer");
804       nvdec->last_ret = GST_FLOW_ERROR;
805       return FALSE;
806     }
807
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));
816     } else {
817       GST_BUFFER_DURATION (output_buffer) = GST_CLOCK_TIME_NONE;
818     }
819   } else {
820     ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (nvdec),
821         frame);
822
823     if (ret != GST_FLOW_OK) {
824       GST_WARNING_OBJECT (nvdec, "failed to allocate output frame");
825       nvdec->last_ret = ret;
826       return FALSE;
827     }
828
829     output_buffer = frame->output_buffer;
830
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)));
835     }
836   }
837
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);
841
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
845      */
846     if (!copy_ret) {
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;
850     }
851   }
852
853   if (!copy_ret)
854 #endif
855   {
856     copy_ret = gst_nvdec_copy_device_to_memory (nvdec, dispinfo, output_buffer);
857   }
858
859   if (!copy_ret) {
860     GST_ERROR_OBJECT (nvdec, "failed to copy decoded picture to output buffer");
861     nvdec->last_ret = GST_FLOW_ERROR;
862
863     if (frame)
864       gst_video_decoder_drop_frame (GST_VIDEO_DECODER (nvdec), frame);
865     else
866       gst_buffer_unref (output_buffer);
867
868     return FALSE;
869   }
870
871   if (!dispinfo->progressive_frame) {
872     GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
873
874     if (dispinfo->top_field_first) {
875       GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
876     }
877
878     if (dispinfo->repeat_first_field == -1) {
879       GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_ONEFIELD);
880     } else {
881       GST_BUFFER_FLAG_SET (output_buffer, GST_VIDEO_BUFFER_FLAG_RFF);
882     }
883   }
884
885   if (frame) {
886     ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (nvdec), frame);
887   } else {
888     ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (nvdec), output_buffer);
889   }
890
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;
895     return FALSE;
896   }
897
898   return TRUE;
899 }
900
901 static gboolean
902 gst_nvdec_open (GstVideoDecoder * decoder)
903 {
904   GstNvDec *nvdec = GST_NVDEC (decoder);
905   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
906   CUresult cuda_ret;
907
908   GST_DEBUG_OBJECT (nvdec, "creating CUDA context");
909
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");
913     return FALSE;
914   }
915
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;
922     }
923     gst_cuda_context_pop (NULL);
924   }
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),
930         SUPPORTED_GL_APIS);
931 #endif
932
933   return TRUE;
934 }
935
936 static gboolean
937 gst_nvdec_start (GstVideoDecoder * decoder)
938 {
939   GstNvDec *nvdec = GST_NVDEC (decoder);
940   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
941
942   nvdec->state = GST_NVDEC_STATE_INIT;
943   nvdec->last_ret = GST_FLOW_OK;
944   gst_video_info_init (&nvdec->out_info);
945
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 ();
950
951   return TRUE;
952 }
953
954 static gboolean
955 maybe_destroy_decoder_and_parser (GstNvDec * nvdec)
956 {
957   gboolean ret = TRUE;
958
959   if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
960     GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
961     return FALSE;
962   }
963
964   if (nvdec->decoder) {
965     GST_DEBUG_OBJECT (nvdec, "destroying decoder");
966     ret = gst_cuda_result (CuvidDestroyDecoder (nvdec->decoder));
967     nvdec->decoder = NULL;
968
969     if (!ret)
970       GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
971   }
972
973   if (nvdec->parser) {
974     GST_DEBUG_OBJECT (nvdec, "destroying parser");
975     if (!gst_cuda_result (CuvidDestroyVideoParser (nvdec->parser))) {
976       GST_ERROR_OBJECT (nvdec, "failed to destroy parser");
977       ret = FALSE;
978     }
979     nvdec->parser = NULL;
980   }
981
982   if (!gst_cuda_context_pop (NULL)) {
983     GST_WARNING_OBJECT (nvdec, "failed to pop CUDA context");
984   }
985
986   return ret;
987 }
988
989 static void
990 gst_nvdec_clear_codec_data (GstNvDec * self)
991 {
992   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (self);
993   guint i;
994
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]);
998     }
999   }
1000
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]);
1005     }
1006
1007     for (i = 0; i < G_N_ELEMENTS (self->pps_nals); i++) {
1008       gst_clear_buffer (&self->pps_nals[i]);
1009     }
1010   }
1011
1012   gst_clear_buffer (&self->codec_data);
1013
1014   self->need_codec_data = TRUE;
1015 }
1016
1017 static gboolean
1018 gst_nvdec_stop (GstVideoDecoder * decoder)
1019 {
1020   GstNvDec *nvdec = GST_NVDEC (decoder);
1021
1022   GST_DEBUG_OBJECT (nvdec, "stop");
1023
1024   if (!maybe_destroy_decoder_and_parser (nvdec))
1025     return FALSE;
1026
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);
1031 #endif
1032
1033   g_clear_pointer (&nvdec->input_state, gst_video_codec_state_unref);
1034   g_clear_pointer (&nvdec->output_state, gst_video_codec_state_unref);
1035
1036   g_clear_pointer (&nvdec->h264_parser, gst_h264_nal_parser_free);
1037   g_clear_pointer (&nvdec->h265_parser, gst_h265_parser_free);
1038
1039   gst_nvdec_clear_codec_data (nvdec);
1040
1041   return TRUE;
1042 }
1043
1044 static gboolean
1045 gst_nvdec_close (GstVideoDecoder * decoder)
1046 {
1047   GstNvDec *nvdec = GST_NVDEC (decoder);
1048
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);
1053     }
1054   }
1055
1056   gst_clear_object (&nvdec->cuda_ctx);
1057   nvdec->cuda_stream = NULL;
1058
1059   return TRUE;
1060 }
1061
1062 static gboolean
1063 gst_nvdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
1064 {
1065   GstNvDec *nvdec = GST_NVDEC (decoder);
1066   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (decoder);
1067   CUVIDPARSERPARAMS parser_params = { 0, };
1068   GstQuery *query;
1069   gboolean ret = TRUE;
1070
1071   GST_DEBUG_OBJECT (nvdec, "set format");
1072
1073   if (nvdec->input_state)
1074     gst_video_codec_state_unref (nvdec->input_state);
1075
1076   nvdec->input_state = gst_video_codec_state_ref (state);
1077
1078   if (!maybe_destroy_decoder_and_parser (nvdec))
1079     return FALSE;
1080
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);
1087
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;
1102
1103   gst_cuda_context_push (nvdec->cuda_ctx);
1104   GST_DEBUG_OBJECT (nvdec, "creating parser");
1105   if (!gst_cuda_result (CuvidCreateVideoParser (&nvdec->parser,
1106               &parser_params))) {
1107     GST_ERROR_OBJECT (nvdec, "failed to create parser");
1108     ret = FALSE;
1109   }
1110
1111   gst_cuda_context_pop (NULL);
1112
1113   /* store codec data */
1114   gst_nvdec_clear_codec_data (nvdec);
1115
1116   if (ret && nvdec->input_state->caps) {
1117     GstStructure *str;
1118
1119     str = gst_caps_get_structure (nvdec->input_state->caps, 0);
1120
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);
1127       }
1128     }
1129
1130     /* For all CODEC we get complete picture ... */
1131     nvdec->recv_complete_picture = TRUE;
1132
1133     /* Except for JPEG, for which it depends on the caps */
1134     if (klass->codec_type == cudaVideoCodec_JPEG) {
1135       gboolean parsed;
1136       if (gst_structure_get_boolean (str, "parsed", &parsed))
1137         nvdec->recv_complete_picture = parsed;
1138       else
1139         nvdec->recv_complete_picture = FALSE;
1140     }
1141   }
1142
1143   return ret;
1144 }
1145
1146 #ifdef HAVE_NVCODEC_GST_GL
1147 typedef struct
1148 {
1149   GstNvDec *nvdec;
1150   CUVIDPARSERDISPINFO *dispinfo;
1151   gboolean ret;
1152   GstBuffer *output_buffer;
1153 } GstNvDecCopyToGLData;
1154
1155 static void
1156 copy_video_frame_to_gl_textures (GstGLContext * context,
1157     GstNvDecCopyToGLData * data)
1158 {
1159   GstNvDec *nvdec = data->nvdec;
1160   CUVIDPARSERDISPINFO *dispinfo = data->dispinfo;
1161   GstCudaGraphicsResource **resources;
1162   guint num_resources;
1163   CUVIDPROCPARAMS proc_params = { 0, };
1164   guintptr dptr;
1165   guint pitch, i;
1166   CUDA_MEMCPY2D mcpy2d = { 0, };
1167   GstVideoInfo *info = &nvdec->output_state->info;
1168
1169   GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
1170
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;
1175
1176   data->ret = TRUE;
1177
1178   num_resources = gst_buffer_n_memory (data->output_buffer);
1179   resources = g_newa (GstCudaGraphicsResource *, num_resources);
1180
1181   for (i = 0; i < num_resources; i++) {
1182     GstMemory *mem;
1183
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);
1188       data->ret = FALSE;
1189
1190       return;
1191     }
1192
1193     /* Need PBO -> texture */
1194     GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
1195   }
1196
1197   if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
1198     GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
1199     data->ret = FALSE;
1200     return;
1201   }
1202
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");
1206     data->ret = FALSE;
1207     goto unlock_cuda_context;
1208   }
1209
1210   mcpy2d.srcMemoryType = CU_MEMORYTYPE_DEVICE;
1211   mcpy2d.srcPitch = pitch;
1212   mcpy2d.dstMemoryType = CU_MEMORYTYPE_DEVICE;
1213
1214   for (i = 0; i < num_resources; i++) {
1215     CUdeviceptr cuda_ptr;
1216     gsize size;
1217     CUgraphicsResource cuda_resource =
1218         gst_cuda_graphics_resource_map (resources[i], nvdec->cuda_stream,
1219         CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1220
1221     if (!cuda_resource) {
1222       GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
1223       data->ret = FALSE;
1224       goto unmap_video_frame;
1225     }
1226
1227     if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&cuda_ptr, &size,
1228                 cuda_resource))) {
1229       GST_WARNING_OBJECT (nvdec, "failed to map CUDA resource");
1230       data->ret = FALSE;
1231       break;
1232     }
1233
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);
1237
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);
1241
1242     if (!gst_cuda_result (CuMemcpy2DAsync (&mcpy2d, nvdec->cuda_stream))) {
1243       GST_WARNING_OBJECT (nvdec, "memcpy to mapped array failed");
1244       data->ret = FALSE;
1245     }
1246   }
1247
1248   gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
1249
1250 unmap_video_frame:
1251   for (i = 0; i < num_resources; i++) {
1252     gst_cuda_graphics_resource_unmap (resources[i], nvdec->cuda_stream);
1253   }
1254
1255   if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
1256     GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
1257
1258 unlock_cuda_context:
1259   if (!gst_cuda_context_pop (NULL))
1260     GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
1261 }
1262
1263 static gboolean
1264 gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
1265     CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
1266 {
1267   GstNvDecCopyToGLData data = { 0, };
1268
1269   data.nvdec = nvdec;
1270   data.dispinfo = dispinfo;
1271   data.output_buffer = output_buffer;
1272
1273   gst_gl_context_thread_add (nvdec->gl_context,
1274       (GstGLContextThreadFunc) copy_video_frame_to_gl_textures, &data);
1275
1276   return data.ret;
1277 }
1278 #endif
1279
1280 static gboolean
1281 gst_nvdec_copy_device_to_memory (GstNvDec * nvdec,
1282     CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
1283 {
1284   CUVIDPROCPARAMS params = { 0, };
1285   CUDA_MEMCPY2D copy_params = { 0, };
1286   guintptr dptr;
1287   guint pitch;
1288   GstVideoFrame video_frame;
1289   GstVideoInfo *info = &nvdec->output_state->info;
1290   gint i;
1291   GstMemory *mem;
1292   gboolean use_device_copy = FALSE;
1293   GstMapFlags map_flags = GST_MAP_WRITE;
1294
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;
1300   }
1301
1302   if (!gst_video_frame_map (&video_frame, info, output_buffer, map_flags)) {
1303     GST_ERROR_OBJECT (nvdec, "frame map failure");
1304     return FALSE;
1305   }
1306
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");
1310     return FALSE;
1311   }
1312
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;
1318
1319   if (!gst_cuda_result (CuvidMapVideoFrame (nvdec->decoder,
1320               dispinfo->picture_index, &dptr, &pitch, &params))) {
1321     GST_ERROR_OBJECT (nvdec, "failed to map video frame");
1322     gst_cuda_context_pop (NULL);
1323     return FALSE;
1324   }
1325
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;
1330
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);
1336     } else {
1337       copy_params.dstHost = GST_VIDEO_FRAME_PLANE_DATA (&video_frame, i);
1338     }
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);
1343
1344     if (!gst_cuda_result (CuMemcpy2DAsync (&copy_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);
1349       return FALSE;
1350     }
1351   }
1352
1353   gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
1354
1355   gst_video_frame_unmap (&video_frame);
1356
1357   if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
1358     GST_WARNING_OBJECT (nvdec, "failed to unmap video frame");
1359
1360   if (!gst_cuda_context_pop (NULL))
1361     GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
1362
1363   return TRUE;
1364 }
1365
1366 static void
1367 gst_nvdec_store_h264_nal (GstNvDec * self, guint id,
1368     GstH264NalUnitType nal_type, GstH264NalUnit * nalu)
1369 {
1370   GstBuffer *buf, **store;
1371   guint size = nalu->size, store_size;
1372   static const guint8 start_code[] = { 0, 0, 1 };
1373
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);
1382   } else {
1383     return;
1384   }
1385
1386   if (id >= store_size) {
1387     GST_DEBUG_OBJECT (self, "unable to store nal, id out-of-range %d", id);
1388     return;
1389   }
1390
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);
1394
1395   if (store[id])
1396     gst_buffer_unref (store[id]);
1397
1398   store[id] = buf;
1399 }
1400
1401 static GstBuffer *
1402 gst_nvdec_handle_h264_buffer (GstNvDec * self, GstBuffer * buffer)
1403 {
1404   GstH264NalParser *parser = self->h264_parser;
1405   GstH264NalUnit nalu;
1406   GstH264ParserResult pres;
1407   GstMapInfo map;
1408   gboolean have_sps = FALSE;
1409   gboolean have_pps = FALSE;
1410   guint i;
1411   GstBuffer *new_buf;
1412
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);
1416   }
1417
1418   memset (&nalu, 0, sizeof (GstH264NalUnit));
1419
1420   do {
1421     pres = gst_h264_parser_identify_nalu (parser,
1422         map.data, nalu.offset + nalu.size, map.size, &nalu);
1423
1424     if (pres == GST_H264_PARSER_NO_NAL_END)
1425       pres = GST_H264_PARSER_OK;
1426
1427     switch (nalu.type) {
1428       case GST_H264_NAL_SPS:
1429       case GST_H264_NAL_SUBSET_SPS:{
1430         GstH264SPS sps;
1431
1432         if (nalu.type == GST_H264_NAL_SPS) {
1433           pres = gst_h264_parser_parse_sps (parser, &nalu, &sps);
1434         } else {
1435           pres = gst_h264_parser_parse_subset_sps (parser, &nalu, &sps);
1436         }
1437
1438         if (pres != GST_H264_PARSER_OK)
1439           break;
1440
1441         have_sps = TRUE;
1442         gst_nvdec_store_h264_nal (self, sps.id, nalu.type, &nalu);
1443         gst_h264_sps_clear (&sps);
1444         break;
1445       }
1446       case GST_H264_NAL_PPS:{
1447         GstH264PPS pps;
1448
1449         pres = gst_h264_parser_parse_pps (parser, &nalu, &pps);
1450         if (pres != GST_H264_PARSER_OK)
1451           break;
1452
1453         have_pps = TRUE;
1454         gst_nvdec_store_h264_nal (self, pps.id, nalu.type, &nalu);
1455         gst_h264_pps_clear (&pps);
1456         break;
1457       }
1458       default:
1459         break;
1460     }
1461   } while (pres == GST_H264_PARSER_OK);
1462
1463   gst_buffer_unmap (buffer, &map);
1464
1465   if (!self->need_codec_data || (have_sps && have_pps)) {
1466     self->need_codec_data = FALSE;
1467     return gst_buffer_ref (buffer);
1468   }
1469
1470   new_buf = gst_buffer_new ();
1471   if (!have_sps) {
1472     for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
1473       if (!self->sps_nals[i])
1474         continue;
1475
1476       have_sps = TRUE;
1477       new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->sps_nals[i]));
1478     }
1479   }
1480
1481   if (!have_pps) {
1482     for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
1483       if (!self->pps_nals[i])
1484         continue;
1485
1486       have_pps = TRUE;
1487       new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->pps_nals[i]));
1488     }
1489   }
1490
1491   new_buf = gst_buffer_append (new_buf, gst_buffer_ref (buffer));
1492
1493   if (have_sps && have_pps)
1494     self->need_codec_data = FALSE;
1495
1496   return new_buf;
1497 }
1498
1499 static void
1500 gst_nvdec_store_h265_nal (GstNvDec * self, guint id,
1501     GstH265NalUnitType nal_type, GstH265NalUnit * nalu)
1502 {
1503   GstBuffer *buf, **store;
1504   guint size = nalu->size, store_size;
1505   static const guint8 start_code[] = { 0, 0, 1 };
1506
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);
1519   } else {
1520     return;
1521   }
1522
1523   if (id >= store_size) {
1524     GST_DEBUG_OBJECT (self, "unable to store nal, id out-of-range %d", id);
1525     return;
1526   }
1527
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);
1531
1532   if (store[id])
1533     gst_buffer_unref (store[id]);
1534
1535   store[id] = buf;
1536 }
1537
1538 static GstBuffer *
1539 gst_nvdec_handle_h265_buffer (GstNvDec * self, GstBuffer * buffer)
1540 {
1541   GstH265Parser *parser = self->h265_parser;
1542   GstH265NalUnit nalu;
1543   GstH265ParserResult pres;
1544   GstMapInfo map;
1545   gboolean have_vps = FALSE;
1546   gboolean have_sps = FALSE;
1547   gboolean have_pps = FALSE;
1548   GstBuffer *new_buf;
1549   guint i;
1550
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);
1554   }
1555
1556   memset (&nalu, 0, sizeof (GstH265NalUnit));
1557
1558   do {
1559     pres = gst_h265_parser_identify_nalu (parser,
1560         map.data, nalu.offset + nalu.size, map.size, &nalu);
1561
1562     if (pres == GST_H265_PARSER_NO_NAL_END)
1563       pres = GST_H265_PARSER_OK;
1564
1565     switch (nalu.type) {
1566       case GST_H265_NAL_VPS:{
1567         GstH265VPS vps;
1568
1569         pres = gst_h265_parser_parse_vps (parser, &nalu, &vps);
1570         if (pres != GST_H265_PARSER_OK)
1571           break;
1572
1573         have_vps = TRUE;
1574         gst_nvdec_store_h265_nal (self, vps.id, nalu.type, &nalu);
1575         break;
1576       }
1577       case GST_H265_NAL_SPS:{
1578         GstH265SPS sps;
1579
1580         pres = gst_h265_parser_parse_sps (parser, &nalu, &sps, FALSE);
1581         if (pres != GST_H265_PARSER_OK)
1582           break;
1583
1584         have_sps = TRUE;
1585         gst_nvdec_store_h265_nal (self, sps.id, nalu.type, &nalu);
1586         break;
1587       }
1588       case GST_H265_NAL_PPS:{
1589         GstH265PPS pps;
1590
1591         pres = gst_h265_parser_parse_pps (parser, &nalu, &pps);
1592         if (pres != GST_H265_PARSER_OK)
1593           break;
1594
1595         have_pps = TRUE;
1596         gst_nvdec_store_h265_nal (self, pps.id, nalu.type, &nalu);
1597         break;
1598       }
1599       default:
1600         break;
1601     }
1602   } while (pres == GST_H265_PARSER_OK);
1603
1604   gst_buffer_unmap (buffer, &map);
1605
1606   if (!self->need_codec_data || (have_sps && have_pps)) {
1607     self->need_codec_data = FALSE;
1608     return gst_buffer_ref (buffer);
1609   }
1610
1611   new_buf = gst_buffer_new ();
1612   if (!have_vps) {
1613     for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1614       if (!self->vps_nals[i])
1615         continue;
1616
1617       new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->vps_nals[i]));
1618     }
1619   }
1620
1621   if (!have_sps) {
1622     for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1623       if (!self->sps_nals[i])
1624         continue;
1625
1626       have_sps = TRUE;
1627       new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->sps_nals[i]));
1628     }
1629   }
1630
1631   if (!have_pps) {
1632     for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
1633       if (!self->pps_nals[i])
1634         continue;
1635
1636       have_pps = TRUE;
1637       new_buf = gst_buffer_append (new_buf, gst_buffer_ref (self->pps_nals[i]));
1638     }
1639   }
1640
1641   if (have_sps && have_pps)
1642     self->need_codec_data = FALSE;
1643
1644   return gst_buffer_append (new_buf, gst_buffer_ref (buffer));
1645 }
1646
1647 static GstBuffer *
1648 gst_nvdec_process_input (GstNvDec * self, GstBuffer * inbuf)
1649 {
1650   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (self);
1651   gboolean parse_nal = FALSE;
1652
1653   if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT) ||
1654       self->need_codec_data) {
1655     parse_nal = TRUE;
1656   }
1657
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);
1666   }
1667
1668   return gst_buffer_ref (inbuf);
1669 }
1670
1671 static GstFlowReturn
1672 gst_nvdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
1673 {
1674   GstNvDec *nvdec = GST_NVDEC (decoder);
1675   GstMapInfo map_info = GST_MAP_INFO_INIT;
1676   CUVIDSOURCEDATAPACKET packet = { 0, };
1677   GstBuffer *in_buffer;
1678
1679   GST_LOG_OBJECT (nvdec, "handle frame");
1680
1681   /* initialize with zero to keep track of frames */
1682   gst_video_codec_frame_set_user_data (frame, GUINT_TO_POINTER (0), NULL);
1683
1684   in_buffer = gst_nvdec_process_input (nvdec, frame->input_buffer);
1685
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;
1691   }
1692
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;
1697
1698   if (nvdec->recv_complete_picture)
1699     packet.flags |= CUVID_PKT_ENDOFPICTURE;
1700
1701   nvdec->state = GST_NVDEC_STATE_PARSE;
1702   nvdec->last_ret = GST_FLOW_OK;
1703
1704   if (!gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1705     GST_WARNING_OBJECT (nvdec, "parser failed");
1706
1707   gst_buffer_unmap (in_buffer, &map_info);
1708   gst_buffer_unref (in_buffer);
1709   gst_video_codec_frame_unref (frame);
1710
1711   return nvdec->last_ret;
1712 }
1713
1714 static gboolean
1715 gst_nvdec_flush (GstVideoDecoder * decoder)
1716 {
1717   GstNvDec *nvdec = GST_NVDEC (decoder);
1718   CUVIDSOURCEDATAPACKET packet = { 0, };
1719
1720   GST_DEBUG_OBJECT (nvdec, "flush");
1721
1722   packet.payload_size = 0;
1723   packet.payload = NULL;
1724   packet.flags = CUVID_PKT_ENDOFSTREAM;
1725
1726   nvdec->state = GST_NVDEC_STATE_PARSE;
1727   nvdec->last_ret = GST_FLOW_OK;
1728
1729   if (nvdec->parser
1730       && !gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1731     GST_WARNING_OBJECT (nvdec, "parser failed");
1732
1733   nvdec->need_codec_data = TRUE;
1734
1735   return TRUE;
1736 }
1737
1738 static GstFlowReturn
1739 gst_nvdec_drain (GstVideoDecoder * decoder)
1740 {
1741   GstNvDec *nvdec = GST_NVDEC (decoder);
1742   CUVIDSOURCEDATAPACKET packet = { 0, };
1743
1744   GST_DEBUG_OBJECT (nvdec, "draining decoder");
1745
1746   packet.payload_size = 0;
1747   packet.payload = NULL;
1748   packet.flags = CUVID_PKT_ENDOFSTREAM;
1749
1750   nvdec->state = GST_NVDEC_STATE_PARSE;
1751   nvdec->last_ret = GST_FLOW_OK;
1752
1753   if (nvdec->parser
1754       && !gst_cuda_result (CuvidParseVideoData (nvdec->parser, &packet)))
1755     GST_WARNING_OBJECT (nvdec, "parser failed");
1756
1757   nvdec->need_codec_data = TRUE;
1758
1759   return nvdec->last_ret;
1760 }
1761
1762 static GstFlowReturn
1763 gst_nvdec_finish (GstVideoDecoder * decoder)
1764 {
1765   GST_DEBUG_OBJECT (decoder, "finish");
1766
1767   return gst_nvdec_drain (decoder);
1768 }
1769
1770 #ifdef HAVE_NVCODEC_GST_GL
1771 static void
1772 gst_nvdec_check_cuda_device_from_context (GstGLContext * context,
1773     gboolean * ret)
1774 {
1775   guint device_count = 0;
1776   CUdevice device_list[1] = { 0, };
1777   CUresult cuda_ret;
1778
1779   *ret = FALSE;
1780
1781   cuda_ret = CuGLGetDevices (&device_count,
1782       device_list, 1, CU_GL_DEVICE_LIST_ALL);
1783
1784   if (!gst_cuda_result (cuda_ret) || device_count == 0)
1785     return;
1786
1787   *ret = TRUE;
1788
1789   return;
1790 }
1791
1792 static gboolean
1793 gst_nvdec_ensure_gl_context (GstNvDec * nvdec)
1794 {
1795   gboolean ret;
1796
1797   if (!nvdec->gl_display) {
1798     GST_DEBUG_OBJECT (nvdec, "No available OpenGL display");
1799     return FALSE;
1800   }
1801
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);
1807     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");
1816         return FALSE;
1817       }
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");
1821         return FALSE;
1822       }
1823     }
1824   }
1825
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");
1829     return FALSE;
1830   }
1831
1832   gst_gl_context_thread_add (nvdec->gl_context,
1833       (GstGLContextThreadFunc) gst_nvdec_check_cuda_device_from_context, &ret);
1834
1835   if (!ret) {
1836     GST_WARNING_OBJECT (nvdec, "Current OpenGL context is not CUDA-compatible");
1837     return FALSE;
1838   }
1839
1840   return TRUE;
1841 }
1842
1843 static gboolean
1844 gst_nvdec_ensure_gl_pool (GstNvDec * nvdec, GstQuery * query)
1845 {
1846   GstCaps *outcaps;
1847   GstBufferPool *pool = NULL;
1848   guint n, size, min, max;
1849   GstVideoInfo vinfo = { 0, };
1850   GstStructure *config;
1851
1852   GST_DEBUG_OBJECT (nvdec, "decide allocation");
1853
1854   gst_query_parse_allocation (query, &outcaps, NULL);
1855   n = gst_query_get_n_allocation_pools (query);
1856   if (n > 0)
1857     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1858
1859   if (pool && !GST_IS_GL_BUFFER_POOL (pool)) {
1860     gst_object_unref (pool);
1861     pool = NULL;
1862   }
1863
1864   if (!pool) {
1865     GST_DEBUG_OBJECT (nvdec, "no downstream pool, create our pool");
1866     pool = gst_gl_buffer_pool_new (nvdec->gl_context);
1867
1868     if (outcaps)
1869       gst_video_info_from_caps (&vinfo, outcaps);
1870     size = (guint) vinfo.size;
1871     min = max = 0;
1872   }
1873
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);
1878   if (n > 0)
1879     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1880   else
1881     gst_query_add_allocation_pool (query, pool, size, min, max);
1882   gst_object_unref (pool);
1883
1884   return TRUE;
1885 }
1886 #endif
1887
1888 static gboolean
1889 gst_nvdec_ensure_cuda_pool (GstNvDec * nvdec, GstQuery * query)
1890 {
1891   GstCaps *outcaps;
1892   GstBufferPool *pool = NULL;
1893   guint n, size, min, max;
1894   GstVideoInfo vinfo = { 0, };
1895   GstStructure *config;
1896
1897   gst_query_parse_allocation (query, &outcaps, NULL);
1898   n = gst_query_get_n_allocation_pools (query);
1899   if (n > 0) {
1900     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1901     if (pool) {
1902       if (!GST_IS_CUDA_BUFFER_POOL (pool)) {
1903         gst_clear_object (&pool);
1904       } else {
1905         GstCudaBufferPool *cpool = GST_CUDA_BUFFER_POOL (pool);
1906
1907         if (cpool->context != nvdec->cuda_ctx)
1908           gst_clear_object (&pool);
1909       }
1910     }
1911   }
1912
1913   if (!pool) {
1914     GST_DEBUG_OBJECT (nvdec, "no downstream pool, create our pool");
1915     pool = gst_cuda_buffer_pool_new (nvdec->cuda_ctx);
1916
1917     if (outcaps)
1918       gst_video_info_from_caps (&vinfo, outcaps);
1919     size = (guint) vinfo.size;
1920     min = max = 0;
1921   }
1922
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);
1927
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);
1932
1933   if (n > 0)
1934     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1935   else
1936     gst_query_add_allocation_pool (query, pool, size, min, max);
1937   gst_object_unref (pool);
1938
1939   return TRUE;
1940 }
1941
1942 static gboolean
1943 gst_nvdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1944 {
1945   GstNvDec *nvdec = GST_NVDEC (decoder);
1946
1947   GST_DEBUG_OBJECT (nvdec, "decide allocation");
1948
1949   if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_SYSTEM)
1950     goto done;
1951
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))
1955       return FALSE;
1956   } else
1957 #endif
1958   if (!gst_nvdec_ensure_cuda_pool (nvdec, query)) {
1959     return FALSE;
1960   }
1961
1962 done:
1963   return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->decide_allocation
1964       (decoder, query);
1965 }
1966
1967 static gboolean
1968 gst_nvdec_src_query (GstVideoDecoder * decoder, GstQuery * query)
1969 {
1970   GstNvDec *nvdec = GST_NVDEC (decoder);
1971
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)) {
1976         return TRUE;
1977       }
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),
1983               SUPPORTED_GL_APIS);
1984         return TRUE;
1985       }
1986 #endif
1987       break;
1988     default:
1989       break;
1990   }
1991
1992   return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->src_query (decoder,
1993       query);
1994 }
1995
1996 static void
1997 gst_nvdec_set_context (GstElement * element, GstContext * context)
1998 {
1999   GstNvDec *nvdec = GST_NVDEC (element);
2000   GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
2001
2002   GST_DEBUG_OBJECT (nvdec, "set context %s",
2003       gst_context_get_context_type (context));
2004
2005   if (gst_cuda_handle_set_context (element,
2006           context, klass->cuda_device_id, &nvdec->cuda_ctx)) {
2007     goto done;
2008   }
2009 #ifdef HAVE_NVCODEC_GST_GL
2010   gst_gl_handle_set_context (element, context, &nvdec->gl_display,
2011       &nvdec->other_gl_context);
2012 #endif
2013
2014 done:
2015   GST_ELEMENT_CLASS (gst_nvdec_parent_class)->set_context (element, context);
2016 }
2017
2018 typedef struct
2019 {
2020   GstCaps *sink_caps;
2021   GstCaps *src_caps;
2022   cudaVideoCodec codec_type;
2023   gchar *codec;
2024   guint cuda_device_id;
2025   gboolean is_default;
2026 } GstNvDecClassData;
2027
2028 static void
2029 gst_nvdec_subclass_init (gpointer g_class, gpointer data)
2030 {
2031   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
2032   GstNvDecClass *nvdec_class = GST_NVDEC_CLASS (g_class);
2033   GstNvDecClassData *cdata = data;
2034   gchar *long_name;
2035
2036   if (cdata->is_default) {
2037     long_name = g_strdup_printf ("NVDEC %s Video Decoder", cdata->codec);
2038   } else {
2039     long_name = g_strdup_printf ("NVDEC %s Video Decoder with device %d",
2040         cdata->codec, cdata->cuda_device_id);
2041   }
2042
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>");
2047   g_free (long_name);
2048
2049   gst_element_class_add_pad_template (element_class,
2050       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
2051           cdata->sink_caps));
2052   gst_element_class_add_pad_template (element_class,
2053       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
2054           cdata->src_caps));
2055
2056   nvdec_class->codec_type = cdata->codec_type;
2057   nvdec_class->cuda_device_id = cdata->cuda_device_id;
2058
2059   gst_caps_unref (cdata->sink_caps);
2060   gst_caps_unref (cdata->src_caps);
2061   g_free (cdata->codec);
2062   g_free (cdata);
2063 }
2064
2065 static void
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)
2069 {
2070   GTypeQuery type_query;
2071   GTypeInfo type_info = { 0, };
2072   GType subtype;
2073   gchar *type_name;
2074   GstNvDecClassData *cdata;
2075   gboolean is_default = TRUE;
2076   gint index = 0;
2077
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;
2084
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;
2091
2092   type_name = g_strdup_printf ("nv%sdec", codec);
2093   while (g_type_from_name (type_name)) {
2094     index++;
2095     g_free (type_name);
2096     type_name = g_strdup_printf ("nv%sdevice%ddec", codec, index);
2097     is_default = FALSE;
2098   }
2099
2100   cdata->is_default = is_default;
2101   subtype = g_type_register_static (type, type_name, &type_info, 0);
2102
2103   /* make lower rank than default device */
2104   if (rank > 0 && !is_default)
2105     rank--;
2106
2107   if (!gst_element_register (plugin, type_name, rank, subtype))
2108     GST_WARNING ("Failed to register plugin '%s'", type_name);
2109
2110   g_free (type_name);
2111 }
2112
2113 void
2114 gst_nvdec_plugin_init (GstPlugin * plugin, guint device_index,
2115     cudaVideoCodec codec, const gchar * codec_name, GstCaps * sink_template,
2116     GstCaps * src_template)
2117 {
2118   gst_nvdec_subclass_register (plugin, GST_TYPE_NVDEC, codec,
2119       codec_name, device_index, GST_RANK_PRIMARY, sink_template, src_template);
2120 }