nvcodec: Fix various typos
[platform/upstream/gstreamer.git] / sys / nvcodec / gstnvdecoder.c
1 /* GStreamer
2  * Copyright (C) 2017 Ericsson AB. All rights reserved.
3  * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer
13  *    in the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * This library is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU Library General Public
30  * License as published by the Free Software Foundation; either
31  * version 2 of the License, or (at your option) any later version.
32  *
33  * This library is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36  * Library General Public License for more details.
37  *
38  * You should have received a copy of the GNU Library General Public
39  * License along with this library; if not, write to the
40  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
41  * Boston, MA 02110-1301, USA.
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #ifdef HAVE_NVCODEC_GST_GL
49 #include <gst/gl/gl.h>
50 #include <gst/gl/gstglfuncs.h>
51 #endif
52
53 #include "gstcudamemory.h"
54 #include "gstnvdecoder.h"
55 #include "gstcudabufferpool.h"
56 #include <string.h>
57
58 GST_DEBUG_CATEGORY_EXTERN (gst_nv_decoder_debug);
59 #define GST_CAT_DEFAULT gst_nv_decoder_debug
60
61 #ifdef HAVE_NVCODEC_GST_GL
62 #define SUPPORTED_GL_APIS (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)
63 #endif
64
65 typedef struct _GstNvDecoderFrameInfo
66 {
67   gboolean available;
68 } GstNvDecoderFrameInfo;
69
70 typedef enum
71 {
72   GST_NV_DECODER_OUTPUT_TYPE_SYSTEM = 0,
73   GST_NV_DECODER_OUTPUT_TYPE_GL,
74   GST_NV_DECODER_OUTPUT_TYPE_CUDA,
75   /* FIXME: add support D3D11 memory */
76 } GstNvDecoderOutputType;
77
78 struct _GstNvDecoder
79 {
80   GstObject parent;
81   GstCudaContext *context;
82   CUstream cuda_stream;
83   CUvideodecoder decoder_handle;
84
85   GstNvDecoderFrameInfo *frame_pool;
86   guint pool_size;
87
88   GstVideoInfo info;
89   GstVideoInfo coded_info;
90
91   gboolean configured;
92
93   /* For OpenGL interop. */
94   GstObject *gl_display;
95   GstObject *gl_context;
96   GstObject *other_gl_context;
97
98   GstNvDecoderOutputType output_type;
99 };
100
101 static void gst_nv_decoder_dispose (GObject * object);
102 static void gst_nv_decoder_reset (GstNvDecoder * self);
103
104 #define parent_class gst_nv_decoder_parent_class
105 G_DEFINE_TYPE (GstNvDecoder, gst_nv_decoder, GST_TYPE_OBJECT);
106
107 static void
108 gst_nv_decoder_class_init (GstNvDecoderClass * klass)
109 {
110   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
111
112   gobject_class->dispose = gst_nv_decoder_dispose;
113 }
114
115 static void
116 gst_nv_decoder_init (GstNvDecoder * self)
117 {
118 }
119
120 static void
121 gst_nv_decoder_dispose (GObject * object)
122 {
123   GstNvDecoder *self = GST_NV_DECODER (object);
124
125   gst_nv_decoder_reset (self);
126
127   if (self->context && self->cuda_stream) {
128     if (gst_cuda_context_push (self->context)) {
129       gst_cuda_result (CuStreamDestroy (self->cuda_stream));
130       gst_cuda_context_pop (NULL);
131       self->cuda_stream = NULL;
132     }
133   }
134
135   gst_clear_object (&self->context);
136   gst_clear_object (&self->gl_display);
137   gst_clear_object (&self->gl_context);
138   gst_clear_object (&self->other_gl_context);
139
140   G_OBJECT_CLASS (parent_class)->dispose (object);
141 }
142
143 static cudaVideoChromaFormat
144 chroma_format_from_video_format (GstVideoFormat format)
145 {
146   switch (format) {
147     case GST_VIDEO_FORMAT_NV12:
148     case GST_VIDEO_FORMAT_P010_10LE:
149     case GST_VIDEO_FORMAT_P010_10BE:
150     case GST_VIDEO_FORMAT_P016_LE:
151     case GST_VIDEO_FORMAT_P016_BE:
152       return cudaVideoChromaFormat_420;
153     case GST_VIDEO_FORMAT_Y444:
154     case GST_VIDEO_FORMAT_Y444_16LE:
155     case GST_VIDEO_FORMAT_Y444_16BE:
156       return cudaVideoChromaFormat_444;
157     default:
158       g_assert_not_reached ();
159       break;
160   }
161
162   return cudaVideoChromaFormat_420;
163 }
164
165 static guint
166 bitdepth_minus8_from_video_format (GstVideoFormat format)
167 {
168   switch (format) {
169     case GST_VIDEO_FORMAT_NV12:
170     case GST_VIDEO_FORMAT_Y444:
171       return 0;
172     case GST_VIDEO_FORMAT_P010_10LE:
173     case GST_VIDEO_FORMAT_P010_10BE:
174       return 2;
175     case GST_VIDEO_FORMAT_P016_LE:
176     case GST_VIDEO_FORMAT_P016_BE:
177     case GST_VIDEO_FORMAT_Y444_16LE:
178     case GST_VIDEO_FORMAT_Y444_16BE:
179       return 8;
180     default:
181       g_assert_not_reached ();
182       break;
183   }
184
185   return 0;
186 }
187
188 static cudaVideoSurfaceFormat
189 output_format_from_video_format (GstVideoFormat format)
190 {
191   switch (format) {
192     case GST_VIDEO_FORMAT_NV12:
193       return cudaVideoSurfaceFormat_NV12;
194     case GST_VIDEO_FORMAT_P010_10LE:
195     case GST_VIDEO_FORMAT_P010_10BE:
196     case GST_VIDEO_FORMAT_P016_LE:
197     case GST_VIDEO_FORMAT_P016_BE:
198       return cudaVideoSurfaceFormat_P016;
199     case GST_VIDEO_FORMAT_Y444:
200       return cudaVideoSurfaceFormat_YUV444;
201     case GST_VIDEO_FORMAT_Y444_16LE:
202     case GST_VIDEO_FORMAT_Y444_16BE:
203       return cudaVideoSurfaceFormat_YUV444_16Bit;
204     default:
205       g_assert_not_reached ();
206       break;
207   }
208
209   return cudaVideoSurfaceFormat_NV12;
210 }
211
212 static gboolean
213 gst_nv_decoder_prepare_frame_pool (GstNvDecoder * self, guint pool_size)
214 {
215   gint i;
216
217   self->frame_pool = g_new (GstNvDecoderFrameInfo, pool_size);
218
219   for (i = 0; i < pool_size; i++)
220     self->frame_pool[i].available = TRUE;
221
222   self->pool_size = pool_size;
223
224   return TRUE;
225 }
226
227 GstNvDecoder *
228 gst_nv_decoder_new (GstCudaContext * context)
229 {
230   GstNvDecoder *self;
231
232   g_return_val_if_fail (GST_IS_CUDA_CONTEXT (context), NULL);
233
234   self = g_object_new (GST_TYPE_NV_DECODER, NULL);
235   self->context = gst_object_ref (context);
236   gst_object_ref_sink (self);
237
238   if (gst_cuda_context_push (context)) {
239     CUresult cuda_ret;
240     cuda_ret = CuStreamCreate (&self->cuda_stream, CU_STREAM_DEFAULT);
241     if (!gst_cuda_result (cuda_ret)) {
242       GST_WARNING_OBJECT (self,
243           "Could not create CUDA stream, will use default stream");
244       self->cuda_stream = NULL;
245     }
246
247     gst_cuda_context_pop (NULL);
248   }
249
250   return self;
251 }
252
253 gboolean
254 gst_nv_decoder_is_configured (GstNvDecoder * decoder)
255 {
256   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
257
258   return decoder->configured;
259 }
260
261 static void
262 gst_nv_decoder_reset (GstNvDecoder * self)
263 {
264   g_clear_pointer (&self->frame_pool, g_free);
265
266   if (self->decoder_handle) {
267     gst_cuda_context_push (self->context);
268     CuvidDestroyDecoder (self->decoder_handle);
269     gst_cuda_context_pop (NULL);
270     self->decoder_handle = NULL;
271   }
272
273   self->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
274   self->configured = FALSE;
275 }
276
277 gboolean
278 gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec,
279     GstVideoInfo * info, gint coded_width, gint coded_height, guint pool_size)
280 {
281   CUVIDDECODECREATEINFO create_info = { 0, };
282   GstVideoFormat format;
283   gboolean ret;
284
285   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
286   g_return_val_if_fail (codec < cudaVideoCodec_NumCodecs, FALSE);
287   g_return_val_if_fail (info != NULL, FALSE);
288   g_return_val_if_fail (coded_width >= GST_VIDEO_INFO_WIDTH (info), FALSE);
289   g_return_val_if_fail (coded_height >= GST_VIDEO_INFO_HEIGHT (info), FALSE);
290   g_return_val_if_fail (pool_size > 0, FALSE);
291
292   gst_nv_decoder_reset (decoder);
293
294   decoder->info = *info;
295   gst_video_info_set_format (&decoder->coded_info, GST_VIDEO_INFO_FORMAT (info),
296       coded_width, coded_height);
297
298   format = GST_VIDEO_INFO_FORMAT (info);
299
300   /* FIXME: check aligned resolution or actual coded resolution */
301   create_info.ulWidth = GST_VIDEO_INFO_WIDTH (&decoder->coded_info);
302   create_info.ulHeight = GST_VIDEO_INFO_HEIGHT (&decoder->coded_info);
303   create_info.ulNumDecodeSurfaces = pool_size;
304   create_info.CodecType = codec;
305   create_info.ChromaFormat = chroma_format_from_video_format (format);
306   create_info.ulCreationFlags = cudaVideoCreate_Default;
307   create_info.bitDepthMinus8 = bitdepth_minus8_from_video_format (format);
308   create_info.ulIntraDecodeOnly = 0;
309
310   create_info.display_area.left = 0;
311   create_info.display_area.top = 0;
312   create_info.display_area.right = GST_VIDEO_INFO_WIDTH (info);
313   create_info.display_area.bottom = GST_VIDEO_INFO_HEIGHT (info);
314   create_info.OutputFormat = output_format_from_video_format (format);
315   create_info.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
316
317   create_info.ulTargetWidth = GST_VIDEO_INFO_WIDTH (&decoder->coded_info);
318   create_info.ulTargetHeight = GST_VIDEO_INFO_HEIGHT (&decoder->coded_info);
319   /* we always copy decoded picture to output buffer */
320   create_info.ulNumOutputSurfaces = 1;
321
322   create_info.target_rect.left = 0;
323   create_info.target_rect.top = 0;
324   create_info.target_rect.right = GST_VIDEO_INFO_WIDTH (&decoder->coded_info);
325   create_info.target_rect.bottom = GST_VIDEO_INFO_HEIGHT (&decoder->coded_info);
326
327   if (!gst_cuda_context_push (decoder->context)) {
328     GST_ERROR_OBJECT (decoder, "Failed to lock CUDA context");
329     return FALSE;
330   }
331
332   ret = gst_cuda_result (CuvidCreateDecoder (&decoder->decoder_handle,
333           &create_info));
334   gst_cuda_context_pop (NULL);
335
336   if (!ret) {
337     GST_ERROR_OBJECT (decoder, "Cannot create decoder instance");
338     return FALSE;
339   }
340
341   if (!gst_nv_decoder_prepare_frame_pool (decoder, pool_size)) {
342     GST_ERROR_OBJECT (decoder, "Cannot prepare internal surface buffer pool");
343     gst_nv_decoder_reset (decoder);
344     return FALSE;
345   }
346
347   decoder->configured = TRUE;
348
349   return TRUE;
350 }
351
352 GstNvDecoderFrame *
353 gst_nv_decoder_new_frame (GstNvDecoder * decoder)
354 {
355   GstNvDecoderFrame *frame;
356   gint i;
357   gint index_to_use = -1;
358
359   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), NULL);
360
361   for (i = 0; i < decoder->pool_size; i++) {
362     if (decoder->frame_pool[i].available) {
363       decoder->frame_pool[i].available = FALSE;
364       index_to_use = i;
365       break;
366     }
367   }
368
369   if (index_to_use < 0) {
370     GST_ERROR_OBJECT (decoder, "No available frame");
371     return NULL;
372   }
373
374   frame = g_new0 (GstNvDecoderFrame, 1);
375   frame->index = index_to_use;
376   frame->decoder = gst_object_ref (decoder);
377   frame->ref_count = 1;
378
379   GST_LOG_OBJECT (decoder, "New frame %p (index %d)", frame, frame->index);
380
381   return frame;
382 }
383
384 /* must be called with gst_cuda_context_push */
385 static gboolean
386 gst_nv_decoder_frame_map (GstNvDecoderFrame * frame)
387 {
388   GstNvDecoder *self;
389   CUVIDPROCPARAMS params = { 0 };
390
391   g_return_val_if_fail (frame != NULL, FALSE);
392   g_return_val_if_fail (frame->index >= 0, FALSE);
393   g_return_val_if_fail (GST_IS_NV_DECODER (frame->decoder), FALSE);
394
395   self = frame->decoder;
396
397   /* TODO: check interlaced */
398   params.progressive_frame = 1;
399
400   if (frame->mapped) {
401     GST_WARNING_OBJECT (self, "Frame %p is mapped already", frame);
402     return TRUE;
403   }
404
405   if (!gst_cuda_result (CuvidMapVideoFrame (self->decoder_handle,
406               frame->index, &frame->devptr, &frame->pitch, &params))) {
407     GST_ERROR_OBJECT (self, "Cannot map picture");
408     return FALSE;
409   }
410
411   frame->mapped = TRUE;
412
413   return TRUE;
414 }
415
416 /* must be called with gst_cuda_context_push */
417 static void
418 gst_nv_decoder_frame_unmap (GstNvDecoderFrame * frame)
419 {
420   GstNvDecoder *self;
421
422   g_return_if_fail (frame != NULL);
423   g_return_if_fail (frame->index >= 0);
424   g_return_if_fail (GST_IS_NV_DECODER (frame->decoder));
425
426   self = frame->decoder;
427
428   if (!frame->mapped) {
429     GST_WARNING_OBJECT (self, "Frame %p is not mapped", frame);
430     return;
431   }
432
433   if (!gst_cuda_result (CuvidUnmapVideoFrame (self->decoder_handle,
434               frame->devptr))) {
435     GST_ERROR_OBJECT (self, "Cannot unmap picture");
436   }
437
438   frame->mapped = FALSE;
439 }
440
441 GstNvDecoderFrame *
442 gst_nv_decoder_frame_ref (GstNvDecoderFrame * frame)
443 {
444   g_assert (frame != NULL);
445
446   g_atomic_int_add (&frame->ref_count, 1);
447
448   return frame;
449 }
450
451 void
452 gst_nv_decoder_frame_unref (GstNvDecoderFrame * frame)
453 {
454   GstNvDecoder *self;
455
456   g_assert (frame != NULL);
457
458   if (g_atomic_int_dec_and_test (&frame->ref_count)) {
459     GST_LOG ("Free frame %p (index %d)", frame, frame->index);
460
461     if (frame->decoder) {
462       self = frame->decoder;
463       if (frame->mapped && gst_cuda_context_push (self->context)) {
464         gst_nv_decoder_frame_unmap (frame);
465         gst_cuda_context_pop (NULL);
466       }
467
468       if (frame->index < self->pool_size) {
469         self->frame_pool[frame->index].available = TRUE;
470       } else {
471         GST_WARNING_OBJECT (self,
472             "Frame %p has invalid index %d", frame, frame->index);
473       }
474
475       gst_object_unref (self);
476     }
477
478     g_free (frame);
479   }
480 }
481
482 gboolean
483 gst_nv_decoder_decode_picture (GstNvDecoder * decoder, CUVIDPICPARAMS * params)
484 {
485   GstCudaContext *ctx = decoder->context;
486   gboolean ret = TRUE;
487
488   GST_LOG_OBJECT (decoder, "picture index: %u", params->CurrPicIdx);
489
490   if (!gst_cuda_context_push (ctx)) {
491     GST_ERROR_OBJECT (decoder, "Failed to push CUDA context");
492     return FALSE;
493   }
494
495   if (!gst_cuda_result (CuvidDecodePicture (decoder->decoder_handle, params))) {
496     GST_ERROR_OBJECT (decoder, "Failed to decode picture");
497     ret = FALSE;
498   }
499
500   if (!gst_cuda_context_pop (NULL)) {
501     GST_WARNING_OBJECT (decoder, "Failed to pop CUDA context");
502   }
503
504   return ret;
505 }
506
507 #ifdef HAVE_NVCODEC_GST_GL
508 static gboolean
509 gst_nv_decoder_register_cuda_resource (GstNvDecoder * self, GstMemory * mem,
510     GstCudaGraphicsResource * resource)
511 {
512   GstMapInfo info;
513   gboolean ret = FALSE;
514
515   if (!gst_cuda_context_push (self->context)) {
516     GST_ERROR_OBJECT (self, "Failed to push CUDA context");
517     return FALSE;
518   }
519
520   if (gst_memory_map (mem, &info, GST_MAP_READ | GST_MAP_GL)) {
521     GstGLMemoryPBO *gl_mem = (GstGLMemoryPBO *) mem;
522     GstGLBuffer *gl_buffer = gl_mem->pbo;
523
524     GST_LOG_OBJECT (self,
525         "Register glbuffer %d to CUDA resource", gl_buffer->id);
526
527     /* register resource without read/write only flags, since
528      * downstream CUDA elements (e.g., nvenc) might want to access
529      * this resource later. Instead, use map flags during map/unmap */
530     if (gst_cuda_graphics_resource_register_gl_buffer (resource,
531             gl_buffer->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) {
532       ret = TRUE;
533     } else {
534       GST_WARNING_OBJECT (self, "Failed to register memory");
535     }
536
537     gst_memory_unmap (mem, &info);
538   } else {
539     GST_WARNING_OBJECT (self, "Failed to map memory");
540   }
541
542   if (!gst_cuda_context_pop (NULL))
543     GST_WARNING_OBJECT (self, "Failed to pop CUDA context");
544
545   return ret;
546 }
547
548 static GstCudaGraphicsResource *
549 gst_nv_decoder_ensure_cuda_graphics_resource (GstNvDecoder * self,
550     GstMemory * mem)
551 {
552   GQuark quark;
553   GstCudaGraphicsResource *resource;
554
555   if (!gst_is_gl_memory_pbo (mem)) {
556     GST_WARNING_OBJECT (self, "memory is not GL PBO memory, %s",
557         mem->allocator->mem_type);
558     return NULL;
559   }
560
561   quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
562
563   resource = (GstCudaGraphicsResource *)
564       gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
565
566   if (!resource) {
567     gboolean ret;
568
569     resource = gst_cuda_graphics_resource_new (self->context,
570         GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context),
571         GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER);
572
573     ret = gst_nv_decoder_register_cuda_resource (self, mem, resource);
574     if (!ret) {
575       GST_WARNING_OBJECT (self, "Couldn't register resource");
576       gst_cuda_graphics_resource_free (resource);
577
578       return NULL;
579     }
580
581     gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, resource,
582         (GDestroyNotify) gst_cuda_graphics_resource_free);
583   }
584
585   return resource;
586 }
587
588 typedef struct
589 {
590   GstNvDecoder *self;
591   gboolean ret;
592   GstNvDecoderFrame *frame;
593   GstBuffer *output_buffer;
594 } GstNvDecoderCopyToGLData;
595
596 static void
597 gst_nv_decoder_copy_frame_to_gl_internal (GstGLContext * context,
598     GstNvDecoderCopyToGLData * data)
599 {
600   GstNvDecoder *self = data->self;
601   GstNvDecoderFrame *frame = data->frame;
602   GstCudaGraphicsResource **resources;
603   guint num_resources;
604   guint i;
605   CUDA_MEMCPY2D copy_params = { 0, };
606   GstVideoInfo *info = &self->info;
607
608   data->ret = TRUE;
609
610   num_resources = gst_buffer_n_memory (data->output_buffer);
611   resources = g_newa (GstCudaGraphicsResource *, num_resources);
612
613   for (i = 0; i < num_resources; i++) {
614     GstMemory *mem;
615
616     mem = gst_buffer_peek_memory (data->output_buffer, i);
617     resources[i] = gst_nv_decoder_ensure_cuda_graphics_resource (self, mem);
618     if (!resources[i]) {
619       GST_WARNING_OBJECT (self, "could not register %dth memory", i);
620       data->ret = FALSE;
621
622       return;
623     }
624
625     /* Need PBO -> texture */
626     GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
627   }
628
629   if (!gst_cuda_context_push (self->context)) {
630     GST_WARNING_OBJECT (self, "Failed to push CUDA context");
631     data->ret = FALSE;
632     return;
633   }
634
635   copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
636   copy_params.srcPitch = frame->pitch;
637   copy_params.dstMemoryType = CU_MEMORYTYPE_DEVICE;
638
639   for (i = 0; i < num_resources; i++) {
640     CUdeviceptr dst_ptr;
641     gsize size;
642     CUgraphicsResource cuda_resource =
643         gst_cuda_graphics_resource_map (resources[i], NULL,
644         CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
645
646     if (!cuda_resource) {
647       GST_WARNING_OBJECT (self, "failed to map CUDA resources");
648       data->ret = FALSE;
649       goto unmap_video_frame;
650     }
651
652     if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&dst_ptr, &size,
653                 cuda_resource))) {
654       GST_WARNING_OBJECT (self, "failed to map CUDA resource");
655       data->ret = FALSE;
656       break;
657     }
658
659     copy_params.dstPitch = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
660     copy_params.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (info, i)
661         * GST_VIDEO_INFO_COMP_PSTRIDE (info, i);
662
663     copy_params.srcDevice = frame->devptr +
664         (i * frame->pitch * GST_VIDEO_INFO_HEIGHT (&self->coded_info));
665     copy_params.dstDevice = dst_ptr;
666     copy_params.Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
667
668     if (!gst_cuda_result (CuMemcpy2DAsync (&copy_params, NULL))) {
669       GST_WARNING_OBJECT (self, "memcpy to mapped array failed");
670       data->ret = FALSE;
671     }
672   }
673
674   gst_cuda_result (CuStreamSynchronize (NULL));
675
676 unmap_video_frame:
677   for (i = 0; i < num_resources; i++) {
678     gst_cuda_graphics_resource_unmap (resources[i], NULL);
679   }
680
681   if (!gst_cuda_context_pop (NULL))
682     GST_WARNING_OBJECT (self, "Failed to pop CUDA context");
683 }
684
685 static gboolean
686 gst_nv_decoder_copy_frame_to_gl (GstNvDecoder * decoder,
687     GstGLContext * context, GstNvDecoderFrame * frame, GstBuffer * buffer)
688 {
689   GstNvDecoderCopyToGLData data;
690
691   data.self = decoder;
692   data.frame = frame;
693   data.output_buffer = buffer;
694
695   gst_gl_context_thread_add (context,
696       (GstGLContextThreadFunc) gst_nv_decoder_copy_frame_to_gl_internal, &data);
697
698   GST_LOG_OBJECT (decoder, "Copy frame to GL ret %d", data.ret);
699
700   return data.ret;
701 }
702 #endif
703
704 static gboolean
705 gst_nv_decoder_copy_frame_to_system (GstNvDecoder * decoder,
706     GstNvDecoderFrame * frame, GstBuffer * buffer)
707 {
708   GstVideoFrame video_frame;
709   CUDA_MEMCPY2D copy_params = { 0, };
710   gint i;
711   gboolean ret = FALSE;
712
713   if (!gst_video_frame_map (&video_frame, &decoder->info, buffer,
714           GST_MAP_WRITE)) {
715     GST_ERROR_OBJECT (decoder, "Couldn't map video frame");
716     return FALSE;
717   }
718
719   if (!gst_cuda_context_push (decoder->context)) {
720     GST_ERROR_OBJECT (decoder, "Failed to push CUDA context");
721     gst_video_frame_unmap (&video_frame);
722     return FALSE;
723   }
724
725   copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
726   copy_params.srcPitch = frame->pitch;
727   copy_params.dstMemoryType = CU_MEMORYTYPE_HOST;
728   copy_params.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (&decoder->info, 0)
729       * GST_VIDEO_INFO_COMP_PSTRIDE (&decoder->info, 0);
730
731   for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&video_frame); i++) {
732     copy_params.srcDevice = frame->devptr +
733         (i * frame->pitch * GST_VIDEO_INFO_HEIGHT (&decoder->coded_info));
734     copy_params.dstHost = GST_VIDEO_FRAME_PLANE_DATA (&video_frame, i);
735     copy_params.dstPitch = GST_VIDEO_FRAME_PLANE_STRIDE (&video_frame, i);
736     copy_params.Height = GST_VIDEO_FRAME_COMP_HEIGHT (&video_frame, i);
737
738     if (!gst_cuda_result (CuMemcpy2DAsync (&copy_params, decoder->cuda_stream))) {
739       GST_ERROR_OBJECT (decoder, "failed to copy %dth plane", i);
740       goto done;
741     }
742   }
743
744   gst_cuda_result (CuStreamSynchronize (decoder->cuda_stream));
745
746   ret = TRUE;
747
748 done:
749   gst_cuda_context_pop (NULL);
750
751   gst_video_frame_unmap (&video_frame);
752
753   GST_LOG_OBJECT (decoder, "Copy frame to system ret %d", ret);
754
755   return ret;
756 }
757
758 static gboolean
759 gst_nv_decoder_copy_frame_to_cuda (GstNvDecoder * decoder,
760     GstNvDecoderFrame * frame, GstBuffer * buffer)
761 {
762   CUDA_MEMCPY2D copy_params = { 0, };
763   GstMemory *mem;
764   GstCudaMemory *cuda_mem = NULL;
765   gint i;
766   gboolean ret = FALSE;
767
768   mem = gst_buffer_peek_memory (buffer, 0);
769   if (!gst_is_cuda_memory (mem)) {
770     GST_WARNING_OBJECT (decoder, "Not a CUDA memory");
771     return FALSE;
772   } else {
773     GstCudaMemory *cmem = GST_CUDA_MEMORY_CAST (mem);
774
775     if (cmem->context == decoder->context ||
776         gst_cuda_context_get_handle (cmem->context) ==
777         gst_cuda_context_get_handle (decoder->context) ||
778         (gst_cuda_context_can_access_peer (cmem->context, decoder->context) &&
779             gst_cuda_context_can_access_peer (decoder->context,
780                 cmem->context))) {
781       cuda_mem = cmem;
782     }
783   }
784
785   if (!cuda_mem) {
786     GST_WARNING_OBJECT (decoder, "Access to CUDA memory is not allowed");
787     return FALSE;
788   }
789
790   if (!gst_cuda_context_push (decoder->context)) {
791     GST_ERROR_OBJECT (decoder, "Failed to push CUDA context");
792     return FALSE;
793   }
794
795   copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
796   copy_params.srcPitch = frame->pitch;
797   copy_params.dstMemoryType = CU_MEMORYTYPE_DEVICE;
798
799   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&decoder->info); i++) {
800     copy_params.srcDevice = frame->devptr +
801         (i * frame->pitch * GST_VIDEO_INFO_HEIGHT (&decoder->info));
802     copy_params.dstDevice = cuda_mem->data + cuda_mem->offset[i];
803     copy_params.dstPitch = cuda_mem->stride;
804     copy_params.WidthInBytes = GST_VIDEO_INFO_COMP_WIDTH (&decoder->info, 0)
805         * GST_VIDEO_INFO_COMP_PSTRIDE (&decoder->info, 0);
806     copy_params.Height = GST_VIDEO_INFO_COMP_HEIGHT (&decoder->info, i);
807
808     if (!gst_cuda_result (CuMemcpy2DAsync (&copy_params, decoder->cuda_stream))) {
809       GST_ERROR_OBJECT (decoder, "failed to copy %dth plane", i);
810       goto done;
811     }
812   }
813
814   gst_cuda_result (CuStreamSynchronize (decoder->cuda_stream));
815
816   ret = TRUE;
817
818 done:
819   gst_cuda_context_pop (NULL);
820
821   GST_LOG_OBJECT (decoder, "Copy frame to CUDA ret %d", ret);
822
823   return ret;
824 }
825
826 gboolean
827 gst_nv_decoder_finish_frame (GstNvDecoder * decoder, GstVideoDecoder * videodec,
828     GstNvDecoderFrame * frame, GstBuffer ** buffer)
829 {
830   GstBuffer *outbuf = NULL;
831   gboolean ret = FALSE;
832
833   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), GST_FLOW_ERROR);
834   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), GST_FLOW_ERROR);
835   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
836   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
837
838   outbuf = gst_video_decoder_allocate_output_buffer (videodec);
839   if (!outbuf) {
840     GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer");
841     return FALSE;
842   }
843
844   if (!gst_cuda_context_push (decoder->context)) {
845     GST_ERROR_OBJECT (decoder, "Failed to push CUDA context");
846     goto error;
847   }
848
849   if (!gst_nv_decoder_frame_map (frame)) {
850     GST_ERROR_OBJECT (decoder, "Couldn't map frame");
851     gst_cuda_context_pop (NULL);
852     goto error;
853   }
854
855   gst_cuda_context_pop (NULL);
856
857   switch (decoder->output_type) {
858     case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM:
859       ret = gst_nv_decoder_copy_frame_to_system (decoder, frame, outbuf);
860       break;
861 #ifdef HAVE_NVCODEC_GST_GL
862     case GST_NV_DECODER_OUTPUT_TYPE_GL:
863       g_assert (decoder->gl_context != NULL);
864
865       ret = gst_nv_decoder_copy_frame_to_gl (decoder,
866           GST_GL_CONTEXT (decoder->gl_context), frame, outbuf);
867       break;
868 #endif
869     case GST_NV_DECODER_OUTPUT_TYPE_CUDA:
870       ret = gst_nv_decoder_copy_frame_to_cuda (decoder, frame, outbuf);
871       break;
872     default:
873       g_assert_not_reached ();
874       goto error;
875   }
876
877   /* FIXME: This is the case where OpenGL context of downstream glbufferpool
878    * belongs to non-nvidia (or different device).
879    * There should be enhancement to ensure nvdec has compatible OpenGL context
880    */
881   if (!ret && decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL) {
882     GST_WARNING_OBJECT (videodec,
883         "Couldn't copy frame to GL memory, fallback to system memory");
884     decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
885
886     ret = gst_nv_decoder_copy_frame_to_system (decoder, frame, outbuf);
887   }
888
889   gst_cuda_context_push (decoder->context);
890   gst_nv_decoder_frame_unmap (frame);
891   gst_cuda_context_pop (NULL);
892
893   if (!ret) {
894     GST_WARNING_OBJECT (videodec, "Failed to copy frame");
895     goto error;
896   }
897
898   *buffer = outbuf;
899
900   return TRUE;
901
902 error:
903   gst_clear_buffer (&outbuf);
904   return FALSE;
905 }
906
907 typedef enum
908 {
909   GST_NV_DECODER_FORMAT_FLAG_NONE = (1 << 0),
910   GST_NV_DECODER_FORMAT_FLAG_420_8BITS = (1 << 1),
911   GST_NV_DECODER_FORMAT_FLAG_420_10BITS = (1 << 2),
912   GST_NV_DECODER_FORMAT_FLAG_420_12BITS = (1 << 3),
913   GST_NV_DECODER_FORMAT_FLAG_444_8BITS = (1 << 4),
914   GST_NV_DECODER_FORMAT_FLAG_444_10BITS = (1 << 5),
915   GST_NV_DECODER_FORMAT_FLAG_444_12BITS = (1 << 6),
916 } GstNvDecoderFormatFlags;
917
918 static gboolean
919 gst_nv_decoder_get_supported_codec_profiles (GValue * profiles,
920     cudaVideoCodec codec, GstNvDecoderFormatFlags flags)
921 {
922   GValue val = G_VALUE_INIT;
923   gboolean ret = FALSE;
924
925   g_value_init (&val, G_TYPE_STRING);
926
927   switch (codec) {
928     case cudaVideoCodec_H264:
929       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_8BITS) ==
930           GST_NV_DECODER_FORMAT_FLAG_420_8BITS) {
931         g_value_set_static_string (&val, "constrained-baseline");
932         gst_value_list_append_value (profiles, &val);
933
934         g_value_set_static_string (&val, "baseline");
935         gst_value_list_append_value (profiles, &val);
936
937         g_value_set_static_string (&val, "main");
938         gst_value_list_append_value (profiles, &val);
939
940         g_value_set_static_string (&val, "high");
941         gst_value_list_append_value (profiles, &val);
942
943         g_value_set_static_string (&val, "constrained-high");
944         gst_value_list_append_value (profiles, &val);
945
946         g_value_set_static_string (&val, "progressive-high");
947         gst_value_list_append_value (profiles, &val);
948       }
949
950       /* NVDEC supports only 4:2:0 8bits h264 decoding.
951        * following conditions are for the future enhancement */
952       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_10BITS) ==
953           GST_NV_DECODER_FORMAT_FLAG_420_10BITS) {
954         g_value_set_static_string (&val, "high-10");
955         gst_value_list_append_value (profiles, &val);
956
957         g_value_set_static_string (&val, "progressive-high-10");
958         gst_value_list_append_value (profiles, &val);
959       }
960
961       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_12BITS) ==
962           GST_NV_DECODER_FORMAT_FLAG_420_12BITS ||
963           (flags & GST_NV_DECODER_FORMAT_FLAG_444_8BITS) ==
964           GST_NV_DECODER_FORMAT_FLAG_444_8BITS ||
965           (flags & GST_NV_DECODER_FORMAT_FLAG_444_10BITS) ==
966           GST_NV_DECODER_FORMAT_FLAG_444_10BITS ||
967           (flags & GST_NV_DECODER_FORMAT_FLAG_444_12BITS) ==
968           GST_NV_DECODER_FORMAT_FLAG_444_12BITS) {
969         g_value_set_static_string (&val, "high-4:4:4");
970         gst_value_list_append_value (profiles, &val);
971       }
972
973       ret = TRUE;
974       break;
975     case cudaVideoCodec_HEVC:
976       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_8BITS) ==
977           GST_NV_DECODER_FORMAT_FLAG_420_8BITS) {
978         g_value_set_static_string (&val, "main");
979         gst_value_list_append_value (profiles, &val);
980       }
981
982       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_10BITS) ==
983           GST_NV_DECODER_FORMAT_FLAG_420_10BITS) {
984         g_value_set_static_string (&val, "main-10");
985         gst_value_list_append_value (profiles, &val);
986       }
987
988       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_12BITS) ==
989           GST_NV_DECODER_FORMAT_FLAG_420_12BITS) {
990         g_value_set_static_string (&val, "main-12");
991         gst_value_list_append_value (profiles, &val);
992       }
993
994       if ((flags & GST_NV_DECODER_FORMAT_FLAG_444_8BITS) ==
995           GST_NV_DECODER_FORMAT_FLAG_444_8BITS) {
996         g_value_set_static_string (&val, "main-444");
997         gst_value_list_append_value (profiles, &val);
998       }
999
1000       if ((flags & GST_NV_DECODER_FORMAT_FLAG_444_10BITS) ==
1001           GST_NV_DECODER_FORMAT_FLAG_444_10BITS) {
1002         g_value_set_static_string (&val, "main-444-10");
1003         gst_value_list_append_value (profiles, &val);
1004       }
1005
1006       if ((flags & GST_NV_DECODER_FORMAT_FLAG_444_12BITS) ==
1007           GST_NV_DECODER_FORMAT_FLAG_444_12BITS) {
1008         g_value_set_static_string (&val, "main-444-12");
1009         gst_value_list_append_value (profiles, &val);
1010       }
1011
1012       ret = TRUE;
1013       break;
1014     case cudaVideoCodec_VP9:
1015       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_8BITS) ==
1016           GST_NV_DECODER_FORMAT_FLAG_420_8BITS) {
1017         g_value_set_static_string (&val, "0");
1018         gst_value_list_append_value (profiles, &val);
1019       }
1020
1021       if ((flags & GST_NV_DECODER_FORMAT_FLAG_420_10BITS) ==
1022           GST_NV_DECODER_FORMAT_FLAG_420_10BITS) {
1023         g_value_set_static_string (&val, "2");
1024         gst_value_list_append_value (profiles, &val);
1025       }
1026
1027       ret = TRUE;
1028       break;
1029     default:
1030       break;
1031   }
1032
1033   g_value_unset (&val);
1034
1035   return ret;
1036 }
1037
1038 typedef struct
1039 {
1040   cudaVideoCodec codec;
1041   const gchar *codec_name;
1042   const gchar *sink_caps_string;
1043 } GstNvdecoderCodecMap;
1044
1045 const GstNvdecoderCodecMap codec_map_list[] = {
1046   {cudaVideoCodec_MPEG1, "mpegvideo",
1047       "video/mpeg, mpegversion = (int) 1, systemstream = (boolean) false"},
1048   {cudaVideoCodec_MPEG2, "mpeg2video",
1049       "video/mpeg, mpegversion = (int) 2, systemstream = (boolean) false"},
1050   {cudaVideoCodec_MPEG4, "mpeg4video",
1051       "video/mpeg, mpegversion = (int) 4, systemstream = (boolean) false"},
1052 #if 0
1053   /* FIXME: need verification */
1054   {cudaVideoCodec_VC1, "vc1"},
1055 #endif
1056   /* NOTE: common supported h264 profiles for all GPU architecture
1057    * 4:2:0, baseline, main, and high profiles
1058    */
1059   {cudaVideoCodec_H264, "h264",
1060       "video/x-h264, stream-format = (string) byte-stream"
1061         ", alignment = (string) au"
1062         ", profile = (string) { constrained-baseline, baseline, main, high, constrained-high, progressive-high }"},
1063   {cudaVideoCodec_JPEG, "jpeg", "image/jpeg"},
1064 #if 0
1065   /* FIXME: need verification */
1066   {cudaVideoCodec_H264_SVC, "h264svc"},
1067   {cudaVideoCodec_H264_MVC, "h264mvc"},
1068 #endif
1069   {cudaVideoCodec_HEVC, "h265",
1070       "video/x-h265, stream-format = (string) byte-stream"
1071         ", alignment = (string) au, profile = (string) { main }"},
1072   {cudaVideoCodec_VP8, "vp8", "video/x-vp8"},
1073   {cudaVideoCodec_VP9, "vp9", "video/x-vp9"}
1074 };
1075
1076 gboolean
1077 gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec,
1078     GstCaps ** sink_template, GstCaps ** src_template)
1079 {
1080   CUresult cuda_ret;
1081   gint max_width = 0, min_width = G_MAXINT;
1082   gint max_height = 0, min_height = G_MAXINT;
1083   GstCaps *sink_templ = NULL;
1084   GstCaps *src_templ = NULL;
1085   /* FIXME: support 12bits format */
1086   guint bitdepth_minus8[3] = { 0, 2, 4 };
1087   GstNvDecoderFormatFlags format_flags = 0;
1088   gint c_idx, b_idx;
1089   guint num_support = 0;
1090   cudaVideoChromaFormat chroma_list[] = {
1091 #if 0
1092     /* FIXME: support monochrome */
1093     cudaVideoChromaFormat_Monochrome,
1094     /* FIXME: Can our OpenGL support NV16 and its 10/12bits variant?? */
1095     cudaVideoChromaFormat_422,
1096 #endif
1097     cudaVideoChromaFormat_420,
1098     cudaVideoChromaFormat_444,
1099   };
1100   GValue format_list = G_VALUE_INIT;
1101   GValue format = G_VALUE_INIT;
1102   GValue profile_list = G_VALUE_INIT;
1103   const GstNvdecoderCodecMap *codec_map = NULL;
1104   guint i;
1105   gboolean ret = FALSE;
1106
1107   for (i = 0; i < G_N_ELEMENTS (codec_map_list); i++) {
1108     if (codec_map_list[i].codec == codec) {
1109       codec_map = &codec_map_list[i];
1110       break;
1111     }
1112   }
1113
1114   if (!codec_map) {
1115     GST_INFO ("No codec map corresponding to codec %d", codec);
1116     return FALSE;
1117   }
1118
1119   if (!gst_cuvid_can_get_decoder_caps ()) {
1120     GST_INFO ("Too old nvidia driver to query decoder capability");
1121
1122     src_templ = gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("NV12"));
1123
1124     {
1125       GstCaps *cuda_caps = gst_caps_copy (src_templ);
1126       gst_caps_set_features_simple (cuda_caps,
1127           gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY));
1128
1129 #if HAVE_NVCODEC_GST_GL
1130       {
1131         GstCaps *gl_caps = gst_caps_copy (src_templ);
1132         gst_caps_set_features_simple (gl_caps,
1133             gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
1134         gst_caps_append (src_templ, gl_caps);
1135       }
1136 #endif
1137
1138       gst_caps_append (src_templ, cuda_caps);
1139     }
1140
1141     sink_templ = gst_caps_from_string (codec_map->sink_caps_string);
1142
1143     *src_template = src_templ;
1144     *sink_template = sink_templ;
1145
1146     return TRUE;
1147   }
1148
1149   g_value_init (&format_list, GST_TYPE_LIST);
1150   g_value_init (&format, G_TYPE_STRING);
1151   g_value_init (&profile_list, GST_TYPE_LIST);
1152
1153   if (CuCtxPushCurrent (cuda_ctx) != CUDA_SUCCESS)
1154     goto done;
1155
1156   for (c_idx = 0; c_idx < G_N_ELEMENTS (chroma_list); c_idx++) {
1157     for (b_idx = 0; b_idx < G_N_ELEMENTS (bitdepth_minus8); b_idx++) {
1158       CUVIDDECODECAPS decoder_caps = { 0, };
1159       GstNvDecoderFormatFlags cur_flag = 0;
1160
1161       decoder_caps.eCodecType = codec;
1162       decoder_caps.eChromaFormat = chroma_list[c_idx];
1163       decoder_caps.nBitDepthMinus8 = bitdepth_minus8[b_idx];
1164
1165       cuda_ret = CuvidGetDecoderCaps (&decoder_caps);
1166       if (cuda_ret != CUDA_SUCCESS) {
1167         GST_INFO ("could not query %s decoder capability, ret %d",
1168             codec_map->codec_name, cuda_ret);
1169         continue;
1170       } else if (!decoder_caps.bIsSupported) {
1171         GST_LOG ("%s bit-depth %d with chroma format %d is not supported",
1172             codec_map->codec_name, bitdepth_minus8[b_idx] + 8, c_idx);
1173         continue;
1174       }
1175
1176       if (min_width > decoder_caps.nMinWidth)
1177         min_width = decoder_caps.nMinWidth;
1178       if (min_height > decoder_caps.nMinHeight)
1179         min_height = decoder_caps.nMinHeight;
1180       if (max_width < decoder_caps.nMaxWidth)
1181         max_width = decoder_caps.nMaxWidth;
1182       if (max_height < decoder_caps.nMaxHeight)
1183         max_height = decoder_caps.nMaxHeight;
1184
1185       if (chroma_list[c_idx] == cudaVideoChromaFormat_420)
1186         cur_flag = GST_NV_DECODER_FORMAT_FLAG_420_8BITS;
1187       else
1188         cur_flag = GST_NV_DECODER_FORMAT_FLAG_444_8BITS;
1189
1190       format_flags |= (cur_flag << (bitdepth_minus8[b_idx] / 2));
1191
1192       GST_INFO ("%s bit-depth %d with chroma format %d [%d - %d] x [%d - %d]",
1193           codec_map->codec_name, bitdepth_minus8[b_idx] + 8, c_idx, min_width,
1194           max_width, min_height, max_height);
1195
1196       switch (chroma_list[c_idx]) {
1197         case cudaVideoChromaFormat_420:
1198           if (bitdepth_minus8[b_idx] == 0) {
1199             g_value_set_string (&format, "NV12");
1200           } else if (bitdepth_minus8[b_idx] == 2) {
1201 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1202             g_value_set_string (&format, "P010_10LE");
1203 #else
1204             g_value_set_string (&format, "P010_10BE");
1205 #endif
1206           } else if (bitdepth_minus8[b_idx] == 4) {
1207 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1208             g_value_set_string (&format, "P016_LE");
1209 #else
1210             g_value_set_string (&format, "P016_BE");
1211 #endif
1212           } else {
1213             GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8);
1214             break;
1215           }
1216           num_support++;
1217           gst_value_list_append_value (&format_list, &format);
1218           break;
1219         case cudaVideoChromaFormat_444:
1220           if (cudaVideoCodec_JPEG == codec) {
1221             /* NVDEC jpeg decoder can decode 4:4:4 format
1222              * but it produces 4:2:0 frame */
1223             break;
1224           }
1225
1226           if (bitdepth_minus8[b_idx] == 0) {
1227             g_value_set_string (&format, "Y444");
1228           } else if (bitdepth_minus8[b_idx] == 2 || bitdepth_minus8[b_idx] == 4) {
1229 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1230             g_value_set_string (&format, "Y444_16LE");
1231 #else
1232             g_value_set_string (&format, "Y444_16BE");
1233 #endif
1234           } else {
1235             GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8);
1236             break;
1237           }
1238           num_support++;
1239           gst_value_list_append_value (&format_list, &format);
1240           break;
1241         default:
1242           break;
1243       }
1244     }
1245   }
1246
1247   if (num_support == 0) {
1248     GST_INFO ("device can not support %s", codec_map->codec_name);
1249     goto done;
1250   }
1251
1252   src_templ = gst_caps_new_simple ("video/x-raw",
1253       "width", GST_TYPE_INT_RANGE, min_width, max_width,
1254       "height", GST_TYPE_INT_RANGE, min_height, max_height,
1255       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1256
1257   gst_caps_set_value (src_templ, "format", &format_list);
1258
1259   {
1260     GstCaps *cuda_caps = gst_caps_copy (src_templ);
1261     gst_caps_set_features_simple (cuda_caps,
1262         gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY));
1263
1264     /* OpenGL specific */
1265 #if HAVE_NVCODEC_GST_GL
1266     {
1267       GstCaps *gl_caps = gst_caps_copy (src_templ);
1268       gst_caps_set_features_simple (gl_caps,
1269           gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
1270       gst_caps_append (src_templ, gl_caps);
1271     }
1272 #endif
1273
1274     gst_caps_append (src_templ, cuda_caps);
1275   }
1276
1277   sink_templ = gst_caps_from_string (codec_map->sink_caps_string);
1278   gst_caps_set_simple (sink_templ,
1279       "width", GST_TYPE_INT_RANGE, min_width, max_width,
1280       "height", GST_TYPE_INT_RANGE, min_height, max_height, NULL);
1281
1282   if (gst_nv_decoder_get_supported_codec_profiles (&profile_list, codec,
1283           format_flags)) {
1284     gst_caps_set_value (sink_templ, "profile", &profile_list);
1285   }
1286
1287   GST_DEBUG ("sink template caps %" GST_PTR_FORMAT, sink_templ);
1288   GST_DEBUG ("src template caps %" GST_PTR_FORMAT, src_templ);
1289
1290   CuCtxPopCurrent (NULL);
1291
1292 done:
1293   g_value_unset (&format_list);
1294   g_value_unset (&format);
1295   g_value_unset (&profile_list);
1296
1297   if (!sink_templ || !src_templ) {
1298     gst_clear_caps (&sink_templ);
1299     gst_clear_caps (&src_templ);
1300
1301     ret = FALSE;
1302   } else {
1303     /* class data will be leaked if the element never gets instantiated */
1304     GST_MINI_OBJECT_FLAG_SET (src_templ, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1305     GST_MINI_OBJECT_FLAG_SET (sink_templ, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1306
1307     *src_template = src_templ;
1308     *sink_template = sink_templ;
1309
1310     ret = TRUE;
1311   }
1312
1313   return ret;
1314 }
1315
1316 const gchar *
1317 gst_cuda_video_codec_to_string (cudaVideoCodec codec)
1318 {
1319   gint i;
1320
1321   for (i = 0; i < G_N_ELEMENTS (codec_map_list); i++) {
1322     if (codec_map_list[i].codec == codec)
1323       return codec_map_list[i].codec_name;
1324   }
1325
1326   return "unknown";
1327 }
1328
1329 gboolean
1330 gst_nv_decoder_handle_set_context (GstNvDecoder * decoder,
1331     GstElement * videodec, GstContext * context)
1332 {
1333   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
1334   g_return_val_if_fail (GST_IS_ELEMENT (videodec), FALSE);
1335
1336 #ifdef HAVE_NVCODEC_GST_GL
1337   if (gst_gl_handle_set_context (videodec, context,
1338           (GstGLDisplay **) & decoder->gl_display,
1339           (GstGLContext **) & decoder->other_gl_context)) {
1340     return TRUE;
1341   }
1342 #endif
1343
1344   return FALSE;
1345 }
1346
1347 gboolean
1348 gst_nv_decoder_handle_context_query (GstNvDecoder * decoder,
1349     GstVideoDecoder * videodec, GstQuery * query)
1350 {
1351   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
1352   g_return_val_if_fail (GST_IS_ELEMENT (videodec), FALSE);
1353
1354 #ifdef HAVE_NVCODEC_GST_GL
1355   if (gst_gl_handle_context_query (GST_ELEMENT (videodec), query,
1356           (GstGLDisplay *) decoder->gl_display,
1357           (GstGLContext *) decoder->gl_context,
1358           (GstGLContext *) decoder->other_gl_context)) {
1359     if (decoder->gl_display)
1360       gst_gl_display_filter_gl_api (GST_GL_DISPLAY (decoder->gl_display),
1361           SUPPORTED_GL_APIS);
1362     return TRUE;
1363   }
1364 #endif
1365
1366   return FALSE;
1367 }
1368
1369 #ifdef HAVE_NVCODEC_GST_GL
1370 static void
1371 gst_nv_decoder_check_cuda_device_from_context (GstGLContext * context,
1372     gboolean * ret)
1373 {
1374   guint device_count = 0;
1375   CUdevice device_list[1] = { 0, };
1376   CUresult cuda_ret;
1377
1378   *ret = FALSE;
1379
1380   cuda_ret = CuGLGetDevices (&device_count,
1381       device_list, 1, CU_GL_DEVICE_LIST_ALL);
1382
1383   if (!gst_cuda_result (cuda_ret) || device_count == 0)
1384     return;
1385
1386   *ret = TRUE;
1387
1388   return;
1389 }
1390
1391 static gboolean
1392 gst_nv_decoder_ensure_gl_context (GstNvDecoder * decoder, GstElement * videodec)
1393 {
1394   gboolean ret;
1395   GstGLDisplay *display;
1396   GstGLContext *context;
1397
1398   if (!gst_gl_ensure_element_data (videodec,
1399           (GstGLDisplay **) & decoder->gl_display,
1400           (GstGLContext **) & decoder->other_gl_context)) {
1401     GST_DEBUG_OBJECT (videodec, "No available OpenGL display");
1402     return FALSE;
1403   }
1404
1405   display = GST_GL_DISPLAY (decoder->gl_display);
1406
1407   if (!gst_gl_query_local_gl_context (videodec, GST_PAD_SRC,
1408           (GstGLContext **) & decoder->gl_context)) {
1409     GST_INFO_OBJECT (videodec, "failed to query local OpenGL context");
1410
1411     gst_clear_object (&decoder->gl_context);
1412     decoder->gl_context =
1413         (GstObject *) gst_gl_display_get_gl_context_for_thread (display, NULL);
1414     if (decoder->gl_context == NULL
1415         || !gst_gl_display_add_context (display,
1416             GST_GL_CONTEXT (decoder->gl_context))) {
1417       gst_clear_object (&decoder->gl_context);
1418       if (!gst_gl_display_create_context (display,
1419               (GstGLContext *) decoder->other_gl_context,
1420               (GstGLContext **) & decoder->gl_context, NULL)) {
1421         GST_WARNING_OBJECT (videodec, "failed to create OpenGL context");
1422         return FALSE;
1423       }
1424
1425       if (!gst_gl_display_add_context (display,
1426               (GstGLContext *) decoder->gl_context)) {
1427         GST_WARNING_OBJECT (videodec,
1428             "failed to add the OpenGL context to the display");
1429         return FALSE;
1430       }
1431     }
1432   }
1433
1434   context = GST_GL_CONTEXT (decoder->gl_context);
1435
1436   if (!gst_gl_context_check_gl_version (context, SUPPORTED_GL_APIS, 3, 0)) {
1437     GST_WARNING_OBJECT (videodec,
1438         "OpenGL context could not support PBO download");
1439     return FALSE;
1440   }
1441
1442   gst_gl_context_thread_add (context,
1443       (GstGLContextThreadFunc) gst_nv_decoder_check_cuda_device_from_context,
1444       &ret);
1445
1446   if (!ret) {
1447     GST_WARNING_OBJECT (videodec,
1448         "Current OpenGL context is not CUDA-compatible");
1449     return FALSE;
1450   }
1451
1452   return TRUE;
1453 }
1454 #endif
1455
1456 gboolean
1457 gst_nv_decoder_negotiate (GstNvDecoder * decoder,
1458     GstVideoDecoder * videodec, GstVideoCodecState * input_state,
1459     GstVideoCodecState ** output_state)
1460 {
1461   GstVideoCodecState *state;
1462   GstVideoInfo *info;
1463
1464   g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
1465   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1466   g_return_val_if_fail (input_state != NULL, FALSE);
1467   g_return_val_if_fail (output_state != NULL, FALSE);
1468
1469   if (!decoder->configured) {
1470     GST_ERROR_OBJECT (videodec, "Should configure decoder first");
1471     return FALSE;
1472   }
1473
1474   info = &decoder->info;
1475   state = gst_video_decoder_set_output_state (videodec,
1476       GST_VIDEO_INFO_FORMAT (info),
1477       GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), input_state);
1478   state->caps = gst_video_info_to_caps (&state->info);
1479
1480   if (*output_state)
1481     gst_video_codec_state_unref (*output_state);
1482   *output_state = state;
1483
1484   decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
1485
1486   {
1487     GstCaps *caps;
1488     caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (videodec));
1489     GST_DEBUG_OBJECT (videodec, "Allowed caps %" GST_PTR_FORMAT, caps);
1490
1491     if (!caps || gst_caps_is_any (caps)) {
1492       GST_DEBUG_OBJECT (videodec,
1493           "cannot determine output format, using system memory");
1494     } else {
1495       GstCapsFeatures *features;
1496       guint size = gst_caps_get_size (caps);
1497       guint i;
1498       gboolean have_cuda = FALSE;
1499       gboolean have_gl = FALSE;
1500
1501       for (i = 0; i < size; i++) {
1502         features = gst_caps_get_features (caps, i);
1503         if (features && gst_caps_features_contains (features,
1504                 GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) {
1505           GST_DEBUG_OBJECT (videodec, "found CUDA memory feature");
1506           have_cuda = TRUE;
1507           break;
1508         }
1509 #ifdef HAVE_NVCODEC_GST_GL
1510         if (features && gst_caps_features_contains (features,
1511                 GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
1512           GST_DEBUG_OBJECT (videodec, "found GL memory feature");
1513           have_gl = TRUE;
1514         }
1515 #endif
1516       }
1517
1518       if (have_cuda)
1519         decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_CUDA;
1520       else if (have_gl)
1521         decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_GL;
1522     }
1523     gst_clear_caps (&caps);
1524   }
1525
1526 #ifdef HAVE_NVCODEC_GST_GL
1527   if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL &&
1528       !gst_nv_decoder_ensure_gl_context (decoder, GST_ELEMENT (videodec))) {
1529     GST_WARNING_OBJECT (videodec,
1530         "OpenGL context is not CUDA-compatible, fallback to system memory");
1531     decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
1532   }
1533 #endif
1534
1535   switch (decoder->output_type) {
1536     case GST_NV_DECODER_OUTPUT_TYPE_CUDA:
1537       GST_DEBUG_OBJECT (videodec, "using CUDA memory");
1538       gst_caps_set_features (state->caps, 0,
1539           gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, NULL));
1540       break;
1541 #ifdef HAVE_NVCODEC_GST_GL
1542     case GST_NV_DECODER_OUTPUT_TYPE_GL:
1543       GST_DEBUG_OBJECT (videodec, "using GL memory");
1544       gst_caps_set_features (state->caps, 0,
1545           gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, NULL));
1546       gst_caps_set_simple (state->caps, "texture-target", G_TYPE_STRING,
1547           "2D", NULL);
1548       break;
1549 #endif
1550     default:
1551       GST_DEBUG_OBJECT (videodec, "using system memory");
1552       break;
1553   }
1554
1555   return TRUE;
1556 }
1557
1558 static gboolean
1559 gst_nv_decoder_ensure_cuda_pool (GstNvDecoder * decoder, GstQuery * query)
1560 {
1561   GstCaps *outcaps;
1562   GstBufferPool *pool = NULL;
1563   guint n, size, min, max;
1564   GstVideoInfo vinfo = { 0, };
1565   GstStructure *config;
1566
1567   gst_query_parse_allocation (query, &outcaps, NULL);
1568   n = gst_query_get_n_allocation_pools (query);
1569   if (n > 0) {
1570     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1571     if (pool && !GST_IS_CUDA_BUFFER_POOL (pool)) {
1572       gst_object_unref (pool);
1573       pool = NULL;
1574     }
1575   }
1576
1577   if (!pool) {
1578     GST_DEBUG_OBJECT (decoder, "no downstream pool, create our pool");
1579     pool = gst_cuda_buffer_pool_new (decoder->context);
1580
1581     if (outcaps)
1582       gst_video_info_from_caps (&vinfo, outcaps);
1583     size = (guint) vinfo.size;
1584     min = max = 0;
1585   }
1586
1587   config = gst_buffer_pool_get_config (pool);
1588   gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1589   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1590   gst_buffer_pool_set_config (pool, config);
1591   if (n > 0)
1592     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1593   else
1594     gst_query_add_allocation_pool (query, pool, size, min, max);
1595   gst_object_unref (pool);
1596
1597   return TRUE;
1598 }
1599
1600 #ifdef HAVE_NVCODEC_GST_GL
1601 static gboolean
1602 gst_nv_decoder_ensure_gl_pool (GstNvDecoder * decoder, GstQuery * query)
1603 {
1604   GstCaps *outcaps;
1605   GstBufferPool *pool = NULL;
1606   guint n, size, min, max;
1607   GstVideoInfo vinfo = { 0, };
1608   GstStructure *config;
1609   GstGLContext *gl_context;
1610
1611   GST_DEBUG_OBJECT (decoder, "decide allocation");
1612
1613   if (!decoder->gl_context) {
1614     GST_ERROR_OBJECT (decoder, "GL context is not available");
1615     return FALSE;
1616   }
1617
1618   gl_context = GST_GL_CONTEXT (decoder->gl_context);
1619
1620   gst_query_parse_allocation (query, &outcaps, NULL);
1621   n = gst_query_get_n_allocation_pools (query);
1622   if (n > 0)
1623     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1624
1625   if (pool && !GST_IS_GL_BUFFER_POOL (pool)) {
1626     gst_object_unref (pool);
1627     pool = NULL;
1628   }
1629
1630   if (!pool) {
1631     GST_DEBUG_OBJECT (decoder, "no downstream pool, create our pool");
1632     pool = gst_gl_buffer_pool_new (GST_GL_CONTEXT (gl_context));
1633
1634     if (outcaps)
1635       gst_video_info_from_caps (&vinfo, outcaps);
1636     size = (guint) vinfo.size;
1637     min = max = 0;
1638   }
1639
1640   config = gst_buffer_pool_get_config (pool);
1641   gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1642   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1643   gst_buffer_pool_set_config (pool, config);
1644   if (n > 0)
1645     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1646   else
1647     gst_query_add_allocation_pool (query, pool, size, min, max);
1648   gst_object_unref (pool);
1649
1650   return TRUE;
1651 }
1652 #endif
1653
1654 gboolean
1655 gst_nv_decoder_decide_allocation (GstNvDecoder * decoder,
1656     GstVideoDecoder * videodec, GstQuery * query)
1657 {
1658   gboolean ret = TRUE;
1659
1660   GST_DEBUG_OBJECT (videodec, "decide allocation");
1661
1662   switch (decoder->output_type) {
1663     case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM:
1664       /* GstVideoDecoder will take care this case */
1665       break;
1666 #ifdef HAVE_NVCODEC_GST_GL
1667     case GST_NV_DECODER_OUTPUT_TYPE_GL:
1668       ret = gst_nv_decoder_ensure_gl_pool (decoder, query);
1669       break;
1670 #endif
1671     case GST_NV_DECODER_OUTPUT_TYPE_CUDA:
1672       ret = gst_nv_decoder_ensure_cuda_pool (decoder, query);
1673       break;
1674     default:
1675       g_assert_not_reached ();
1676       return FALSE;
1677   }
1678
1679   return ret;
1680 }