nvcodec: Introduce NVIDA CUDA helpers

New object and helper functions can remove duplicated code
from nvenc/nvdec. Also this is prework for CUDA device context sharing
among nvdec(s)/nvenc(s).
This commit is contained in:
Seungha Yang 2018-11-23 22:01:41 +09:00 committed by Matthew Waters
parent aea20f207d
commit 094e4a9f5c
6 changed files with 799 additions and 2 deletions

View file

@ -8,7 +8,9 @@ libgstnvcodec_la_SOURCES = \
gstnvh265enc.c \
gstcudaloader.c \
gstnvdec.c \
gstcuvidloader.c
gstcuvidloader.c \
gstcudacontext.c \
gstcudautils.c
noinst_HEADERS = \
gstnvdec.h \
@ -21,7 +23,9 @@ noinst_HEADERS = \
cuviddec.h \
nvcuvid.h \
gstcuvidloader.h \
stub/cuda.h
stub/cuda.h \
gstcudacontext.h \
gstcudautils.h
libgstnvcodec_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \

View file

@ -0,0 +1,276 @@
/* GStreamer
* Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstcudaloader.h"
#include "gstcudacontext.h"
#include "gstcudautils.h"
GST_DEBUG_CATEGORY_STATIC (gst_cuda_context_debug);
#define GST_CAT_DEFAULT gst_cuda_context_debug
enum
{
PROP_0,
PROP_DEVICE_ID
};
#define DEFAULT_DEVICE_ID -1
struct _GstCudaContextPrivate
{
CUcontext context;
CUdevice device;
gint device_id;
};
#define gst_cuda_context_parent_class parent_class
G_DEFINE_TYPE_WITH_PRIVATE (GstCudaContext, gst_cuda_context, GST_TYPE_OBJECT);
static void gst_cuda_context_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_cuda_context_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_cuda_context_constructed (GObject * object);
static void gst_cuda_context_finalize (GObject * object);
static void
gst_cuda_context_class_init (GstCudaContextClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_cuda_context_set_property;
gobject_class->get_property = gst_cuda_context_get_property;
gobject_class->constructed = gst_cuda_context_constructed;
gobject_class->finalize = gst_cuda_context_finalize;
g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
g_param_spec_int ("cuda-device-id", "Cuda Device ID",
"Set the GPU device to use for operations (-1 = auto)",
-1, G_MAXINT, DEFAULT_DEVICE_ID,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
GST_DEBUG_CATEGORY_INIT (gst_cuda_context_debug,
"cudacontext", 0, "CUDA Context");
}
static void
gst_cuda_context_init (GstCudaContext * context)
{
GstCudaContextPrivate *priv = gst_cuda_context_get_instance_private (context);
priv->context = NULL;
priv->device_id = DEFAULT_DEVICE_ID;
context->priv = priv;
}
static void
gst_cuda_context_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstCudaContext *context = GST_CUDA_CONTEXT (object);
GstCudaContextPrivate *priv = context->priv;
switch (prop_id) {
case PROP_DEVICE_ID:
priv->device_id = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_cuda_context_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstCudaContext *context = GST_CUDA_CONTEXT (object);
GstCudaContextPrivate *priv = context->priv;
switch (prop_id) {
case PROP_DEVICE_ID:
g_value_set_int (value, priv->device_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_cuda_context_constructed (GObject * object)
{
static volatile gsize once = 0;
GstCudaContext *context = GST_CUDA_CONTEXT (object);
GstCudaContextPrivate *priv = context->priv;
CUcontext cuda_ctx, old_ctx;
gboolean ret = TRUE;
CUdevice cdev = 0, cuda_dev = -1;
gint dev_count = 0;
gchar name[256];
gint min = 0, maj = 0;
gint i;
if (g_once_init_enter (&once)) {
if (CuInit (0) != CUDA_SUCCESS) {
GST_ERROR_OBJECT (context, "Failed to cuInit");
ret = FALSE;
}
g_once_init_leave (&once, ret);
if (!ret)
return;
}
if (!gst_cuda_result (CuDeviceGetCount (&dev_count)) || dev_count == 0) {
GST_WARNING ("No CUDA devices detected");
return;
}
for (i = 0; i < dev_count; ++i) {
if (gst_cuda_result (CuDeviceGet (&cdev, i)) &&
gst_cuda_result (CuDeviceGetName (name, sizeof (name), cdev)) &&
gst_cuda_result (CuDeviceGetAttribute (&maj,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cdev)) &&
gst_cuda_result (CuDeviceGetAttribute (&min,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cdev))) {
GST_INFO ("GPU #%d supports NVENC: %s (%s) (Compute SM %d.%d)", i,
(((maj << 4) + min) >= 0x30) ? "yes" : "no", name, maj, min);
if (priv->device_id == -1 || priv->device_id == cdev) {
priv->device_id = cuda_dev = cdev;
}
}
}
if (cuda_dev == -1) {
GST_WARNING ("Device with id %d does not exist", priv->device_id);
return;
}
GST_DEBUG ("Creating cuda context for device index %d", cuda_dev);
if (!gst_cuda_result (CuCtxCreate (&cuda_ctx, 0, cuda_dev))) {
GST_WARNING ("Failed to create CUDA context for cuda device %d", cuda_dev);
return;
}
if (!gst_cuda_result (CuCtxPopCurrent (&old_ctx))) {
return;
}
GST_INFO ("Created CUDA context %p with device-id %d", cuda_ctx, cuda_dev);
priv->context = cuda_ctx;
priv->device = cuda_dev;
}
static void
gst_cuda_context_finalize (GObject * object)
{
GstCudaContext *context = GST_CUDA_CONTEXT_CAST (object);
GstCudaContextPrivate *priv = context->priv;
if (priv->context) {
GST_DEBUG_OBJECT (context, "Destroying CUDA context %p", priv->context);
gst_cuda_result (CuCtxDestroy (priv->context));
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
* gst_cuda_context_new:
* @device_id: device-id for creating #GstCudaContext or -1 for auto selection
*
* Create #GstCudaContext with given device_id. If the @device_id was not -1
* but was out of range (e.g., exceed the number of device),
* #GstCudaContext will not be created.
*
* Returns: a new #GstCudaContext or %NULL on failure
*/
GstCudaContext *
gst_cuda_context_new (gint device_id)
{
GstCudaContext *self =
g_object_new (GST_TYPE_CUDA_CONTEXT, "cuda-device-id", device_id, NULL);
gst_object_ref_sink (self);
if (!self->priv->context) {
GST_ERROR ("Failed to create CUDA context");
gst_clear_object (&self);
}
return self;
}
/**
* gst_cuda_context_push:
* @ctx: a #GstCudaContext to push current thread
*
* Pushes the given @ctx onto the CPU thread's stack of current contexts.
* The specified context becomes the CPU thread's current context,
* so all CUDA functions that operate on the current context are affected.
*
* Returns: %TRUE if @ctx was pushed without error.
*/
gboolean
gst_cuda_context_push (GstCudaContext * ctx)
{
g_return_val_if_fail (ctx, FALSE);
g_return_val_if_fail (GST_IS_CUDA_CONTEXT (ctx), FALSE);
return gst_cuda_result (CuCtxPushCurrent (ctx->priv->context));
}
/**
* gst_cuda_context_pop:
*
* Pops the current CUDA context from CPU thread
*
* Returns: %TRUE if @ctx was pushed without error.
*/
gboolean
gst_cuda_context_pop (CUcontext * cuda_ctx)
{
return gst_cuda_result (CuCtxPopCurrent (cuda_ctx));
}
/**
* gst_cuda_context_get_handle:
* @ctx: a #GstCudaContext
*
* Get CUDA device context. Caller must not modify and/or destroy
* returned device context.
*
* Returns: the #CUcontext of @ctx
*/
gpointer
gst_cuda_context_get_handle (GstCudaContext * ctx)
{
g_return_val_if_fail (ctx, NULL);
g_return_val_if_fail (GST_IS_CUDA_CONTEXT (ctx), NULL);
return ctx->priv->context;
}

View file

@ -0,0 +1,77 @@
/* GStreamer
* Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CUDA_CONTEXT_H__
#define __GST_CUDA_CONTEXT_H__
#include <gst/gst.h>
#include <cuda.h>
G_BEGIN_DECLS
#define GST_TYPE_CUDA_CONTEXT (gst_cuda_context_get_type())
#define GST_CUDA_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CUDA_CONTEXT,GstCudaContext))
#define GST_CUDA_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CUDA_CONTEXT,GstCudaContextClass))
#define GST_CUDA_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_CUDA_CONTEXT,GstCudaContextClass))
#define GST_IS_CUDA_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),GST_TYPE_CUDA_CONTEXT))
#define GST_IS_CUDA_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CUDA_CONTEXT))
#define GST_CUDA_CONTEXT_CAST(obj) ((GstCudaContext*)(obj))
#define GST_CUDA_CONTEXT_TYPE "gst.cuda.context"
typedef struct _GstCudaContext GstCudaContext;
typedef struct _GstCudaContextClass GstCudaContextClass;
typedef struct _GstCudaContextPrivate GstCudaContextPrivate;
/*
* GstCudaContext:
*/
struct _GstCudaContext
{
GstObject object;
/*< private >*/
GstCudaContextPrivate *priv;
};
/*
* GstCudaContextClass:
*/
struct _GstCudaContextClass
{
GstObjectClass parent_class;
};
GType gst_cuda_context_get_type (void);
G_GNUC_INTERNAL
GstCudaContext * gst_cuda_context_new (gint device_id);
G_GNUC_INTERNAL
gboolean gst_cuda_context_push (GstCudaContext * ctx);
G_GNUC_INTERNAL
gboolean gst_cuda_context_pop (CUcontext * cuda_ctx);
G_GNUC_INTERNAL
gpointer gst_cuda_context_get_handle (GstCudaContext * ctx);
G_END_DECLS
#endif /* __GST_CUDA_CONTEXT_H__ */

342
sys/nvcodec/gstcudautils.c Normal file
View file

@ -0,0 +1,342 @@
/* GStreamer
* Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstcudautils.h"
#include "gstcudacontext.h"
GST_DEBUG_CATEGORY_STATIC (gst_cuda_utils_debug);
#define GST_CAT_DEFAULT gst_cuda_utils_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
static void
_init_debug (void)
{
static volatile gsize once_init = 0;
if (g_once_init_enter (&once_init)) {
GST_DEBUG_CATEGORY_INIT (gst_cuda_utils_debug, "cudautils", 0,
"CUDA utils");
GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
g_once_init_leave (&once_init, 1);
}
}
static gboolean
pad_query (const GValue * item, GValue * value, gpointer user_data)
{
GstPad *pad = g_value_get_object (item);
GstQuery *query = user_data;
gboolean res;
res = gst_pad_peer_query (pad, query);
if (res) {
g_value_set_boolean (value, TRUE);
return FALSE;
}
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed");
return TRUE;
}
static gboolean
run_query (GstElement * element, GstQuery * query, GstPadDirection direction)
{
GstIterator *it;
GstIteratorFoldFunction func = pad_query;
GValue res = { 0 };
g_value_init (&res, G_TYPE_BOOLEAN);
g_value_set_boolean (&res, FALSE);
/* Ask neighbor */
if (direction == GST_PAD_SRC)
it = gst_element_iterate_src_pads (element);
else
it = gst_element_iterate_sink_pads (element);
while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
return g_value_get_boolean (&res);
}
static void
find_cuda_context (GstElement * element, GstCudaContext ** cuda_ctx)
{
GstQuery *query;
GstContext *ctxt;
/* 1) Query downstream with GST_QUERY_CONTEXT for the context and
* check if upstream already has a context of the specific type
* 2) Query upstream as above.
*/
query = gst_query_new_context (GST_CUDA_CONTEXT_TYPE);
if (run_query (element, query, GST_PAD_SRC)) {
gst_query_parse_context (query, &ctxt);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%p) in downstream query", ctxt);
gst_element_set_context (element, ctxt);
}
/* although we found cuda context above, the element does not want
* to use the context. Then try to find from the other direction */
if (*cuda_ctx == NULL && run_query (element, query, GST_PAD_SINK)) {
gst_query_parse_context (query, &ctxt);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%p) in upstream query", ctxt);
gst_element_set_context (element, ctxt);
}
if (*cuda_ctx == NULL) {
/* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
* the required context type and afterwards check if a
* usable context was set now. The message could
* be handled by the parent bins of the element and the
* application.
*/
GstMessage *msg;
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting need context message");
msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
GST_CUDA_CONTEXT_TYPE);
gst_element_post_message (element, msg);
}
/*
* Whomever responds to the need-context message performs a
* GstElement::set_context() with the required context in which the element
* is required to update the cuda_ctx or call gst_cuda_handle_set_context().
*/
gst_query_unref (query);
}
static void
context_set_cuda_context (GstContext * context, GstCudaContext * cuda_ctx)
{
GstStructure *s;
gint device_id;
g_return_if_fail (context != NULL);
g_object_get (G_OBJECT (cuda_ctx), "cuda-device-id", &device_id, NULL);
GST_CAT_LOG (GST_CAT_CONTEXT,
"setting GstCudaContext(%" GST_PTR_FORMAT
") with cuda-device-id %d on context(%" GST_PTR_FORMAT ")",
cuda_ctx, device_id, context);
s = gst_context_writable_structure (context);
gst_structure_set (s, GST_CUDA_CONTEXT_TYPE, GST_TYPE_CUDA_CONTEXT,
cuda_ctx, "cuda-device-id", G_TYPE_INT, device_id, NULL);
}
/**
* gst_cuda_ensure_element_context:
* @element: the #GstElement running the query
* @device_id: prefered device-id, pass device_id >=0 when
* the device_id explicitly required. Otherwise, set -1.
* @cuda_ctx: (inout): the resulting #GstCudaContext
*
* Perform the steps necessary for retrieving a #GstCudaContext from the
* surrounding elements or from the application using the #GstContext mechanism.
*
* If the content of @cuda_ctx is not %NULL, then no #GstContext query is
* necessary for #GstCudaContext.
*
* Returns: whether a #GstCudaContext exists in @cuda_ctx
*/
gboolean
gst_cuda_ensure_element_context (GstElement * element, gint device_id,
GstCudaContext ** cuda_ctx)
{
g_return_val_if_fail (element != NULL, FALSE);
g_return_val_if_fail (cuda_ctx != NULL, FALSE);
_init_debug ();
if (*cuda_ctx)
return TRUE;
find_cuda_context (element, cuda_ctx);
if (*cuda_ctx)
return TRUE;
/* No available CUDA context in pipeline, create new one here */
*cuda_ctx = gst_cuda_context_new (device_id);
if (*cuda_ctx == NULL) {
GST_CAT_ERROR_OBJECT (GST_CAT_CONTEXT, element,
"Failed to create CUDA context with device-id %d", device_id);
return FALSE;
} else {
GstContext *context;
GstMessage *msg;
/* Propagate new CUDA context */
context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
context_set_cuda_context (context, *cuda_ctx);
gst_element_set_context (element, context);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting have context (%p) message with CUDA context (%p)",
context, *cuda_ctx);
msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
gst_element_post_message (GST_ELEMENT_CAST (element), msg);
}
return TRUE;
}
/**
* gst_cuda_handle_set_context:
* @element: a #GstElement
* @context: a #GstContext
* @device_id: prefered device-id, pass device_id >=0 when
* the device_id explicitly required. Otherwise, set -1.
* @cuda_ctx: (inout) (transfer full): location of a #GstCudaContext
*
* Helper function for implementing #GstElementClass.set_context() in
* CUDA capable elements.
*
* Retrieves the #GstCudaContext in @context and places the result in @cuda_ctx.
*
* Returns: whether the @cuda_ctx could be set successfully
*/
gboolean
gst_cuda_handle_set_context (GstElement * element,
GstContext * context, gint device_id, GstCudaContext ** cuda_ctx)
{
const gchar *context_type;
g_return_val_if_fail (element != NULL, FALSE);
g_return_val_if_fail (cuda_ctx != NULL, FALSE);
_init_debug ();
if (!context)
return FALSE;
context_type = gst_context_get_context_type (context);
if (g_strcmp0 (context_type, GST_CUDA_CONTEXT_TYPE) == 0) {
const GstStructure *str;
GstCudaContext *other_ctx = NULL;
gint other_device_id = 0;
/* If we had context already, will not replace it */
if (*cuda_ctx)
return TRUE;
str = gst_context_get_structure (context);
if (gst_structure_get (str, GST_CUDA_CONTEXT_TYPE, GST_TYPE_CUDA_CONTEXT,
&other_ctx, NULL)) {
g_object_get (other_ctx, "cuda-device-id", &other_device_id, NULL);
if (device_id == -1 || other_device_id == device_id) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element, "Found CUDA context");
*cuda_ctx = other_ctx;
return TRUE;
}
gst_object_unref (other_ctx);
}
}
return FALSE;
}
/**
* gst_cuda_handle_context_query:
* @element: a #GstElement
* @query: a #GstQuery of type %GST_QUERY_CONTEXT
* @cuda_ctx: (transfer none) (nullable): a #GstCudaContext
*
* Returns: Whether the @query was successfully responded to from the passed
* @context.
*/
gboolean
gst_cuda_handle_context_query (GstElement * element,
GstQuery * query, GstCudaContext * cuda_ctx)
{
const gchar *context_type;
GstContext *context, *old_context;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
g_return_val_if_fail (cuda_ctx == NULL
|| GST_IS_CUDA_CONTEXT (cuda_ctx), FALSE);
_init_debug ();
GST_CAT_LOG_OBJECT (GST_CAT_CONTEXT, element,
"handle context query %" GST_PTR_FORMAT, query);
gst_query_parse_context_type (query, &context_type);
if (cuda_ctx && g_strcmp0 (context_type, GST_CUDA_CONTEXT_TYPE) == 0) {
gst_query_parse_context (query, &old_context);
if (old_context)
context = gst_context_copy (old_context);
else
context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
context_set_cuda_context (context, cuda_ctx);
gst_query_set_context (query, context);
gst_context_unref (context);
GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element,
"successfully set %" GST_PTR_FORMAT " on %" GST_PTR_FORMAT, cuda_ctx,
query);
return TRUE;
}
return FALSE;
}
/**
* gst_context_new_cuda_context:
* @cuda_ctx: (transfer none) a #GstCudaContext
*
* Returns: (transfer full) (nullable): a new #GstContext embedding the @cuda_ctx
* or %NULL
*/
GstContext *
gst_context_new_cuda_context (GstCudaContext * cuda_ctx)
{
GstContext *context;
g_return_val_if_fail (GST_IS_CUDA_CONTEXT (cuda_ctx), NULL);
context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
context_set_cuda_context (context, cuda_ctx);
return context;
}

View file

@ -0,0 +1,96 @@
/* GStreamer
* Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CUDA_UTILS_H__
#define __GST_CUDA_UTILS_H__
#include <gst/gst.h>
#include "gstcudaloader.h"
#include "gstcudacontext.h"
G_BEGIN_DECLS
#ifndef GST_DISABLE_GST_DEBUG
static inline gboolean
_gst_cuda_debug(CUresult result, GstDebugCategory * category,
const gchar * file, const gchar * function, gint line)
{
const gchar *_error_name, *_error_text;
if (result != CUDA_SUCCESS) {
CuGetErrorName (result, &_error_name);
CuGetErrorString (result, &_error_text);
gst_debug_log (category, GST_LEVEL_WARNING, file, function, line,
NULL, "CUDA call failed: %s, %s", _error_name, _error_text);
return FALSE;
}
return TRUE;
}
/**
* gst_cuda_result:
* @result: CUDA device API return code #CUresult
*
* Returns: %TRUE if CUDA device API call result is CUDA_SUCCESS
*/
#define gst_cuda_result(result) \
_gst_cuda_debug(result, GST_CAT_DEFAULT, __FILE__, GST_FUNCTION, __LINE__)
#else
static inline gboolean
_gst_cuda_debug(CUresult result, GstDebugCategory * category,
const gchar * file, const gchar * function, gint line)
{
return result == CUDA_SUCCESS;
}
/**
* gst_cuda_result:
* @result: CUDA device API return code #CUresult
*
* Returns: %TRUE if CUDA device API call result is CUDA_SUCCESS
*/
#define gst_cuda_result(result) \
_gst_cuda_debug(result, NULL, __FILE__, GST_FUNCTION, __LINE__)
#endif
G_GNUC_INTERNAL
gboolean gst_cuda_ensure_element_context (GstElement * element,
gint device_id,
GstCudaContext ** cuda_ctx);
G_GNUC_INTERNAL
gboolean gst_cuda_handle_set_context (GstElement * element,
GstContext * context,
gint device_id,
GstCudaContext ** cuda_ctx);
G_GNUC_INTERNAL
gboolean gst_cuda_handle_context_query (GstElement * element,
GstQuery * query,
GstCudaContext * cuda_ctx);
G_GNUC_INTERNAL
GstContext * gst_context_new_cuda_context (GstCudaContext * context);
G_END_DECLS
#endif /* __GST_CUDA_UTILS_H__ */

View file

@ -7,6 +7,8 @@ nvcodec_sources = [
'gstcudaloader.c',
'gstnvdec.c',
'gstcuvidloader.c',
'gstcudacontext.c',
'gstcudautils.c',
]
if get_option('nvcodec').disabled()