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