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