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;
61 #ifdef GST_CUDA_HAS_D3D
62 GstD3D11Device *device;
66 GstNvEncoderDeviceMode subclass_device_mode;
67 GstNvEncoderDeviceMode selected_device_mode;
68 gint64 dxgi_adapter_luid;
71 NV_ENC_INITIALIZE_PARAMS init_params;
75 GstVideoCodecState *input_state;
77 GstBufferPool *internal_pool;
79 GstClockTime dts_offset;
81 /* Array of GstNvEncoderTask, holding ownership */
90 GRecMutex context_lock;
92 GThread *encoding_thread;
94 GstFlowReturn last_flow;
102 #define gst_nv_encoder_parent_class parent_class
103 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstNvEncoder, gst_nv_encoder,
104 GST_TYPE_VIDEO_ENCODER);
106 static void gst_nv_encoder_finalize (GObject * object);
107 static void gst_nv_encoder_set_context (GstElement * element,
108 GstContext * context);
109 static gboolean gst_nv_encoder_open (GstVideoEncoder * encoder);
110 static gboolean gst_nv_encoder_close (GstVideoEncoder * encoder);
111 static gboolean gst_nv_encoder_stop (GstVideoEncoder * encoder);
112 static gboolean gst_nv_encoder_sink_query (GstVideoEncoder * encoder,
114 static gboolean gst_nv_encoder_src_query (GstVideoEncoder * encoder,
116 static gboolean gst_nv_encoder_propose_allocation (GstVideoEncoder *
117 encoder, GstQuery * query);
118 static gboolean gst_nv_encoder_set_format (GstVideoEncoder * encoder,
119 GstVideoCodecState * state);
120 static GstFlowReturn gst_nv_encoder_handle_frame (GstVideoEncoder *
121 encoder, GstVideoCodecFrame * frame);
122 static GstFlowReturn gst_nv_encoder_finish (GstVideoEncoder * encoder);
123 static gboolean gst_nv_encoder_flush (GstVideoEncoder * encoder);
124 static void gst_nv_encoder_task_clear (GstNvEncoderTask * task);
127 gst_nv_encoder_class_init (GstNvEncoderClass * klass)
129 GObjectClass *object_class = G_OBJECT_CLASS (klass);
130 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
131 GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
133 object_class->finalize = gst_nv_encoder_finalize;
135 element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_encoder_set_context);
137 videoenc_class->open = GST_DEBUG_FUNCPTR (gst_nv_encoder_open);
138 videoenc_class->close = GST_DEBUG_FUNCPTR (gst_nv_encoder_close);
139 videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_nv_encoder_stop);
140 videoenc_class->sink_query = GST_DEBUG_FUNCPTR (gst_nv_encoder_sink_query);
141 videoenc_class->src_query = GST_DEBUG_FUNCPTR (gst_nv_encoder_src_query);
142 videoenc_class->propose_allocation =
143 GST_DEBUG_FUNCPTR (gst_nv_encoder_propose_allocation);
144 videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_encoder_set_format);
145 videoenc_class->handle_frame =
146 GST_DEBUG_FUNCPTR (gst_nv_encoder_handle_frame);
147 videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_nv_encoder_finish);
148 videoenc_class->flush = GST_DEBUG_FUNCPTR (gst_nv_encoder_flush);
150 GST_DEBUG_CATEGORY_INIT (gst_nv_encoder_debug, "nvencoder", 0, "nvencoder");
152 gst_type_mark_as_plugin_api (GST_TYPE_NV_ENCODER, (GstPluginAPIFlags) 0);
153 gst_type_mark_as_plugin_api (GST_TYPE_NV_ENCODER_PRESET,
154 (GstPluginAPIFlags) 0);
155 gst_type_mark_as_plugin_api (GST_TYPE_NV_ENCODER_RC_MODE,
156 (GstPluginAPIFlags) 0);
160 gst_nv_encoder_init (GstNvEncoder * self)
162 GstNvEncoderPrivate *priv;
164 self->priv = priv = (GstNvEncoderPrivate *)
165 gst_nv_encoder_get_instance_private (self);
167 priv->task_pool = g_array_new (FALSE, TRUE, sizeof (GstNvEncoderTask));
168 g_array_set_clear_func (priv->task_pool,
169 (GDestroyNotify) gst_nv_encoder_task_clear);
171 g_queue_init (&priv->free_tasks);
172 g_queue_init (&priv->output_tasks);
174 g_mutex_init (&priv->lock);
175 g_cond_init (&priv->cond);
177 g_rec_mutex_init (&priv->context_lock);
179 gst_video_encoder_set_min_pts (GST_VIDEO_ENCODER (self),
180 GST_SECOND * 60 * 60 * 1000);
184 gst_nv_encoder_finalize (GObject * object)
186 GstNvEncoder *self = GST_NV_ENCODER (object);
187 GstNvEncoderPrivate *priv = self->priv;
189 g_array_unref (priv->task_pool);
191 g_mutex_clear (&priv->lock);
192 g_cond_clear (&priv->cond);
194 g_rec_mutex_clear (&priv->context_lock);
196 G_OBJECT_CLASS (parent_class)->finalize (object);
200 gst_nv_encoder_set_context (GstElement * element, GstContext * context)
202 GstNvEncoder *self = GST_NV_ENCODER (element);
203 GstNvEncoderPrivate *priv = self->priv;
205 g_rec_mutex_lock (&priv->context_lock);
207 switch (priv->selected_device_mode) {
208 #ifdef GST_CUDA_HAS_D3D
209 case GST_NV_ENCODER_DEVICE_D3D11:
210 gst_d3d11_handle_set_context_for_adapter_luid (element,
211 context, priv->dxgi_adapter_luid, &priv->device);
214 case GST_NV_ENCODER_DEVICE_CUDA:
215 gst_cuda_handle_set_context (element, context, priv->cuda_device_id,
222 g_rec_mutex_unlock (&priv->context_lock);
224 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
228 gst_nv_encoder_reset (GstNvEncoder * self)
230 GstNvEncoderPrivate *priv = self->priv;
232 GST_LOG_OBJECT (self, "Reset");
234 g_array_set_size (priv->task_pool, 0);
236 if (priv->internal_pool) {
237 gst_buffer_pool_set_active (priv->internal_pool, FALSE);
238 gst_clear_object (&priv->internal_pool);
242 NvEncDestroyEncoder (priv->session);
243 priv->session = NULL;
246 g_queue_clear (&priv->free_tasks);
247 g_queue_clear (&priv->output_tasks);
249 priv->last_flow = GST_FLOW_OK;
255 gst_nv_encoder_device_lock (GstNvEncoder * self)
257 GstNvEncoderPrivate *priv = self->priv;
260 switch (priv->selected_device_mode) {
261 #ifdef GST_CUDA_HAS_D3D
262 case GST_NV_ENCODER_DEVICE_D3D11:
263 gst_d3d11_device_lock (priv->device);
266 case GST_NV_ENCODER_DEVICE_CUDA:
267 ret = gst_cuda_context_push (priv->context);
277 gst_nv_encoder_device_unlock (GstNvEncoder * self)
279 GstNvEncoderPrivate *priv = self->priv;
282 switch (priv->selected_device_mode) {
283 #ifdef GST_CUDA_HAS_D3D
284 case GST_NV_ENCODER_DEVICE_D3D11:
285 gst_d3d11_device_unlock (priv->device);
288 case GST_NV_ENCODER_DEVICE_CUDA:
289 ret = gst_cuda_context_pop (nullptr);
299 gst_nv_encoder_get_free_task (GstNvEncoder * self, GstNvEncoderTask ** task,
300 gboolean check_last_flow)
302 GstNvEncoderPrivate *priv = self->priv;
303 GstFlowReturn ret = GST_FLOW_OK;
304 GstNvEncoderTask *free_task = NULL;
306 GST_NV_ENCODER_LOCK (self);
307 if (check_last_flow) {
308 if (priv->last_flow != GST_FLOW_OK) {
309 ret = priv->last_flow;
310 GST_NV_ENCODER_UNLOCK (self);
314 while (priv->last_flow == GST_FLOW_OK && (free_task = (GstNvEncoderTask *)
315 g_queue_pop_head (&priv->free_tasks)) == NULL) {
316 g_cond_wait (&priv->cond, &priv->lock);
319 ret = priv->last_flow;
320 if (ret != GST_FLOW_OK && free_task) {
321 g_queue_push_tail (&priv->free_tasks, free_task);
325 while ((free_task = (GstNvEncoderTask *)
326 g_queue_pop_head (&priv->free_tasks)) == NULL)
327 g_cond_wait (&priv->cond, &priv->lock);
329 GST_NV_ENCODER_UNLOCK (self);
337 gst_nv_encoder_drain (GstNvEncoder * self, gboolean locked)
339 GstNvEncoderPrivate *priv = self->priv;
340 NV_ENC_PIC_PARAMS pic_params = { 0, };
342 GstNvEncoderTask *task;
344 if (!priv->session || !priv->encoding_thread)
347 GST_DEBUG_OBJECT (self, "Drain");
350 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
352 gst_nv_encoder_get_free_task (self, &task, FALSE);
356 pic_params.version = gst_nvenc_get_pic_params_version ();
357 pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
358 pic_params.completionEvent = task->event_handle;
360 gst_nv_encoder_device_lock (self);
361 status = NvEncEncodePicture (priv->session, &pic_params);
362 if (status != NV_ENC_SUCCESS) {
363 GST_DEBUG_OBJECT (self, "Drain returned status %" GST_NVENC_STATUS_FORMAT,
364 GST_NVENC_STATUS_ARGS (status));
366 if (task->event_handle) {
367 SetEvent (task->event_handle);
371 gst_nv_encoder_device_unlock (self);
373 GST_NV_ENCODER_LOCK (self);
374 g_queue_push_tail (&priv->output_tasks, task);
375 g_cond_broadcast (&priv->cond);
376 GST_NV_ENCODER_UNLOCK (self);
378 g_clear_pointer (&priv->encoding_thread, g_thread_join);
379 gst_nv_encoder_reset (self);
382 GST_VIDEO_ENCODER_STREAM_LOCK (self);
387 #ifdef GST_CUDA_HAS_D3D
389 gst_nv_encoder_open_d3d11_device (GstNvEncoder * self)
391 GstNvEncoderPrivate *priv = self->priv;
392 ComPtr < ID3D10Multithread > multi_thread;
393 ID3D11Device *device_handle;
396 if (!gst_d3d11_ensure_element_data_for_adapter_luid (GST_ELEMENT (self),
397 priv->dxgi_adapter_luid, &priv->device)) {
398 GST_ERROR_OBJECT (self, "Cannot create d3d11device");
402 device_handle = gst_d3d11_device_get_device_handle (priv->device);
403 hr = device_handle->QueryInterface (IID_PPV_ARGS (&multi_thread));
404 if (!gst_d3d11_result (hr, priv->device)) {
405 GST_ERROR_OBJECT (self, "ID3D10Multithread interface is unavailable");
406 gst_clear_object (&priv->device);
411 multi_thread->SetMultithreadProtected (TRUE);
418 gst_nv_encoder_open (GstVideoEncoder * encoder)
420 GstNvEncoder *self = GST_NV_ENCODER (encoder);
421 GstNvEncoderPrivate *priv = self->priv;
423 switch (priv->selected_device_mode) {
424 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
425 /* Will open GPU later */
427 #ifdef GST_CUDA_HAS_D3D
428 case GST_NV_ENCODER_DEVICE_D3D11:
429 return gst_nv_encoder_open_d3d11_device (self);
431 case GST_NV_ENCODER_DEVICE_CUDA:
432 if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (encoder),
433 priv->cuda_device_id, &priv->context)) {
434 GST_ERROR_OBJECT (self, "failed to create CUDA context");
439 g_assert_not_reached ();
447 gst_nv_encoder_close (GstVideoEncoder * encoder)
449 GstNvEncoder *self = GST_NV_ENCODER (encoder);
450 GstNvEncoderPrivate *priv = self->priv;
452 gst_clear_object (&priv->context);
453 #ifdef GST_CUDA_HAS_D3D
454 gst_clear_d3d11_fence (&priv->fence);
455 gst_clear_object (&priv->device);
462 gst_nv_encoder_stop (GstVideoEncoder * encoder)
464 GstNvEncoder *self = GST_NV_ENCODER (encoder);
465 GstNvEncoderPrivate *priv = self->priv;
467 GST_DEBUG_OBJECT (self, "Stop");
469 gst_nv_encoder_drain (self, FALSE);
471 if (priv->subclass_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
472 gst_clear_object (&priv->context);
473 #ifdef GST_CUDA_HAS_D3D
474 gst_clear_object (&priv->device);
476 priv->selected_device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
479 g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
485 gst_nv_encoder_handle_context_query (GstNvEncoder * self, GstQuery * query)
487 GstNvEncoderPrivate *priv = self->priv;
488 gboolean ret = FALSE;
490 g_rec_mutex_lock (&priv->context_lock);
492 switch (priv->selected_device_mode) {
493 #ifdef GST_CUDA_HAS_D3D
494 case GST_NV_ENCODER_DEVICE_D3D11:
495 ret = gst_d3d11_handle_context_query (GST_ELEMENT (self),
496 query, priv->device);
499 case GST_NV_ENCODER_DEVICE_CUDA:
500 ret = gst_cuda_handle_context_query (GST_ELEMENT (self),
501 query, priv->context);
507 g_rec_mutex_unlock (&priv->context_lock);
513 gst_nv_encoder_sink_query (GstVideoEncoder * encoder, GstQuery * query)
515 GstNvEncoder *self = GST_NV_ENCODER (encoder);
517 switch (GST_QUERY_TYPE (query)) {
518 case GST_QUERY_CONTEXT:
519 if (gst_nv_encoder_handle_context_query (self, query))
526 return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
530 gst_nv_encoder_src_query (GstVideoEncoder * encoder, GstQuery * query)
532 GstNvEncoder *self = GST_NV_ENCODER (encoder);
534 switch (GST_QUERY_TYPE (query)) {
535 case GST_QUERY_CONTEXT:
536 if (gst_nv_encoder_handle_context_query (self, query))
543 return GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
547 gst_nv_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
549 GstNvEncoder *self = GST_NV_ENCODER (encoder);
550 GstNvEncoderPrivate *priv = self->priv;
552 GstBufferPool *pool = NULL;
555 GstStructure *config;
556 GstCapsFeatures *features;
559 gst_query_parse_allocation (query, &caps, NULL);
561 GST_WARNING_OBJECT (self, "null caps in query");
565 if (!gst_video_info_from_caps (&info, caps)) {
566 GST_WARNING_OBJECT (self, "Failed to convert caps into info");
570 features = gst_caps_get_features (caps, 0);
571 min_buffers = gst_nv_encoder_get_task_size (self);
573 switch (priv->subclass_device_mode) {
574 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
575 /* Use upstream pool in case of auto select mode. We don't know which
576 * GPU to use at this moment */
577 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
578 gst_query_add_allocation_pool (query, nullptr, info.size, min_buffers, 0);
580 #ifdef GST_CUDA_HAS_D3D
581 case GST_NV_ENCODER_DEVICE_D3D11:
582 if (features && gst_caps_features_contains (features,
583 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
584 GST_DEBUG_OBJECT (self, "upstream support d3d11 memory");
585 pool = gst_d3d11_buffer_pool_new (priv->device);
589 case GST_NV_ENCODER_DEVICE_CUDA:
590 if (features && gst_caps_features_contains (features,
591 GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) {
592 GST_DEBUG_OBJECT (self, "upstream support CUDA memory");
593 pool = gst_cuda_buffer_pool_new (priv->context);
597 g_assert_not_reached ();
602 pool = gst_video_buffer_pool_new ();
604 config = gst_buffer_pool_get_config (pool);
605 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
608 size = GST_VIDEO_INFO_SIZE (&info);
609 gst_buffer_pool_config_set_params (config, caps, size, min_buffers, 0);
611 if (!gst_buffer_pool_set_config (pool, config)) {
612 GST_WARNING_OBJECT (self, "Failed to set pool config");
613 gst_object_unref (pool);
617 config = gst_buffer_pool_get_config (pool);
618 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
619 gst_structure_free (config);
621 gst_query_add_allocation_pool (query, pool, size, min_buffers, 0);
622 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
623 gst_object_unref (pool);
628 /* called with lock */
630 gst_nv_encoder_task_reset (GstNvEncoder * self, GstNvEncoderTask * task)
632 GstNvEncoderPrivate *priv = self->priv;
638 gst_nv_encoder_device_lock (self);
640 NvEncUnmapInputResource (priv->session,
641 task->mapped_resource.mappedResource);
642 NvEncUnregisterResource (priv->session,
643 task->register_resource.registeredResource);
645 gst_nv_encoder_device_unlock (self);
647 gst_buffer_unmap (task->buffer, &task->map_info);
648 gst_clear_buffer (&task->buffer);
651 if (task->event_handle)
652 ResetEvent (task->event_handle);
655 task->is_eos = FALSE;
657 g_queue_push_head (&priv->free_tasks, task);
661 gst_nv_encoder_create_event_handle (GstNvEncoder * self, gpointer session,
662 gpointer * event_handle)
665 NV_ENC_EVENT_PARAMS event_params = { 0, };
668 event_params.version = gst_nvenc_get_event_params_version ();
669 event_params.completionEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
670 status = NvEncRegisterAsyncEvent (session, &event_params);
672 if (status != NV_ENC_SUCCESS) {
673 GST_ERROR_OBJECT (self,
674 "Failed to register async event handle, status %"
675 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
676 CloseHandle (event_params.completionEvent);
680 *event_handle = event_params.completionEvent;
687 gst_d3d11_encoder_wait_for_event_handle (GstNvEncoder * self,
688 gpointer event_handle)
691 /* NVCODEC SDK uses 20s */
692 if (WaitForSingleObject (event_handle, 20000) == WAIT_FAILED) {
693 GST_ERROR_OBJECT (self, "Failed to wait for completion event");
702 gst_nv_encoder_destroy_event_handle (GstNvEncoder * self, gpointer session,
703 gpointer event_handle)
706 NV_ENC_EVENT_PARAMS event_params = { 0, };
709 event_params.version = gst_nvenc_get_event_params_version ();
710 event_params.completionEvent = event_handle;
711 status = NvEncUnregisterAsyncEvent (session, &event_params);
712 CloseHandle (event_handle);
714 if (status != NV_ENC_SUCCESS) {
715 GST_ERROR_OBJECT (self,
716 "Failed to unregister async event handle, status %"
717 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
723 gst_nv_encoder_task_clear (GstNvEncoderTask * task)
726 GstNvEncoderPrivate *priv;
731 self = task->encoder;
735 gst_nv_encoder_device_lock (self);
737 NvEncUnmapInputResource (priv->session,
738 task->mapped_resource.mappedResource);
739 NvEncUnregisterResource (priv->session,
740 task->register_resource.registeredResource);
742 if (task->output_ptr)
743 NvEncDestroyBitstreamBuffer (priv->session, task->output_ptr);
744 if (task->input_buffer.inputBuffer)
745 NvEncDestroyInputBuffer (priv->session, task->input_buffer.inputBuffer);
746 if (task->event_handle) {
747 gst_nv_encoder_destroy_event_handle (self, priv->session,
751 gst_nv_encoder_device_unlock (self);
755 gst_buffer_unmap (task->buffer, &task->map_info);
756 gst_clear_buffer (&task->buffer);
759 memset (task, 0, sizeof (GstNvEncoderTask));
762 static NV_ENC_PIC_STRUCT
763 gst_nv_encoder_get_pic_struct (GstNvEncoder * self, GstBuffer * buffer)
765 GstNvEncoderPrivate *priv = self->priv;
766 GstVideoInfo *info = &priv->input_state->info;
768 if (!GST_VIDEO_INFO_IS_INTERLACED (info))
769 return NV_ENC_PIC_STRUCT_FRAME;
771 if (GST_VIDEO_INFO_INTERLACE_MODE (info) == GST_VIDEO_INTERLACE_MODE_MIXED) {
772 if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
773 return NV_ENC_PIC_STRUCT_FRAME;
776 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
777 return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
779 return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
782 switch (GST_VIDEO_INFO_FIELD_ORDER (info)) {
783 case GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST:
784 return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
786 case GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST:
787 return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
793 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
794 return NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
796 return NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
800 gst_nv_encoder_encode_frame (GstNvEncoder * self,
801 GstVideoCodecFrame * frame, GstNvEncoderTask * task)
803 GstNvEncoderPrivate *priv = self->priv;
804 NV_ENC_PIC_PARAMS pic_params = { 0, };
806 guint retry_count = 0;
807 const guint retry_threshold = 100;
809 pic_params.version = gst_nvenc_get_pic_params_version ();
811 pic_params.inputWidth = task->register_resource.width;
812 pic_params.inputHeight = task->register_resource.height;
813 pic_params.inputPitch = task->register_resource.pitch;
814 pic_params.inputBuffer = task->mapped_resource.mappedResource;
815 pic_params.bufferFmt = task->mapped_resource.mappedBufferFmt;
817 pic_params.inputWidth = task->input_buffer.width;
818 pic_params.inputHeight = task->input_buffer.height;
819 pic_params.inputPitch = task->lk_input_buffer.pitch;
820 pic_params.inputBuffer = task->input_buffer.inputBuffer;
821 pic_params.bufferFmt = task->input_buffer.bufferFmt;
824 pic_params.frameIdx = frame->system_frame_number;
825 pic_params.inputTimeStamp = frame->pts;
826 pic_params.inputDuration = frame->duration;
827 pic_params.outputBitstream = task->output_ptr;
828 pic_params.completionEvent = task->event_handle;
829 pic_params.pictureStruct = gst_nv_encoder_get_pic_struct (self, task->buffer);
830 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
831 pic_params.encodePicFlags = NV_ENC_PIC_FLAG_FORCEIDR;
834 gst_nv_encoder_device_lock (self);
835 status = NvEncEncodePicture (priv->session, &pic_params);
836 gst_nv_encoder_device_unlock (self);
838 if (status == NV_ENC_ERR_ENCODER_BUSY) {
839 if (retry_count < 100) {
840 GST_DEBUG_OBJECT (self, "GPU is busy, retry count (%d/%d)", retry_count,
844 /* Magic number 1ms */
848 GST_ERROR_OBJECT (self, "GPU is keep busy, give up");
856 GST_NV_ENCODER_LOCK (self);
857 if (status != NV_ENC_SUCCESS && status != NV_ENC_ERR_NEED_MORE_INPUT) {
858 GST_ERROR_OBJECT (self, "Encode return %" GST_NVENC_STATUS_FORMAT,
859 GST_NVENC_STATUS_ARGS (status));
860 gst_nv_encoder_task_reset (self, task);
861 GST_NV_ENCODER_UNLOCK (self);
863 return GST_FLOW_ERROR;
866 gst_video_codec_frame_set_user_data (frame, task, NULL);
867 g_queue_push_tail (&priv->output_tasks, task);
868 g_cond_broadcast (&priv->cond);
869 GST_NV_ENCODER_UNLOCK (self);
874 static GstVideoCodecFrame *
875 gst_nv_encoder_find_output_frame (GstVideoEncoder * self,
876 GstNvEncoderTask * task)
878 GList *frames, *iter;
879 GstVideoCodecFrame *ret = NULL;
881 frames = gst_video_encoder_get_frames (self);
883 for (iter = frames; iter; iter = g_list_next (iter)) {
884 GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
885 GstNvEncoderTask *other = (GstNvEncoderTask *)
886 gst_video_codec_frame_get_user_data (frame);
898 gst_video_codec_frame_ref (ret);
901 g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
907 gst_nv_encoder_thread_func (GstNvEncoder * self)
909 GstVideoEncoder *encoder = GST_VIDEO_ENCODER (self);
910 GstNvEncoderClass *klass = GST_NV_ENCODER_GET_CLASS (self);
911 GstNvEncoderPrivate *priv = self->priv;
912 GstNvEncoderTask *task = NULL;
915 NV_ENC_LOCK_BITSTREAM bitstream = { 0, };
917 GstVideoCodecFrame *frame;
920 GST_NV_ENCODER_LOCK (self);
921 while ((task = (GstNvEncoderTask *)
922 g_queue_pop_head (&priv->output_tasks)) == NULL) {
923 g_cond_wait (&priv->cond, &priv->lock);
925 GST_NV_ENCODER_UNLOCK (self);
927 if (task->event_handle) {
928 if (!gst_d3d11_encoder_wait_for_event_handle (self, task->event_handle)) {
929 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
930 ("Failed to wait for event signal"));
936 GST_INFO_OBJECT (self, "Got EOS packet");
938 GST_NV_ENCODER_LOCK (self);
939 gst_nv_encoder_task_reset (self, task);
940 g_cond_broadcast (&priv->cond);
941 GST_NV_ENCODER_UNLOCK (self);
946 frame = gst_nv_encoder_find_output_frame (encoder, task);
948 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
949 ("Failed to find associated codec frame"));
953 if (!gst_nv_encoder_device_lock (self)) {
954 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
955 ("Failed to lock device"));
959 bitstream.version = gst_nvenc_get_lock_bitstream_version ();
960 bitstream.outputBitstream = task->output_ptr;
962 status = NvEncLockBitstream (priv->session, &bitstream);
963 if (status != NV_ENC_SUCCESS) {
964 gst_nv_encoder_device_unlock (self);
965 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
966 ("Failed to lock bitstream, status: %" GST_NVENC_STATUS_FORMAT,
967 GST_NVENC_STATUS_ARGS (status)));
971 if (klass->create_output_buffer) {
972 frame->output_buffer = klass->create_output_buffer (self, &bitstream);
974 frame->output_buffer =
975 gst_buffer_new_memdup (bitstream.bitstreamBufferPtr,
976 bitstream.bitstreamSizeInBytes);
979 GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_MARKER);
981 if (bitstream.pictureType == NV_ENC_PIC_TYPE_IDR)
982 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
984 NvEncUnlockBitstream (priv->session, task->output_ptr);
985 gst_nv_encoder_device_unlock (self);
987 frame->dts = frame->pts - priv->dts_offset;
988 frame->pts = bitstream.outputTimeStamp;
989 frame->duration = bitstream.outputDuration;
991 ret = gst_video_encoder_finish_frame (encoder, frame);
992 if (ret != GST_FLOW_OK) {
993 GST_INFO_OBJECT (self,
994 "Finish frame returned %s", gst_flow_get_name (ret));
997 GST_NV_ENCODER_LOCK (self);
998 gst_nv_encoder_task_reset (self, task);
999 priv->last_flow = ret;
1000 g_cond_broadcast (&priv->cond);
1001 GST_NV_ENCODER_UNLOCK (self);
1003 if (ret != GST_FLOW_OK) {
1004 GST_INFO_OBJECT (self, "Push returned %s", gst_flow_get_name (ret));
1011 GST_INFO_OBJECT (self, "Exiting thread");
1018 GST_NV_ENCODER_LOCK (self);
1019 gst_nv_encoder_task_reset (self, task);
1020 priv->last_flow = GST_FLOW_ERROR;
1021 g_cond_broadcast (&priv->cond);
1022 GST_NV_ENCODER_UNLOCK (self);
1029 gst_nv_encoder_calculate_task_pool_size (GstNvEncoder * self,
1030 NV_ENC_CONFIG * config)
1034 /* At least 4 surfaces are required as documented by Nvidia Encoder guide */
1037 /* lookahead depth */
1038 num_tasks += config->rcParams.lookaheadDepth;
1041 num_tasks += MAX (0, config->frameIntervalP - 1) + 1;
1043 GST_DEBUG_OBJECT (self, "Calculated task pool size: %d "
1044 "(lookahead %d, frameIntervalP %d)",
1045 num_tasks, config->rcParams.lookaheadDepth, config->frameIntervalP);
1051 gst_nv_encoder_open_encode_session (GstNvEncoder * self, gpointer * session)
1053 GstNvEncoderPrivate *priv = self->priv;
1054 NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
1055 session_params.version =
1056 gst_nvenc_get_open_encode_session_ex_params_version ();
1057 session_params.apiVersion = gst_nvenc_get_api_version ();
1060 switch (priv->selected_device_mode) {
1061 #ifdef GST_CUDA_HAS_D3D
1062 case GST_NV_ENCODER_DEVICE_D3D11:
1063 session_params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
1064 session_params.device = gst_d3d11_device_get_device_handle (priv->device);
1067 case GST_NV_ENCODER_DEVICE_CUDA:
1068 session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
1069 session_params.device = gst_cuda_context_get_handle (priv->context);
1072 g_assert_not_reached ();
1076 status = NvEncOpenEncodeSessionEx (&session_params, session);
1077 if (status != NV_ENC_SUCCESS) {
1078 GST_ERROR_OBJECT (self, "Failed to open session, status: %"
1079 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1086 #ifdef GST_CUDA_HAS_D3D
1087 static GstBufferPool *
1088 gst_nv_encoder_create_d3d11_pool (GstNvEncoder * self,
1089 GstVideoCodecState * state)
1091 GstNvEncoderPrivate *priv = self->priv;
1092 GstStructure *config;
1093 GstBufferPool *pool = NULL;
1094 GstD3D11AllocationParams *params;
1096 params = gst_d3d11_allocation_params_new (priv->device, &state->info,
1097 GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, D3D11_RESOURCE_MISC_SHARED);
1099 pool = gst_d3d11_buffer_pool_new (priv->device);
1101 config = gst_buffer_pool_get_config (pool);
1102 gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
1103 gst_d3d11_allocation_params_free (params);
1105 gst_buffer_pool_config_set_params (config, state->caps,
1106 GST_VIDEO_INFO_SIZE (&state->info), 0, 0);
1107 if (!gst_buffer_pool_set_config (pool, config)) {
1108 GST_ERROR_OBJECT (self, "Failed to set pool config");
1109 gst_object_unref (pool);
1114 if (!gst_buffer_pool_set_active (pool, TRUE)) {
1115 GST_ERROR_OBJECT (self, "Failed to set active");
1116 gst_object_unref (pool);
1124 static GstBufferPool *
1125 gst_nv_encoder_create_pool (GstNvEncoder * self, GstVideoCodecState * state)
1127 GstNvEncoderPrivate *priv = self->priv;
1128 GstStructure *config;
1129 GstBufferPool *pool = NULL;
1131 /* At this moment device type must be selected already */
1132 switch (priv->selected_device_mode) {
1133 #ifdef GST_CUDA_HAS_D3D
1134 case GST_NV_ENCODER_DEVICE_D3D11:
1135 return gst_nv_encoder_create_d3d11_pool (self, state);
1137 case GST_NV_ENCODER_DEVICE_CUDA:
1138 pool = gst_cuda_buffer_pool_new (priv->context);
1141 g_assert_not_reached ();
1145 config = gst_buffer_pool_get_config (pool);
1146 gst_buffer_pool_config_set_params (config, state->caps,
1147 GST_VIDEO_INFO_SIZE (&state->info), 0, 0);
1148 if (!gst_buffer_pool_set_config (pool, config)) {
1149 GST_ERROR_OBJECT (self, "Failed to set pool config");
1150 gst_object_unref (pool);
1155 if (!gst_buffer_pool_set_active (pool, TRUE)) {
1156 GST_ERROR_OBJECT (self, "Failed to set active");
1157 gst_object_unref (pool);
1165 gst_nv_encoder_init_session (GstNvEncoder * self, GstBuffer * in_buf)
1167 GstNvEncoderPrivate *priv = self->priv;
1168 GstNvEncoderClass *klass = GST_NV_ENCODER_GET_CLASS (self);
1169 GstVideoCodecState *state = priv->input_state;
1170 GstVideoInfo *info = &state->info;
1172 guint task_pool_size;
1174 GstClockTime frame_duration, min_latency, max_latency;
1177 gst_nv_encoder_reset (self);
1179 memset (&priv->init_params, 0, sizeof (NV_ENC_INITIALIZE_PARAMS));
1180 memset (&priv->config, 0, sizeof (NV_ENC_CONFIG));
1182 if (priv->selected_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1183 GstNvEncoderDeviceData data;
1187 GST_DEBUG_OBJECT (self, "Unknown device mode, open session later");
1191 if (!klass->select_device (self, info, in_buf, &data)) {
1192 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1193 ("Failed to select device mode"));
1197 GST_DEBUG_OBJECT (self,
1198 "Selected device mode: %d, cuda-device-id: %d, adapter-luid %"
1199 G_GINT64_FORMAT, data.device_mode, data.cuda_device_id,
1202 g_assert (data.device_mode == GST_NV_ENCODER_DEVICE_CUDA ||
1203 data.device_mode == GST_NV_ENCODER_DEVICE_D3D11);
1205 g_rec_mutex_lock (&priv->context_lock);
1206 priv->selected_device_mode = data.device_mode;
1207 priv->cuda_device_id = data.cuda_device_id;
1208 priv->dxgi_adapter_luid = data.adapter_luid;
1209 gst_clear_object (&priv->context);
1210 if (data.device_mode == GST_NV_ENCODER_DEVICE_CUDA)
1211 priv->context = (GstCudaContext *) data.device;
1212 #ifdef GST_CUDA_HAS_D3D
1213 gst_clear_object (&priv->device);
1214 if (data.device_mode == GST_NV_ENCODER_DEVICE_D3D11)
1215 priv->device = (GstD3D11Device *) data.device;
1218 ret = gst_nv_encoder_open (GST_VIDEO_ENCODER (self));
1219 g_rec_mutex_unlock (&priv->context_lock);
1222 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1223 ("Failed to open device"));
1228 priv->internal_pool = gst_nv_encoder_create_pool (self, state);
1229 if (!priv->internal_pool) {
1230 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1231 ("Failed to create internal pool"));
1235 if (!gst_nv_encoder_device_lock (self)) {
1236 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), ("Failed to lock device"));
1237 gst_nv_encoder_reset (self);
1241 if (!gst_nv_encoder_open_encode_session (self, &priv->session)) {
1242 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1243 ("Failed to open session"));
1247 if (!klass->set_format (self, state, priv->session, &priv->init_params,
1249 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL), ("Failed to set format"));
1253 priv->init_params.encodeConfig = &priv->config;
1254 status = NvEncInitializeEncoder (priv->session, &priv->init_params);
1255 if (status != NV_ENC_SUCCESS) {
1256 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1257 ("Failed to init encoder, status: %"
1258 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status)));
1262 task_pool_size = gst_nv_encoder_calculate_task_pool_size (self,
1264 g_array_set_size (priv->task_pool, task_pool_size);
1266 for (i = 0; i < task_pool_size; i++) {
1267 NV_ENC_CREATE_BITSTREAM_BUFFER buffer_params = { 0, };
1268 GstNvEncoderTask *task = (GstNvEncoderTask *)
1269 & g_array_index (priv->task_pool, GstNvEncoderTask, i);
1271 task->encoder = self;
1273 buffer_params.version = gst_nvenc_get_create_bitstream_buffer_version ();
1274 status = NvEncCreateBitstreamBuffer (priv->session, &buffer_params);
1276 if (status != NV_ENC_SUCCESS) {
1277 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1278 ("Failed to create bitstream buffer, status: %"
1279 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status)));
1283 task->output_ptr = buffer_params.bitstreamBuffer;
1285 if (priv->init_params.enableEncodeAsync) {
1286 if (!gst_nv_encoder_create_event_handle (self,
1287 priv->session, &task->event_handle)) {
1288 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1289 ("Failed to create async event handle"));
1294 g_queue_push_tail (&priv->free_tasks, task);
1296 gst_nv_encoder_device_unlock (self);
1298 if (!klass->set_output_state (self, priv->input_state, priv->session)) {
1299 GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
1300 ("Failed to set output state"));
1301 gst_nv_encoder_reset (self);
1305 priv->encoding_thread = g_thread_new ("GstNvEncoderThread",
1306 (GThreadFunc) gst_nv_encoder_thread_func, self);
1308 if (info->fps_n > 0 && info->fps_d > 0) {
1309 fps_n = info->fps_n;
1310 fps_d = info->fps_d;
1316 frame_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
1318 priv->dts_offset = 0;
1319 /* Calculate DTS offset for B frame. NVENC does not provide DTS */
1320 if (priv->config.frameIntervalP > 1)
1321 priv->dts_offset = frame_duration * (priv->config.frameIntervalP - 1);
1323 min_latency = priv->dts_offset +
1324 priv->config.rcParams.lookaheadDepth * frame_duration;
1325 max_latency = frame_duration * priv->task_pool->len;
1326 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (self),
1327 min_latency, max_latency);
1332 gst_nv_encoder_device_unlock (self);
1334 gst_nv_encoder_reset (self);
1340 gst_nv_encoder_reconfigure_session (GstNvEncoder * self)
1342 GstNvEncoderPrivate *priv = self->priv;
1343 NV_ENC_RECONFIGURE_PARAMS params = { 0, };
1346 if (!priv->session) {
1347 GST_WARNING_OBJECT (self,
1348 "Encoding session was not configured, open session");
1349 gst_nv_encoder_drain (self, TRUE);
1351 return gst_nv_encoder_init_session (self, nullptr);
1354 params.version = gst_nvenc_get_reconfigure_params_version ();
1355 params.reInitEncodeParams = priv->init_params;
1356 params.reInitEncodeParams.encodeConfig = &priv->config;
1358 status = NvEncReconfigureEncoder (priv->session, ¶ms);
1359 if (status != NV_ENC_SUCCESS) {
1360 GST_WARNING_OBJECT (self, "Failed to reconfigure encoder, status %"
1361 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1362 gst_nv_encoder_drain (self, TRUE);
1364 return gst_nv_encoder_init_session (self, nullptr);
1371 gst_nv_encoder_set_format (GstVideoEncoder * encoder,
1372 GstVideoCodecState * state)
1374 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1375 GstNvEncoderPrivate *priv = self->priv;
1377 gst_nv_encoder_drain (self, TRUE);
1379 g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
1380 priv->input_state = gst_video_codec_state_ref (state);
1381 priv->last_flow = GST_FLOW_OK;
1383 /* select device again on next buffer */
1384 if (priv->subclass_device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT)
1385 priv->selected_device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
1387 return gst_nv_encoder_init_session (self, nullptr);
1390 static NV_ENC_BUFFER_FORMAT
1391 gst_nv_encoder_get_buffer_format (GstNvEncoder * self, GstVideoFormat format)
1394 case GST_VIDEO_FORMAT_NV12:
1395 return NV_ENC_BUFFER_FORMAT_NV12;
1396 case GST_VIDEO_FORMAT_Y444:
1397 return NV_ENC_BUFFER_FORMAT_YUV444;
1398 case GST_VIDEO_FORMAT_P010_10LE:
1399 return NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
1400 case GST_VIDEO_FORMAT_Y444_16LE:
1401 return NV_ENC_BUFFER_FORMAT_YUV444_10BIT;
1403 GST_ERROR_OBJECT (self, "Unexpected format %s",
1404 gst_video_format_to_string (format));
1405 g_assert_not_reached ();
1409 return NV_ENC_BUFFER_FORMAT_UNDEFINED;
1412 static GstFlowReturn
1413 gst_nv_encoder_copy_system (GstNvEncoder * self, const GstVideoInfo * info,
1414 GstBuffer * buffer, gpointer session, GstNvEncoderTask * task)
1417 GstVideoFrame frame;
1419 NV_ENC_BUFFER_FORMAT format;
1422 gst_nv_encoder_get_buffer_format (self, GST_VIDEO_INFO_FORMAT (info));
1423 if (format == NV_ENC_BUFFER_FORMAT_UNDEFINED)
1424 return GST_FLOW_ERROR;
1426 if (!gst_video_frame_map (&frame, info, buffer, GST_MAP_READ)) {
1427 GST_ERROR_OBJECT (self, "Failed to map buffer");
1428 return GST_FLOW_ERROR;
1431 if (!task->input_buffer.inputBuffer) {
1432 NV_ENC_CREATE_INPUT_BUFFER input_buffer = { 0, };
1433 input_buffer.version = gst_nvenc_get_create_input_buffer_version ();
1434 input_buffer.width = info->width;
1435 input_buffer.height = info->height;
1436 input_buffer.bufferFmt = format;
1438 status = NvEncCreateInputBuffer (session, &input_buffer);
1439 if (status != NV_ENC_SUCCESS) {
1440 GST_ERROR_OBJECT (self, "Failed to create input buffer, status %"
1441 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1442 gst_video_frame_unmap (&frame);
1443 return GST_FLOW_ERROR;
1446 task->input_buffer = input_buffer;
1449 task->lk_input_buffer.version = gst_nvenc_get_lock_input_buffer_version ();
1450 task->lk_input_buffer.inputBuffer = task->input_buffer.inputBuffer;
1451 status = NvEncLockInputBuffer (session, &task->lk_input_buffer);
1452 if (status != NV_ENC_SUCCESS) {
1453 GST_ERROR_OBJECT (self, "Failed to lock input buffer, status %"
1454 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1455 gst_video_frame_unmap (&frame);
1456 return GST_FLOW_ERROR;
1459 dst_data = (guint8 *) task->lk_input_buffer.bufferDataPtr;
1461 for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&frame); i++) {
1462 guint8 *src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame, i);
1463 guint width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i) *
1464 GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, i);
1465 guint stride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, i);
1466 guint height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
1468 for (guint j = 0; j < height; j++) {
1469 memcpy (dst_data, src_data, width_in_bytes);
1470 dst_data += task->lk_input_buffer.pitch;
1475 NvEncUnlockInputBuffer (session, task->input_buffer.inputBuffer);
1476 gst_video_frame_unmap (&frame);
1481 static GstFlowReturn
1482 gst_nv_encoder_prepare_task_input_cuda (GstNvEncoder * self,
1483 const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1484 GstNvEncoderTask * task)
1486 GstNvEncoderPrivate *priv = self->priv;
1488 GstCudaMemory *cmem;
1491 mem = gst_buffer_peek_memory (buffer, 0);
1492 if (!gst_is_cuda_memory (mem)) {
1493 GST_LOG_OBJECT (self, "Not a CUDA buffer, system copy");
1494 return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1497 cmem = GST_CUDA_MEMORY_CAST (mem);
1498 if (cmem->context != priv->context) {
1499 GST_LOG_OBJECT (self, "Different context, system copy");
1500 return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1503 task->buffer = gst_buffer_ref (buffer);
1504 if (!gst_buffer_map (task->buffer, &task->map_info,
1505 (GstMapFlags) (GST_MAP_READ | GST_MAP_CUDA))) {
1506 GST_ERROR_OBJECT (self, "Failed to map buffer");
1507 gst_clear_buffer (&task->buffer);
1509 return GST_FLOW_ERROR;
1512 cmem = (GstCudaMemory *) gst_buffer_peek_memory (task->buffer, 0);
1514 task->register_resource.version = gst_nvenc_get_register_resource_version ();
1515 task->register_resource.resourceType =
1516 NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR;
1517 task->register_resource.width = cmem->info.width;
1518 task->register_resource.height = cmem->info.height;
1519 task->register_resource.pitch = cmem->info.stride[0];
1520 task->register_resource.resourceToRegister = task->map_info.data;
1521 task->register_resource.bufferFormat =
1522 gst_nv_encoder_get_buffer_format (self, GST_VIDEO_INFO_FORMAT (info));
1523 if (task->register_resource.bufferFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED)
1524 return GST_FLOW_ERROR;
1526 status = NvEncRegisterResource (session, &task->register_resource);
1527 if (status != NV_ENC_SUCCESS) {
1528 GST_ERROR_OBJECT (self, "Failed to register resource, status %"
1529 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1531 gst_buffer_unmap (task->buffer, &task->map_info);
1532 gst_clear_buffer (&task->buffer);
1534 return GST_FLOW_ERROR;
1537 task->mapped_resource.version = gst_nvenc_get_map_input_resource_version ();
1538 task->mapped_resource.registeredResource =
1539 task->register_resource.registeredResource;
1540 status = NvEncMapInputResource (session, &task->mapped_resource);
1541 if (status != NV_ENC_SUCCESS) {
1542 GST_ERROR_OBJECT (self, "Failed to map input resource, status %"
1543 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1544 NvEncUnregisterResource (session,
1545 task->register_resource.registeredResource);
1547 gst_buffer_unmap (task->buffer, &task->map_info);
1548 gst_clear_buffer (&task->buffer);
1550 return GST_FLOW_ERROR;
1556 #ifdef GST_CUDA_HAS_D3D
1558 gst_nv_encoder_copy_d3d11 (GstNvEncoder * self,
1559 GstBuffer * src_buffer, GstBufferPool * pool, gboolean shared)
1561 GstNvEncoderPrivate *priv = self->priv;
1562 D3D11_TEXTURE2D_DESC src_desc, dst_desc;
1564 guint subresource_idx;
1565 GstMemory *src_mem, *dst_mem;
1566 GstMapInfo src_info, dst_info;
1567 ID3D11Texture2D *src_tex, *dst_tex;
1568 ID3D11Device *device_handle;
1569 ID3D11DeviceContext *device_context;
1570 GstBuffer *dst_buffer;
1572 ComPtr < IDXGIResource > dxgi_resource;
1573 ComPtr < ID3D11Texture2D > shared_texture;
1574 HANDLE shared_handle;
1575 GstD3D11Device *device;
1578 ret = gst_buffer_pool_acquire_buffer (pool, &dst_buffer, NULL);
1579 if (ret != GST_FLOW_OK) {
1580 GST_ERROR_OBJECT (self, "Failed to acquire buffer");
1584 src_mem = gst_buffer_peek_memory (src_buffer, 0);
1585 dst_mem = gst_buffer_peek_memory (dst_buffer, 0);
1587 device = GST_D3D11_MEMORY_CAST (src_mem)->device;
1589 device_handle = gst_d3d11_device_get_device_handle (device);
1590 device_context = gst_d3d11_device_get_device_context_handle (device);
1592 if (!gst_memory_map (src_mem, &src_info,
1593 (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
1594 GST_WARNING ("Failed to map src memory");
1595 gst_buffer_unref (dst_buffer);
1599 if (!gst_memory_map (dst_mem, &dst_info,
1600 (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
1601 GST_WARNING ("Failed to map dst memory");
1602 gst_memory_unmap (src_mem, &src_info);
1603 gst_buffer_unref (dst_buffer);
1607 src_tex = (ID3D11Texture2D *) src_info.data;
1608 dst_tex = (ID3D11Texture2D *) dst_info.data;
1610 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (src_mem),
1612 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (dst_mem),
1615 gst_d3d11_memory_get_subresource_index (GST_D3D11_MEMORY_CAST (src_mem));
1618 hr = dst_tex->QueryInterface (IID_PPV_ARGS (&dxgi_resource));
1619 if (!gst_d3d11_result (hr, priv->device)) {
1620 GST_ERROR_OBJECT (self,
1621 "IDXGIResource interface is not available, hr: 0x%x", (guint) hr);
1625 hr = dxgi_resource->GetSharedHandle (&shared_handle);
1626 if (!gst_d3d11_result (hr, priv->device)) {
1627 GST_ERROR_OBJECT (self, "Failed to get shared handle, hr: 0x%x",
1632 hr = device_handle->OpenSharedResource (shared_handle,
1633 IID_PPV_ARGS (&shared_texture));
1635 if (!gst_d3d11_result (hr, device)) {
1636 GST_ERROR_OBJECT (self, "Failed to get shared texture, hr: 0x%x",
1641 dst_tex = shared_texture.Get ();
1648 src_box.right = MIN (src_desc.Width, dst_desc.Width);
1649 src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
1652 if (priv->fence && priv->fence->device != device)
1653 gst_clear_d3d11_fence (&priv->fence);
1656 priv->fence = gst_d3d11_device_create_fence (device);
1659 GST_ERROR_OBJECT (self, "Couldn't crete fence");
1663 gst_d3d11_device_lock (device);
1666 device_context->CopySubresourceRegion (dst_tex, 0,
1667 0, 0, 0, src_tex, subresource_idx, &src_box);
1670 if (!gst_d3d11_fence_signal (priv->fence) ||
1671 !gst_d3d11_fence_wait (priv->fence)) {
1672 GST_ERROR_OBJECT (self, "Couldn't sync GPU operation");
1673 gst_d3d11_device_unlock (device);
1674 gst_clear_d3d11_fence (&priv->fence);
1678 gst_d3d11_device_unlock (device);
1681 gst_memory_unmap (dst_mem, &dst_info);
1682 gst_memory_unmap (src_mem, &src_info);
1687 gst_memory_unmap (dst_mem, &dst_info);
1688 gst_memory_unmap (src_mem, &src_info);
1689 gst_buffer_unref (dst_buffer);
1695 gst_nv_encoder_upload_d3d11_frame (GstNvEncoder * self,
1696 const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
1698 GstD3D11Memory *dmem;
1699 D3D11_TEXTURE2D_DESC desc;
1701 dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
1703 gst_d3d11_memory_get_texture_desc (dmem, &desc);
1704 if (desc.Usage != D3D11_USAGE_DEFAULT) {
1705 GST_TRACE_OBJECT (self, "Not a default usage texture, d3d11 copy");
1706 return gst_nv_encoder_copy_d3d11 (self, buffer, pool, FALSE);
1709 GST_TRACE_OBJECT (self, "Use input buffer without copy");
1711 return gst_buffer_ref (buffer);
1714 static GstFlowReturn
1715 gst_nv_encoder_prepare_task_input_d3d11 (GstNvEncoder * self,
1716 const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1717 GstBufferPool * pool, GstNvEncoderTask * task)
1719 GstNvEncoderPrivate *priv = self->priv;
1721 GstD3D11Memory *dmem;
1722 D3D11_TEXTURE2D_DESC desc;
1725 if (gst_buffer_n_memory (buffer) > 1) {
1726 GST_LOG_OBJECT (self, "Not a native DXGI format, system copy");
1727 return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1730 mem = gst_buffer_peek_memory (buffer, 0);
1731 if (!gst_is_d3d11_memory (mem)) {
1732 GST_LOG_OBJECT (self, "Not a D3D11 buffer, system copy");
1733 return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1736 dmem = GST_D3D11_MEMORY_CAST (mem);
1737 if (dmem->device != priv->device) {
1738 gint64 adapter_luid;
1740 g_object_get (dmem->device, "adapter-luid", &adapter_luid, NULL);
1741 if (adapter_luid == priv->dxgi_adapter_luid) {
1742 GST_LOG_OBJECT (self, "Different device but same GPU, copy d3d11");
1743 task->buffer = gst_nv_encoder_copy_d3d11 (self, buffer, pool, TRUE);
1745 GST_LOG_OBJECT (self, "Different device, system copy");
1746 return gst_nv_encoder_copy_system (self, info, buffer, session, task);
1751 task->buffer = gst_nv_encoder_upload_d3d11_frame (self, info, buffer, pool);
1753 if (!task->buffer) {
1754 GST_ERROR_OBJECT (self, "Failed to upload buffer");
1755 return GST_FLOW_ERROR;
1758 if (!gst_buffer_map (task->buffer, &task->map_info,
1759 (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
1760 GST_ERROR_OBJECT (self, "Failed to map buffer");
1761 gst_clear_buffer (&task->buffer);
1763 return GST_FLOW_ERROR;
1766 dmem = (GstD3D11Memory *) gst_buffer_peek_memory (task->buffer, 0);
1767 gst_d3d11_memory_get_texture_desc (dmem, &desc);
1769 task->register_resource.version = gst_nvenc_get_register_resource_version ();
1770 task->register_resource.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
1771 task->register_resource.width = desc.Width;
1772 task->register_resource.height = desc.Height;
1773 switch (desc.Format) {
1774 case DXGI_FORMAT_NV12:
1775 task->register_resource.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
1777 case DXGI_FORMAT_P010:
1778 task->register_resource.bufferFormat = NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
1781 GST_ERROR_OBJECT (self, "Unexpected DXGI format %d", desc.Format);
1782 g_assert_not_reached ();
1783 return GST_FLOW_ERROR;
1786 task->register_resource.subResourceIndex =
1787 gst_d3d11_memory_get_subresource_index (dmem);
1788 task->register_resource.resourceToRegister =
1789 gst_d3d11_memory_get_resource_handle (dmem);
1791 status = NvEncRegisterResource (session, &task->register_resource);
1792 if (status != NV_ENC_SUCCESS) {
1793 GST_ERROR_OBJECT (self, "Failed to register resource, status %"
1794 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1796 gst_buffer_unmap (task->buffer, &task->map_info);
1797 gst_clear_buffer (&task->buffer);
1799 return GST_FLOW_ERROR;
1802 task->mapped_resource.version = gst_nvenc_get_map_input_resource_version ();
1803 task->mapped_resource.registeredResource =
1804 task->register_resource.registeredResource;
1805 status = NvEncMapInputResource (session, &task->mapped_resource);
1806 if (status != NV_ENC_SUCCESS) {
1807 GST_ERROR_OBJECT (self, "Failed to map input resource, status %"
1808 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1809 NvEncUnregisterResource (session,
1810 task->register_resource.registeredResource);
1812 gst_buffer_unmap (task->buffer, &task->map_info);
1813 gst_clear_buffer (&task->buffer);
1815 return GST_FLOW_ERROR;
1822 static GstFlowReturn
1823 gst_nv_encoder_prepare_task_input (GstNvEncoder * self,
1824 const GstVideoInfo * info, GstBuffer * buffer, gpointer session,
1825 GstBufferPool * pool, GstNvEncoderTask * task)
1827 GstNvEncoderPrivate *priv = self->priv;
1828 GstFlowReturn ret = GST_FLOW_ERROR;
1830 switch (priv->selected_device_mode) {
1831 #ifdef GST_CUDA_HAS_D3D
1832 case GST_NV_ENCODER_DEVICE_D3D11:
1833 ret = gst_nv_encoder_prepare_task_input_d3d11 (self, info, buffer,
1834 session, pool, task);
1837 case GST_NV_ENCODER_DEVICE_CUDA:
1838 ret = gst_nv_encoder_prepare_task_input_cuda (self, info, buffer,
1842 g_assert_not_reached ();
1849 static GstFlowReturn
1850 gst_nv_encoder_handle_frame (GstVideoEncoder * encoder,
1851 GstVideoCodecFrame * frame)
1853 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1854 GstNvEncoderPrivate *priv = self->priv;
1855 GstNvEncoderClass *klass = GST_NV_ENCODER_GET_CLASS (self);
1856 GstFlowReturn ret = GST_FLOW_ERROR;
1857 GstNvEncoderTask *task = NULL;
1858 GstNvEncoderReconfigure reconfig;
1859 GstBuffer *in_buf = frame->input_buffer;
1861 GST_TRACE_OBJECT (self, "Handle frame");
1863 GST_NV_ENCODER_LOCK (self);
1864 ret = priv->last_flow;
1865 GST_NV_ENCODER_UNLOCK (self);
1867 if (ret != GST_FLOW_OK) {
1868 GST_INFO_OBJECT (self, "Last flow was %s", gst_flow_get_name (ret));
1869 gst_video_encoder_finish_frame (encoder, frame);
1874 if (!priv->session && !gst_nv_encoder_init_session (self, in_buf)) {
1875 GST_ERROR_OBJECT (self, "Encoder object was not configured");
1876 gst_video_encoder_finish_frame (encoder, frame);
1878 return GST_FLOW_NOT_NEGOTIATED;
1881 reconfig = klass->check_reconfigure (self, &priv->config);
1883 case GST_NV_ENCODER_RECONFIGURE_BITRATE:
1884 if (!gst_nv_encoder_reconfigure_session (self)) {
1885 gst_video_encoder_finish_frame (encoder, frame);
1886 return GST_FLOW_NOT_NEGOTIATED;
1889 case GST_NV_ENCODER_RECONFIGURE_FULL:
1891 gst_nv_encoder_drain (self, TRUE);
1892 if (!gst_nv_encoder_init_session (self, nullptr)) {
1893 gst_video_encoder_finish_frame (encoder, frame);
1894 return GST_FLOW_NOT_NEGOTIATED;
1902 /* Release stream lock temporarily for encoding thread to be able to
1903 * push encoded data */
1904 GST_VIDEO_ENCODER_STREAM_UNLOCK (self);
1905 ret = gst_nv_encoder_get_free_task (self, &task, TRUE);
1906 GST_VIDEO_ENCODER_STREAM_LOCK (self);
1907 if (ret != GST_FLOW_OK) {
1908 GST_DEBUG_OBJECT (self, "Last flow was %s", gst_flow_get_name (ret));
1909 gst_video_encoder_finish_frame (encoder, frame);
1913 if (!gst_nv_encoder_device_lock (self)) {
1914 GST_ERROR_OBJECT (self, "Failed to lock device");
1915 gst_video_encoder_finish_frame (encoder, frame);
1917 return GST_FLOW_ERROR;
1920 g_assert (task->buffer == NULL);
1921 ret = gst_nv_encoder_prepare_task_input (self, &priv->input_state->info,
1922 in_buf, priv->session, priv->internal_pool, task);
1923 gst_nv_encoder_device_unlock (self);
1925 if (ret != GST_FLOW_OK) {
1926 GST_ERROR_OBJECT (self, "Failed to upload frame");
1927 GST_NV_ENCODER_LOCK (self);
1928 gst_nv_encoder_task_reset (self, task);
1929 GST_NV_ENCODER_UNLOCK (self);
1931 gst_video_encoder_finish_frame (encoder, frame);
1936 ret = gst_nv_encoder_encode_frame (self, frame, task);
1937 if (ret != GST_FLOW_OK) {
1938 GST_ERROR_OBJECT (self, "Failed to encode frame");
1939 gst_video_encoder_finish_frame (encoder, frame);
1944 gst_video_codec_frame_unref (frame);
1949 static GstFlowReturn
1950 gst_nv_encoder_finish (GstVideoEncoder * encoder)
1952 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1954 GST_DEBUG_OBJECT (self, "Finish");
1956 gst_nv_encoder_drain (self, TRUE);
1962 gst_nv_encoder_flush (GstVideoEncoder * encoder)
1964 GstNvEncoder *self = GST_NV_ENCODER (encoder);
1965 GstNvEncoderPrivate *priv = self->priv;
1967 GST_DEBUG_OBJECT (self, "Flush");
1969 gst_nv_encoder_drain (self, TRUE);
1971 priv->last_flow = GST_FLOW_OK;
1977 gst_nv_encoder_get_task_size (GstNvEncoder * encoder)
1979 g_return_val_if_fail (GST_IS_NV_ENCODER (encoder), 0);
1981 return encoder->priv->task_pool->len;
1985 gst_nv_encoder_set_device_mode (GstNvEncoder * encoder,
1986 GstNvEncoderDeviceMode mode, guint cuda_device_id, gint64 adapter_luid)
1988 GstNvEncoderPrivate *priv = encoder->priv;
1990 priv->subclass_device_mode = mode;
1991 priv->selected_device_mode = mode;
1992 priv->cuda_device_id = cuda_device_id;
1993 priv->dxgi_adapter_luid = adapter_luid;
1997 * GstNvEncoderPreset:
2002 gst_nv_encoder_preset_get_type (void)
2004 static GType preset_type = 0;
2005 static const GEnumValue presets[] = {
2006 {GST_NV_ENCODER_PRESET_DEFAULT, "Default", "default"},
2007 {GST_NV_ENCODER_PRESET_HP, "High Performance", "hp"},
2008 {GST_NV_ENCODER_PRESET_HQ, "High Quality", "hq"},
2009 {GST_NV_ENCODER_PRESET_LOW_LATENCY_DEFAULT, "Low Latency", "low-latency"},
2010 {GST_NV_ENCODER_PRESET_LOW_LATENCY_HQ, "Low Latency, High Quality",
2012 {GST_NV_ENCODER_PRESET_LOW_LATENCY_HP, "Low Latency, High Performance",
2014 {GST_NV_ENCODER_PRESET_LOSSLESS_DEFAULT, "Lossless", "lossless"},
2015 {GST_NV_ENCODER_PRESET_LOSSLESS_HP, "Lossless, High Performance",
2020 if (g_once_init_enter (&preset_type)) {
2021 GType type = g_enum_register_static ("GstNvEncoderPreset", presets);
2023 g_once_init_leave (&preset_type, type);
2030 gst_nv_encoder_preset_to_guid (GstNvEncoderPreset preset, GUID * guid)
2033 case GST_NV_ENCODER_PRESET_DEFAULT:
2034 *guid = NV_ENC_PRESET_DEFAULT_GUID;
2036 case GST_NV_ENCODER_PRESET_HP:
2037 *guid = NV_ENC_PRESET_HP_GUID;
2039 case GST_NV_ENCODER_PRESET_HQ:
2040 *guid = NV_ENC_PRESET_HQ_GUID;
2042 case GST_NV_ENCODER_PRESET_LOW_LATENCY_DEFAULT:
2043 *guid = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
2045 case GST_NV_ENCODER_PRESET_LOW_LATENCY_HQ:
2046 *guid = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
2048 case GST_NV_ENCODER_PRESET_LOW_LATENCY_HP:
2049 *guid = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
2051 case GST_NV_ENCODER_PRESET_LOSSLESS_DEFAULT:
2052 *guid = NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
2054 case GST_NV_ENCODER_PRESET_LOSSLESS_HP:
2055 *guid = NV_ENC_PRESET_LOSSLESS_HP_GUID;
2061 *guid = NV_ENC_PRESET_DEFAULT_GUID;
2065 * GstNvEncoderRCMode:
2070 gst_nv_encoder_rc_mode_get_type (void)
2072 static GType rc_mode_type = 0;
2073 static const GEnumValue rc_modes[] = {
2074 {GST_NV_ENCODER_RC_MODE_CONSTQP, "Constant Quantization", "cqp"},
2075 {GST_NV_ENCODER_RC_MODE_VBR, "Variable Bit Rate", "vbr"},
2076 {GST_NV_ENCODER_RC_MODE_CBR, "Constant Bit Rate", "cbr"},
2077 {GST_NV_ENCODER_RC_MODE_CBR_LOWDELAY_HQ,
2078 "Low-Delay CBR, High Quality", "cbr-ld-hq"},
2079 {GST_NV_ENCODER_RC_MODE_CBR_HQ, "CBR, High Quality (slower)", "cbr-hq"},
2080 {GST_NV_ENCODER_RC_MODE_VBR_HQ, "VBR, High Quality (slower)", "vbr-hq"},
2084 if (g_once_init_enter (&rc_mode_type)) {
2085 GType type = g_enum_register_static ("GstNvEncoderRCMode", rc_modes);
2087 g_once_init_leave (&rc_mode_type, type);
2090 return rc_mode_type;
2093 NV_ENC_PARAMS_RC_MODE
2094 gst_nv_encoder_rc_mode_to_native (GstNvEncoderRCMode rc_mode)
2097 case GST_NV_ENCODER_RC_MODE_CONSTQP:
2098 return NV_ENC_PARAMS_RC_CONSTQP;
2099 case GST_NV_ENCODER_RC_MODE_VBR:
2100 return NV_ENC_PARAMS_RC_VBR;
2101 case GST_NV_ENCODER_RC_MODE_CBR:
2102 return NV_ENC_PARAMS_RC_CBR;
2103 case GST_NV_ENCODER_RC_MODE_CBR_LOWDELAY_HQ:
2104 return NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ;
2105 case GST_NV_ENCODER_RC_MODE_CBR_HQ:
2106 return NV_ENC_PARAMS_RC_CBR_HQ;
2107 case GST_NV_ENCODER_RC_MODE_VBR_HQ:
2108 return NV_ENC_PARAMS_RC_VBR_HQ;
2113 return NV_ENC_PARAMS_RC_VBR;
2117 gst_nv_encoder_status_to_string (NVENCSTATUS status)
2121 return G_STRINGIFY (err);
2124 CASE (NV_ENC_SUCCESS);
2125 CASE (NV_ENC_ERR_NO_ENCODE_DEVICE);
2126 CASE (NV_ENC_ERR_UNSUPPORTED_DEVICE);
2127 CASE (NV_ENC_ERR_INVALID_ENCODERDEVICE);
2128 CASE (NV_ENC_ERR_INVALID_DEVICE);
2129 CASE (NV_ENC_ERR_DEVICE_NOT_EXIST);
2130 CASE (NV_ENC_ERR_INVALID_PTR);
2131 CASE (NV_ENC_ERR_INVALID_EVENT);
2132 CASE (NV_ENC_ERR_INVALID_PARAM);
2133 CASE (NV_ENC_ERR_INVALID_CALL);
2134 CASE (NV_ENC_ERR_OUT_OF_MEMORY);
2135 CASE (NV_ENC_ERR_ENCODER_NOT_INITIALIZED);
2136 CASE (NV_ENC_ERR_UNSUPPORTED_PARAM);
2137 CASE (NV_ENC_ERR_LOCK_BUSY);
2138 CASE (NV_ENC_ERR_NOT_ENOUGH_BUFFER);
2139 CASE (NV_ENC_ERR_INVALID_VERSION);
2140 CASE (NV_ENC_ERR_MAP_FAILED);
2141 CASE (NV_ENC_ERR_NEED_MORE_INPUT);
2142 CASE (NV_ENC_ERR_ENCODER_BUSY);
2143 CASE (NV_ENC_ERR_EVENT_NOT_REGISTERD);
2144 CASE (NV_ENC_ERR_GENERIC);
2145 CASE (NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY);
2146 CASE (NV_ENC_ERR_UNIMPLEMENTED);
2147 CASE (NV_ENC_ERR_RESOURCE_REGISTER_FAILED);
2148 CASE (NV_ENC_ERR_RESOURCE_NOT_REGISTERED);
2149 CASE (NV_ENC_ERR_RESOURCE_NOT_MAPPED);
2158 GstNvEncoderClassData *
2159 gst_nv_encoder_class_data_new (void)
2161 GstNvEncoderClassData *data = g_new0 (GstNvEncoderClassData, 1);
2162 data->ref_count = 1;
2167 GstNvEncoderClassData *
2168 gst_nv_encoder_class_data_ref (GstNvEncoderClassData * cdata)
2170 g_atomic_int_add (&cdata->ref_count, 1);
2176 gst_nv_encoder_class_data_unref (GstNvEncoderClassData * cdata)
2178 if (g_atomic_int_dec_and_test (&cdata->ref_count)) {
2179 gst_clear_caps (&cdata->sink_caps);
2180 gst_clear_caps (&cdata->src_caps);
2182 g_list_free_full (cdata->formats, (GDestroyNotify) g_free);
2183 if (cdata->profiles)
2184 g_list_free_full (cdata->profiles, (GDestroyNotify) g_free);
2190 gst_nv_encoder_get_encoder_caps (gpointer session, const GUID * encode_guid,
2191 GstNvEncoderDeviceCaps * device_caps)
2193 GstNvEncoderDeviceCaps dev_caps = { 0, };
2194 NV_ENC_CAPS_PARAM caps_param = { 0, };
2196 GUID guid = *encode_guid;
2198 GST_DEBUG_CATEGORY_INIT (gst_nv_encoder_debug, "nvencoder", 0, "nvencoder");
2200 caps_param.version = gst_nvenc_get_caps_param_version ();
2202 #define CHECK_CAPS(to_query,val,default_val) G_STMT_START { \
2204 caps_param.capsToQuery = to_query; \
2205 status = NvEncGetEncodeCaps (session, guid, &caps_param, \
2207 if (status != NV_ENC_SUCCESS) { \
2208 GST_WARNING ("Unable to query %s, status: %" \
2209 GST_NVENC_STATUS_FORMAT, G_STRINGIFY (to_query), \
2210 GST_NVENC_STATUS_ARGS (status)); \
2211 val = default_val; \
2213 GST_DEBUG ("%s: %d", G_STRINGIFY (to_query), _val); \
2218 CHECK_CAPS (NV_ENC_CAPS_NUM_MAX_BFRAMES, dev_caps.max_bframes, 0);
2219 CHECK_CAPS (NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES,
2220 dev_caps.ratecontrol_modes, NV_ENC_PARAMS_RC_VBR);
2221 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_FIELD_ENCODING, dev_caps.field_encoding, 0);
2222 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_MONOCHROME, dev_caps.monochrome, 0);
2223 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_FMO, dev_caps.fmo, 0);
2224 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_QPELMV, dev_caps.qpelmv, 0);
2225 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_BDIRECT_MODE, dev_caps.bdirect_mode, 0);
2226 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_CABAC, dev_caps.cabac, 0);
2227 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_ADAPTIVE_TRANSFORM,
2228 dev_caps.adaptive_transform, 0);
2229 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_STEREO_MVC, dev_caps.stereo_mvc, 0);
2230 CHECK_CAPS (NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS, dev_caps.temoral_layers, 0);
2231 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_HIERARCHICAL_PFRAMES,
2232 dev_caps.hierarchical_pframes, 0);
2233 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_HIERARCHICAL_BFRAMES,
2234 dev_caps.hierarchical_bframes, 0);
2235 CHECK_CAPS (NV_ENC_CAPS_LEVEL_MAX, dev_caps.level_max, 0);
2236 CHECK_CAPS (NV_ENC_CAPS_LEVEL_MIN, dev_caps.level_min, 0);
2237 CHECK_CAPS (NV_ENC_CAPS_SEPARATE_COLOUR_PLANE,
2238 dev_caps.separate_colour_plane, 0);
2239 CHECK_CAPS (NV_ENC_CAPS_WIDTH_MAX, dev_caps.width_max, 4096);
2240 CHECK_CAPS (NV_ENC_CAPS_HEIGHT_MAX, dev_caps.height_max, 4096);
2241 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_TEMPORAL_SVC, dev_caps.temporal_svc, 0);
2242 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE, dev_caps.dyn_res_change, 0);
2243 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE,
2244 dev_caps.dyn_bitrate_change, 0);
2245 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_FORCE_CONSTQP,
2246 dev_caps.dyn_force_constqp, 0);
2247 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYN_RCMODE_CHANGE,
2248 dev_caps.dyn_rcmode_change, 0);
2249 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_SUBFRAME_READBACK,
2250 dev_caps.subframe_readback, 0);
2251 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_CONSTRAINED_ENCODING,
2252 dev_caps.constrained_encoding, 0);
2253 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_INTRA_REFRESH, dev_caps.intra_refresh, 0);
2254 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE,
2255 dev_caps.custom_vbv_buf_size, 0);
2256 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_DYNAMIC_SLICE_MODE,
2257 dev_caps.dynamic_slice_mode, 0);
2258 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_REF_PIC_INVALIDATION,
2259 dev_caps.ref_pic_invalidation, 0);
2260 CHECK_CAPS (NV_ENC_CAPS_PREPROC_SUPPORT, dev_caps.preproc_support, 0);
2261 /* NOTE: Async is Windows only */
2263 CHECK_CAPS (NV_ENC_CAPS_ASYNC_ENCODE_SUPPORT,
2264 dev_caps.async_encoding_support, 0);
2266 CHECK_CAPS (NV_ENC_CAPS_MB_NUM_MAX, dev_caps.mb_num_max, 0);
2267 CHECK_CAPS (NV_ENC_CAPS_MB_PER_SEC_MAX, dev_caps.mb_per_sec_max, 0);
2268 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_YUV444_ENCODE, dev_caps.yuv444_encode, 0);
2269 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE, dev_caps.lossless_encode, 0);
2270 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_SAO, dev_caps.sao, 0);
2271 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_MEONLY_MODE, dev_caps.meonly_mode, 0);
2272 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_LOOKAHEAD, dev_caps.lookahead, 0);
2273 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ, dev_caps.temporal_aq, 0);
2274 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_10BIT_ENCODE,
2275 dev_caps.supports_10bit_encode, 0);
2276 CHECK_CAPS (NV_ENC_CAPS_NUM_MAX_LTR_FRAMES, dev_caps.num_max_ltr_frames, 0);
2277 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION,
2278 dev_caps.weighted_prediction, 0);
2279 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE, dev_caps.bframe_ref_mode, 0);
2280 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_EMPHASIS_LEVEL_MAP,
2281 dev_caps.emphasis_level_map, 0);
2282 CHECK_CAPS (NV_ENC_CAPS_WIDTH_MIN, dev_caps.width_min, 16);
2283 CHECK_CAPS (NV_ENC_CAPS_HEIGHT_MIN, dev_caps.height_min, 16);
2284 CHECK_CAPS (NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES,
2285 dev_caps.multiple_ref_frames, 0);
2288 *device_caps = dev_caps;
2292 gst_nv_encoder_merge_device_caps (const GstNvEncoderDeviceCaps * a,
2293 const GstNvEncoderDeviceCaps * b, GstNvEncoderDeviceCaps * merged)
2295 GstNvEncoderDeviceCaps caps;
2297 #define SELECT_MAX(value) G_STMT_START { \
2298 caps.value = MAX (a->value, b->value); \
2301 #define SELECT_MIN(value) G_STMT_START { \
2302 caps.value = MAX (MIN (a->value, b->value), 1); \
2305 SELECT_MAX (max_bframes);
2306 SELECT_MAX (ratecontrol_modes);
2307 SELECT_MAX (field_encoding);
2308 SELECT_MAX (monochrome);
2310 SELECT_MAX (qpelmv);
2311 SELECT_MAX (bdirect_mode);
2313 SELECT_MAX (adaptive_transform);
2314 SELECT_MAX (stereo_mvc);
2315 SELECT_MAX (temoral_layers);
2316 SELECT_MAX (hierarchical_pframes);
2317 SELECT_MAX (hierarchical_bframes);
2318 SELECT_MAX (level_max);
2319 SELECT_MAX (level_min);
2320 SELECT_MAX (separate_colour_plane);
2321 SELECT_MAX (width_max);
2322 SELECT_MAX (height_max);
2323 SELECT_MAX (temporal_svc);
2324 SELECT_MAX (dyn_res_change);
2325 SELECT_MAX (dyn_bitrate_change);
2326 SELECT_MAX (dyn_force_constqp);
2327 SELECT_MAX (dyn_rcmode_change);
2328 SELECT_MAX (subframe_readback);
2329 SELECT_MAX (constrained_encoding);
2330 SELECT_MAX (intra_refresh);
2331 SELECT_MAX (custom_vbv_buf_size);
2332 SELECT_MAX (dynamic_slice_mode);
2333 SELECT_MAX (ref_pic_invalidation);
2334 SELECT_MAX (preproc_support);
2335 SELECT_MAX (async_encoding_support);
2336 SELECT_MAX (mb_num_max);
2337 SELECT_MAX (mb_per_sec_max);
2338 SELECT_MAX (yuv444_encode);
2339 SELECT_MAX (lossless_encode);
2341 SELECT_MAX (meonly_mode);
2342 SELECT_MAX (lookahead);
2343 SELECT_MAX (temporal_aq);
2344 SELECT_MAX (supports_10bit_encode);
2345 SELECT_MAX (num_max_ltr_frames);
2346 SELECT_MAX (weighted_prediction);
2347 SELECT_MAX (bframe_ref_mode);
2348 SELECT_MAX (emphasis_level_map);
2349 SELECT_MIN (width_min);
2350 SELECT_MIN (height_min);
2351 SELECT_MAX (multiple_ref_frames);