a5d4fa468c5eaff165ee64fb6eda83271f02cc1d
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / nvcodec / gstnvencoder.cpp
1 /* GStreamer
2  * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstnvencoder.h"
25
26 #include <gst/cuda/gstcudautils.h>
27 #include <gst/cuda/gstcudamemory.h>
28 #include <gst/cuda/gstcudabufferpool.h>
29 #include <string.h>
30
31 #ifdef GST_CUDA_HAS_D3D
32 #include <gst/d3d11/gstd3d11.h>
33 #endif
34
35 #ifdef G_OS_WIN32
36 #include <wrl.h>
37
38 /* *INDENT-OFF* */
39 using namespace Microsoft::WRL;
40 /* *INDENT-ON* */
41 #endif
42
43 GST_DEBUG_CATEGORY_STATIC (gst_nv_encoder_debug);
44 #define GST_CAT_DEFAULT gst_nv_encoder_debug
45
46 #define GET_LOCK(e) (&(GST_NV_ENCODER_CAST(e)->priv->lock))
47 #define GST_NV_ENCODER_LOCK(e) G_STMT_START { \
48   GST_TRACE_OBJECT (e, "Locking from thread %p", g_thread_self ()); \
49   g_mutex_lock(GET_LOCK(e)); \
50   GST_TRACE_OBJECT (e, "Locked from thread %p", g_thread_self ()); \
51 } G_STMT_END
52
53 #define GST_NV_ENCODER_UNLOCK(e) G_STMT_START { \
54   GST_TRACE_OBJECT (e, "Unlocking from thread %p", g_thread_self ()); \
55   g_mutex_unlock(GET_LOCK(e)); \
56 } G_STMT_END
57
58 struct _GstNvEncoderPrivate
59 {
60   GstCudaContext *context;
61   CUstream cuda_stream;
62
63 #ifdef GST_CUDA_HAS_D3D
64   GstD3D11Device *device;
65   GstD3D11Fence *fence;
66 #endif
67
68   GstNvEncoderDeviceMode subclass_device_mode;
69   GstNvEncoderDeviceMode selected_device_mode;
70   gint64 dxgi_adapter_luid;
71   guint cuda_device_id;
72
73   NV_ENC_INITIALIZE_PARAMS init_params;
74   NV_ENC_CONFIG config;
75   gpointer session;
76
77   GstVideoCodecState *input_state;
78
79   GstBufferPool *internal_pool;
80
81   GstClockTime dts_offset;
82
83   /* Array of GstNvEncoderTask, holding ownership */
84   GArray *task_pool;
85
86   GQueue free_tasks;
87   GQueue output_tasks;
88
89   GMutex lock;
90   GCond cond;
91
92   GRecMutex context_lock;
93
94   GThread *encoding_thread;
95
96   GstFlowReturn last_flow;
97 };
98
99 /**
100  * GstNvEncoder:
101  *
102  * Since: 1.22
103  */
104 #define gst_nv_encoder_parent_class parent_class
105 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstNvEncoder, gst_nv_encoder,
106     GST_TYPE_VIDEO_ENCODER);
107
108 static void gst_nv_encoder_finalize (GObject * object);
109 static void gst_nv_encoder_set_context (GstElement * element,
110     GstContext * context);
111 static gboolean gst_nv_encoder_open (GstVideoEncoder * encoder);
112 static gboolean gst_nv_encoder_close (GstVideoEncoder * encoder);
113 static gboolean gst_nv_encoder_stop (GstVideoEncoder * encoder);
114 static gboolean gst_nv_encoder_sink_query (GstVideoEncoder * encoder,
115     GstQuery * query);
116 static gboolean gst_nv_encoder_src_query (GstVideoEncoder * encoder,
117     GstQuery * query);
118 static gboolean gst_nv_encoder_propose_allocation (GstVideoEncoder *
119     encoder, GstQuery * query);
120 static gboolean gst_nv_encoder_set_format (GstVideoEncoder * encoder,
121     GstVideoCodecState * state);
122 static GstFlowReturn gst_nv_encoder_handle_frame (GstVideoEncoder *
123     encoder, GstVideoCodecFrame * frame);
124 static GstFlowReturn gst_nv_encoder_finish (GstVideoEncoder * encoder);
125 static gboolean gst_nv_encoder_flush (GstVideoEncoder * encoder);
126 static void gst_nv_encoder_task_clear (GstNvEncoderTask * task);
127
128 static void
129 gst_nv_encoder_class_init (GstNvEncoderClass * klass)
130 {
131   GObjectClass *object_class = G_OBJECT_CLASS (klass);
132   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
133   GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
134
135   object_class->finalize = gst_nv_encoder_finalize;
136
137   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_encoder_set_context);
138
139   videoenc_class->open = GST_DEBUG_FUNCPTR (gst_nv_encoder_open);
140   videoenc_class->close = GST_DEBUG_FUNCPTR (gst_nv_encoder_close);
141   videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_nv_encoder_stop);
142   videoenc_class->sink_query = GST_DEBUG_FUNCPTR (gst_nv_encoder_sink_query);
143   videoenc_class->src_query = GST_DEBUG_FUNCPTR (gst_nv_encoder_src_query);
144   videoenc_class->propose_allocation =
145       GST_DEBUG_FUNCPTR (gst_nv_encoder_propose_allocation);
146   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_encoder_set_format);
147   videoenc_class->handle_frame =
148       GST_DEBUG_FUNCPTR (gst_nv_encoder_handle_frame);
149   videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_nv_encoder_finish);
150   videoenc_class->flush = GST_DEBUG_FUNCPTR (gst_nv_encoder_flush);
151
152   GST_DEBUG_CATEGORY_INIT (gst_nv_encoder_debug, "nvencoder", 0, "nvencoder");
153
154   gst_type_mark_as_plugin_api (GST_TYPE_NV_ENCODER, (GstPluginAPIFlags) 0);
155   gst_type_mark_as_plugin_api (GST_TYPE_NV_ENCODER_PRESET,
156       (GstPluginAPIFlags) 0);
157   gst_type_mark_as_plugin_api (GST_TYPE_NV_ENCODER_RC_MODE,
158       (GstPluginAPIFlags) 0);
159 }
160
161 static void
162 gst_nv_encoder_init (GstNvEncoder * self)
163 {
164   GstNvEncoderPrivate *priv;
165
166   self->priv = priv = (GstNvEncoderPrivate *)
167       gst_nv_encoder_get_instance_private (self);
168
169   priv->task_pool = g_array_new (FALSE, TRUE, sizeof (GstNvEncoderTask));
170   g_array_set_clear_func (priv->task_pool,
171       (GDestroyNotify) gst_nv_encoder_task_clear);
172
173   g_queue_init (&priv->free_tasks);
174   g_queue_init (&priv->output_tasks);
175
176   g_mutex_init (&priv->lock);
177   g_cond_init (&priv->cond);
178
179   g_rec_mutex_init (&priv->context_lock);
180
181   gst_video_encoder_set_min_pts (GST_VIDEO_ENCODER (self),
182       GST_SECOND * 60 * 60 * 1000);
183 }
184
185 static void
186 gst_nv_encoder_finalize (GObject * object)
187 {
188   GstNvEncoder *self = GST_NV_ENCODER (object);
189   GstNvEncoderPrivate *priv = self->priv;
190
191   g_array_unref (priv->task_pool);
192
193   g_mutex_clear (&priv->lock);
194   g_cond_clear (&priv->cond);
195
196   g_rec_mutex_clear (&priv->context_lock);
197
198   G_OBJECT_CLASS (parent_class)->finalize (object);
199 }
200
201 static void
202 gst_nv_encoder_set_context (GstElement * element, GstContext * context)
203 {
204   GstNvEncoder *self = GST_NV_ENCODER (element);
205   GstNvEncoderPrivate *priv = self->priv;
206
207   g_rec_mutex_lock (&priv->context_lock);
208
209   switch (priv->selected_device_mode) {
210 #ifdef GST_CUDA_HAS_D3D
211     case GST_NV_ENCODER_DEVICE_D3D11:
212       gst_d3d11_handle_set_context_for_adapter_luid (element,
213           context, priv->dxgi_adapter_luid, &priv->device);
214       break;
215 #endif
216     case GST_NV_ENCODER_DEVICE_CUDA:
217       gst_cuda_handle_set_context (element, context, priv->cuda_device_id,
218           &priv->context);
219       break;
220     default:
221       break;
222   }
223
224   g_rec_mutex_unlock (&priv->context_lock);
225
226   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
227 }
228
229 static gboolean
230 gst_nv_encoder_reset (GstNvEncoder * self)
231 {
232   GstNvEncoderPrivate *priv = self->priv;
233
234   GST_LOG_OBJECT (self, "Reset");
235
236   g_array_set_size (priv->task_pool, 0);
237
238   if (priv->internal_pool) {
239     gst_buffer_pool_set_active (priv->internal_pool, FALSE);
240     gst_clear_object (&priv->internal_pool);
241   }
242
243   if (priv->session) {
244     NvEncDestroyEncoder (priv->session);
245     priv->session = NULL;
246   }
247
248   if (priv->context && priv->cuda_stream) {
249     gst_cuda_context_push (priv->context);
250     CuStreamDestroy (priv->cuda_stream);
251     gst_cuda_context_pop (nullptr);
252     priv->cuda_stream = nullptr;
253   }
254
255   g_queue_clear (&priv->free_tasks);
256   g_queue_clear (&priv->output_tasks);
257
258   priv->last_flow = GST_FLOW_OK;
259
260   return TRUE;
261 }
262
263 static gboolean
264 gst_nv_encoder_device_lock (GstNvEncoder * self)
265 {
266   GstNvEncoderPrivate *priv = self->priv;
267   gboolean ret = TRUE;
268
269   switch (priv->selected_device_mode) {
270 #ifdef GST_CUDA_HAS_D3D
271     case GST_NV_ENCODER_DEVICE_D3D11:
272       gst_d3d11_device_lock (priv->device);
273       break;
274 #endif
275     case GST_NV_ENCODER_DEVICE_CUDA:
276       ret = gst_cuda_context_push (priv->context);
277       break;
278     default:
279       break;
280   }
281
282   return ret;
283 }
284
285 static gboolean
286 gst_nv_encoder_device_unlock (GstNvEncoder * self)
287 {
288   GstNvEncoderPrivate *priv = self->priv;
289   gboolean ret = TRUE;
290
291   switch (priv->selected_device_mode) {
292 #ifdef GST_CUDA_HAS_D3D
293     case GST_NV_ENCODER_DEVICE_D3D11:
294       gst_d3d11_device_unlock (priv->device);
295       break;
296 #endif
297     case GST_NV_ENCODER_DEVICE_CUDA:
298       ret = gst_cuda_context_pop (nullptr);
299       break;
300     default:
301       break;
302   }
303
304   return ret;
305 }
306
307 static GstFlowReturn
308 gst_nv_encoder_get_free_task (GstNvEncoder * self, GstNvEncoderTask ** task,
309     gboolean check_last_flow)
310 {
311   GstNvEncoderPrivate *priv = self->priv;
312   GstFlowReturn ret = GST_FLOW_OK;
313   GstNvEncoderTask *free_task = NULL;
314
315   GST_NV_ENCODER_LOCK (self);
316   if (check_last_flow) {
317     if (priv->last_flow != GST_FLOW_OK) {
318       ret = priv->last_flow;
319       GST_NV_ENCODER_UNLOCK (self);
320       return ret;
321     }
322
323     while (priv->last_flow == GST_FLOW_OK && (free_task = (GstNvEncoderTask *)
324             g_queue_pop_head (&priv->free_tasks)) == NULL) {
325       g_cond_wait (&priv->cond, &priv->lock);
326     }
327
328     ret = priv->last_flow;
329     if (ret != GST_FLOW_OK && free_task) {
330       g_queue_push_tail (&priv->free_tasks, free_task);
331       free_task = NULL;
332     }
333   } else {
334     while ((free_task = (GstNvEncoderTask *)
335             g_queue_pop_head (&priv->free_tasks)) == NULL)
336       g_cond_wait (&priv->cond, &priv->lock);
337   }
338   GST_NV_ENCODER_UNLOCK (self);
339
340   *task = free_task;
341
342   return ret;
343 }
344
345 static gboolean
346 gst_nv_encoder_drain (GstNvEncoder * self, gboolean locked)
347 {
348   GstNvEncoderPrivate *priv = self->priv;
349   NV_ENC_PIC_PARAMS pic_params = { 0, };
350   NVENCSTATUS status;
351   GstNvEncoderTask *task;
352
353   if (!priv->session || !priv->encoding_thread)
354     return TRUE;
355
356   GST_DEBUG_OBJECT (self, "Drain");
357
358   if (locked)
359     GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
360
361   gst_nv_encoder_get_free_task (self, &task, FALSE);
362
363   task->is_eos = TRUE;
364
365   pic_params.version = gst_nvenc_get_pic_params_version ();
366   pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
367   pic_params.completionEvent = task->event_handle;
368
369   gst_nv_encoder_device_lock (self);
370   status = NvEncEncodePicture (priv->session, &pic_params);
371   if (status != NV_ENC_SUCCESS) {
372     GST_DEBUG_OBJECT (self, "Drain returned status %" GST_NVENC_STATUS_FORMAT,
373         GST_NVENC_STATUS_ARGS (status));
374 #ifdef G_OS_WIN32
375     if (task->event_handle) {
376       SetEvent (task->event_handle);
377     }
378 #endif
379   }
380   gst_nv_encoder_device_unlock (self);
381
382   GST_NV_ENCODER_LOCK (self);
383   g_queue_push_tail (&priv->output_tasks, task);
384   g_cond_broadcast (&priv->cond);
385   GST_NV_ENCODER_UNLOCK (self);
386
387   g_clear_pointer (&priv->encoding_thread, g_thread_join);
388   gst_nv_encoder_reset (self);
389
390   if (locked)
391     GST_VIDEO_ENCODER_STREAM_LOCK (self);
392
393   return TRUE;
394 }
395
396 #ifdef GST_CUDA_HAS_D3D
397 static gboolean
398 gst_nv_encoder_open_d3d11_device (GstNvEncoder * self)
399 {
400   GstNvEncoderPrivate *priv = self->priv;
401   ComPtr < ID3D10Multithread > multi_thread;
402   ID3D11Device *device_handle;
403   HRESULT hr;
404
405   if (!gst_d3d11_ensure_element_data_for_adapter_luid (GST_ELEMENT (self),
406           priv->dxgi_adapter_luid, &priv->device)) {
407     GST_ERROR_OBJECT (self, "Cannot create d3d11device");
408     return FALSE;
409   }
410
411   device_handle = gst_d3d11_device_get_device_handle (priv->device);
412   hr = device_handle->QueryInterface (IID_PPV_ARGS (&multi_thread));
413   if (!gst_d3d11_result (hr, priv->device)) {
414     GST_ERROR_OBJECT (self, "ID3D10Multithread interface is unavailable");
415     gst_clear_object (&priv->device);
416
417     return FALSE;
418   }
419
420   multi_thread->SetMultithreadProtected (TRUE);
421
422   return TRUE;
423 }
424 #endif
425
426 static gboolean
427 gst_nv_encoder_open (GstVideoEncoder * encoder)
428 {
429   GstNvEncoder *self = GST_NV_ENCODER (encoder);
430   GstNvEncoderPrivate *priv = self->priv;
431
432   switch (priv->selected_device_mode) {
433     case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
434       /* Will open GPU later */
435       return TRUE;
436 #ifdef GST_CUDA_HAS_D3D
437     case GST_NV_ENCODER_DEVICE_D3D11:
438       return gst_nv_encoder_open_d3d11_device (self);
439 #endif
440     case GST_NV_ENCODER_DEVICE_CUDA:
441       if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (encoder),
442               priv->cuda_device_id, &priv->context)) {
443         GST_ERROR_OBJECT (self, "failed to create CUDA context");
444         return FALSE;
445       }
446       break;
447     default:
448       g_assert_not_reached ();
449       return FALSE;
450   }
451
452   return TRUE;
453 }
454
455 static gboolean
456 gst_nv_encoder_close (GstVideoEncoder * encoder)
457 {
458   GstNvEncoder *self = GST_NV_ENCODER (encoder);
459   GstNvEncoderPrivate *priv = self->priv;
460
461   gst_clear_object (&priv->context);
462 #ifdef GST_CUDA_HAS_D3D
463   gst_clear_d3d11_fence (&priv->fence);
464   gst_clear_object (&priv->device);
465 #endif
466
467   return TRUE;
468 }
469
470 static gboolean
471 gst_nv_encoder_stop (GstVideoEncoder * encoder)
472 {
473   GstNvEncoder *self = GST_NV_ENCODER (encoder);
474   GstNvEncoderPrivate *priv = self->priv;
475
476   GST_DEBUG_OBJECT (self, "Stop");
477
478   gst_nv_encoder_drain (self, FALSE);
479
480   if (priv->subclass_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
481     gst_clear_object (&priv->context);
482 #ifdef GST_CUDA_HAS_D3D
483     gst_clear_object (&priv->device);
484 #endif
485     priv->selected_device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
486   }
487
488   g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
489
490   return TRUE;
491 }
492
493 static gboolean
494 gst_nv_encoder_handle_context_query (GstNvEncoder * self, GstQuery * query)
495 {
496   GstNvEncoderPrivate *priv = self->priv;
497   gboolean ret = FALSE;
498
499   g_rec_mutex_lock (&priv->context_lock);
500
501   switch (priv->selected_device_mode) {
502 #ifdef GST_CUDA_HAS_D3D
503     case GST_NV_ENCODER_DEVICE_D3D11:
504       ret = gst_d3d11_handle_context_query (GST_ELEMENT (self),
505           query, priv->device);
506       break;
507 #endif
508     case GST_NV_ENCODER_DEVICE_CUDA:
509       ret = gst_cuda_handle_context_query (GST_ELEMENT (self),
510           query, priv->context);
511       break;
512     default:
513       break;
514   }
515
516   g_rec_mutex_unlock (&priv->context_lock);
517
518   return ret;
519 }
520
521 static gboolean
522 gst_nv_encoder_sink_query (GstVideoEncoder * encoder, GstQuery * query)
523 {
524   GstNvEncoder *self = GST_NV_ENCODER (encoder);
525
526   switch (GST_QUERY_TYPE (query)) {
527     case GST_QUERY_CONTEXT:
528       if (gst_nv_encoder_handle_context_query (self, query))
529         return TRUE;
530       break;
531     default:
532       break;
533   }
534
535   return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
536 }
537
538 static gboolean
539 gst_nv_encoder_src_query (GstVideoEncoder * encoder, GstQuery * query)
540 {
541   GstNvEncoder *self = GST_NV_ENCODER (encoder);
542
543   switch (GST_QUERY_TYPE (query)) {
544     case GST_QUERY_CONTEXT:
545       if (gst_nv_encoder_handle_context_query (self, query))
546         return TRUE;
547       break;
548     default:
549       break;
550   }
551
552   return GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
553 }
554
555 static gboolean
556 gst_nv_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
557 {
558   GstNvEncoder *self = GST_NV_ENCODER (encoder);
559   GstNvEncoderPrivate *priv = self->priv;
560   GstVideoInfo info;
561   GstBufferPool *pool = NULL;
562   GstCaps *caps;
563   guint size;
564   GstStructure *config;
565   GstCapsFeatures *features;
566   guint min_buffers;
567
568   gst_query_parse_allocation (query, &caps, NULL);
569   if (!caps) {
570     GST_WARNING_OBJECT (self, "null caps in query");
571     return FALSE;
572   }
573
574   if (!gst_video_info_from_caps (&info, caps)) {
575     GST_WARNING_OBJECT (self, "Failed to convert caps into info");
576     return FALSE;
577   }
578
579   features = gst_caps_get_features (caps, 0);
580   min_buffers = gst_nv_encoder_get_task_size (self);
581
582   switch (priv->subclass_device_mode) {
583     case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
584       /* Use upstream pool in case of auto select mode. We don't know which
585        * GPU to use at this moment */
586       gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
587       gst_query_add_allocation_pool (query, nullptr, info.size, min_buffers, 0);
588       return TRUE;
589 #ifdef GST_CUDA_HAS_D3D
590     case GST_NV_ENCODER_DEVICE_D3D11:
591       if (features && gst_caps_features_contains (features,
592               GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
593         GST_DEBUG_OBJECT (self, "upstream support d3d11 memory");
594         pool = gst_d3d11_buffer_pool_new (priv->device);
595       }
596       break;
597 #endif
598     case GST_NV_ENCODER_DEVICE_CUDA:
599       if (features && gst_caps_features_contains (features,
600               GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) {
601         GST_DEBUG_OBJECT (self, "upstream support CUDA memory");
602         pool = gst_cuda_buffer_pool_new (priv->context);
603       }
604       break;
605     default:
606       g_assert_not_reached ();
607       return FALSE;
608   }
609
610   if (!pool)
611     pool = gst_video_buffer_pool_new ();
612
613   config = gst_buffer_pool_get_config (pool);
614   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
615
616
617   size = GST_VIDEO_INFO_SIZE (&info);
618   gst_buffer_pool_config_set_params (config, caps, size, min_buffers, 0);
619
620   if (!gst_buffer_pool_set_config (pool, config)) {
621     GST_WARNING_OBJECT (self, "Failed to set pool config");
622     gst_object_unref (pool);
623     return FALSE;
624   }
625
626   config = gst_buffer_pool_get_config (pool);
627   gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
628   gst_structure_free (config);
629
630   gst_query_add_allocation_pool (query, pool, size, min_buffers, 0);
631   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
632   gst_object_unref (pool);
633
634   return TRUE;
635 }
636
637 /* called with lock */
638 static void
639 gst_nv_encoder_task_reset (GstNvEncoder * self, GstNvEncoderTask * task)
640 {
641   GstNvEncoderPrivate *priv = self->priv;
642
643   if (!task)
644     return;
645
646   if (task->buffer) {
647     gst_nv_encoder_device_lock (self);
648     if (priv->session) {
649       NvEncUnmapInputResource (priv->session,
650           task->mapped_resource.mappedResource);
651       NvEncUnregisterResource (priv->session,
652           task->register_resource.registeredResource);
653     }
654     gst_nv_encoder_device_unlock (self);
655
656     gst_buffer_unmap (task->buffer, &task->map_info);
657     gst_clear_buffer (&task->buffer);
658   }
659 #ifdef G_OS_WIN32
660   if (task->event_handle)
661     ResetEvent (task->event_handle);
662 #endif
663
664   task->is_eos = FALSE;
665
666   g_queue_push_head (&priv->free_tasks, task);
667 }
668
669 static gboolean
670 gst_nv_encoder_create_event_handle (GstNvEncoder * self, gpointer session,
671     gpointer * event_handle)
672 {
673 #ifdef G_OS_WIN32
674   NV_ENC_EVENT_PARAMS event_params = { 0, };
675   NVENCSTATUS status;
676
677   event_params.version = gst_nvenc_get_event_params_version ();
678   event_params.completionEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
679   status = NvEncRegisterAsyncEvent (session, &event_params);
680
681   if (status != NV_ENC_SUCCESS) {
682     GST_ERROR_OBJECT (self,
683         "Failed to register async event handle, status %"
684         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
685     CloseHandle (event_params.completionEvent);
686     return FALSE;
687   }
688
689   *event_handle = event_params.completionEvent;
690 #endif
691
692   return TRUE;
693 }
694
695 static gboolean
696 gst_d3d11_encoder_wait_for_event_handle (GstNvEncoder * self,
697     gpointer event_handle)
698 {
699 #ifdef G_OS_WIN32
700   /* NVCODEC SDK uses 20s */
701   if (WaitForSingleObject (event_handle, 20000) == WAIT_FAILED) {
702     GST_ERROR_OBJECT (self, "Failed to wait for completion event");
703     return FALSE;
704   }
705 #endif
706
707   return TRUE;
708 }
709
710 static void
711 gst_nv_encoder_destroy_event_handle (GstNvEncoder * self, gpointer session,
712     gpointer event_handle)
713 {
714 #ifdef G_OS_WIN32
715   NV_ENC_EVENT_PARAMS event_params = { 0, };
716   NVENCSTATUS status;
717
718   event_params.version = gst_nvenc_get_event_params_version ();
719   event_params.completionEvent = event_handle;
720   status = NvEncUnregisterAsyncEvent (session, &event_params);
721   CloseHandle (event_handle);
722
723   if (status != NV_ENC_SUCCESS) {
724     GST_ERROR_OBJECT (self,
725         "Failed to unregister async event handle, status %"
726         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
727   }
728 #endif
729 }
730
731 static void
732 gst_nv_encoder_task_clear (GstNvEncoderTask * task)
733 {
734   GstNvEncoder *self;
735   GstNvEncoderPrivate *priv;
736
737   if (!task)
738     return;
739
740   self = task->encoder;
741   priv = self->priv;
742
743   if (priv->session) {
744     gst_nv_encoder_device_lock (self);
745     if (task->buffer) {
746       NvEncUnmapInputResource (priv->session,
747           task->mapped_resource.mappedResource);
748       NvEncUnregisterResource (priv->session,
749           task->register_resource.registeredResource);
750     }
751     if (task->output_ptr)
752       NvEncDestroyBitstreamBuffer (priv->session, task->output_ptr);
753     if (task->input_buffer.inputBuffer)
754       NvEncDestroyInputBuffer (priv->session, task->input_buffer.inputBuffer);
755     if (task->event_handle) {
756       gst_nv_encoder_destroy_event_handle (self, priv->session,
757           task->event_handle);
758     }
759
760     gst_nv_encoder_device_unlock (self);
761   }
762
763   if (task->buffer) {
764     gst_buffer_unmap (task->buffer, &task->map_info);
765     gst_clear_buffer (&task->buffer);
766   }
767
768   memset (task, 0, sizeof (GstNvEncoderTask));
769 }
770
771 static NV_ENC_PIC_STRUCT
772 gst_nv_encoder_get_pic_struct (GstNvEncoder * self, GstBuffer * buffer)
773 {
774   GstNvEncoderPrivate *priv = self->priv;
775   GstVideoInfo *info = &priv->input_state->info;
776
777   if (!GST_VIDEO_INFO_IS_INTERLACED (info))
778     return NV_ENC_PIC_STRUCT_FRAME;
779
780   if (GST_VIDEO_INFO_INTERLACE_MODE (info) == GST_VIDEO_INTERLACE_MODE_MIXED) {
781     if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
782       return NV_ENC_PIC_STRUCT_FRAME;
783     }
784
785     if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
786       return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
787
788     return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
789   }
790
791   switch (GST_VIDEO_INFO_FIELD_ORDER (info)) {
792     case GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST:
793       return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
794       break;
795     case GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST:
796       return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
797       break;
798     default:
799       break;
800   }
801
802   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
803     return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
804
805   return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
806 }
807
808 static GstFlowReturn
809 gst_nv_encoder_encode_frame (GstNvEncoder * self,
810     GstVideoCodecFrame * frame, GstNvEncoderTask * task)
811 {
812   GstNvEncoderPrivate *priv = self->priv;
813   NV_ENC_PIC_PARAMS pic_params = { 0, };
814   NVENCSTATUS status;
815   guint retry_count = 0;
816   const guint retry_threshold = 100;
817
818   pic_params.version = gst_nvenc_get_pic_params_version ();
819   if (task->buffer) {
820     pic_params.inputWidth = task->register_resource.width;
821     pic_params.inputHeight = task->register_resource.height;
822     pic_params.inputPitch = task->register_resource.pitch;
823     pic_params.inputBuffer = task->mapped_resource.mappedResource;
824     pic_params.bufferFmt = task->mapped_resource.mappedBufferFmt;
825   } else {
826     pic_params.inputWidth = task->input_buffer.width;
827     pic_params.inputHeight = task->input_buffer.height;
828     pic_params.inputPitch = task->lk_input_buffer.pitch;
829     pic_params.inputBuffer = task->input_buffer.inputBuffer;
830     pic_params.bufferFmt = task->input_buffer.bufferFmt;
831   }
832
833   pic_params.frameIdx = frame->system_frame_number;
834   pic_params.inputTimeStamp = frame->pts;
835   pic_params.inputDuration = frame->duration;
836   pic_params.outputBitstream = task->output_ptr;
837   pic_params.completionEvent = task->event_handle;
838   pic_params.pictureStruct = gst_nv_encoder_get_pic_struct (self, task->buffer);
839   if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
840     pic_params.encodePicFlags = NV_ENC_PIC_FLAG_FORCEIDR;
841
842   do {
843     gst_nv_encoder_device_lock (self);
844     status = NvEncEncodePicture (priv->session, &pic_params);
845     gst_nv_encoder_device_unlock (self);
846
847     if (status == NV_ENC_ERR_ENCODER_BUSY) {
848       if (retry_count < 100) {
849         GST_DEBUG_OBJECT (self, "GPU is busy, retry count (%d/%d)", retry_count,
850             retry_threshold);
851         retry_count++;
852
853         /* Magic number 1ms */
854         g_usleep (1000);
855         continue;
856       } else {
857         GST_ERROR_OBJECT (self, "GPU is keep busy, give up");
858         break;
859       }
860     }
861
862     break;
863   } while (TRUE);
864
865   GST_NV_ENCODER_LOCK (self);
866   if (status != NV_ENC_SUCCESS && status != NV_ENC_ERR_NEED_MORE_INPUT) {
867     GST_ERROR_OBJECT (self, "Encode return %" GST_NVENC_STATUS_FORMAT,
868         GST_NVENC_STATUS_ARGS (status));
869     gst_nv_encoder_task_reset (self, task);
870     GST_NV_ENCODER_UNLOCK (self);
871
872     return GST_FLOW_ERROR;
873   }
874
875   gst_video_codec_frame_set_user_data (frame, task, NULL);
876   g_queue_push_tail (&priv->output_tasks, task);
877   g_cond_broadcast (&priv->cond);
878   GST_NV_ENCODER_UNLOCK (self);
879
880   return GST_FLOW_OK;
881 }
882
883 static GstVideoCodecFrame *
884 gst_nv_encoder_find_output_frame (GstVideoEncoder * self,
885     GstNvEncoderTask * task)
886 {
887   GList *frames, *iter;
888   GstVideoCodecFrame *ret = NULL;
889
890   frames = gst_video_encoder_get_frames (self);
891
892   for (iter = frames; iter; iter = g_list_next (iter)) {
893     GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
894     GstNvEncoderTask *other = (GstNvEncoderTask *)
895         gst_video_codec_frame_get_user_data (frame);
896
897     if (!other)
898       continue;
899
900     if (other == task) {
901       ret = frame;
902       break;
903     }
904   }
905
906   if (ret)
907     gst_video_codec_frame_ref (ret);
908
909   if (frames)
910     g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
911
912   return ret;
913 }
914
915 static gpointer
916 gst_nv_encoder_thread_func (GstNvEncoder * self)
917 {
918   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (self);
919   GstNvEncoderClass *klass = GST_NV_ENCODER_GET_CLASS (self);
920   GstNvEncoderPrivate *priv = self->priv;
921   GstNvEncoderTask *task = NULL;
922
923   do {
924     NV_ENC_LOCK_BITSTREAM bitstream = { 0, };
925     NVENCSTATUS status;
926     GstVideoCodecFrame *frame;
927     GstFlowReturn ret;
928
929     GST_NV_ENCODER_LOCK (self);
930     while ((task = (GstNvEncoderTask *)
931             g_queue_pop_head (&priv->output_tasks)) == NULL) {
932       g_cond_wait (&priv->cond, &priv->lock);
933     }
934     GST_NV_ENCODER_UNLOCK (self);
935
936     if (task->event_handle) {
937       if (!gst_d3d11_encoder_wait_for_event_handle (self, task->event_handle)) {
938         GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
939             ("Failed to wait for event signal"));
940         goto error;
941       }
942     }
943
944     if (task->is_eos) {
945       GST_INFO_OBJECT (self, "Got EOS packet");
946
947       GST_NV_ENCODER_LOCK (self);
948       gst_nv_encoder_task_reset (self, task);
949       g_cond_broadcast (&priv->cond);
950       GST_NV_ENCODER_UNLOCK (self);
951
952       goto exit_thread;
953     }
954
955     frame = gst_nv_encoder_find_output_frame (encoder, task);
956     if (!frame) {
957       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
958           ("Failed to find associated codec frame"));
959       goto error;
960     }
961
962     if (!gst_nv_encoder_device_lock (self)) {
963       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
964           ("Failed to lock device"));
965       goto error;
966     }
967
968     bitstream.version = gst_nvenc_get_lock_bitstream_version ();
969     bitstream.outputBitstream = task->output_ptr;
970
971     status = NvEncLockBitstream (priv->session, &bitstream);
972     if (status != NV_ENC_SUCCESS) {
973       gst_nv_encoder_device_unlock (self);
974       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
975           ("Failed to lock bitstream, status: %" GST_NVENC_STATUS_FORMAT,
976               GST_NVENC_STATUS_ARGS (status)));
977       goto error;
978     }
979
980     if (klass->create_output_buffer) {
981       frame->output_buffer = klass->create_output_buffer (self, &bitstream);
982     } else {
983       frame->output_buffer =
984           gst_buffer_new_memdup (bitstream.bitstreamBufferPtr,
985           bitstream.bitstreamSizeInBytes);
986     }
987
988     GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_MARKER);
989
990     if (bitstream.pictureType == NV_ENC_PIC_TYPE_IDR)
991       GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
992
993     NvEncUnlockBitstream (priv->session, task->output_ptr);
994     gst_nv_encoder_device_unlock (self);
995
996     frame->dts = frame->pts - priv->dts_offset;
997     frame->pts = bitstream.outputTimeStamp;
998     frame->duration = bitstream.outputDuration;
999
1000     ret = gst_video_encoder_finish_frame (encoder, frame);
1001     if (ret != GST_FLOW_OK) {
1002       GST_INFO_OBJECT (self,
1003           "Finish frame returned %s", gst_flow_get_name (ret));
1004     }
1005
1006     GST_NV_ENCODER_LOCK (self);
1007     gst_nv_encoder_task_reset (self, task);
1008     priv->last_flow = ret;
1009     g_cond_broadcast (&priv->cond);
1010     GST_NV_ENCODER_UNLOCK (self);
1011
1012     if (ret != GST_FLOW_OK) {
1013       GST_INFO_OBJECT (self, "Push returned %s", gst_flow_get_name (ret));
1014       goto exit_thread;
1015     }
1016   } while (TRUE);
1017
1018 exit_thread:
1019   {
1020     GST_INFO_OBJECT (self, "Exiting thread");
1021
1022     return NULL;
1023
1024   }
1025 error:
1026   {
1027     GST_NV_ENCODER_LOCK (self);
1028     gst_nv_encoder_task_reset (self, task);
1029     priv->last_flow = GST_FLOW_ERROR;
1030     g_cond_broadcast (&priv->cond);
1031     GST_NV_ENCODER_UNLOCK (self);
1032
1033     goto exit_thread;
1034   }
1035 }
1036
1037 static guint
1038 gst_nv_encoder_calculate_task_pool_size (GstNvEncoder * self,
1039     NV_ENC_CONFIG * config)
1040 {
1041   guint num_tasks;
1042
1043   /* At least 4 surfaces are required as documented by Nvidia Encoder guide */
1044   num_tasks = 4;
1045
1046   /* lookahead depth */
1047   num_tasks += config->rcParams.lookaheadDepth;
1048
1049   /* B frames + 1 */
1050   num_tasks += MAX (0, config->frameIntervalP - 1) + 1;
1051
1052   GST_DEBUG_OBJECT (self, "Calculated task pool size: %d "
1053       "(lookahead %d, frameIntervalP %d)",
1054       num_tasks, config->rcParams.lookaheadDepth, config->frameIntervalP);
1055
1056   return num_tasks;
1057 }
1058
1059 static gboolean
1060 gst_nv_encoder_open_encode_session (GstNvEncoder * self, gpointer * session)
1061 {
1062   GstNvEncoderPrivate *priv = self->priv;
1063   NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
1064   session_params.version =
1065       gst_nvenc_get_open_encode_session_ex_params_version ();
1066   session_params.apiVersion = gst_nvenc_get_api_version ();
1067   NVENCSTATUS status;
1068
1069   switch (priv->selected_device_mode) {
1070 #ifdef GST_CUDA_HAS_D3D
1071     case GST_NV_ENCODER_DEVICE_D3D11:
1072       session_params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
1073       session_params.device = gst_d3d11_device_get_device_handle (priv->device);
1074       break;
1075 #endif
1076     case GST_NV_ENCODER_DEVICE_CUDA:
1077       session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
1078       session_params.device = gst_cuda_context_get_handle (priv->context);
1079       break;
1080     default:
1081       g_assert_not_reached ();
1082       return FALSE;
1083   }
1084
1085   status = NvEncOpenEncodeSessionEx (&session_params, session);
1086   if (status != NV_ENC_SUCCESS) {
1087     GST_ERROR_OBJECT (self, "Failed to open session, status: %"
1088         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1089     return FALSE;
1090   }
1091
1092   return TRUE;
1093 }
1094
1095 #ifdef GST_CUDA_HAS_D3D
1096 static GstBufferPool *
1097 gst_nv_encoder_create_d3d11_pool (GstNvEncoder * self,
1098     GstVideoCodecState * state)
1099 {
1100   GstNvEncoderPrivate *priv = self->priv;
1101   GstStructure *config;
1102   GstBufferPool *pool = NULL;
1103   GstD3D11AllocationParams *params;
1104
1105   params = gst_d3d11_allocation_params_new (priv->device, &state->info,
1106       GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, D3D11_RESOURCE_MISC_SHARED);
1107
1108   pool = gst_d3d11_buffer_pool_new (priv->device);
1109
1110   config = gst_buffer_pool_get_config (pool);
1111   gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
1112   gst_d3d11_allocation_params_free (params);
1113
1114   gst_buffer_pool_config_set_params (config, state->caps,
1115       GST_VIDEO_INFO_SIZE (&state->info), 0, 0);
1116   if (!gst_buffer_pool_set_config (pool, config)) {
1117     GST_ERROR_OBJECT (self, "Failed to set pool config");
1118     gst_object_unref (pool);
1119
1120     return NULL;
1121   }
1122
1123   if (!gst_buffer_pool_set_active (pool, TRUE)) {
1124     GST_ERROR_OBJECT (self, "Failed to set active");
1125     gst_object_unref (pool);
1126     return NULL;
1127   }
1128
1129   return pool;
1130 }
1131 #endif
1132
1133 static GstBufferPool *
1134 gst_nv_encoder_create_pool (GstNvEncoder * self, GstVideoCodecState * state)
1135 {
1136   GstNvEncoderPrivate *priv = self->priv;
1137   GstStructure *config;
1138   GstBufferPool *pool = NULL;
1139
1140   /* At this moment device type must be selected already */
1141   switch (priv->selected_device_mode) {
1142 #ifdef GST_CUDA_HAS_D3D
1143     case GST_NV_ENCODER_DEVICE_D3D11:
1144       return gst_nv_encoder_create_d3d11_pool (self, state);
1145 #endif
1146     case GST_NV_ENCODER_DEVICE_CUDA:
1147       pool = gst_cuda_buffer_pool_new (priv->context);
1148       break;
1149     default:
1150       g_assert_not_reached ();
1151       return FALSE;
1152   }
1153
1154   config = gst_buffer_pool_get_config (pool);
1155   gst_buffer_pool_config_set_params (config, state->caps,
1156       GST_VIDEO_INFO_SIZE (&state->info), 0, 0);
1157   if (!gst_buffer_pool_set_config (pool, config)) {
1158     GST_ERROR_OBJECT (self, "Failed to set pool config");
1159     gst_object_unref (pool);
1160
1161     return NULL;
1162   }
1163
1164   if (!gst_buffer_pool_set_active (pool, TRUE)) {
1165     GST_ERROR_OBJECT (self, "Failed to set active");
1166     gst_object_unref (pool);
1167     return NULL;
1168   }
1169
1170   return pool;
1171 }
1172
1173 static gboolean
1174 gst_nv_encoder_init_session (GstNvEncoder * self, GstBuffer * in_buf)
1175 {
1176   GstNvEncoderPrivate *priv = self->priv;
1177   GstNvEncoderClass *klass = GST_NV_ENCODER_GET_CLASS (self);
1178   GstVideoCodecState *state = priv->input_state;
1179   GstVideoInfo *info = &state->info;
1180   NVENCSTATUS status;
1181   guint task_pool_size;
1182   gint fps_n, fps_d;
1183   GstClockTime frame_duration, min_latency, max_latency;
1184   guint i;
1185
1186   gst_nv_encoder_reset (self);
1187
1188   memset (&priv->init_params, 0, sizeof (NV_ENC_INITIALIZE_PARAMS));
1189   memset (&priv->config, 0, sizeof (NV_ENC_CONFIG));
1190
1191   if (priv->selected_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1192     GstNvEncoderDeviceData data;
1193     gboolean ret;
1194
1195     if (!in_buf) {
1196       GST_DEBUG_OBJECT (self, "Unknown device mode, open session later");
1197       return TRUE;
1198     }
1199
1200     if (!klass->select_device (self, info, in_buf, &data)) {
1201       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1202           ("Failed to select device mode"));
1203       return FALSE;
1204     }
1205
1206     GST_DEBUG_OBJECT (self,
1207         "Selected device mode: %d, cuda-device-id: %d, adapter-luid %"
1208         G_GINT64_FORMAT, data.device_mode, data.cuda_device_id,
1209         data.adapter_luid);
1210
1211     g_assert (data.device_mode == GST_NV_ENCODER_DEVICE_CUDA ||
1212         data.device_mode == GST_NV_ENCODER_DEVICE_D3D11);
1213
1214     g_rec_mutex_lock (&priv->context_lock);
1215     priv->selected_device_mode = data.device_mode;
1216     priv->cuda_device_id = data.cuda_device_id;
1217     priv->dxgi_adapter_luid = data.adapter_luid;
1218     gst_clear_object (&priv->context);
1219     if (data.device_mode == GST_NV_ENCODER_DEVICE_CUDA)
1220       priv->context = (GstCudaContext *) data.device;
1221 #ifdef GST_CUDA_HAS_D3D
1222     gst_clear_object (&priv->device);
1223     if (data.device_mode == GST_NV_ENCODER_DEVICE_D3D11)
1224       priv->device = (GstD3D11Device *) data.device;
1225 #endif
1226
1227     ret = gst_nv_encoder_open (GST_VIDEO_ENCODER (self));
1228     g_rec_mutex_unlock (&priv->context_lock);
1229
1230     if (!ret) {
1231       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1232           ("Failed to open device"));
1233       return FALSE;
1234     }
1235   }
1236
1237   priv->internal_pool = gst_nv_encoder_create_pool (self, state);
1238   if (!priv->internal_pool) {
1239     GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1240         ("Failed to create internal pool"));
1241     return FALSE;
1242   }
1243
1244   if (!gst_nv_encoder_device_lock (self)) {
1245     GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), ("Failed to lock device"));
1246     gst_nv_encoder_reset (self);
1247     return FALSE;
1248   }
1249
1250   if (!gst_nv_encoder_open_encode_session (self, &priv->session)) {
1251     GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1252         ("Failed to open session"));
1253     goto error;
1254   }
1255
1256   if (!klass->set_format (self, state, priv->session, &priv->init_params,
1257           &priv->config)) {
1258     GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), ("Failed to set format"));
1259     goto error;
1260   }
1261
1262   priv->init_params.encodeConfig = &priv->config;
1263   status = NvEncInitializeEncoder (priv->session, &priv->init_params);
1264   if (status != NV_ENC_SUCCESS) {
1265     GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1266         ("Failed to init encoder, status: %"
1267             GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status)));
1268     goto error;
1269   }
1270
1271   if (priv->selected_device_mode == GST_NV_ENCODER_DEVICE_CUDA &&
1272       gst_nvenc_have_set_io_cuda_streams ()) {
1273     CUresult cuda_ret = CuStreamCreate (&priv->cuda_stream, CU_STREAM_DEFAULT);
1274
1275     if (gst_cuda_result (cuda_ret)) {
1276       status = NvEncSetIOCudaStreams (priv->session,
1277           (NV_ENC_CUSTREAM_PTR) & priv->cuda_stream,
1278           (NV_ENC_CUSTREAM_PTR) & priv->cuda_stream);
1279       if (status != NV_ENC_SUCCESS) {
1280         GST_WARNING_OBJECT (self, "NvEncSetIOCudaStreams failed, status: %"
1281             GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1282       }
1283     }
1284   }
1285
1286   task_pool_size = gst_nv_encoder_calculate_task_pool_size (self,
1287       &priv->config);
1288   g_array_set_size (priv->task_pool, task_pool_size);
1289
1290   for (i = 0; i < task_pool_size; i++) {
1291     NV_ENC_CREATE_BITSTREAM_BUFFER buffer_params = { 0, };
1292     GstNvEncoderTask *task = (GstNvEncoderTask *)
1293         & g_array_index (priv->task_pool, GstNvEncoderTask, i);
1294
1295     task->encoder = self;
1296
1297     buffer_params.version = gst_nvenc_get_create_bitstream_buffer_version ();
1298     status = NvEncCreateBitstreamBuffer (priv->session, &buffer_params);
1299
1300     if (status != NV_ENC_SUCCESS) {
1301       GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1302           ("Failed to create bitstream buffer, status: %"
1303               GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status)));
1304       goto error;
1305     }
1306
1307     task->output_ptr = buffer_params.bitstreamBuffer;
1308
1309     if (priv->init_params.enableEncodeAsync) {
1310       if (!gst_nv_encoder_create_event_handle (self,
1311               priv->session, &task->event_handle)) {
1312         GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1313             ("Failed to create async event handle"));
1314         goto error;
1315       }
1316     }
1317
1318     g_queue_push_tail (&priv->free_tasks, task);
1319   }
1320   gst_nv_encoder_device_unlock (self);
1321
1322   if (!klass->set_output_state (self, priv->input_state, priv->session)) {
1323     GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1324         ("Failed to set output state"));
1325     gst_nv_encoder_reset (self);
1326     return FALSE;
1327   }
1328
1329   priv->encoding_thread = g_thread_new ("GstNvEncoderThread",
1330       (GThreadFunc) gst_nv_encoder_thread_func, self);
1331
1332   if (info->fps_n > 0 && info->fps_d > 0) {
1333     fps_n = info->fps_n;
1334     fps_d = info->fps_d;
1335   } else {
1336     fps_n = 25;
1337     fps_d = 1;
1338   }
1339
1340   frame_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
1341
1342   priv->dts_offset = 0;
1343   /* Calculate DTS offset for B frame. NVENC does not provide DTS */
1344   if (priv->config.frameIntervalP > 1)
1345     priv->dts_offset = frame_duration * (priv->config.frameIntervalP - 1);
1346
1347   min_latency = priv->dts_offset +
1348       priv->config.rcParams.lookaheadDepth * frame_duration;
1349   max_latency = frame_duration * priv->task_pool->len;
1350   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (self),
1351       min_latency, max_latency);
1352
1353   return TRUE;
1354
1355 error:
1356   gst_nv_encoder_device_unlock (self);
1357
1358   gst_nv_encoder_reset (self);
1359
1360   return FALSE;
1361 }
1362
1363 static gboolean
1364 gst_nv_encoder_reconfigure_session (GstNvEncoder * self)
1365 {
1366   GstNvEncoderPrivate *priv = self->priv;
1367   NV_ENC_RECONFIGURE_PARAMS params = { 0, };
1368   NVENCSTATUS status;
1369
1370   if (!priv->session) {
1371     GST_WARNING_OBJECT (self,
1372         "Encoding session was not configured, open session");
1373     gst_nv_encoder_drain (self, TRUE);
1374
1375     return gst_nv_encoder_init_session (self, nullptr);
1376   }
1377
1378   params.version = gst_nvenc_get_reconfigure_params_version ();
1379   params.reInitEncodeParams = priv->init_params;
1380   params.reInitEncodeParams.encodeConfig = &priv->config;
1381
1382   status = NvEncReconfigureEncoder (priv->session, &params);
1383   if (status != NV_ENC_SUCCESS) {
1384     GST_WARNING_OBJECT (self, "Failed to reconfigure encoder, status %"
1385         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1386     gst_nv_encoder_drain (self, TRUE);
1387
1388     return gst_nv_encoder_init_session (self, nullptr);
1389   }
1390
1391   return TRUE;
1392 }
1393
1394 static gboolean
1395 gst_nv_encoder_set_format (GstVideoEncoder * encoder,
1396     GstVideoCodecState * state)
1397 {
1398   GstNvEncoder *self = GST_NV_ENCODER (encoder);
1399   GstNvEncoderPrivate *priv = self->priv;
1400
1401   gst_nv_encoder_drain (self, TRUE);
1402
1403   g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
1404   priv->input_state = gst_video_codec_state_ref (state);
1405   priv->last_flow = GST_FLOW_OK;
1406
1407   /* select device again on next buffer */
1408   if (priv->subclass_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT)
1409     priv->selected_device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
1410
1411   return gst_nv_encoder_init_session (self, nullptr);
1412 }
1413
1414 static NV_ENC_BUFFER_FORMAT
1415 gst_nv_encoder_get_buffer_format (GstNvEncoder * self, GstVideoFormat format)
1416 {
1417   switch (format) {
1418     case GST_VIDEO_FORMAT_NV12:
1419       return NV_ENC_BUFFER_FORMAT_NV12;
1420     case GST_VIDEO_FORMAT_Y444:
1421       return NV_ENC_BUFFER_FORMAT_YUV444;
1422     case GST_VIDEO_FORMAT_P010_10LE:
1423       return NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
1424     case GST_VIDEO_FORMAT_Y444_16LE:
1425       return NV_ENC_BUFFER_FORMAT_YUV444_10BIT;
1426     default:
1427       GST_ERROR_OBJECT (self, "Unexpected format %s",
1428           gst_video_format_to_string (format));
1429       g_assert_not_reached ();
1430       break;
1431   }
1432
1433   return NV_ENC_BUFFER_FORMAT_UNDEFINED;
1434 }
1435
1436 static GstFlowReturn
1437 gst_nv_encoder_copy_system (GstNvEncoder * self, const GstVideoInfo * info,
1438     GstBuffer * buffer, gpointer session, GstNvEncoderTask * task)
1439 {
1440   NVENCSTATUS status;
1441   GstVideoFrame frame;
1442   guint8 *dst_data;
1443   NV_ENC_BUFFER_FORMAT format;
1444
1445   format =
1446       gst_nv_encoder_get_buffer_format (self, GST_VIDEO_INFO_FORMAT (info));
1447   if (format == NV_ENC_BUFFER_FORMAT_UNDEFINED)
1448     return GST_FLOW_ERROR;
1449
1450   if (!gst_video_frame_map (&frame, info, buffer, GST_MAP_READ)) {
1451     GST_ERROR_OBJECT (self, "Failed to map buffer");
1452     return GST_FLOW_ERROR;
1453   }
1454
1455   if (!task->input_buffer.inputBuffer) {
1456     NV_ENC_CREATE_INPUT_BUFFER input_buffer = { 0, };
1457     input_buffer.version = gst_nvenc_get_create_input_buffer_version ();
1458     input_buffer.width = info->width;
1459     input_buffer.height = info->height;
1460     input_buffer.bufferFmt = format;
1461
1462     status = NvEncCreateInputBuffer (session, &input_buffer);
1463     if (status != NV_ENC_SUCCESS) {
1464       GST_ERROR_OBJECT (self, "Failed to create input buffer, status %"
1465           GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1466       gst_video_frame_unmap (&frame);
1467       return GST_FLOW_ERROR;
1468     }
1469
1470     task->input_buffer = input_buffer;
1471   }
1472
1473   task->lk_input_buffer.version = gst_nvenc_get_lock_input_buffer_version ();
1474   task->lk_input_buffer.inputBuffer = task->input_buffer.inputBuffer;
1475   status = NvEncLockInputBuffer (session, &task->lk_input_buffer);
1476   if (status != NV_ENC_SUCCESS) {
1477     GST_ERROR_OBJECT (self, "Failed to lock input buffer, status %"
1478         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1479     gst_video_frame_unmap (&frame);
1480     return GST_FLOW_ERROR;
1481   }
1482
1483   dst_data = (guint8 *) task->lk_input_buffer.bufferDataPtr;
1484
1485   for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&frame); i++) {
1486     guint8 *src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame, i);
1487     guint width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i) *
1488         GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, i);
1489     guint stride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, i);
1490     guint height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
1491
1492     for (guint j = 0; j < height; j++) {
1493       memcpy (dst_data, src_data, width_in_bytes);
1494       dst_data += task->lk_input_buffer.pitch;
1495       src_data += stride;
1496     }
1497   }
1498
1499   NvEncUnlockInputBuffer (session, task->input_buffer.inputBuffer);
1500   gst_video_frame_unmap (&frame);
1501
1502   return GST_FLOW_OK;
1503 }
1504
1505 static GstFlowReturn
1506 gst_nv_encoder_prepare_task_input_cuda (GstNvEncoder * self,
1507     const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1508     GstNvEncoderTask * task)
1509 {
1510   GstNvEncoderPrivate *priv = self->priv;
1511   GstMemory *mem;
1512   GstCudaMemory *cmem;
1513   NVENCSTATUS status;
1514
1515   mem = gst_buffer_peek_memory (buffer, 0);
1516   if (!gst_is_cuda_memory (mem)) {
1517     GST_LOG_OBJECT (self, "Not a CUDA buffer, system copy");
1518     return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1519   }
1520
1521   cmem = GST_CUDA_MEMORY_CAST (mem);
1522   if (cmem->context != priv->context) {
1523     GST_LOG_OBJECT (self, "Different context, system copy");
1524     return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1525   }
1526
1527   task->buffer = gst_buffer_ref (buffer);
1528   if (!gst_buffer_map (task->buffer, &task->map_info,
1529           (GstMapFlags) (GST_MAP_READ | GST_MAP_CUDA))) {
1530     GST_ERROR_OBJECT (self, "Failed to map buffer");
1531     gst_clear_buffer (&task->buffer);
1532
1533     return GST_FLOW_ERROR;
1534   }
1535
1536   cmem = (GstCudaMemory *) gst_buffer_peek_memory (task->buffer, 0);
1537
1538   task->register_resource.version = gst_nvenc_get_register_resource_version ();
1539   task->register_resource.resourceType =
1540       NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR;
1541   task->register_resource.width = cmem->info.width;
1542   task->register_resource.height = cmem->info.height;
1543   task->register_resource.pitch = cmem->info.stride[0];
1544   task->register_resource.resourceToRegister = task->map_info.data;
1545   task->register_resource.bufferFormat =
1546       gst_nv_encoder_get_buffer_format (self, GST_VIDEO_INFO_FORMAT (info));
1547   if (task->register_resource.bufferFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED)
1548     return GST_FLOW_ERROR;
1549
1550   status = NvEncRegisterResource (session, &task->register_resource);
1551   if (status != NV_ENC_SUCCESS) {
1552     GST_ERROR_OBJECT (self, "Failed to register resource, status %"
1553         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1554
1555     gst_buffer_unmap (task->buffer, &task->map_info);
1556     gst_clear_buffer (&task->buffer);
1557
1558     return GST_FLOW_ERROR;
1559   }
1560
1561   task->mapped_resource.version = gst_nvenc_get_map_input_resource_version ();
1562   task->mapped_resource.registeredResource =
1563       task->register_resource.registeredResource;
1564   status = NvEncMapInputResource (session, &task->mapped_resource);
1565   if (status != NV_ENC_SUCCESS) {
1566     GST_ERROR_OBJECT (self, "Failed to map input resource, status %"
1567         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1568     NvEncUnregisterResource (session,
1569         task->register_resource.registeredResource);
1570
1571     gst_buffer_unmap (task->buffer, &task->map_info);
1572     gst_clear_buffer (&task->buffer);
1573
1574     return GST_FLOW_ERROR;
1575   }
1576
1577   return GST_FLOW_OK;
1578 }
1579
1580 #ifdef GST_CUDA_HAS_D3D
1581 static GstBuffer *
1582 gst_nv_encoder_copy_d3d11 (GstNvEncoder * self,
1583     GstBuffer * src_buffer, GstBufferPool * pool, gboolean shared)
1584 {
1585   GstNvEncoderPrivate *priv = self->priv;
1586   D3D11_TEXTURE2D_DESC src_desc, dst_desc;
1587   D3D11_BOX src_box;
1588   guint subresource_idx;
1589   GstMemory *src_mem, *dst_mem;
1590   GstMapInfo src_info, dst_info;
1591   ID3D11Texture2D *src_tex, *dst_tex;
1592   ID3D11Device *device_handle;
1593   ID3D11DeviceContext *device_context;
1594   GstBuffer *dst_buffer;
1595   GstFlowReturn ret;
1596   ComPtr < IDXGIResource > dxgi_resource;
1597   ComPtr < ID3D11Texture2D > shared_texture;
1598   HANDLE shared_handle;
1599   GstD3D11Device *device;
1600   HRESULT hr;
1601
1602   ret = gst_buffer_pool_acquire_buffer (pool, &dst_buffer, NULL);
1603   if (ret != GST_FLOW_OK) {
1604     GST_ERROR_OBJECT (self, "Failed to acquire buffer");
1605     return NULL;
1606   }
1607
1608   src_mem = gst_buffer_peek_memory (src_buffer, 0);
1609   dst_mem = gst_buffer_peek_memory (dst_buffer, 0);
1610
1611   device = GST_D3D11_MEMORY_CAST (src_mem)->device;
1612
1613   device_handle = gst_d3d11_device_get_device_handle (device);
1614   device_context = gst_d3d11_device_get_device_context_handle (device);
1615
1616   if (!gst_memory_map (src_mem, &src_info,
1617           (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
1618     GST_WARNING ("Failed to map src memory");
1619     gst_buffer_unref (dst_buffer);
1620     return NULL;
1621   }
1622
1623   if (!gst_memory_map (dst_mem, &dst_info,
1624           (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
1625     GST_WARNING ("Failed to map dst memory");
1626     gst_memory_unmap (src_mem, &src_info);
1627     gst_buffer_unref (dst_buffer);
1628     return NULL;
1629   }
1630
1631   src_tex = (ID3D11Texture2D *) src_info.data;
1632   dst_tex = (ID3D11Texture2D *) dst_info.data;
1633
1634   gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (src_mem),
1635       &src_desc);
1636   gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (dst_mem),
1637       &dst_desc);
1638   subresource_idx =
1639       gst_d3d11_memory_get_subresource_index (GST_D3D11_MEMORY_CAST (src_mem));
1640
1641   if (shared) {
1642     hr = dst_tex->QueryInterface (IID_PPV_ARGS (&dxgi_resource));
1643     if (!gst_d3d11_result (hr, priv->device)) {
1644       GST_ERROR_OBJECT (self,
1645           "IDXGIResource interface is not available, hr: 0x%x", (guint) hr);
1646       goto error;
1647     }
1648
1649     hr = dxgi_resource->GetSharedHandle (&shared_handle);
1650     if (!gst_d3d11_result (hr, priv->device)) {
1651       GST_ERROR_OBJECT (self, "Failed to get shared handle, hr: 0x%x",
1652           (guint) hr);
1653       goto error;
1654     }
1655
1656     hr = device_handle->OpenSharedResource (shared_handle,
1657         IID_PPV_ARGS (&shared_texture));
1658
1659     if (!gst_d3d11_result (hr, device)) {
1660       GST_ERROR_OBJECT (self, "Failed to get shared texture, hr: 0x%x",
1661           (guint) hr);
1662       goto error;
1663     }
1664
1665     dst_tex = shared_texture.Get ();
1666   }
1667
1668   src_box.left = 0;
1669   src_box.top = 0;
1670   src_box.front = 0;
1671   src_box.back = 1;
1672   src_box.right = MIN (src_desc.Width, dst_desc.Width);
1673   src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
1674
1675   if (shared) {
1676     if (priv->fence && priv->fence->device != device)
1677       gst_clear_d3d11_fence (&priv->fence);
1678
1679     if (!priv->fence)
1680       priv->fence = gst_d3d11_device_create_fence (device);
1681
1682     if (!priv->fence) {
1683       GST_ERROR_OBJECT (self, "Couldn't crete fence");
1684       goto error;
1685     }
1686
1687     gst_d3d11_device_lock (device);
1688   }
1689
1690   device_context->CopySubresourceRegion (dst_tex, 0,
1691       0, 0, 0, src_tex, subresource_idx, &src_box);
1692
1693   if (shared) {
1694     if (!gst_d3d11_fence_signal (priv->fence) ||
1695         !gst_d3d11_fence_wait (priv->fence)) {
1696       GST_ERROR_OBJECT (self, "Couldn't sync GPU operation");
1697       gst_d3d11_device_unlock (device);
1698       gst_clear_d3d11_fence (&priv->fence);
1699       goto error;
1700     }
1701
1702     gst_d3d11_device_unlock (device);
1703   }
1704
1705   gst_memory_unmap (dst_mem, &dst_info);
1706   gst_memory_unmap (src_mem, &src_info);
1707
1708   return dst_buffer;
1709
1710 error:
1711   gst_memory_unmap (dst_mem, &dst_info);
1712   gst_memory_unmap (src_mem, &src_info);
1713   gst_buffer_unref (dst_buffer);
1714
1715   return NULL;
1716 }
1717
1718 static GstBuffer *
1719 gst_nv_encoder_upload_d3d11_frame (GstNvEncoder * self,
1720     const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
1721 {
1722   GstD3D11Memory *dmem;
1723   D3D11_TEXTURE2D_DESC desc;
1724
1725   dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
1726
1727   gst_d3d11_memory_get_texture_desc (dmem, &desc);
1728   if (desc.Usage != D3D11_USAGE_DEFAULT) {
1729     GST_TRACE_OBJECT (self, "Not a default usage texture, d3d11 copy");
1730     return gst_nv_encoder_copy_d3d11 (self, buffer, pool, FALSE);
1731   }
1732
1733   GST_TRACE_OBJECT (self, "Use input buffer without copy");
1734
1735   return gst_buffer_ref (buffer);
1736 }
1737
1738 static GstFlowReturn
1739 gst_nv_encoder_prepare_task_input_d3d11 (GstNvEncoder * self,
1740     const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1741     GstBufferPool * pool, GstNvEncoderTask * task)
1742 {
1743   GstNvEncoderPrivate *priv = self->priv;
1744   GstMemory *mem;
1745   GstD3D11Memory *dmem;
1746   D3D11_TEXTURE2D_DESC desc;
1747   NVENCSTATUS status;
1748
1749   if (gst_buffer_n_memory (buffer) > 1) {
1750     GST_LOG_OBJECT (self, "Not a native DXGI format, system copy");
1751     return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1752   }
1753
1754   mem = gst_buffer_peek_memory (buffer, 0);
1755   if (!gst_is_d3d11_memory (mem)) {
1756     GST_LOG_OBJECT (self, "Not a D3D11 buffer, system copy");
1757     return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1758   }
1759
1760   dmem = GST_D3D11_MEMORY_CAST (mem);
1761   if (dmem->device != priv->device) {
1762     gint64 adapter_luid;
1763
1764     g_object_get (dmem->device, "adapter-luid", &adapter_luid, NULL);
1765     if (adapter_luid == priv->dxgi_adapter_luid) {
1766       GST_LOG_OBJECT (self, "Different device but same GPU, copy d3d11");
1767       task->buffer = gst_nv_encoder_copy_d3d11 (self, buffer, pool, TRUE);
1768     } else {
1769       GST_LOG_OBJECT (self, "Different device, system copy");
1770       return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1771     }
1772   }
1773
1774   if (!task->buffer)
1775     task->buffer = gst_nv_encoder_upload_d3d11_frame (self, info, buffer, pool);
1776
1777   if (!task->buffer) {
1778     GST_ERROR_OBJECT (self, "Failed to upload buffer");
1779     return GST_FLOW_ERROR;
1780   }
1781
1782   if (!gst_buffer_map (task->buffer, &task->map_info,
1783           (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
1784     GST_ERROR_OBJECT (self, "Failed to map buffer");
1785     gst_clear_buffer (&task->buffer);
1786
1787     return GST_FLOW_ERROR;
1788   }
1789
1790   dmem = (GstD3D11Memory *) gst_buffer_peek_memory (task->buffer, 0);
1791   gst_d3d11_memory_get_texture_desc (dmem, &desc);
1792
1793   task->register_resource.version = gst_nvenc_get_register_resource_version ();
1794   task->register_resource.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
1795   task->register_resource.width = desc.Width;
1796   task->register_resource.height = desc.Height;
1797   switch (desc.Format) {
1798     case DXGI_FORMAT_NV12:
1799       task->register_resource.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
1800       break;
1801     case DXGI_FORMAT_P010:
1802       task->register_resource.bufferFormat = NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
1803       break;
1804     default:
1805       GST_ERROR_OBJECT (self, "Unexpected DXGI format %d", desc.Format);
1806       g_assert_not_reached ();
1807       return GST_FLOW_ERROR;
1808   }
1809
1810   task->register_resource.subResourceIndex =
1811       gst_d3d11_memory_get_subresource_index (dmem);
1812   task->register_resource.resourceToRegister =
1813       gst_d3d11_memory_get_resource_handle (dmem);
1814
1815   status = NvEncRegisterResource (session, &task->register_resource);
1816   if (status != NV_ENC_SUCCESS) {
1817     GST_ERROR_OBJECT (self, "Failed to register resource, status %"
1818         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1819
1820     gst_buffer_unmap (task->buffer, &task->map_info);
1821     gst_clear_buffer (&task->buffer);
1822
1823     return GST_FLOW_ERROR;
1824   }
1825
1826   task->mapped_resource.version = gst_nvenc_get_map_input_resource_version ();
1827   task->mapped_resource.registeredResource =
1828       task->register_resource.registeredResource;
1829   status = NvEncMapInputResource (session, &task->mapped_resource);
1830   if (status != NV_ENC_SUCCESS) {
1831     GST_ERROR_OBJECT (self, "Failed to map input resource, status %"
1832         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1833     NvEncUnregisterResource (session,
1834         task->register_resource.registeredResource);
1835
1836     gst_buffer_unmap (task->buffer, &task->map_info);
1837     gst_clear_buffer (&task->buffer);
1838
1839     return GST_FLOW_ERROR;
1840   }
1841
1842   return GST_FLOW_OK;
1843 }
1844 #endif
1845
1846 static GstFlowReturn
1847 gst_nv_encoder_prepare_task_input (GstNvEncoder * self,
1848     const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1849     GstBufferPool * pool, GstNvEncoderTask * task)
1850 {
1851   GstNvEncoderPrivate *priv = self->priv;
1852   GstFlowReturn ret = GST_FLOW_ERROR;
1853
1854   switch (priv->selected_device_mode) {
1855 #ifdef GST_CUDA_HAS_D3D
1856     case GST_NV_ENCODER_DEVICE_D3D11:
1857       ret = gst_nv_encoder_prepare_task_input_d3d11 (self, info, buffer,
1858           session, pool, task);
1859       break;
1860 #endif
1861     case GST_NV_ENCODER_DEVICE_CUDA:
1862       ret = gst_nv_encoder_prepare_task_input_cuda (self, info, buffer,
1863           session, task);
1864       break;
1865     default:
1866       g_assert_not_reached ();
1867       break;
1868   }
1869
1870   return ret;
1871 }
1872
1873 static GstFlowReturn
1874 gst_nv_encoder_handle_frame (GstVideoEncoder * encoder,
1875     GstVideoCodecFrame * frame)
1876 {
1877   GstNvEncoder *self = GST_NV_ENCODER (encoder);
1878   GstNvEncoderPrivate *priv = self->priv;
1879   GstNvEncoderClass *klass = GST_NV_ENCODER_GET_CLASS (self);
1880   GstFlowReturn ret = GST_FLOW_ERROR;
1881   GstNvEncoderTask *task = NULL;
1882   GstNvEncoderReconfigure reconfig;
1883   GstBuffer *in_buf = frame->input_buffer;
1884
1885   GST_TRACE_OBJECT (self, "Handle frame");
1886
1887   GST_NV_ENCODER_LOCK (self);
1888   ret = priv->last_flow;
1889   GST_NV_ENCODER_UNLOCK (self);
1890
1891   if (ret != GST_FLOW_OK) {
1892     GST_INFO_OBJECT (self, "Last flow was %s", gst_flow_get_name (ret));
1893     gst_video_encoder_finish_frame (encoder, frame);
1894
1895     return ret;
1896   }
1897
1898   if (!priv->session && !gst_nv_encoder_init_session (self, in_buf)) {
1899     GST_ERROR_OBJECT (self, "Encoder object was not configured");
1900     gst_video_encoder_finish_frame (encoder, frame);
1901
1902     return GST_FLOW_NOT_NEGOTIATED;
1903   }
1904
1905   reconfig = klass->check_reconfigure (self, &priv->config);
1906   switch (reconfig) {
1907     case GST_NV_ENCODER_RECONFIGURE_BITRATE:
1908       if (!gst_nv_encoder_reconfigure_session (self)) {
1909         gst_video_encoder_finish_frame (encoder, frame);
1910         return GST_FLOW_NOT_NEGOTIATED;
1911       }
1912       break;
1913     case GST_NV_ENCODER_RECONFIGURE_FULL:
1914     {
1915       gst_nv_encoder_drain (self, TRUE);
1916       if (!gst_nv_encoder_init_session (self, nullptr)) {
1917         gst_video_encoder_finish_frame (encoder, frame);
1918         return GST_FLOW_NOT_NEGOTIATED;
1919       }
1920       break;
1921     }
1922     default:
1923       break;
1924   }
1925
1926   /* Release stream lock temporarily for encoding thread to be able to
1927    * push encoded data */
1928   GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1929   ret = gst_nv_encoder_get_free_task (self, &task, TRUE);
1930   GST_VIDEO_ENCODER_STREAM_LOCK (self);
1931   if (ret != GST_FLOW_OK) {
1932     GST_DEBUG_OBJECT (self, "Last flow was %s", gst_flow_get_name (ret));
1933     gst_video_encoder_finish_frame (encoder, frame);
1934     return ret;
1935   }
1936
1937   if (!gst_nv_encoder_device_lock (self)) {
1938     GST_ERROR_OBJECT (self, "Failed to lock device");
1939     gst_video_encoder_finish_frame (encoder, frame);
1940
1941     return GST_FLOW_ERROR;
1942   }
1943
1944   g_assert (task->buffer == NULL);
1945   ret = gst_nv_encoder_prepare_task_input (self, &priv->input_state->info,
1946       in_buf, priv->session, priv->internal_pool, task);
1947   gst_nv_encoder_device_unlock (self);
1948
1949   if (ret != GST_FLOW_OK) {
1950     GST_ERROR_OBJECT (self, "Failed to upload frame");
1951     GST_NV_ENCODER_LOCK (self);
1952     gst_nv_encoder_task_reset (self, task);
1953     GST_NV_ENCODER_UNLOCK (self);
1954
1955     gst_video_encoder_finish_frame (encoder, frame);
1956
1957     return ret;
1958   }
1959
1960   ret = gst_nv_encoder_encode_frame (self, frame, task);
1961   if (ret != GST_FLOW_OK) {
1962     GST_ERROR_OBJECT (self, "Failed to encode frame");
1963     gst_video_encoder_finish_frame (encoder, frame);
1964
1965     return ret;
1966   }
1967
1968   gst_video_codec_frame_unref (frame);
1969
1970   return GST_FLOW_OK;
1971 }
1972
1973 static GstFlowReturn
1974 gst_nv_encoder_finish (GstVideoEncoder * encoder)
1975 {
1976   GstNvEncoder *self = GST_NV_ENCODER (encoder);
1977
1978   GST_DEBUG_OBJECT (self, "Finish");
1979
1980   gst_nv_encoder_drain (self, TRUE);
1981
1982   return GST_FLOW_OK;
1983 }
1984
1985 static gboolean
1986 gst_nv_encoder_flush (GstVideoEncoder * encoder)
1987 {
1988   GstNvEncoder *self = GST_NV_ENCODER (encoder);
1989   GstNvEncoderPrivate *priv = self->priv;
1990
1991   GST_DEBUG_OBJECT (self, "Flush");
1992
1993   gst_nv_encoder_drain (self, TRUE);
1994
1995   priv->last_flow = GST_FLOW_OK;
1996
1997   return TRUE;
1998 }
1999
2000 guint
2001 gst_nv_encoder_get_task_size (GstNvEncoder * encoder)
2002 {
2003   g_return_val_if_fail (GST_IS_NV_ENCODER (encoder), 0);
2004
2005   return encoder->priv->task_pool->len;
2006 }
2007
2008 void
2009 gst_nv_encoder_set_device_mode (GstNvEncoder * encoder,
2010     GstNvEncoderDeviceMode mode, guint cuda_device_id, gint64 adapter_luid)
2011 {
2012   GstNvEncoderPrivate *priv = encoder->priv;
2013
2014   priv->subclass_device_mode = mode;
2015   priv->selected_device_mode = mode;
2016   priv->cuda_device_id = cuda_device_id;
2017   priv->dxgi_adapter_luid = adapter_luid;
2018 }
2019
2020 /**
2021  * GstNvEncoderPreset:
2022  *
2023  * Since: 1.22
2024  */
2025 GType
2026 gst_nv_encoder_preset_get_type (void)
2027 {
2028   static GType preset_type = 0;
2029   static const GEnumValue presets[] = {
2030     {GST_NV_ENCODER_PRESET_DEFAULT, "Default", "default"},
2031     {GST_NV_ENCODER_PRESET_HP, "High Performance", "hp"},
2032     {GST_NV_ENCODER_PRESET_HQ, "High Quality", "hq"},
2033     {GST_NV_ENCODER_PRESET_LOW_LATENCY_DEFAULT, "Low Latency", "low-latency"},
2034     {GST_NV_ENCODER_PRESET_LOW_LATENCY_HQ, "Low Latency, High Quality",
2035         "low-latency-hq"},
2036     {GST_NV_ENCODER_PRESET_LOW_LATENCY_HP, "Low Latency, High Performance",
2037         "low-latency-hp"},
2038     {GST_NV_ENCODER_PRESET_LOSSLESS_DEFAULT, "Lossless", "lossless"},
2039     {GST_NV_ENCODER_PRESET_LOSSLESS_HP, "Lossless, High Performance",
2040         "lossless-hp"},
2041     {0, NULL, NULL},
2042   };
2043
2044   if (g_once_init_enter (&preset_type)) {
2045     GType type = g_enum_register_static ("GstNvEncoderPreset", presets);
2046
2047     g_once_init_leave (&preset_type, type);
2048   }
2049
2050   return preset_type;
2051 }
2052
2053 void
2054 gst_nv_encoder_preset_to_guid (GstNvEncoderPreset preset, GUID * guid)
2055 {
2056   switch (preset) {
2057     case GST_NV_ENCODER_PRESET_DEFAULT:
2058       *guid = NV_ENC_PRESET_DEFAULT_GUID;
2059       break;
2060     case GST_NV_ENCODER_PRESET_HP:
2061       *guid = NV_ENC_PRESET_HP_GUID;
2062       break;
2063     case GST_NV_ENCODER_PRESET_HQ:
2064       *guid = NV_ENC_PRESET_HQ_GUID;
2065       break;
2066     case GST_NV_ENCODER_PRESET_LOW_LATENCY_DEFAULT:
2067       *guid = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
2068       break;
2069     case GST_NV_ENCODER_PRESET_LOW_LATENCY_HQ:
2070       *guid = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
2071       break;
2072     case GST_NV_ENCODER_PRESET_LOW_LATENCY_HP:
2073       *guid = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
2074       break;
2075     case GST_NV_ENCODER_PRESET_LOSSLESS_DEFAULT:
2076       *guid = NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
2077       break;
2078     case GST_NV_ENCODER_PRESET_LOSSLESS_HP:
2079       *guid = NV_ENC_PRESET_LOSSLESS_HP_GUID;
2080       break;
2081     default:
2082       break;
2083   }
2084
2085   *guid = NV_ENC_PRESET_DEFAULT_GUID;
2086 }
2087
2088 /**
2089  * GstNvEncoderRCMode:
2090  *
2091  * Since: 1.22
2092  */
2093 GType
2094 gst_nv_encoder_rc_mode_get_type (void)
2095 {
2096   static GType rc_mode_type = 0;
2097   static const GEnumValue rc_modes[] = {
2098     {GST_NV_ENCODER_RC_MODE_CONSTQP, "Constant Quantization", "cqp"},
2099     {GST_NV_ENCODER_RC_MODE_VBR, "Variable Bit Rate", "vbr"},
2100     {GST_NV_ENCODER_RC_MODE_CBR, "Constant Bit Rate", "cbr"},
2101     {GST_NV_ENCODER_RC_MODE_CBR_LOWDELAY_HQ,
2102         "Low-Delay CBR, High Quality", "cbr-ld-hq"},
2103     {GST_NV_ENCODER_RC_MODE_CBR_HQ, "CBR, High Quality (slower)", "cbr-hq"},
2104     {GST_NV_ENCODER_RC_MODE_VBR_HQ, "VBR, High Quality (slower)", "vbr-hq"},
2105     {0, NULL, NULL},
2106   };
2107
2108   if (g_once_init_enter (&rc_mode_type)) {
2109     GType type = g_enum_register_static ("GstNvEncoderRCMode", rc_modes);
2110
2111     g_once_init_leave (&rc_mode_type, type);
2112   }
2113
2114   return rc_mode_type;
2115 }
2116
2117 NV_ENC_PARAMS_RC_MODE
2118 gst_nv_encoder_rc_mode_to_native (GstNvEncoderRCMode rc_mode)
2119 {
2120   switch (rc_mode) {
2121     case GST_NV_ENCODER_RC_MODE_CONSTQP:
2122       return NV_ENC_PARAMS_RC_CONSTQP;
2123     case GST_NV_ENCODER_RC_MODE_VBR:
2124       return NV_ENC_PARAMS_RC_VBR;
2125     case GST_NV_ENCODER_RC_MODE_CBR:
2126       return NV_ENC_PARAMS_RC_CBR;
2127     case GST_NV_ENCODER_RC_MODE_CBR_LOWDELAY_HQ:
2128       return NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ;
2129     case GST_NV_ENCODER_RC_MODE_CBR_HQ:
2130       return NV_ENC_PARAMS_RC_CBR_HQ;
2131     case GST_NV_ENCODER_RC_MODE_VBR_HQ:
2132       return NV_ENC_PARAMS_RC_VBR_HQ;
2133     default:
2134       break;
2135   }
2136
2137   return NV_ENC_PARAMS_RC_VBR;
2138 }
2139
2140 const gchar *
2141 gst_nv_encoder_status_to_string (NVENCSTATUS status)
2142 {
2143 #define CASE(err) \
2144     case err: \
2145     return G_STRINGIFY (err);
2146
2147   switch (status) {
2148       CASE (NV_ENC_SUCCESS);
2149       CASE (NV_ENC_ERR_NO_ENCODE_DEVICE);
2150       CASE (NV_ENC_ERR_UNSUPPORTED_DEVICE);
2151       CASE (NV_ENC_ERR_INVALID_ENCODERDEVICE);
2152       CASE (NV_ENC_ERR_INVALID_DEVICE);
2153       CASE (NV_ENC_ERR_DEVICE_NOT_EXIST);
2154       CASE (NV_ENC_ERR_INVALID_PTR);
2155       CASE (NV_ENC_ERR_INVALID_EVENT);
2156       CASE (NV_ENC_ERR_INVALID_PARAM);
2157       CASE (NV_ENC_ERR_INVALID_CALL);
2158       CASE (NV_ENC_ERR_OUT_OF_MEMORY);
2159       CASE (NV_ENC_ERR_ENCODER_NOT_INITIALIZED);
2160       CASE (NV_ENC_ERR_UNSUPPORTED_PARAM);
2161       CASE (NV_ENC_ERR_LOCK_BUSY);
2162       CASE (NV_ENC_ERR_NOT_ENOUGH_BUFFER);
2163       CASE (NV_ENC_ERR_INVALID_VERSION);
2164       CASE (NV_ENC_ERR_MAP_FAILED);
2165       CASE (NV_ENC_ERR_NEED_MORE_INPUT);
2166       CASE (NV_ENC_ERR_ENCODER_BUSY);
2167       CASE (NV_ENC_ERR_EVENT_NOT_REGISTERD);
2168       CASE (NV_ENC_ERR_GENERIC);
2169       CASE (NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY);
2170       CASE (NV_ENC_ERR_UNIMPLEMENTED);
2171       CASE (NV_ENC_ERR_RESOURCE_REGISTER_FAILED);
2172       CASE (NV_ENC_ERR_RESOURCE_NOT_REGISTERED);
2173       CASE (NV_ENC_ERR_RESOURCE_NOT_MAPPED);
2174     default:
2175       break;
2176   }
2177 #undef CASE
2178
2179   return "Unknown";
2180 }
2181
2182 GstNvEncoderClassData *
2183 gst_nv_encoder_class_data_new (void)
2184 {
2185   GstNvEncoderClassData *data = g_new0 (GstNvEncoderClassData, 1);
2186   data->ref_count = 1;
2187
2188   return data;
2189 }
2190
2191 GstNvEncoderClassData *
2192 gst_nv_encoder_class_data_ref (GstNvEncoderClassData * cdata)
2193 {
2194   g_atomic_int_add (&cdata->ref_count, 1);
2195
2196   return cdata;
2197 }
2198
2199 void
2200 gst_nv_encoder_class_data_unref (GstNvEncoderClassData * cdata)
2201 {
2202   if (g_atomic_int_dec_and_test (&cdata->ref_count)) {
2203     gst_clear_caps (&cdata->sink_caps);
2204     gst_clear_caps (&cdata->src_caps);
2205     if (cdata->formats)
2206       g_list_free_full (cdata->formats, (GDestroyNotify) g_free);
2207     if (cdata->profiles)
2208       g_list_free_full (cdata->profiles, (GDestroyNotify) g_free);
2209     g_free (cdata);
2210   }
2211 }
2212
2213 void
2214 gst_nv_encoder_get_encoder_caps (gpointer session, const GUID * encode_guid,
2215     GstNvEncoderDeviceCaps * device_caps)
2216 {
2217   GstNvEncoderDeviceCaps dev_caps = { 0, };
2218   NV_ENC_CAPS_PARAM caps_param = { 0, };
2219   NVENCSTATUS status;
2220   GUID guid = *encode_guid;
2221
2222   GST_DEBUG_CATEGORY_INIT (gst_nv_encoder_debug, "nvencoder", 0, "nvencoder");
2223
2224   caps_param.version = gst_nvenc_get_caps_param_version ();
2225
2226 #define CHECK_CAPS(to_query,val,default_val) G_STMT_START { \
2227   gint _val; \
2228   caps_param.capsToQuery = to_query; \
2229   status = NvEncGetEncodeCaps (session, guid, &caps_param, \
2230       &_val); \
2231   if (status != NV_ENC_SUCCESS) { \
2232     GST_WARNING ("Unable to query %s, status: %" \
2233         GST_NVENC_STATUS_FORMAT, G_STRINGIFY (to_query), \
2234         GST_NVENC_STATUS_ARGS (status)); \
2235     val = default_val; \
2236   } else { \
2237     GST_DEBUG ("%s: %d", G_STRINGIFY (to_query), _val); \
2238     val = _val; \
2239   } \
2240 } G_STMT_END
2241
2242   CHECK_CAPS (NV_ENC_CAPS_NUM_MAX_BFRAMES, dev_caps.max_bframes, 0);
2243   CHECK_CAPS (NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES,
2244       dev_caps.ratecontrol_modes, NV_ENC_PARAMS_RC_VBR);
2245   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_FIELD_ENCODING, dev_caps.field_encoding, 0);
2246   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_MONOCHROME, dev_caps.monochrome, 0);
2247   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_FMO, dev_caps.fmo, 0);
2248   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_QPELMV, dev_caps.qpelmv, 0);
2249   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_BDIRECT_MODE, dev_caps.bdirect_mode, 0);
2250   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_CABAC, dev_caps.cabac, 0);
2251   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_ADAPTIVE_TRANSFORM,
2252       dev_caps.adaptive_transform, 0);
2253   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_STEREO_MVC, dev_caps.stereo_mvc, 0);
2254   CHECK_CAPS (NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS, dev_caps.temoral_layers, 0);
2255   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_HIERARCHICAL_PFRAMES,
2256       dev_caps.hierarchical_pframes, 0);
2257   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_HIERARCHICAL_BFRAMES,
2258       dev_caps.hierarchical_bframes, 0);
2259   CHECK_CAPS (NV_ENC_CAPS_LEVEL_MAX, dev_caps.level_max, 0);
2260   CHECK_CAPS (NV_ENC_CAPS_LEVEL_MIN, dev_caps.level_min, 0);
2261   CHECK_CAPS (NV_ENC_CAPS_SEPARATE_COLOUR_PLANE,
2262       dev_caps.separate_colour_plane, 0);
2263   CHECK_CAPS (NV_ENC_CAPS_WIDTH_MAX, dev_caps.width_max, 4096);
2264   CHECK_CAPS (NV_ENC_CAPS_HEIGHT_MAX, dev_caps.height_max, 4096);
2265   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_TEMPORAL_SVC, dev_caps.temporal_svc, 0);
2266   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE, dev_caps.dyn_res_change, 0);
2267   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE,
2268       dev_caps.dyn_bitrate_change, 0);
2269   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_FORCE_CONSTQP,
2270       dev_caps.dyn_force_constqp, 0);
2271   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_RCMODE_CHANGE,
2272       dev_caps.dyn_rcmode_change, 0);
2273   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_SUBFRAME_READBACK,
2274       dev_caps.subframe_readback, 0);
2275   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_CONSTRAINED_ENCODING,
2276       dev_caps.constrained_encoding, 0);
2277   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_INTRA_REFRESH, dev_caps.intra_refresh, 0);
2278   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE,
2279       dev_caps.custom_vbv_buf_size, 0);
2280   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYNAMIC_SLICE_MODE,
2281       dev_caps.dynamic_slice_mode, 0);
2282   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_REF_PIC_INVALIDATION,
2283       dev_caps.ref_pic_invalidation, 0);
2284   CHECK_CAPS (NV_ENC_CAPS_PREPROC_SUPPORT, dev_caps.preproc_support, 0);
2285   /* NOTE: Async is Windows only */
2286 #ifdef G_OS_WIN32
2287   CHECK_CAPS (NV_ENC_CAPS_ASYNC_ENCODE_SUPPORT,
2288       dev_caps.async_encoding_support, 0);
2289 #endif
2290   CHECK_CAPS (NV_ENC_CAPS_MB_NUM_MAX, dev_caps.mb_num_max, 0);
2291   CHECK_CAPS (NV_ENC_CAPS_MB_PER_SEC_MAX, dev_caps.mb_per_sec_max, 0);
2292   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_YUV444_ENCODE, dev_caps.yuv444_encode, 0);
2293   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE, dev_caps.lossless_encode, 0);
2294   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_SAO, dev_caps.sao, 0);
2295   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_MEONLY_MODE, dev_caps.meonly_mode, 0);
2296   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_LOOKAHEAD, dev_caps.lookahead, 0);
2297   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ, dev_caps.temporal_aq, 0);
2298   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_10BIT_ENCODE,
2299       dev_caps.supports_10bit_encode, 0);
2300   CHECK_CAPS (NV_ENC_CAPS_NUM_MAX_LTR_FRAMES, dev_caps.num_max_ltr_frames, 0);
2301   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION,
2302       dev_caps.weighted_prediction, 0);
2303   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE, dev_caps.bframe_ref_mode, 0);
2304   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_EMPHASIS_LEVEL_MAP,
2305       dev_caps.emphasis_level_map, 0);
2306   CHECK_CAPS (NV_ENC_CAPS_WIDTH_MIN, dev_caps.width_min, 16);
2307   CHECK_CAPS (NV_ENC_CAPS_HEIGHT_MIN, dev_caps.height_min, 16);
2308   CHECK_CAPS (NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES,
2309       dev_caps.multiple_ref_frames, 0);
2310 #undef CHECK_CAPS
2311
2312   *device_caps = dev_caps;
2313 }
2314
2315 void
2316 gst_nv_encoder_merge_device_caps (const GstNvEncoderDeviceCaps * a,
2317     const GstNvEncoderDeviceCaps * b, GstNvEncoderDeviceCaps * merged)
2318 {
2319   GstNvEncoderDeviceCaps caps;
2320
2321 #define SELECT_MAX(value) G_STMT_START { \
2322   caps.value = MAX (a->value, b->value); \
2323 } G_STMT_END
2324
2325 #define SELECT_MIN(value) G_STMT_START { \
2326   caps.value = MAX (MIN (a->value, b->value), 1); \
2327 } G_STMT_END
2328
2329   SELECT_MAX (max_bframes);
2330   SELECT_MAX (ratecontrol_modes);
2331   SELECT_MAX (field_encoding);
2332   SELECT_MAX (monochrome);
2333   SELECT_MAX (fmo);
2334   SELECT_MAX (qpelmv);
2335   SELECT_MAX (bdirect_mode);
2336   SELECT_MAX (cabac);
2337   SELECT_MAX (adaptive_transform);
2338   SELECT_MAX (stereo_mvc);
2339   SELECT_MAX (temoral_layers);
2340   SELECT_MAX (hierarchical_pframes);
2341   SELECT_MAX (hierarchical_bframes);
2342   SELECT_MAX (level_max);
2343   SELECT_MAX (level_min);
2344   SELECT_MAX (separate_colour_plane);
2345   SELECT_MAX (width_max);
2346   SELECT_MAX (height_max);
2347   SELECT_MAX (temporal_svc);
2348   SELECT_MAX (dyn_res_change);
2349   SELECT_MAX (dyn_bitrate_change);
2350   SELECT_MAX (dyn_force_constqp);
2351   SELECT_MAX (dyn_rcmode_change);
2352   SELECT_MAX (subframe_readback);
2353   SELECT_MAX (constrained_encoding);
2354   SELECT_MAX (intra_refresh);
2355   SELECT_MAX (custom_vbv_buf_size);
2356   SELECT_MAX (dynamic_slice_mode);
2357   SELECT_MAX (ref_pic_invalidation);
2358   SELECT_MAX (preproc_support);
2359   SELECT_MAX (async_encoding_support);
2360   SELECT_MAX (mb_num_max);
2361   SELECT_MAX (mb_per_sec_max);
2362   SELECT_MAX (yuv444_encode);
2363   SELECT_MAX (lossless_encode);
2364   SELECT_MAX (sao);
2365   SELECT_MAX (meonly_mode);
2366   SELECT_MAX (lookahead);
2367   SELECT_MAX (temporal_aq);
2368   SELECT_MAX (supports_10bit_encode);
2369   SELECT_MAX (num_max_ltr_frames);
2370   SELECT_MAX (weighted_prediction);
2371   SELECT_MAX (bframe_ref_mode);
2372   SELECT_MAX (emphasis_level_map);
2373   SELECT_MIN (width_min);
2374   SELECT_MIN (height_min);
2375   SELECT_MAX (multiple_ref_frames);
2376
2377 #undef SELECT_MAX
2378 #undef SELECT_MIN
2379
2380   *merged = caps;
2381 }