1 /*
2  * Copyright (C) 2017 Ericsson AB. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include "gstnvdec.h"
33 
34 typedef enum
35 {
36   GST_NVDEC_QUEUE_ITEM_TYPE_SEQUENCE,
37   GST_NVDEC_QUEUE_ITEM_TYPE_DECODE,
38   GST_NVDEC_QUEUE_ITEM_TYPE_DISPLAY
39 } GstNvDecQueueItemType;
40 
41 typedef struct _GstNvDecQueueItem
42 {
43   GstNvDecQueueItemType type;
44   gpointer data;
45 } GstNvDecQueueItem;
46 
47 GST_DEBUG_CATEGORY_STATIC (gst_nvdec_debug_category);
48 #define GST_CAT_DEFAULT gst_nvdec_debug_category
49 
50 static inline gboolean
cuda_OK(CUresult result)51 cuda_OK (CUresult result)
52 {
53   const gchar *error_name, *error_text;
54 
55   if (result != CUDA_SUCCESS) {
56     cuGetErrorName (result, &error_name);
57     cuGetErrorString (result, &error_text);
58     GST_WARNING ("CUDA call failed: %s, %s", error_name, error_text);
59     return FALSE;
60   }
61 
62   return TRUE;
63 }
64 
65 G_DEFINE_TYPE (GstNvDecCudaContext, gst_nvdec_cuda_context, G_TYPE_OBJECT);
66 
67 static void
gst_nvdec_cuda_context_finalize(GObject * object)68 gst_nvdec_cuda_context_finalize (GObject * object)
69 {
70   GstNvDecCudaContext *self = (GstNvDecCudaContext *) object;
71 
72   if (self->lock) {
73     GST_DEBUG ("destroying CUDA context lock");
74     if (cuda_OK (cuvidCtxLockDestroy (self->lock)))
75       self->lock = NULL;
76     else
77       GST_ERROR ("failed to destroy CUDA context lock");
78   }
79 
80   if (self->context) {
81     GST_DEBUG ("destroying CUDA context");
82     if (cuda_OK (cuCtxDestroy (self->context)))
83       self->context = NULL;
84     else
85       GST_ERROR ("failed to destroy CUDA context");
86   }
87 
88   G_OBJECT_CLASS (gst_nvdec_cuda_context_parent_class)->finalize (object);
89 }
90 
91 static void
gst_nvdec_cuda_context_class_init(GstNvDecCudaContextClass * klass)92 gst_nvdec_cuda_context_class_init (GstNvDecCudaContextClass * klass)
93 {
94   G_OBJECT_CLASS (klass)->finalize = gst_nvdec_cuda_context_finalize;
95 }
96 
97 static void
gst_nvdec_cuda_context_init(GstNvDecCudaContext * self)98 gst_nvdec_cuda_context_init (GstNvDecCudaContext * self)
99 {
100   if (!cuda_OK (cuInit (0)))
101     GST_ERROR ("failed to init CUDA");
102 
103   if (!cuda_OK (cuCtxCreate (&self->context, CU_CTX_SCHED_AUTO, 0)))
104     GST_ERROR ("failed to create CUDA context");
105 
106   if (!cuda_OK (cuCtxPopCurrent (NULL)))
107     GST_ERROR ("failed to pop current CUDA context");
108 
109   if (!cuda_OK (cuvidCtxLockCreate (&self->lock, self->context)))
110     GST_ERROR ("failed to create CUDA context lock");
111 }
112 
113 typedef struct _GstNvDecCudaGraphicsResourceInfo
114 {
115   GstGLContext *gl_context;
116   GstNvDecCudaContext *cuda_context;
117   CUgraphicsResource resource;
118 } GstNvDecCudaGraphicsResourceInfo;
119 
120 static void
register_cuda_resource(GstGLContext * context,gpointer * args)121 register_cuda_resource (GstGLContext * context, gpointer * args)
122 {
123   GstMemory *mem = GST_MEMORY_CAST (args[0]);
124   GstNvDecCudaGraphicsResourceInfo *cgr_info =
125       (GstNvDecCudaGraphicsResourceInfo *) args[1];
126   GstMapInfo map_info = GST_MAP_INFO_INIT;
127   guint texture_id;
128 
129   if (!cuda_OK (cuvidCtxLock (cgr_info->cuda_context->lock, 0)))
130     GST_WARNING ("failed to lock CUDA context");
131 
132   if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) {
133     texture_id = *(guint *) map_info.data;
134 
135     if (!cuda_OK (cuGraphicsGLRegisterImage (&cgr_info->resource, texture_id,
136                 GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD)))
137       GST_WARNING ("failed to register texture with CUDA");
138 
139     gst_memory_unmap (mem, &map_info);
140   } else
141     GST_WARNING ("failed to map memory");
142 
143   if (!cuda_OK (cuvidCtxUnlock (cgr_info->cuda_context->lock, 0)))
144     GST_WARNING ("failed to unlock CUDA context");
145 }
146 
147 static void
unregister_cuda_resource(GstGLContext * context,GstNvDecCudaGraphicsResourceInfo * cgr_info)148 unregister_cuda_resource (GstGLContext * context,
149     GstNvDecCudaGraphicsResourceInfo * cgr_info)
150 {
151   if (!cuda_OK (cuvidCtxLock (cgr_info->cuda_context->lock, 0)))
152     GST_WARNING ("failed to lock CUDA context");
153 
154   if (!cuda_OK (cuGraphicsUnregisterResource ((const CUgraphicsResource)
155               cgr_info->resource)))
156     GST_WARNING ("failed to unregister resource");
157 
158   if (!cuda_OK (cuvidCtxUnlock (cgr_info->cuda_context->lock, 0)))
159     GST_WARNING ("failed to unlock CUDA context");
160 }
161 
162 static void
free_cgr_info(GstNvDecCudaGraphicsResourceInfo * cgr_info)163 free_cgr_info (GstNvDecCudaGraphicsResourceInfo * cgr_info)
164 {
165   gst_gl_context_thread_add (cgr_info->gl_context,
166       (GstGLContextThreadFunc) unregister_cuda_resource, cgr_info);
167   gst_object_unref (cgr_info->gl_context);
168   g_object_unref (cgr_info->cuda_context);
169   g_slice_free (GstNvDecCudaGraphicsResourceInfo, cgr_info);
170 }
171 
172 static CUgraphicsResource
ensure_cuda_graphics_resource(GstMemory * mem,GstNvDecCudaContext * cuda_context)173 ensure_cuda_graphics_resource (GstMemory * mem,
174     GstNvDecCudaContext * cuda_context)
175 {
176   static GQuark quark = 0;
177   GstNvDecCudaGraphicsResourceInfo *cgr_info;
178   gpointer args[2];
179 
180   if (!gst_is_gl_base_memory (mem)) {
181     GST_WARNING ("memory is not GL base memory");
182     return NULL;
183   }
184 
185   if (!quark)
186     quark = g_quark_from_static_string ("GstNvDecCudaGraphicsResourceInfo");
187 
188   cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
189   if (!cgr_info) {
190     cgr_info = g_slice_new (GstNvDecCudaGraphicsResourceInfo);
191     cgr_info->gl_context =
192         gst_object_ref (GST_GL_BASE_MEMORY_CAST (mem)->context);
193     cgr_info->cuda_context = g_object_ref (cuda_context);
194     args[0] = mem;
195     args[1] = cgr_info;
196     gst_gl_context_thread_add (cgr_info->gl_context,
197         (GstGLContextThreadFunc) register_cuda_resource, args);
198     gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
199         (GDestroyNotify) free_cgr_info);
200   }
201 
202   return cgr_info->resource;
203 }
204 
205 static gboolean gst_nvdec_start (GstVideoDecoder * decoder);
206 static gboolean gst_nvdec_stop (GstVideoDecoder * decoder);
207 static gboolean gst_nvdec_set_format (GstVideoDecoder * decoder,
208     GstVideoCodecState * state);
209 static GstFlowReturn gst_nvdec_handle_frame (GstVideoDecoder * decoder,
210     GstVideoCodecFrame * frame);
211 static gboolean gst_nvdec_decide_allocation (GstVideoDecoder * decoder,
212     GstQuery * query);
213 static void gst_nvdec_set_context (GstElement * element, GstContext * context);
214 static gboolean gst_nvdec_src_query (GstVideoDecoder * decoder,
215     GstQuery * query);
216 static gboolean gst_nvdec_flush (GstVideoDecoder * decoder);
217 static GstFlowReturn gst_nvdec_drain (GstVideoDecoder * decoder);
218 static GstFlowReturn gst_nvdec_finish (GstVideoDecoder * decoder);
219 
220 static GstStaticPadTemplate gst_nvdec_sink_template =
221     GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
222     GST_PAD_SINK, GST_PAD_ALWAYS,
223     GST_STATIC_CAPS ("video/x-h264, stream-format=byte-stream, alignment=au; "
224         "video/x-h265, stream-format=byte-stream, alignment=au; "
225         "video/mpeg, mpegversion={ 1, 2, 4 }, systemstream=false; "
226         "image/jpeg; video/x-vp8; video/x-vp9")
227     );
228 
229 static GstStaticPadTemplate gst_nvdec_src_template =
230 GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME,
231     GST_PAD_SRC, GST_PAD_ALWAYS,
232     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
233         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "NV12") ", texture-target=2D")
234     );
235 
236 G_DEFINE_TYPE_WITH_CODE (GstNvDec, gst_nvdec, GST_TYPE_VIDEO_DECODER,
237     GST_DEBUG_CATEGORY_INIT (gst_nvdec_debug_category, "nvdec", 0,
238         "Debug category for the nvdec element"));
239 
240 static void
gst_nvdec_class_init(GstNvDecClass * klass)241 gst_nvdec_class_init (GstNvDecClass * klass)
242 {
243   GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
244   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
245 
246   gst_element_class_add_static_pad_template (element_class,
247       &gst_nvdec_sink_template);
248   gst_element_class_add_static_pad_template (element_class,
249       &gst_nvdec_src_template);
250 
251   gst_element_class_set_static_metadata (element_class, "NVDEC video decoder",
252       "Codec/Decoder/Video/Hardware", "NVDEC video decoder",
253       "Ericsson AB, http://www.ericsson.com");
254 
255   video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_nvdec_start);
256   video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_nvdec_stop);
257   video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_nvdec_set_format);
258   video_decoder_class->handle_frame =
259       GST_DEBUG_FUNCPTR (gst_nvdec_handle_frame);
260   video_decoder_class->decide_allocation =
261       GST_DEBUG_FUNCPTR (gst_nvdec_decide_allocation);
262   video_decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_nvdec_src_query);
263   video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_nvdec_drain);
264   video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_nvdec_flush);
265   video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_nvdec_finish);
266 
267   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nvdec_set_context);
268 }
269 
270 static void
gst_nvdec_init(GstNvDec * nvdec)271 gst_nvdec_init (GstNvDec * nvdec)
272 {
273   gst_video_decoder_set_packetized (GST_VIDEO_DECODER (nvdec), TRUE);
274   gst_video_decoder_set_needs_format (GST_VIDEO_DECODER (nvdec), TRUE);
275 }
276 
277 static gboolean
parser_sequence_callback(GstNvDec * nvdec,CUVIDEOFORMAT * format)278 parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
279 {
280   GstNvDecQueueItem *item;
281   guint width, height;
282   CUVIDDECODECREATEINFO create_info = { 0, };
283   gboolean ret = TRUE;
284 
285   width = format->display_area.right - format->display_area.left;
286   height = format->display_area.bottom - format->display_area.top;
287   GST_DEBUG_OBJECT (nvdec, "width: %u, height: %u", width, height);
288 
289   if (!nvdec->decoder || (nvdec->width != width || nvdec->height != height)) {
290     if (!cuda_OK (cuvidCtxLock (nvdec->cuda_context->lock, 0))) {
291       GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
292       return FALSE;
293     }
294 
295     if (nvdec->decoder) {
296       GST_DEBUG_OBJECT (nvdec, "destroying decoder");
297       if (!cuda_OK (cuvidDestroyDecoder (nvdec->decoder))) {
298         GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
299         ret = FALSE;
300       } else
301         nvdec->decoder = NULL;
302     }
303 
304     GST_DEBUG_OBJECT (nvdec, "creating decoder");
305     create_info.ulWidth = width;
306     create_info.ulHeight = height;
307     create_info.ulNumDecodeSurfaces = 20;
308     create_info.CodecType = format->codec;
309     create_info.ChromaFormat = format->chroma_format;
310     create_info.ulCreationFlags = cudaVideoCreate_Default;
311     create_info.display_area.left = format->display_area.left;
312     create_info.display_area.top = format->display_area.top;
313     create_info.display_area.right = format->display_area.right;
314     create_info.display_area.bottom = format->display_area.bottom;
315     create_info.OutputFormat = cudaVideoSurfaceFormat_NV12;
316     create_info.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
317     create_info.ulTargetWidth = width;
318     create_info.ulTargetHeight = height;
319     create_info.ulNumOutputSurfaces = 1;
320     create_info.vidLock = nvdec->cuda_context->lock;
321     create_info.target_rect.left = 0;
322     create_info.target_rect.top = 0;
323     create_info.target_rect.right = width;
324     create_info.target_rect.bottom = height;
325 
326     if (nvdec->decoder
327         || !cuda_OK (cuvidCreateDecoder (&nvdec->decoder, &create_info))) {
328       GST_ERROR_OBJECT (nvdec, "failed to create decoder");
329       ret = FALSE;
330     }
331 
332     if (!cuda_OK (cuvidCtxUnlock (nvdec->cuda_context->lock, 0))) {
333       GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
334       ret = FALSE;
335     }
336   }
337 
338   item = g_slice_new (GstNvDecQueueItem);
339   item->type = GST_NVDEC_QUEUE_ITEM_TYPE_SEQUENCE;
340   item->data = g_memdup (format, sizeof (CUVIDEOFORMAT));
341   g_async_queue_push (nvdec->decode_queue, item);
342 
343   return ret;
344 }
345 
346 static gboolean
parser_decode_callback(GstNvDec * nvdec,CUVIDPICPARAMS * params)347 parser_decode_callback (GstNvDec * nvdec, CUVIDPICPARAMS * params)
348 {
349   GstNvDecQueueItem *item;
350 
351   GST_LOG_OBJECT (nvdec, "picture index: %u", params->CurrPicIdx);
352 
353   if (!cuda_OK (cuvidCtxLock (nvdec->cuda_context->lock, 0)))
354     GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
355 
356   if (!cuda_OK (cuvidDecodePicture (nvdec->decoder, params)))
357     GST_WARNING_OBJECT (nvdec, "failed to decode picture");
358 
359   if (!cuda_OK (cuvidCtxUnlock (nvdec->cuda_context->lock, 0)))
360     GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
361 
362   item = g_slice_new (GstNvDecQueueItem);
363   item->type = GST_NVDEC_QUEUE_ITEM_TYPE_DECODE;
364   item->data = g_memdup (params, sizeof (CUVIDPICPARAMS));
365   ((CUVIDPICPARAMS *) item->data)->pBitstreamData = NULL;
366   ((CUVIDPICPARAMS *) item->data)->pSliceDataOffsets = NULL;
367   g_async_queue_push (nvdec->decode_queue, item);
368 
369   return TRUE;
370 }
371 
372 static gboolean
parser_display_callback(GstNvDec * nvdec,CUVIDPARSERDISPINFO * dispinfo)373 parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
374 {
375   GstNvDecQueueItem *item;
376 
377   GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
378 
379   item = g_slice_new (GstNvDecQueueItem);
380   item->type = GST_NVDEC_QUEUE_ITEM_TYPE_DISPLAY;
381   item->data = g_memdup (dispinfo, sizeof (CUVIDPARSERDISPINFO));
382   g_async_queue_push (nvdec->decode_queue, item);
383 
384   return TRUE;
385 }
386 
387 static gboolean
gst_nvdec_start(GstVideoDecoder * decoder)388 gst_nvdec_start (GstVideoDecoder * decoder)
389 {
390   GstNvDec *nvdec = GST_NVDEC (decoder);
391 
392   GST_DEBUG_OBJECT (nvdec, "creating CUDA context");
393   nvdec->cuda_context = g_object_new (gst_nvdec_cuda_context_get_type (), NULL);
394   nvdec->decode_queue = g_async_queue_new ();
395 
396   if (!nvdec->cuda_context->context || !nvdec->cuda_context->lock) {
397     GST_ERROR_OBJECT (nvdec, "failed to create CUDA context or lock");
398     return FALSE;
399   }
400 
401   return TRUE;
402 }
403 
404 static gboolean
maybe_destroy_decoder_and_parser(GstNvDec * nvdec)405 maybe_destroy_decoder_and_parser (GstNvDec * nvdec)
406 {
407   gboolean ret = TRUE;
408 
409   if (!cuda_OK (cuvidCtxLock (nvdec->cuda_context->lock, 0))) {
410     GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
411     return FALSE;
412   }
413 
414   if (nvdec->decoder) {
415     GST_DEBUG_OBJECT (nvdec, "destroying decoder");
416     ret = cuda_OK (cuvidDestroyDecoder (nvdec->decoder));
417     if (ret)
418       nvdec->decoder = NULL;
419     else
420       GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
421   }
422 
423   if (!cuda_OK (cuvidCtxUnlock (nvdec->cuda_context->lock, 0))) {
424     GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
425     return FALSE;
426   }
427 
428   if (nvdec->parser) {
429     GST_DEBUG_OBJECT (nvdec, "destroying parser");
430     if (!cuda_OK (cuvidDestroyVideoParser (nvdec->parser))) {
431       GST_ERROR_OBJECT (nvdec, "failed to destroy parser");
432       return FALSE;
433     }
434     nvdec->parser = NULL;
435   }
436 
437   return ret;
438 }
439 
440 static gboolean
gst_nvdec_stop(GstVideoDecoder * decoder)441 gst_nvdec_stop (GstVideoDecoder * decoder)
442 {
443   GstNvDec *nvdec = GST_NVDEC (decoder);
444   GstNvDecQueueItem *item;
445 
446   GST_DEBUG_OBJECT (nvdec, "stop");
447 
448   if (!maybe_destroy_decoder_and_parser (nvdec))
449     return FALSE;
450 
451   if (nvdec->cuda_context) {
452     g_object_unref (nvdec->cuda_context);
453     nvdec->cuda_context = NULL;
454   }
455 
456   if (nvdec->gl_context) {
457     gst_object_unref (nvdec->gl_context);
458     nvdec->gl_context = NULL;
459   }
460 
461   if (nvdec->other_gl_context) {
462     gst_object_unref (nvdec->other_gl_context);
463     nvdec->other_gl_context = NULL;
464   }
465 
466   if (nvdec->gl_display) {
467     gst_object_unref (nvdec->gl_display);
468     nvdec->gl_display = NULL;
469   }
470 
471   if (nvdec->input_state) {
472     gst_video_codec_state_unref (nvdec->input_state);
473     nvdec->input_state = NULL;
474   }
475 
476   if (nvdec->decode_queue) {
477     if (g_async_queue_length (nvdec->decode_queue) > 0) {
478       GST_INFO_OBJECT (nvdec, "decode queue not empty");
479 
480       while ((item = g_async_queue_try_pop (nvdec->decode_queue))) {
481         g_free (item->data);
482         g_slice_free (GstNvDecQueueItem, item);
483       }
484     }
485     g_async_queue_unref (nvdec->decode_queue);
486     nvdec->decode_queue = NULL;
487   }
488 
489   return TRUE;
490 }
491 
492 static gboolean
gst_nvdec_set_format(GstVideoDecoder * decoder,GstVideoCodecState * state)493 gst_nvdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
494 {
495   GstNvDec *nvdec = GST_NVDEC (decoder);
496   GstStructure *s;
497   const gchar *caps_name;
498   gint mpegversion = 0;
499   CUVIDPARSERPARAMS parser_params = { 0, };
500 
501   GST_DEBUG_OBJECT (nvdec, "set format");
502 
503   if (nvdec->input_state)
504     gst_video_codec_state_unref (nvdec->input_state);
505 
506   nvdec->input_state = gst_video_codec_state_ref (state);
507 
508   if (!maybe_destroy_decoder_and_parser (nvdec))
509     return FALSE;
510 
511   s = gst_caps_get_structure (state->caps, 0);
512   caps_name = gst_structure_get_name (s);
513   GST_DEBUG_OBJECT (nvdec, "codec is %s", caps_name);
514 
515   if (!g_strcmp0 (caps_name, "video/mpeg")) {
516     if (gst_structure_get_int (s, "mpegversion", &mpegversion)) {
517       switch (mpegversion) {
518         case 1:
519           parser_params.CodecType = cudaVideoCodec_MPEG1;
520           break;
521         case 2:
522           parser_params.CodecType = cudaVideoCodec_MPEG2;
523           break;
524         case 4:
525           parser_params.CodecType = cudaVideoCodec_MPEG4;
526           break;
527       }
528     }
529     if (!mpegversion) {
530       GST_ERROR_OBJECT (nvdec, "could not get MPEG version");
531       return FALSE;
532     }
533   } else if (!g_strcmp0 (caps_name, "video/x-h264")) {
534     parser_params.CodecType = cudaVideoCodec_H264;
535   } else if (!g_strcmp0 (caps_name, "image/jpeg")) {
536     parser_params.CodecType = cudaVideoCodec_JPEG;
537   } else if (!g_strcmp0 (caps_name, "video/x-h265")) {
538     parser_params.CodecType = cudaVideoCodec_HEVC;
539   } else if (!g_strcmp0 (caps_name, "video/x-vp8")) {
540     parser_params.CodecType = cudaVideoCodec_VP8;
541   } else if (!g_strcmp0 (caps_name, "video/x-vp9")) {
542     parser_params.CodecType = cudaVideoCodec_VP9;
543   } else {
544     GST_ERROR_OBJECT (nvdec, "failed to determine codec type");
545     return FALSE;
546   }
547 
548   parser_params.ulMaxNumDecodeSurfaces = 20;
549   parser_params.ulErrorThreshold = 100;
550   parser_params.ulMaxDisplayDelay = 0;
551   parser_params.ulClockRate = GST_SECOND;
552   parser_params.pUserData = nvdec;
553   parser_params.pfnSequenceCallback =
554       (PFNVIDSEQUENCECALLBACK) parser_sequence_callback;
555   parser_params.pfnDecodePicture =
556       (PFNVIDDECODECALLBACK) parser_decode_callback;
557   parser_params.pfnDisplayPicture =
558       (PFNVIDDISPLAYCALLBACK) parser_display_callback;
559 
560   GST_DEBUG_OBJECT (nvdec, "creating parser");
561   if (!cuda_OK (cuvidCreateVideoParser (&nvdec->parser, &parser_params))) {
562     GST_ERROR_OBJECT (nvdec, "failed to create parser");
563     return FALSE;
564   }
565 
566   return TRUE;
567 }
568 
569 static void
copy_video_frame_to_gl_textures(GstGLContext * context,gpointer * args)570 copy_video_frame_to_gl_textures (GstGLContext * context, gpointer * args)
571 {
572   GstNvDec *nvdec = GST_NVDEC (args[0]);
573   CUVIDPARSERDISPINFO *dispinfo = (CUVIDPARSERDISPINFO *) args[1];
574   CUgraphicsResource *resources = (CUgraphicsResource *) args[2];
575   guint num_resources = GPOINTER_TO_UINT (args[3]);
576   CUVIDPROCPARAMS proc_params = { 0, };
577   CUdeviceptr dptr;
578   CUarray array;
579   guint pitch, i;
580   CUDA_MEMCPY2D mcpy2d = { 0, };
581 
582   GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
583 
584   proc_params.progressive_frame = dispinfo->progressive_frame;
585   proc_params.top_field_first = dispinfo->top_field_first;
586   proc_params.unpaired_field = dispinfo->repeat_first_field == -1;
587 
588   if (!cuda_OK (cuvidCtxLock (nvdec->cuda_context->lock, 0))) {
589     GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
590     return;
591   }
592 
593   if (!cuda_OK (cuvidMapVideoFrame (nvdec->decoder, dispinfo->picture_index,
594               &dptr, &pitch, &proc_params))) {
595     GST_WARNING_OBJECT (nvdec, "failed to map CUDA video frame");
596     goto unlock_cuda_context;
597   }
598 
599   if (!cuda_OK (cuGraphicsMapResources (num_resources, resources, NULL))) {
600     GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
601     goto unmap_video_frame;
602   }
603 
604   mcpy2d.srcMemoryType = CU_MEMORYTYPE_DEVICE;
605   mcpy2d.srcPitch = pitch;
606   mcpy2d.dstMemoryType = CU_MEMORYTYPE_ARRAY;
607   mcpy2d.dstPitch = nvdec->width;
608   mcpy2d.WidthInBytes = nvdec->width;
609 
610   for (i = 0; i < num_resources; i++) {
611     if (!cuda_OK (cuGraphicsSubResourceGetMappedArray (&array, resources[i], 0,
612                 0))) {
613       GST_WARNING_OBJECT (nvdec, "failed to map CUDA array");
614       break;
615     }
616 
617     mcpy2d.srcDevice = dptr + (i * pitch * nvdec->height);
618     mcpy2d.dstArray = array;
619     mcpy2d.Height = nvdec->height / (i + 1);
620 
621     if (!cuda_OK (cuMemcpy2D (&mcpy2d)))
622       GST_WARNING_OBJECT (nvdec, "memcpy to mapped array failed");
623   }
624 
625   if (!cuda_OK (cuGraphicsUnmapResources (num_resources, resources, NULL)))
626     GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA resources");
627 
628 unmap_video_frame:
629   if (!cuda_OK (cuvidUnmapVideoFrame (nvdec->decoder, dptr)))
630     GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
631 
632 unlock_cuda_context:
633   if (!cuda_OK (cuvidCtxUnlock (nvdec->cuda_context->lock, 0)))
634     GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
635 }
636 
637 static GstFlowReturn
handle_pending_frames(GstNvDec * nvdec)638 handle_pending_frames (GstNvDec * nvdec)
639 {
640   GstVideoDecoder *decoder = GST_VIDEO_DECODER (nvdec);
641   GList *pending_frames, *list, *tmp;
642   GstVideoCodecFrame *pending_frame;
643   guint frame_number;
644   GstClockTime latency = 0;
645   GstNvDecQueueItem *item;
646   CUVIDEOFORMAT *format;
647   GstVideoCodecState *state;
648   GstVideoInfo *vinfo;
649   guint width, height, fps_n, fps_d, i, num_resources;
650   CUVIDPICPARAMS *decode_params;
651   CUVIDPARSERDISPINFO *dispinfo;
652   CUgraphicsResource *resources;
653   gpointer args[4];
654   GstMemory *mem;
655   GstFlowReturn ret = GST_FLOW_OK;
656 
657   /* find the oldest unused, unfinished frame */
658   pending_frames = list = gst_video_decoder_get_frames (decoder);
659   for (; pending_frames; pending_frames = pending_frames->next) {
660     pending_frame = pending_frames->data;
661     frame_number =
662         GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data (pending_frame));
663     if (!frame_number)
664       break;
665     latency += pending_frame->duration;
666   }
667 
668   while (ret == GST_FLOW_OK && pending_frames
669       && (item =
670           (GstNvDecQueueItem *) g_async_queue_try_pop (nvdec->decode_queue))) {
671     switch (item->type) {
672       case GST_NVDEC_QUEUE_ITEM_TYPE_SEQUENCE:
673         if (!nvdec->decoder) {
674           GST_ERROR_OBJECT (nvdec, "no decoder");
675           ret = GST_FLOW_ERROR;
676           break;
677         }
678 
679         format = (CUVIDEOFORMAT *) item->data;
680         width = format->display_area.right - format->display_area.left;
681         height = format->display_area.bottom - format->display_area.top;
682         fps_n = format->frame_rate.numerator;
683         fps_d = MAX (1, format->frame_rate.denominator);
684 
685         if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (decoder))
686             || width != nvdec->width || height != nvdec->height
687             || fps_n != nvdec->fps_n || fps_d != nvdec->fps_d) {
688           nvdec->width = width;
689           nvdec->height = height;
690           nvdec->fps_n = fps_n;
691           nvdec->fps_d = fps_d;
692 
693           state = gst_video_decoder_set_output_state (decoder,
694               GST_VIDEO_FORMAT_NV12, nvdec->width, nvdec->height,
695               nvdec->input_state);
696           vinfo = &state->info;
697           vinfo->fps_n = fps_n;
698           vinfo->fps_d = fps_d;
699           if (format->progressive_sequence) {
700             vinfo->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
701 
702             /* nvdec doesn't seem to deal with interlacing with hevc so rely
703              * on upstream's value */
704             if (format->codec == cudaVideoCodec_HEVC) {
705               vinfo->interlace_mode = nvdec->input_state->info.interlace_mode;
706             }
707           } else {
708             vinfo->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
709           }
710 
711           GST_LOG_OBJECT (decoder,
712               "Reading colorimetry information full-range %d matrix %d transfer %d primaries %d",
713               format->video_signal_description.video_full_range_flag,
714               format->video_signal_description.matrix_coefficients,
715               format->video_signal_description.transfer_characteristics,
716               format->video_signal_description.color_primaries);
717 
718           switch (format->video_signal_description.color_primaries) {
719             case 1:
720               vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
721               break;
722             case 4:
723               vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
724               break;
725             case 5:
726               vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
727               break;
728             case 6:
729               vinfo->colorimetry.primaries =
730                   GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
731               break;
732             case 7:
733               vinfo->colorimetry.primaries =
734                   GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
735               break;
736             case 8:
737               vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_FILM;
738               break;
739             case 9:
740               vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
741               break;
742             default:
743               vinfo->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
744 
745           }
746 
747           if (format->video_signal_description.video_full_range_flag)
748             vinfo->colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
749           else
750             vinfo->colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
751 
752           switch (format->video_signal_description.transfer_characteristics) {
753             case 1:
754             case 6:
755             case 16:
756               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
757               break;
758             case 4:
759               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA22;
760               break;
761             case 5:
762               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA28;
763               break;
764             case 7:
765               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
766               break;
767             case 8:
768               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA10;
769               break;
770             case 9:
771               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_LOG100;
772               break;
773             case 10:
774               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_LOG316;
775               break;
776             case 15:
777               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_BT2020_12;
778               break;
779             default:
780               vinfo->colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
781               break;
782           }
783           switch (format->video_signal_description.matrix_coefficients) {
784             case 0:
785               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
786               break;
787             case 1:
788               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
789               break;
790             case 4:
791               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_FCC;
792               break;
793             case 5:
794             case 6:
795               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
796               break;
797             case 7:
798               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
799               break;
800             case 9:
801             case 10:
802               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
803               break;
804             default:
805               vinfo->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
806               break;
807           }
808 
809           state->caps = gst_video_info_to_caps (&state->info);
810 
811           gst_caps_set_features (state->caps, 0,
812               gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, NULL));
813           gst_caps_set_simple (state->caps, "texture-target", G_TYPE_STRING,
814               "2D", NULL);
815 
816           gst_video_codec_state_unref (state);
817 
818           if (!gst_video_decoder_negotiate (decoder)) {
819             GST_WARNING_OBJECT (nvdec, "failed to negotiate with downstream");
820             ret = GST_FLOW_NOT_NEGOTIATED;
821             break;
822           }
823         }
824 
825         break;
826 
827       case GST_NVDEC_QUEUE_ITEM_TYPE_DECODE:
828         decode_params = (CUVIDPICPARAMS *) item->data;
829         pending_frame = pending_frames->data;
830         frame_number = decode_params->CurrPicIdx + 1;
831         gst_video_codec_frame_set_user_data (pending_frame,
832             GUINT_TO_POINTER (frame_number), NULL);
833 
834         if (decode_params->intra_pic_flag)
835           GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pending_frame);
836 
837         if (!GST_CLOCK_TIME_IS_VALID (pending_frame->duration)) {
838           pending_frame->duration =
839               nvdec->fps_n ? GST_SECOND * nvdec->fps_d / nvdec->fps_n : 0;
840         }
841         latency += pending_frame->duration;
842 
843         pending_frames = pending_frames->next;
844 
845         break;
846 
847       case GST_NVDEC_QUEUE_ITEM_TYPE_DISPLAY:
848         dispinfo = (CUVIDPARSERDISPINFO *) item->data;
849         for (pending_frame = NULL, tmp = list; !pending_frame && tmp;
850             tmp = tmp->next) {
851           frame_number =
852               GPOINTER_TO_UINT (gst_video_codec_frame_get_user_data
853               (tmp->data));
854           if (frame_number == dispinfo->picture_index + 1)
855             pending_frame = tmp->data;
856         }
857         if (!pending_frame) {
858           GST_INFO_OBJECT (nvdec, "no frame with number %u",
859               dispinfo->picture_index + 1);
860           break;
861         }
862 
863         if (dispinfo->timestamp != pending_frame->pts) {
864           GST_INFO_OBJECT (nvdec,
865               "timestamp mismatch, diff: %" GST_STIME_FORMAT,
866               GST_STIME_ARGS (GST_CLOCK_DIFF (dispinfo->timestamp,
867                       pending_frame->pts)));
868           pending_frame->pts = dispinfo->timestamp;
869         }
870 
871         if (latency > nvdec->min_latency) {
872           nvdec->min_latency = latency;
873           gst_video_decoder_set_latency (decoder, nvdec->min_latency,
874               nvdec->min_latency);
875           GST_DEBUG_OBJECT (nvdec, "latency: %" GST_TIME_FORMAT,
876               GST_TIME_ARGS (latency));
877         }
878         latency -= pending_frame->duration;
879 
880         ret = gst_video_decoder_allocate_output_frame (decoder, pending_frame);
881         if (ret != GST_FLOW_OK) {
882           GST_WARNING_OBJECT (nvdec, "failed to allocate output frame");
883           break;
884         }
885 
886         num_resources = gst_buffer_n_memory (pending_frame->output_buffer);
887         resources = g_new (CUgraphicsResource, num_resources);
888 
889         for (i = 0; i < num_resources; i++) {
890           mem = gst_buffer_get_memory (pending_frame->output_buffer, i);
891           resources[i] =
892               ensure_cuda_graphics_resource (mem, nvdec->cuda_context);
893           GST_MINI_OBJECT_FLAG_SET (mem,
894               GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
895           gst_memory_unref (mem);
896         }
897 
898         args[0] = nvdec;
899         args[1] = dispinfo;
900         args[2] = resources;
901         args[3] = GUINT_TO_POINTER (num_resources);
902         gst_gl_context_thread_add (nvdec->gl_context,
903             (GstGLContextThreadFunc) copy_video_frame_to_gl_textures, args);
904         g_free (resources);
905 
906         if (!dispinfo->progressive_frame) {
907           GST_BUFFER_FLAG_SET (pending_frame->output_buffer,
908               GST_VIDEO_BUFFER_FLAG_INTERLACED);
909 
910           if (dispinfo->top_field_first) {
911             GST_BUFFER_FLAG_SET (pending_frame->output_buffer,
912                 GST_VIDEO_BUFFER_FLAG_TFF);
913           }
914           if (dispinfo->repeat_first_field == -1) {
915             GST_BUFFER_FLAG_SET (pending_frame->output_buffer,
916                 GST_VIDEO_BUFFER_FLAG_ONEFIELD);
917           } else {
918             GST_BUFFER_FLAG_SET (pending_frame->output_buffer,
919                 GST_VIDEO_BUFFER_FLAG_RFF);
920           }
921         }
922 
923         list = g_list_remove (list, pending_frame);
924         ret = gst_video_decoder_finish_frame (decoder, pending_frame);
925         if (ret != GST_FLOW_OK)
926           GST_INFO_OBJECT (nvdec, "failed to finish frame");
927 
928         break;
929 
930       default:
931         g_assert_not_reached ();
932     }
933 
934     g_free (item->data);
935     g_slice_free (GstNvDecQueueItem, item);
936   }
937 
938   g_list_free_full (list, (GDestroyNotify) gst_video_codec_frame_unref);
939 
940   return ret;
941 }
942 
943 static GstFlowReturn
gst_nvdec_handle_frame(GstVideoDecoder * decoder,GstVideoCodecFrame * frame)944 gst_nvdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
945 {
946   GstNvDec *nvdec = GST_NVDEC (decoder);
947   GstMapInfo map_info = GST_MAP_INFO_INIT;
948   CUVIDSOURCEDATAPACKET packet = { 0, };
949 
950   GST_LOG_OBJECT (nvdec, "handle frame");
951 
952   gst_video_codec_frame_set_user_data (frame, GUINT_TO_POINTER (0), NULL);
953 
954   if (!gst_buffer_map (frame->input_buffer, &map_info, GST_MAP_READ)) {
955     GST_ERROR_OBJECT (nvdec, "failed to map input buffer");
956     gst_video_codec_frame_unref (frame);
957     return GST_FLOW_ERROR;
958   }
959 
960   packet.payload_size = (gulong) map_info.size;
961   packet.payload = map_info.data;
962   packet.timestamp = frame->pts;
963   packet.flags = CUVID_PKT_TIMESTAMP;
964 
965   if (GST_BUFFER_IS_DISCONT (frame->input_buffer))
966     packet.flags |= CUVID_PKT_DISCONTINUITY;
967 
968   if (!cuda_OK (cuvidParseVideoData (nvdec->parser, &packet)))
969     GST_WARNING_OBJECT (nvdec, "parser failed");
970 
971   gst_buffer_unmap (frame->input_buffer, &map_info);
972   gst_video_codec_frame_unref (frame);
973 
974   return handle_pending_frames (nvdec);
975 }
976 
977 static gboolean
gst_nvdec_flush(GstVideoDecoder * decoder)978 gst_nvdec_flush (GstVideoDecoder * decoder)
979 {
980   GstNvDec *nvdec = GST_NVDEC (decoder);
981   CUVIDSOURCEDATAPACKET packet = { 0, };
982 
983   GST_DEBUG_OBJECT (nvdec, "flush");
984 
985   packet.payload_size = 0;
986   packet.payload = NULL;
987   packet.flags = CUVID_PKT_ENDOFSTREAM;
988 
989   if (!cuda_OK (cuvidParseVideoData (nvdec->parser, &packet)))
990     GST_WARNING_OBJECT (nvdec, "parser failed");
991 
992   handle_pending_frames (nvdec);
993 
994   return TRUE;
995 }
996 
997 static GstFlowReturn
gst_nvdec_drain(GstVideoDecoder * decoder)998 gst_nvdec_drain (GstVideoDecoder * decoder)
999 {
1000   GstNvDec *nvdec = GST_NVDEC (decoder);
1001   CUVIDSOURCEDATAPACKET packet = { 0, };
1002 
1003   GST_DEBUG_OBJECT (nvdec, "draining decoder");
1004 
1005   packet.payload_size = 0;
1006   packet.payload = NULL;
1007   packet.flags = CUVID_PKT_ENDOFSTREAM;
1008 
1009   if (!cuda_OK (cuvidParseVideoData (nvdec->parser, &packet)))
1010     GST_WARNING_OBJECT (nvdec, "parser failed");
1011 
1012   return handle_pending_frames (nvdec);
1013 }
1014 
1015 static GstFlowReturn
gst_nvdec_finish(GstVideoDecoder * decoder)1016 gst_nvdec_finish (GstVideoDecoder * decoder)
1017 {
1018   GST_DEBUG_OBJECT (decoder, "finish");
1019 
1020   return gst_nvdec_drain (decoder);
1021 }
1022 
1023 static gboolean
gst_nvdec_decide_allocation(GstVideoDecoder * decoder,GstQuery * query)1024 gst_nvdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1025 {
1026   GstNvDec *nvdec = GST_NVDEC (decoder);
1027   GstCaps *outcaps;
1028   GstBufferPool *pool = NULL;
1029   guint n, size, min, max;
1030   GstVideoInfo vinfo = { 0, };
1031   GstStructure *config;
1032 
1033   GST_DEBUG_OBJECT (nvdec, "decide allocation");
1034 
1035   if (!gst_gl_ensure_element_data (nvdec, &nvdec->gl_display,
1036           &nvdec->other_gl_context)) {
1037     GST_ERROR_OBJECT (nvdec, "failed to ensure OpenGL display");
1038     return FALSE;
1039   }
1040 
1041   if (!gst_gl_query_local_gl_context (GST_ELEMENT (decoder), GST_PAD_SRC,
1042           &nvdec->gl_context)) {
1043     GST_INFO_OBJECT (nvdec, "failed to query local OpenGL context");
1044     if (nvdec->gl_context)
1045       gst_object_unref (nvdec->gl_context);
1046     nvdec->gl_context =
1047         gst_gl_display_get_gl_context_for_thread (nvdec->gl_display, NULL);
1048     if (!nvdec->gl_context
1049         || !gst_gl_display_add_context (nvdec->gl_display, nvdec->gl_context)) {
1050       if (nvdec->gl_context)
1051         gst_object_unref (nvdec->gl_context);
1052       if (!gst_gl_display_create_context (nvdec->gl_display,
1053               nvdec->other_gl_context, &nvdec->gl_context, NULL)) {
1054         GST_ERROR_OBJECT (nvdec, "failed to create OpenGL context");
1055         return FALSE;
1056       }
1057       if (!gst_gl_display_add_context (nvdec->gl_display, nvdec->gl_context)) {
1058         GST_ERROR_OBJECT (nvdec,
1059             "failed to add the OpenGL context to the display");
1060         return FALSE;
1061       }
1062     }
1063   }
1064 
1065   gst_query_parse_allocation (query, &outcaps, NULL);
1066   n = gst_query_get_n_allocation_pools (query);
1067   if (n > 0) {
1068     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1069     if (!GST_IS_GL_BUFFER_POOL (pool)) {
1070       gst_object_unref (pool);
1071       pool = NULL;
1072     }
1073   }
1074 
1075   if (!pool) {
1076     pool = gst_gl_buffer_pool_new (nvdec->gl_context);
1077 
1078     if (outcaps)
1079       gst_video_info_from_caps (&vinfo, outcaps);
1080     size = (guint) vinfo.size;
1081     min = max = 0;
1082   }
1083 
1084   config = gst_buffer_pool_get_config (pool);
1085   gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1086   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1087   gst_buffer_pool_set_config (pool, config);
1088   if (n > 0)
1089     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1090   else
1091     gst_query_add_allocation_pool (query, pool, size, min, max);
1092   gst_object_unref (pool);
1093 
1094   return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->decide_allocation
1095       (decoder, query);
1096 }
1097 
1098 static gboolean
gst_nvdec_src_query(GstVideoDecoder * decoder,GstQuery * query)1099 gst_nvdec_src_query (GstVideoDecoder * decoder, GstQuery * query)
1100 {
1101   GstNvDec *nvdec = GST_NVDEC (decoder);
1102 
1103   switch (GST_QUERY_TYPE (query)) {
1104     case GST_QUERY_CONTEXT:
1105       if (gst_gl_handle_context_query (GST_ELEMENT (decoder), query,
1106               nvdec->gl_display, nvdec->gl_context, nvdec->other_gl_context))
1107         return TRUE;
1108       break;
1109     default:
1110       break;
1111   }
1112 
1113   return GST_VIDEO_DECODER_CLASS (gst_nvdec_parent_class)->src_query (decoder,
1114       query);
1115 }
1116 
1117 static void
gst_nvdec_set_context(GstElement * element,GstContext * context)1118 gst_nvdec_set_context (GstElement * element, GstContext * context)
1119 {
1120   GstNvDec *nvdec = GST_NVDEC (element);
1121   GST_DEBUG_OBJECT (nvdec, "set context");
1122 
1123   gst_gl_handle_set_context (element, context, &nvdec->gl_display,
1124       &nvdec->other_gl_context);
1125 
1126   GST_ELEMENT_CLASS (gst_nvdec_parent_class)->set_context (element, context);
1127 }
1128