mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
nvenc: Port to GstCudaContext
... and add support CUDA context sharing similar to glcontext sharing. Multiple CUDA context per GPU is not the best practice. The context sharing method is very similar to that of glcontext. The difference is that there can be multiple context object on a pipeline since the CUDA context is created per GPU id. For example, a pipeline has nvh264dec (uses GPU #0) and nvh264device0dec (uses GPU #1), then two CUDA context will propagated to all pipeline.
This commit is contained in:
parent
094e4a9f5c
commit
5cf0351418
4 changed files with 39 additions and 108 deletions
|
@ -22,6 +22,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstnvbaseenc.h"
|
#include "gstnvbaseenc.h"
|
||||||
|
#include "gstcudautils.h"
|
||||||
|
|
||||||
#include <gst/pbutils/codec-utils.h>
|
#include <gst/pbutils/codec-utils.h>
|
||||||
|
|
||||||
|
@ -292,10 +293,9 @@ gst_nv_base_enc_open (GstVideoEncoder * enc)
|
||||||
GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (enc);
|
GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (enc);
|
||||||
GValue *formats = NULL;
|
GValue *formats = NULL;
|
||||||
|
|
||||||
nvenc->cuda_ctx = gst_nvenc_create_cuda_context (klass->cuda_device_id);
|
if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (enc),
|
||||||
if (nvenc->cuda_ctx == NULL) {
|
klass->cuda_device_id, &nvenc->cuda_ctx)) {
|
||||||
GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
|
GST_ERROR_OBJECT (nvenc, "failed to create CUDA context");
|
||||||
("Failed to create CUDA context, perhaps CUDA is not supported."));
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,13 +305,12 @@ gst_nv_base_enc_open (GstVideoEncoder * enc)
|
||||||
|
|
||||||
params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
|
params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
|
||||||
params.apiVersion = NVENCAPI_VERSION;
|
params.apiVersion = NVENCAPI_VERSION;
|
||||||
params.device = nvenc->cuda_ctx;
|
params.device = gst_cuda_context_get_handle (nvenc->cuda_ctx);
|
||||||
params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
|
params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
|
||||||
nv_ret = NvEncOpenEncodeSessionEx (¶ms, &nvenc->encoder);
|
nv_ret = NvEncOpenEncodeSessionEx (¶ms, &nvenc->encoder);
|
||||||
if (nv_ret != NV_ENC_SUCCESS) {
|
if (nv_ret != NV_ENC_SUCCESS) {
|
||||||
GST_ERROR ("Failed to create NVENC encoder session, ret=%d", nv_ret);
|
GST_ERROR ("Failed to create NVENC encoder session, ret=%d", nv_ret);
|
||||||
if (gst_nvenc_destroy_cuda_context (nvenc->cuda_ctx))
|
gst_clear_object (&nvenc->cuda_ctx);
|
||||||
nvenc->cuda_ctx = NULL;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
GST_INFO ("created NVENC encoder %p", nvenc->encoder);
|
GST_INFO ("created NVENC encoder %p", nvenc->encoder);
|
||||||
|
@ -333,9 +332,14 @@ gst_nv_base_enc_open (GstVideoEncoder * enc)
|
||||||
static void
|
static void
|
||||||
gst_nv_base_enc_set_context (GstElement * element, GstContext * context)
|
gst_nv_base_enc_set_context (GstElement * element, GstContext * context)
|
||||||
{
|
{
|
||||||
#if HAVE_NVCODEC_GST_GL
|
|
||||||
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (element);
|
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (element);
|
||||||
|
GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (nvenc);
|
||||||
|
|
||||||
|
if (gst_cuda_handle_set_context (element, context, klass->cuda_device_id,
|
||||||
|
&nvenc->cuda_ctx)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#if HAVE_NVCODEC_GST_GL
|
||||||
gst_gl_handle_set_context (element, context,
|
gst_gl_handle_set_context (element, context,
|
||||||
(GstGLDisplay **) & nvenc->display,
|
(GstGLDisplay **) & nvenc->display,
|
||||||
(GstGLContext **) & nvenc->other_context);
|
(GstGLContext **) & nvenc->other_context);
|
||||||
|
@ -344,32 +348,38 @@ gst_nv_base_enc_set_context (GstElement * element, GstContext * context)
|
||||||
SUPPORTED_GL_APIS);
|
SUPPORTED_GL_APIS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
done:
|
||||||
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
|
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_nv_base_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
|
gst_nv_base_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
|
||||||
{
|
{
|
||||||
#if HAVE_NVCODEC_GST_GL
|
|
||||||
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
|
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (GST_QUERY_TYPE (query)) {
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
#if HAVE_NVCODEC_GST_GL
|
|
||||||
case GST_QUERY_CONTEXT:{
|
case GST_QUERY_CONTEXT:{
|
||||||
|
if (gst_cuda_handle_context_query (GST_ELEMENT (nvenc),
|
||||||
|
query, nvenc->cuda_ctx))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
#if HAVE_NVCODEC_GST_GL
|
||||||
|
{
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
ret = gst_gl_handle_context_query ((GstElement *) nvenc, query,
|
ret = gst_gl_handle_context_query ((GstElement *) nvenc, query,
|
||||||
nvenc->display, NULL, nvenc->other_context);
|
nvenc->display, NULL, nvenc->other_context);
|
||||||
if (nvenc->display)
|
if (nvenc->display) {
|
||||||
gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display),
|
gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display),
|
||||||
SUPPORTED_GL_APIS);
|
SUPPORTED_GL_APIS);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -629,11 +639,7 @@ gst_nv_base_enc_close (GstVideoEncoder * enc)
|
||||||
nvenc->encoder = NULL;
|
nvenc->encoder = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvenc->cuda_ctx) {
|
gst_clear_object (&nvenc->cuda_ctx);
|
||||||
if (!gst_nvenc_destroy_cuda_context (nvenc->cuda_ctx))
|
|
||||||
return FALSE;
|
|
||||||
nvenc->cuda_ctx = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_OBJECT_LOCK (nvenc);
|
GST_OBJECT_LOCK (nvenc);
|
||||||
if (nvenc->input_formats)
|
if (nvenc->input_formats)
|
||||||
|
@ -977,7 +983,7 @@ gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc)
|
||||||
if (nvenc->gl_input) {
|
if (nvenc->gl_input) {
|
||||||
struct gl_input_resource *in_gl_resource = nvenc->input_bufs[i];
|
struct gl_input_resource *in_gl_resource = nvenc->input_bufs[i];
|
||||||
|
|
||||||
CuCtxPushCurrent (nvenc->cuda_ctx);
|
gst_cuda_context_push (nvenc->cuda_ctx);
|
||||||
|
|
||||||
if (in_gl_resource->mapped) {
|
if (in_gl_resource->mapped) {
|
||||||
GST_LOG_OBJECT (nvenc, "Unmap resource %p", in_gl_resource);
|
GST_LOG_OBJECT (nvenc, "Unmap resource %p", in_gl_resource);
|
||||||
|
@ -1006,7 +1012,7 @@ gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc)
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (in_gl_resource);
|
g_free (in_gl_resource);
|
||||||
CuCtxPopCurrent (NULL);
|
gst_cuda_context_pop (NULL);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -1306,7 +1312,7 @@ gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
|
||||||
pixel_depth += GST_VIDEO_INFO_COMP_DEPTH (info, i);
|
pixel_depth += GST_VIDEO_INFO_COMP_DEPTH (info, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
CuCtxPushCurrent (nvenc->cuda_ctx);
|
gst_cuda_context_push (nvenc->cuda_ctx);
|
||||||
for (i = 0; i < nvenc->n_bufs; ++i) {
|
for (i = 0; i < nvenc->n_bufs; ++i) {
|
||||||
struct gl_input_resource *in_gl_resource =
|
struct gl_input_resource *in_gl_resource =
|
||||||
g_new0 (struct gl_input_resource, 1);
|
g_new0 (struct gl_input_resource, 1);
|
||||||
|
@ -1353,7 +1359,7 @@ gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
|
||||||
g_async_queue_push (nvenc->in_bufs_pool, nvenc->input_bufs[i]);
|
g_async_queue_push (nvenc->in_bufs_pool, nvenc->input_bufs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
CuCtxPopCurrent (NULL);
|
gst_cuda_context_pop (NULL);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -1489,7 +1495,7 @@ _map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
|
||||||
guint i;
|
guint i;
|
||||||
CUDA_MEMCPY2D param;
|
CUDA_MEMCPY2D param;
|
||||||
|
|
||||||
CuCtxPushCurrent (data->nvenc->cuda_ctx);
|
gst_cuda_context_push (data->nvenc->cuda_ctx);
|
||||||
data_pointer = data->in_gl_resource->cuda_pointer;
|
data_pointer = data->in_gl_resource->cuda_pointer;
|
||||||
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->info); i++) {
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->info); i++) {
|
||||||
GstGLBuffer *gl_buf_obj;
|
GstGLBuffer *gl_buf_obj;
|
||||||
|
@ -1585,7 +1591,7 @@ _map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
|
||||||
data_pointer = data_pointer +
|
data_pointer = data_pointer +
|
||||||
dest_stride * _get_plane_height (&data->nvenc->input_info, i);
|
dest_stride * _get_plane_height (&data->nvenc->input_info, i);
|
||||||
}
|
}
|
||||||
CuCtxPopCurrent (NULL);
|
gst_cuda_context_pop (NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "gstnvenc.h"
|
#include "gstnvenc.h"
|
||||||
|
|
||||||
#include <gst/video/gstvideoencoder.h>
|
#include <gst/video/gstvideoencoder.h>
|
||||||
|
#include "gstcudacontext.h"
|
||||||
|
|
||||||
#define GST_TYPE_NV_BASE_ENC \
|
#define GST_TYPE_NV_BASE_ENC \
|
||||||
(gst_nv_base_enc_get_type())
|
(gst_nv_base_enc_get_type())
|
||||||
|
@ -70,7 +71,7 @@ typedef struct {
|
||||||
guint bitrate;
|
guint bitrate;
|
||||||
gint gop_size;
|
gint gop_size;
|
||||||
|
|
||||||
CUcontext cuda_ctx;
|
GstCudaContext * cuda_ctx;
|
||||||
void * encoder;
|
void * encoder;
|
||||||
|
|
||||||
/* the supported input formats */
|
/* the supported input formats */
|
||||||
|
|
|
@ -285,78 +285,6 @@ gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt)
|
||||||
return NV_ENC_BUFFER_FORMAT_UNDEFINED;
|
return NV_ENC_BUFFER_FORMAT_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
CUcontext
|
|
||||||
gst_nvenc_create_cuda_context (guint device_id)
|
|
||||||
{
|
|
||||||
CUcontext cuda_ctx, old_ctx;
|
|
||||||
CUresult cres = CUDA_SUCCESS;
|
|
||||||
CUdevice cdev = 0, cuda_dev = -1;
|
|
||||||
int dev_count = 0;
|
|
||||||
char name[256];
|
|
||||||
int min = 0, maj = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
GST_INFO ("Initialising CUDA..");
|
|
||||||
|
|
||||||
cres = CuInit (0);
|
|
||||||
|
|
||||||
if (cres != CUDA_SUCCESS) {
|
|
||||||
GST_WARNING ("Failed to initialise CUDA, error code: 0x%08x", cres);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_INFO ("Initialised CUDA");
|
|
||||||
|
|
||||||
cres = CuDeviceGetCount (&dev_count);
|
|
||||||
if (cres != CUDA_SUCCESS || dev_count == 0) {
|
|
||||||
GST_WARNING ("No CUDA devices detected");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_INFO ("%d CUDA device(s) detected", dev_count);
|
|
||||||
for (i = 0; i < dev_count; ++i) {
|
|
||||||
if (CuDeviceGet (&cdev, i) == CUDA_SUCCESS
|
|
||||||
&& CuDeviceGetName (name, sizeof (name), cdev) == CUDA_SUCCESS
|
|
||||||
&& CuDeviceGetAttribute (&maj,
|
|
||||||
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cdev) == CUDA_SUCCESS
|
|
||||||
&& CuDeviceGetAttribute (&min,
|
|
||||||
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
|
|
||||||
cdev) == CUDA_SUCCESS) {
|
|
||||||
GST_INFO ("GPU #%d supports NVENC: %s (%s) (Compute SM %d.%d)", i,
|
|
||||||
(((maj << 4) + min) >= 0x30) ? "yes" : "no", name, maj, min);
|
|
||||||
if (i == device_id) {
|
|
||||||
cuda_dev = cdev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cuda_dev == -1) {
|
|
||||||
GST_WARNING ("Device with id %d does not exist or does not support NVENC",
|
|
||||||
device_id);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CuCtxCreate (&cuda_ctx, 0, cuda_dev) != CUDA_SUCCESS) {
|
|
||||||
GST_WARNING ("Failed to create CUDA context for cuda device %d", cuda_dev);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CuCtxPopCurrent (&old_ctx) != CUDA_SUCCESS) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_INFO ("Created CUDA context %p", cuda_ctx);
|
|
||||||
|
|
||||||
return cuda_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
gst_nvenc_destroy_cuda_context (CUcontext ctx)
|
|
||||||
{
|
|
||||||
GST_INFO ("Destroying CUDA context %p", ctx);
|
|
||||||
return (CuCtxDestroy (ctx) == CUDA_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
load_nvenc_library (void)
|
load_nvenc_library (void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,10 +28,6 @@
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (gst_nvenc_debug);
|
GST_DEBUG_CATEGORY_EXTERN (gst_nvenc_debug);
|
||||||
|
|
||||||
CUcontext gst_nvenc_create_cuda_context (guint device_id);
|
|
||||||
|
|
||||||
gboolean gst_nvenc_destroy_cuda_context (CUcontext ctx);
|
|
||||||
|
|
||||||
gboolean gst_nvenc_cmp_guid (GUID g1, GUID g2);
|
gboolean gst_nvenc_cmp_guid (GUID g1, GUID g2);
|
||||||
|
|
||||||
NV_ENC_BUFFER_FORMAT gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt);
|
NV_ENC_BUFFER_FORMAT gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt);
|
||||||
|
|
Loading…
Reference in a new issue