2 * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
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.
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.
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.
24 #include "gstnvencoder.h"
26 #include <gst/cuda/gstcudautils.h>
27 #include <gst/cuda/gstcudamemory.h>
28 #include <gst/cuda/gstcudabufferpool.h>
31 #ifdef GST_CUDA_HAS_D3D
32 #include <gst/d3d11/gstd3d11.h>
39 using namespace Microsoft::WRL;
43 GST_DEBUG_CATEGORY_STATIC (gst_nv_encoder_debug);
44 #define GST_CAT_DEFAULT gst_nv_encoder_debug
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 ()); \
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)); \
58 struct _GstNvEncoderPrivate
60 GstCudaContext *context;
63 #ifdef GST_CUDA_HAS_D3D
64 GstD3D11Device *device;
68 GstNvEncoderDeviceMode subclass_device_mode;
69 GstNvEncoderDeviceMode selected_device_mode;
70 gint64 dxgi_adapter_luid;
73 NV_ENC_INITIALIZE_PARAMS init_params;
77 GstVideoCodecState *input_state;
79 GstBufferPool *internal_pool;
81 GstClockTime dts_offset;
83 /* Array of GstNvEncoderTask, holding ownership */
92 GRecMutex context_lock;
94 GThread *encoding_thread;
96 GstFlowReturn last_flow;
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);
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,
116 static gboolean gst_nv_encoder_src_query (GstVideoEncoder * encoder,
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);
129 gst_nv_encoder_class_init (GstNvEncoderClass * klass)
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);
135 object_class->finalize = gst_nv_encoder_finalize;
137 element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_encoder_set_context);
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);
152 GST_DEBUG_CATEGORY_INIT (gst_nv_encoder_debug, "nvencoder", 0, "nvencoder");
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);
162 gst_nv_encoder_init (GstNvEncoder * self)
164 GstNvEncoderPrivate *priv;
166 self->priv = priv = (GstNvEncoderPrivate *)
167 gst_nv_encoder_get_instance_private (self);
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);
173 g_queue_init (&priv->free_tasks);
174 g_queue_init (&priv->output_tasks);
176 g_mutex_init (&priv->lock);
177 g_cond_init (&priv->cond);
179 g_rec_mutex_init (&priv->context_lock);
181 gst_video_encoder_set_min_pts (GST_VIDEO_ENCODER (self),
182 GST_SECOND * 60 * 60 * 1000);
186 gst_nv_encoder_finalize (GObject * object)
188 GstNvEncoder *self = GST_NV_ENCODER (object);
189 GstNvEncoderPrivate *priv = self->priv;
191 g_array_unref (priv->task_pool);
193 g_mutex_clear (&priv->lock);
194 g_cond_clear (&priv->cond);
196 g_rec_mutex_clear (&priv->context_lock);
198 G_OBJECT_CLASS (parent_class)->finalize (object);
202 gst_nv_encoder_set_context (GstElement * element, GstContext * context)
204 GstNvEncoder *self = GST_NV_ENCODER (element);
205 GstNvEncoderPrivate *priv = self->priv;
207 g_rec_mutex_lock (&priv->context_lock);
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);
216 case GST_NV_ENCODER_DEVICE_CUDA:
217 gst_cuda_handle_set_context (element, context, priv->cuda_device_id,
224 g_rec_mutex_unlock (&priv->context_lock);
226 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
230 gst_nv_encoder_reset (GstNvEncoder * self)
232 GstNvEncoderPrivate *priv = self->priv;
234 GST_LOG_OBJECT (self, "Reset");
236 g_array_set_size (priv->task_pool, 0);
238 if (priv->internal_pool) {
239 gst_buffer_pool_set_active (priv->internal_pool, FALSE);
240 gst_clear_object (&priv->internal_pool);
244 NvEncDestroyEncoder (priv->session);
245 priv->session = NULL;
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;
255 g_queue_clear (&priv->free_tasks);
256 g_queue_clear (&priv->output_tasks);
258 priv->last_flow = GST_FLOW_OK;
264 gst_nv_encoder_device_lock (GstNvEncoder * self)
266 GstNvEncoderPrivate *priv = self->priv;
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);
275 case GST_NV_ENCODER_DEVICE_CUDA:
276 ret = gst_cuda_context_push (priv->context);
286 gst_nv_encoder_device_unlock (GstNvEncoder * self)
288 GstNvEncoderPrivate *priv = self->priv;
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);
297 case GST_NV_ENCODER_DEVICE_CUDA:
298 ret = gst_cuda_context_pop (nullptr);
308 gst_nv_encoder_get_free_task (GstNvEncoder * self, GstNvEncoderTask ** task,
309 gboolean check_last_flow)
311 GstNvEncoderPrivate *priv = self->priv;
312 GstFlowReturn ret = GST_FLOW_OK;
313 GstNvEncoderTask *free_task = NULL;
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);
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);
328 ret = priv->last_flow;
329 if (ret != GST_FLOW_OK && free_task) {
330 g_queue_push_tail (&priv->free_tasks, free_task);
334 while ((free_task = (GstNvEncoderTask *)
335 g_queue_pop_head (&priv->free_tasks)) == NULL)
336 g_cond_wait (&priv->cond, &priv->lock);
338 GST_NV_ENCODER_UNLOCK (self);
346 gst_nv_encoder_drain (GstNvEncoder * self, gboolean locked)
348 GstNvEncoderPrivate *priv = self->priv;
349 NV_ENC_PIC_PARAMS pic_params = { 0, };
351 GstNvEncoderTask *task;
353 if (!priv->session || !priv->encoding_thread)
356 GST_DEBUG_OBJECT (self, "Drain");
359 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
361 gst_nv_encoder_get_free_task (self, &task, FALSE);
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;
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));
375 if (task->event_handle) {
376 SetEvent (task->event_handle);
380 gst_nv_encoder_device_unlock (self);
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);
387 g_clear_pointer (&priv->encoding_thread, g_thread_join);
388 gst_nv_encoder_reset (self);
391 GST_VIDEO_ENCODER_STREAM_LOCK (self);
396 #ifdef GST_CUDA_HAS_D3D
398 gst_nv_encoder_open_d3d11_device (GstNvEncoder * self)
400 GstNvEncoderPrivate *priv = self->priv;
401 ComPtr < ID3D10Multithread > multi_thread;
402 ID3D11Device *device_handle;
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");
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);
420 multi_thread->SetMultithreadProtected (TRUE);
427 gst_nv_encoder_open (GstVideoEncoder * encoder)
429 GstNvEncoder *self = GST_NV_ENCODER (encoder);
430 GstNvEncoderPrivate *priv = self->priv;
432 switch (priv->selected_device_mode) {
433 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
434 /* Will open GPU later */
436 #ifdef GST_CUDA_HAS_D3D
437 case GST_NV_ENCODER_DEVICE_D3D11:
438 return gst_nv_encoder_open_d3d11_device (self);
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");
448 g_assert_not_reached ();
456 gst_nv_encoder_close (GstVideoEncoder * encoder)
458 GstNvEncoder *self = GST_NV_ENCODER (encoder);
459 GstNvEncoderPrivate *priv = self->priv;
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);
471 gst_nv_encoder_stop (GstVideoEncoder * encoder)
473 GstNvEncoder *self = GST_NV_ENCODER (encoder);
474 GstNvEncoderPrivate *priv = self->priv;
476 GST_DEBUG_OBJECT (self, "Stop");
478 gst_nv_encoder_drain (self, FALSE);
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);
485 priv->selected_device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
488 g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
494 gst_nv_encoder_handle_context_query (GstNvEncoder * self, GstQuery * query)
496 GstNvEncoderPrivate *priv = self->priv;
497 gboolean ret = FALSE;
499 g_rec_mutex_lock (&priv->context_lock);
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);
508 case GST_NV_ENCODER_DEVICE_CUDA:
509 ret = gst_cuda_handle_context_query (GST_ELEMENT (self),
510 query, priv->context);
516 g_rec_mutex_unlock (&priv->context_lock);
522 gst_nv_encoder_sink_query (GstVideoEncoder * encoder, GstQuery * query)
524 GstNvEncoder *self = GST_NV_ENCODER (encoder);
526 switch (GST_QUERY_TYPE (query)) {
527 case GST_QUERY_CONTEXT:
528 if (gst_nv_encoder_handle_context_query (self, query))
535 return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
539 gst_nv_encoder_src_query (GstVideoEncoder * encoder, GstQuery * query)
541 GstNvEncoder *self = GST_NV_ENCODER (encoder);
543 switch (GST_QUERY_TYPE (query)) {
544 case GST_QUERY_CONTEXT:
545 if (gst_nv_encoder_handle_context_query (self, query))
552 return GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
556 gst_nv_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
558 GstNvEncoder *self = GST_NV_ENCODER (encoder);
559 GstNvEncoderPrivate *priv = self->priv;
561 GstBufferPool *pool = NULL;
564 GstStructure *config;
565 GstCapsFeatures *features;
568 gst_query_parse_allocation (query, &caps, NULL);
570 GST_WARNING_OBJECT (self, "null caps in query");
574 if (!gst_video_info_from_caps (&info, caps)) {
575 GST_WARNING_OBJECT (self, "Failed to convert caps into info");
579 features = gst_caps_get_features (caps, 0);
580 min_buffers = gst_nv_encoder_get_task_size (self);
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);
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);
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);
606 g_assert_not_reached ();
611 pool = gst_video_buffer_pool_new ();
613 config = gst_buffer_pool_get_config (pool);
614 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
617 size = GST_VIDEO_INFO_SIZE (&info);
618 gst_buffer_pool_config_set_params (config, caps, size, min_buffers, 0);
620 if (!gst_buffer_pool_set_config (pool, config)) {
621 GST_WARNING_OBJECT (self, "Failed to set pool config");
622 gst_object_unref (pool);
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);
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);
637 /* called with lock */
639 gst_nv_encoder_task_reset (GstNvEncoder * self, GstNvEncoderTask * task)
641 GstNvEncoderPrivate *priv = self->priv;
647 gst_nv_encoder_device_lock (self);
649 NvEncUnmapInputResource (priv->session,
650 task->mapped_resource.mappedResource);
651 NvEncUnregisterResource (priv->session,
652 task->register_resource.registeredResource);
654 gst_nv_encoder_device_unlock (self);
656 gst_buffer_unmap (task->buffer, &task->map_info);
657 gst_clear_buffer (&task->buffer);
660 if (task->event_handle)
661 ResetEvent (task->event_handle);
664 task->is_eos = FALSE;
666 g_queue_push_head (&priv->free_tasks, task);
670 gst_nv_encoder_create_event_handle (GstNvEncoder * self, gpointer session,
671 gpointer * event_handle)
674 NV_ENC_EVENT_PARAMS event_params = { 0, };
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);
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);
689 *event_handle = event_params.completionEvent;
696 gst_d3d11_encoder_wait_for_event_handle (GstNvEncoder * self,
697 gpointer event_handle)
700 /* NVCODEC SDK uses 20s */
701 if (WaitForSingleObject (event_handle, 20000) == WAIT_FAILED) {
702 GST_ERROR_OBJECT (self, "Failed to wait for completion event");
711 gst_nv_encoder_destroy_event_handle (GstNvEncoder * self, gpointer session,
712 gpointer event_handle)
715 NV_ENC_EVENT_PARAMS event_params = { 0, };
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);
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));
732 gst_nv_encoder_task_clear (GstNvEncoderTask * task)
735 GstNvEncoderPrivate *priv;
740 self = task->encoder;
744 gst_nv_encoder_device_lock (self);
746 NvEncUnmapInputResource (priv->session,
747 task->mapped_resource.mappedResource);
748 NvEncUnregisterResource (priv->session,
749 task->register_resource.registeredResource);
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,
760 gst_nv_encoder_device_unlock (self);
764 gst_buffer_unmap (task->buffer, &task->map_info);
765 gst_clear_buffer (&task->buffer);
768 memset (task, 0, sizeof (GstNvEncoderTask));
771 static NV_ENC_PIC_STRUCT
772 gst_nv_encoder_get_pic_struct (GstNvEncoder * self, GstBuffer * buffer)
774 GstNvEncoderPrivate *priv = self->priv;
775 GstVideoInfo *info = &priv->input_state->info;
777 if (!GST_VIDEO_INFO_IS_INTERLACED (info))
778 return NV_ENC_PIC_STRUCT_FRAME;
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;
785 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
786 return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
788 return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
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;
795 case GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST:
796 return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
802 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
803 return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
805 return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
809 gst_nv_encoder_encode_frame (GstNvEncoder * self,
810 GstVideoCodecFrame * frame, GstNvEncoderTask * task)
812 GstNvEncoderPrivate *priv = self->priv;
813 NV_ENC_PIC_PARAMS pic_params = { 0, };
815 guint retry_count = 0;
816 const guint retry_threshold = 100;
818 pic_params.version = gst_nvenc_get_pic_params_version ();
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;
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;
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;
843 gst_nv_encoder_device_lock (self);
844 status = NvEncEncodePicture (priv->session, &pic_params);
845 gst_nv_encoder_device_unlock (self);
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,
853 /* Magic number 1ms */
857 GST_ERROR_OBJECT (self, "GPU is keep busy, give up");
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);
872 return GST_FLOW_ERROR;
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);
883 static GstVideoCodecFrame *
884 gst_nv_encoder_find_output_frame (GstVideoEncoder * self,
885 GstNvEncoderTask * task)
887 GList *frames, *iter;
888 GstVideoCodecFrame *ret = NULL;
890 frames = gst_video_encoder_get_frames (self);
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);
907 gst_video_codec_frame_ref (ret);
910 g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
916 gst_nv_encoder_thread_func (GstNvEncoder * self)
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;
924 NV_ENC_LOCK_BITSTREAM bitstream = { 0, };
926 GstVideoCodecFrame *frame;
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);
934 GST_NV_ENCODER_UNLOCK (self);
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"));
945 GST_INFO_OBJECT (self, "Got EOS packet");
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);
955 frame = gst_nv_encoder_find_output_frame (encoder, task);
957 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
958 ("Failed to find associated codec frame"));
962 if (!gst_nv_encoder_device_lock (self)) {
963 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
964 ("Failed to lock device"));
968 bitstream.version = gst_nvenc_get_lock_bitstream_version ();
969 bitstream.outputBitstream = task->output_ptr;
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)));
980 if (klass->create_output_buffer) {
981 frame->output_buffer = klass->create_output_buffer (self, &bitstream);
983 frame->output_buffer =
984 gst_buffer_new_memdup (bitstream.bitstreamBufferPtr,
985 bitstream.bitstreamSizeInBytes);
988 GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_MARKER);
990 if (bitstream.pictureType == NV_ENC_PIC_TYPE_IDR)
991 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
993 NvEncUnlockBitstream (priv->session, task->output_ptr);
994 gst_nv_encoder_device_unlock (self);
996 frame->dts = frame->pts - priv->dts_offset;
997 frame->pts = bitstream.outputTimeStamp;
998 frame->duration = bitstream.outputDuration;
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));
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);
1012 if (ret != GST_FLOW_OK) {
1013 GST_INFO_OBJECT (self, "Push returned %s", gst_flow_get_name (ret));
1020 GST_INFO_OBJECT (self, "Exiting thread");
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);
1038 gst_nv_encoder_calculate_task_pool_size (GstNvEncoder * self,
1039 NV_ENC_CONFIG * config)
1043 /* At least 4 surfaces are required as documented by Nvidia Encoder guide */
1046 /* lookahead depth */
1047 num_tasks += config->rcParams.lookaheadDepth;
1050 num_tasks += MAX (0, config->frameIntervalP - 1) + 1;
1052 GST_DEBUG_OBJECT (self, "Calculated task pool size: %d "
1053 "(lookahead %d, frameIntervalP %d)",
1054 num_tasks, config->rcParams.lookaheadDepth, config->frameIntervalP);
1060 gst_nv_encoder_open_encode_session (GstNvEncoder * self, gpointer * session)
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 ();
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);
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);
1081 g_assert_not_reached ();
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));
1095 #ifdef GST_CUDA_HAS_D3D
1096 static GstBufferPool *
1097 gst_nv_encoder_create_d3d11_pool (GstNvEncoder * self,
1098 GstVideoCodecState * state)
1100 GstNvEncoderPrivate *priv = self->priv;
1101 GstStructure *config;
1102 GstBufferPool *pool = NULL;
1103 GstD3D11AllocationParams *params;
1105 params = gst_d3d11_allocation_params_new (priv->device, &state->info,
1106 GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, D3D11_RESOURCE_MISC_SHARED);
1108 pool = gst_d3d11_buffer_pool_new (priv->device);
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);
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);
1123 if (!gst_buffer_pool_set_active (pool, TRUE)) {
1124 GST_ERROR_OBJECT (self, "Failed to set active");
1125 gst_object_unref (pool);
1133 static GstBufferPool *
1134 gst_nv_encoder_create_pool (GstNvEncoder * self, GstVideoCodecState * state)
1136 GstNvEncoderPrivate *priv = self->priv;
1137 GstStructure *config;
1138 GstBufferPool *pool = NULL;
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);
1146 case GST_NV_ENCODER_DEVICE_CUDA:
1147 pool = gst_cuda_buffer_pool_new (priv->context);
1150 g_assert_not_reached ();
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);
1164 if (!gst_buffer_pool_set_active (pool, TRUE)) {
1165 GST_ERROR_OBJECT (self, "Failed to set active");
1166 gst_object_unref (pool);
1174 gst_nv_encoder_init_session (GstNvEncoder * self, GstBuffer * in_buf)
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;
1181 guint task_pool_size;
1183 GstClockTime frame_duration, min_latency, max_latency;
1186 gst_nv_encoder_reset (self);
1188 memset (&priv->init_params, 0, sizeof (NV_ENC_INITIALIZE_PARAMS));
1189 memset (&priv->config, 0, sizeof (NV_ENC_CONFIG));
1191 if (priv->selected_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1192 GstNvEncoderDeviceData data;
1196 GST_DEBUG_OBJECT (self, "Unknown device mode, open session later");
1200 if (!klass->select_device (self, info, in_buf, &data)) {
1201 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1202 ("Failed to select device mode"));
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,
1211 g_assert (data.device_mode == GST_NV_ENCODER_DEVICE_CUDA ||
1212 data.device_mode == GST_NV_ENCODER_DEVICE_D3D11);
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;
1227 ret = gst_nv_encoder_open (GST_VIDEO_ENCODER (self));
1228 g_rec_mutex_unlock (&priv->context_lock);
1231 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1232 ("Failed to open device"));
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"));
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);
1250 if (!gst_nv_encoder_open_encode_session (self, &priv->session)) {
1251 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1252 ("Failed to open session"));
1256 if (!klass->set_format (self, state, priv->session, &priv->init_params,
1258 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), ("Failed to set format"));
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)));
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);
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));
1286 task_pool_size = gst_nv_encoder_calculate_task_pool_size (self,
1288 g_array_set_size (priv->task_pool, task_pool_size);
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);
1295 task->encoder = self;
1297 buffer_params.version = gst_nvenc_get_create_bitstream_buffer_version ();
1298 status = NvEncCreateBitstreamBuffer (priv->session, &buffer_params);
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)));
1307 task->output_ptr = buffer_params.bitstreamBuffer;
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"));
1318 g_queue_push_tail (&priv->free_tasks, task);
1320 gst_nv_encoder_device_unlock (self);
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);
1329 priv->encoding_thread = g_thread_new ("GstNvEncoderThread",
1330 (GThreadFunc) gst_nv_encoder_thread_func, self);
1332 if (info->fps_n > 0 && info->fps_d > 0) {
1333 fps_n = info->fps_n;
1334 fps_d = info->fps_d;
1340 frame_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
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);
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);
1356 gst_nv_encoder_device_unlock (self);
1358 gst_nv_encoder_reset (self);
1364 gst_nv_encoder_reconfigure_session (GstNvEncoder * self)
1366 GstNvEncoderPrivate *priv = self->priv;
1367 NV_ENC_RECONFIGURE_PARAMS params = { 0, };
1370 if (!priv->session) {
1371 GST_WARNING_OBJECT (self,
1372 "Encoding session was not configured, open session");
1373 gst_nv_encoder_drain (self, TRUE);
1375 return gst_nv_encoder_init_session (self, nullptr);
1378 params.version = gst_nvenc_get_reconfigure_params_version ();
1379 params.reInitEncodeParams = priv->init_params;
1380 params.reInitEncodeParams.encodeConfig = &priv->config;
1382 status = NvEncReconfigureEncoder (priv->session, ¶ms);
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);
1388 return gst_nv_encoder_init_session (self, nullptr);
1395 gst_nv_encoder_set_format (GstVideoEncoder * encoder,
1396 GstVideoCodecState * state)
1398 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1399 GstNvEncoderPrivate *priv = self->priv;
1401 gst_nv_encoder_drain (self, TRUE);
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;
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;
1411 return gst_nv_encoder_init_session (self, nullptr);
1414 static NV_ENC_BUFFER_FORMAT
1415 gst_nv_encoder_get_buffer_format (GstNvEncoder * self, GstVideoFormat 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;
1427 GST_ERROR_OBJECT (self, "Unexpected format %s",
1428 gst_video_format_to_string (format));
1429 g_assert_not_reached ();
1433 return NV_ENC_BUFFER_FORMAT_UNDEFINED;
1436 static GstFlowReturn
1437 gst_nv_encoder_copy_system (GstNvEncoder * self, const GstVideoInfo * info,
1438 GstBuffer * buffer, gpointer session, GstNvEncoderTask * task)
1441 GstVideoFrame frame;
1443 NV_ENC_BUFFER_FORMAT 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;
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;
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;
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;
1470 task->input_buffer = input_buffer;
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;
1483 dst_data = (guint8 *) task->lk_input_buffer.bufferDataPtr;
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);
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;
1499 NvEncUnlockInputBuffer (session, task->input_buffer.inputBuffer);
1500 gst_video_frame_unmap (&frame);
1505 static GstFlowReturn
1506 gst_nv_encoder_prepare_task_input_cuda (GstNvEncoder * self,
1507 const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1508 GstNvEncoderTask * task)
1510 GstNvEncoderPrivate *priv = self->priv;
1512 GstCudaMemory *cmem;
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);
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);
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);
1533 return GST_FLOW_ERROR;
1536 cmem = (GstCudaMemory *) gst_buffer_peek_memory (task->buffer, 0);
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;
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));
1555 gst_buffer_unmap (task->buffer, &task->map_info);
1556 gst_clear_buffer (&task->buffer);
1558 return GST_FLOW_ERROR;
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);
1571 gst_buffer_unmap (task->buffer, &task->map_info);
1572 gst_clear_buffer (&task->buffer);
1574 return GST_FLOW_ERROR;
1580 #ifdef GST_CUDA_HAS_D3D
1582 gst_nv_encoder_copy_d3d11 (GstNvEncoder * self,
1583 GstBuffer * src_buffer, GstBufferPool * pool, gboolean shared)
1585 GstNvEncoderPrivate *priv = self->priv;
1586 D3D11_TEXTURE2D_DESC src_desc, dst_desc;
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;
1596 ComPtr < IDXGIResource > dxgi_resource;
1597 ComPtr < ID3D11Texture2D > shared_texture;
1598 HANDLE shared_handle;
1599 GstD3D11Device *device;
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");
1608 src_mem = gst_buffer_peek_memory (src_buffer, 0);
1609 dst_mem = gst_buffer_peek_memory (dst_buffer, 0);
1611 device = GST_D3D11_MEMORY_CAST (src_mem)->device;
1613 device_handle = gst_d3d11_device_get_device_handle (device);
1614 device_context = gst_d3d11_device_get_device_context_handle (device);
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);
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);
1631 src_tex = (ID3D11Texture2D *) src_info.data;
1632 dst_tex = (ID3D11Texture2D *) dst_info.data;
1634 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (src_mem),
1636 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (dst_mem),
1639 gst_d3d11_memory_get_subresource_index (GST_D3D11_MEMORY_CAST (src_mem));
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);
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",
1656 hr = device_handle->OpenSharedResource (shared_handle,
1657 IID_PPV_ARGS (&shared_texture));
1659 if (!gst_d3d11_result (hr, device)) {
1660 GST_ERROR_OBJECT (self, "Failed to get shared texture, hr: 0x%x",
1665 dst_tex = shared_texture.Get ();
1672 src_box.right = MIN (src_desc.Width, dst_desc.Width);
1673 src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
1676 if (priv->fence && priv->fence->device != device)
1677 gst_clear_d3d11_fence (&priv->fence);
1680 priv->fence = gst_d3d11_device_create_fence (device);
1683 GST_ERROR_OBJECT (self, "Couldn't crete fence");
1687 gst_d3d11_device_lock (device);
1690 device_context->CopySubresourceRegion (dst_tex, 0,
1691 0, 0, 0, src_tex, subresource_idx, &src_box);
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);
1702 gst_d3d11_device_unlock (device);
1705 gst_memory_unmap (dst_mem, &dst_info);
1706 gst_memory_unmap (src_mem, &src_info);
1711 gst_memory_unmap (dst_mem, &dst_info);
1712 gst_memory_unmap (src_mem, &src_info);
1713 gst_buffer_unref (dst_buffer);
1719 gst_nv_encoder_upload_d3d11_frame (GstNvEncoder * self,
1720 const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
1722 GstD3D11Memory *dmem;
1723 D3D11_TEXTURE2D_DESC desc;
1725 dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
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);
1733 GST_TRACE_OBJECT (self, "Use input buffer without copy");
1735 return gst_buffer_ref (buffer);
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)
1743 GstNvEncoderPrivate *priv = self->priv;
1745 GstD3D11Memory *dmem;
1746 D3D11_TEXTURE2D_DESC desc;
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);
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);
1760 dmem = GST_D3D11_MEMORY_CAST (mem);
1761 if (dmem->device != priv->device) {
1762 gint64 adapter_luid;
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);
1769 GST_LOG_OBJECT (self, "Different device, system copy");
1770 return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1775 task->buffer = gst_nv_encoder_upload_d3d11_frame (self, info, buffer, pool);
1777 if (!task->buffer) {
1778 GST_ERROR_OBJECT (self, "Failed to upload buffer");
1779 return GST_FLOW_ERROR;
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);
1787 return GST_FLOW_ERROR;
1790 dmem = (GstD3D11Memory *) gst_buffer_peek_memory (task->buffer, 0);
1791 gst_d3d11_memory_get_texture_desc (dmem, &desc);
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;
1801 case DXGI_FORMAT_P010:
1802 task->register_resource.bufferFormat = NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
1805 GST_ERROR_OBJECT (self, "Unexpected DXGI format %d", desc.Format);
1806 g_assert_not_reached ();
1807 return GST_FLOW_ERROR;
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);
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));
1820 gst_buffer_unmap (task->buffer, &task->map_info);
1821 gst_clear_buffer (&task->buffer);
1823 return GST_FLOW_ERROR;
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);
1836 gst_buffer_unmap (task->buffer, &task->map_info);
1837 gst_clear_buffer (&task->buffer);
1839 return GST_FLOW_ERROR;
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)
1851 GstNvEncoderPrivate *priv = self->priv;
1852 GstFlowReturn ret = GST_FLOW_ERROR;
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);
1861 case GST_NV_ENCODER_DEVICE_CUDA:
1862 ret = gst_nv_encoder_prepare_task_input_cuda (self, info, buffer,
1866 g_assert_not_reached ();
1873 static GstFlowReturn
1874 gst_nv_encoder_handle_frame (GstVideoEncoder * encoder,
1875 GstVideoCodecFrame * frame)
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;
1885 GST_TRACE_OBJECT (self, "Handle frame");
1887 GST_NV_ENCODER_LOCK (self);
1888 ret = priv->last_flow;
1889 GST_NV_ENCODER_UNLOCK (self);
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);
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);
1902 return GST_FLOW_NOT_NEGOTIATED;
1905 reconfig = klass->check_reconfigure (self, &priv->config);
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;
1913 case GST_NV_ENCODER_RECONFIGURE_FULL:
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;
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);
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);
1941 return GST_FLOW_ERROR;
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);
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);
1955 gst_video_encoder_finish_frame (encoder, frame);
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);
1968 gst_video_codec_frame_unref (frame);
1973 static GstFlowReturn
1974 gst_nv_encoder_finish (GstVideoEncoder * encoder)
1976 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1978 GST_DEBUG_OBJECT (self, "Finish");
1980 gst_nv_encoder_drain (self, TRUE);
1986 gst_nv_encoder_flush (GstVideoEncoder * encoder)
1988 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1989 GstNvEncoderPrivate *priv = self->priv;
1991 GST_DEBUG_OBJECT (self, "Flush");
1993 gst_nv_encoder_drain (self, TRUE);
1995 priv->last_flow = GST_FLOW_OK;
2001 gst_nv_encoder_get_task_size (GstNvEncoder * encoder)
2003 g_return_val_if_fail (GST_IS_NV_ENCODER (encoder), 0);
2005 return encoder->priv->task_pool->len;
2009 gst_nv_encoder_set_device_mode (GstNvEncoder * encoder,
2010 GstNvEncoderDeviceMode mode, guint cuda_device_id, gint64 adapter_luid)
2012 GstNvEncoderPrivate *priv = encoder->priv;
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;
2021 * GstNvEncoderPreset:
2026 gst_nv_encoder_preset_get_type (void)
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",
2036 {GST_NV_ENCODER_PRESET_LOW_LATENCY_HP, "Low Latency, High Performance",
2038 {GST_NV_ENCODER_PRESET_LOSSLESS_DEFAULT, "Lossless", "lossless"},
2039 {GST_NV_ENCODER_PRESET_LOSSLESS_HP, "Lossless, High Performance",
2044 if (g_once_init_enter (&preset_type)) {
2045 GType type = g_enum_register_static ("GstNvEncoderPreset", presets);
2047 g_once_init_leave (&preset_type, type);
2054 gst_nv_encoder_preset_to_guid (GstNvEncoderPreset preset, GUID * guid)
2057 case GST_NV_ENCODER_PRESET_DEFAULT:
2058 *guid = NV_ENC_PRESET_DEFAULT_GUID;
2060 case GST_NV_ENCODER_PRESET_HP:
2061 *guid = NV_ENC_PRESET_HP_GUID;
2063 case GST_NV_ENCODER_PRESET_HQ:
2064 *guid = NV_ENC_PRESET_HQ_GUID;
2066 case GST_NV_ENCODER_PRESET_LOW_LATENCY_DEFAULT:
2067 *guid = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
2069 case GST_NV_ENCODER_PRESET_LOW_LATENCY_HQ:
2070 *guid = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
2072 case GST_NV_ENCODER_PRESET_LOW_LATENCY_HP:
2073 *guid = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
2075 case GST_NV_ENCODER_PRESET_LOSSLESS_DEFAULT:
2076 *guid = NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
2078 case GST_NV_ENCODER_PRESET_LOSSLESS_HP:
2079 *guid = NV_ENC_PRESET_LOSSLESS_HP_GUID;
2085 *guid = NV_ENC_PRESET_DEFAULT_GUID;
2089 * GstNvEncoderRCMode:
2094 gst_nv_encoder_rc_mode_get_type (void)
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"},
2108 if (g_once_init_enter (&rc_mode_type)) {
2109 GType type = g_enum_register_static ("GstNvEncoderRCMode", rc_modes);
2111 g_once_init_leave (&rc_mode_type, type);
2114 return rc_mode_type;
2117 NV_ENC_PARAMS_RC_MODE
2118 gst_nv_encoder_rc_mode_to_native (GstNvEncoderRCMode 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;
2137 return NV_ENC_PARAMS_RC_VBR;
2141 gst_nv_encoder_status_to_string (NVENCSTATUS status)
2145 return G_STRINGIFY (err);
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);
2182 GstNvEncoderClassData *
2183 gst_nv_encoder_class_data_new (void)
2185 GstNvEncoderClassData *data = g_new0 (GstNvEncoderClassData, 1);
2186 data->ref_count = 1;
2191 GstNvEncoderClassData *
2192 gst_nv_encoder_class_data_ref (GstNvEncoderClassData * cdata)
2194 g_atomic_int_add (&cdata->ref_count, 1);
2200 gst_nv_encoder_class_data_unref (GstNvEncoderClassData * cdata)
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);
2206 g_list_free_full (cdata->formats, (GDestroyNotify) g_free);
2207 if (cdata->profiles)
2208 g_list_free_full (cdata->profiles, (GDestroyNotify) g_free);
2214 gst_nv_encoder_get_encoder_caps (gpointer session, const GUID * encode_guid,
2215 GstNvEncoderDeviceCaps * device_caps)
2217 GstNvEncoderDeviceCaps dev_caps = { 0, };
2218 NV_ENC_CAPS_PARAM caps_param = { 0, };
2220 GUID guid = *encode_guid;
2222 GST_DEBUG_CATEGORY_INIT (gst_nv_encoder_debug, "nvencoder", 0, "nvencoder");
2224 caps_param.version = gst_nvenc_get_caps_param_version ();
2226 #define CHECK_CAPS(to_query,val,default_val) G_STMT_START { \
2228 caps_param.capsToQuery = to_query; \
2229 status = NvEncGetEncodeCaps (session, guid, &caps_param, \
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; \
2237 GST_DEBUG ("%s: %d", G_STRINGIFY (to_query), _val); \
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 */
2287 CHECK_CAPS (NV_ENC_CAPS_ASYNC_ENCODE_SUPPORT,
2288 dev_caps.async_encoding_support, 0);
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);
2312 *device_caps = dev_caps;
2316 gst_nv_encoder_merge_device_caps (const GstNvEncoderDeviceCaps * a,
2317 const GstNvEncoderDeviceCaps * b, GstNvEncoderDeviceCaps * merged)
2319 GstNvEncoderDeviceCaps caps;
2321 #define SELECT_MAX(value) G_STMT_START { \
2322 caps.value = MAX (a->value, b->value); \
2325 #define SELECT_MIN(value) G_STMT_START { \
2326 caps.value = MAX (MIN (a->value, b->value), 1); \
2329 SELECT_MAX (max_bframes);
2330 SELECT_MAX (ratecontrol_modes);
2331 SELECT_MAX (field_encoding);
2332 SELECT_MAX (monochrome);
2334 SELECT_MAX (qpelmv);
2335 SELECT_MAX (bdirect_mode);
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);
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);