mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 15:27:07 +00:00
nvdec: Register elements per device/codec with capability check
By this commit, each codec has its own element factory so the nvdec element factory is removed. Also, if there are more than one device, additional nvdec element factory will be created per device like nvh264device{device-id}dec, so that the element factory can expose the exact capability of the device for the codec.
This commit is contained in:
parent
9ec62418c3
commit
1df2f13d0c
5 changed files with 368 additions and 85 deletions
|
@ -30,11 +30,14 @@
|
|||
#define NVCUVID_LIBNAME "libnvcuvid.so.1"
|
||||
#endif
|
||||
|
||||
#define LOAD_SYMBOL(name,func) G_STMT_START { \
|
||||
#define LOAD_SYMBOL(name,func,mandatory) G_STMT_START { \
|
||||
if (!g_module_symbol (module, G_STRINGIFY (name), (gpointer *) &vtable->func)) { \
|
||||
if (mandatory) { \
|
||||
GST_ERROR ("Failed to load '%s' from %s, %s", G_STRINGIFY (name), filename, g_module_error()); \
|
||||
goto error; \
|
||||
} \
|
||||
GST_WARNING ("Failed to load '%s' from %s, %s", G_STRINGIFY (name), filename, g_module_error()); \
|
||||
} \
|
||||
} G_STMT_END;
|
||||
|
||||
typedef struct _GstnvdecCuvidVTable
|
||||
|
@ -59,6 +62,7 @@ typedef struct _GstnvdecCuvidVTable
|
|||
CUresult (*CuvidMapVideoFrame) (CUvideodecoder hDecoder, int nPicIdx,
|
||||
guintptr * pDevPtr, unsigned int *pPitch, CUVIDPROCPARAMS * pVPP);
|
||||
CUresult (*CuvidUnmapVideoFrame) (CUvideodecoder hDecoder, guintptr DevPtr);
|
||||
CUresult (*CuvidGetDecoderCaps) (CUVIDDECODECAPS * pdc);
|
||||
} GstnvdecCuvidVTable;
|
||||
|
||||
static GstnvdecCuvidVTable gst_cuvid_vtable = { 0, };
|
||||
|
@ -81,18 +85,19 @@ gst_cuvid_load_library (void)
|
|||
|
||||
vtable = &gst_cuvid_vtable;
|
||||
|
||||
LOAD_SYMBOL (cuvidCtxLockCreate, CuvidCtxLockCreate);
|
||||
LOAD_SYMBOL (cuvidCtxLockDestroy, CuvidCtxLockDestroy);
|
||||
LOAD_SYMBOL (cuvidCtxLock, CuvidCtxLock);
|
||||
LOAD_SYMBOL (cuvidCtxUnlock, CuvidCtxUnlock);
|
||||
LOAD_SYMBOL (cuvidCreateDecoder, CuvidCreateDecoder);
|
||||
LOAD_SYMBOL (cuvidDestroyDecoder, CuvidDestroyDecoder);
|
||||
LOAD_SYMBOL (cuvidDecodePicture, CuvidDecodePicture);
|
||||
LOAD_SYMBOL (cuvidCreateVideoParser, CuvidCreateVideoParser);
|
||||
LOAD_SYMBOL (cuvidParseVideoData, CuvidParseVideoData);
|
||||
LOAD_SYMBOL (cuvidDestroyVideoParser, CuvidDestroyVideoParser);
|
||||
LOAD_SYMBOL (cuvidMapVideoFrame, CuvidMapVideoFrame);
|
||||
LOAD_SYMBOL (cuvidUnmapVideoFrame, CuvidUnmapVideoFrame);
|
||||
LOAD_SYMBOL (cuvidCtxLockCreate, CuvidCtxLockCreate, TRUE);
|
||||
LOAD_SYMBOL (cuvidCtxLockDestroy, CuvidCtxLockDestroy, TRUE);
|
||||
LOAD_SYMBOL (cuvidCtxLock, CuvidCtxLock, TRUE);
|
||||
LOAD_SYMBOL (cuvidCtxUnlock, CuvidCtxUnlock, TRUE);
|
||||
LOAD_SYMBOL (cuvidCreateDecoder, CuvidCreateDecoder, TRUE);
|
||||
LOAD_SYMBOL (cuvidDestroyDecoder, CuvidDestroyDecoder, TRUE);
|
||||
LOAD_SYMBOL (cuvidDecodePicture, CuvidDecodePicture, TRUE);
|
||||
LOAD_SYMBOL (cuvidCreateVideoParser, CuvidCreateVideoParser, TRUE);
|
||||
LOAD_SYMBOL (cuvidParseVideoData, CuvidParseVideoData, TRUE);
|
||||
LOAD_SYMBOL (cuvidDestroyVideoParser, CuvidDestroyVideoParser, TRUE);
|
||||
LOAD_SYMBOL (cuvidMapVideoFrame, CuvidMapVideoFrame, TRUE);
|
||||
LOAD_SYMBOL (cuvidUnmapVideoFrame, CuvidUnmapVideoFrame, TRUE);
|
||||
LOAD_SYMBOL (cuvidGetDecoderCaps, CuvidGetDecoderCaps, FALSE);
|
||||
|
||||
vtable->loaded = TRUE;
|
||||
|
||||
|
@ -104,6 +109,12 @@ error:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_cuvid_can_get_decoder_caps (void)
|
||||
{
|
||||
return ! !gst_cuvid_vtable.CuvidGetDecoderCaps;
|
||||
}
|
||||
|
||||
CUresult
|
||||
CuvidCtxLockCreate (CUvideoctxlock * pLock, CUcontext ctx)
|
||||
{
|
||||
|
@ -201,3 +212,11 @@ CuvidUnmapVideoFrame (CUvideodecoder hDecoder, guintptr DevPtr)
|
|||
|
||||
return gst_cuvid_vtable.CuvidUnmapVideoFrame (hDecoder, DevPtr);
|
||||
}
|
||||
|
||||
CUresult
|
||||
CuvidGetDecoderCaps (CUVIDDECODECAPS * pdc)
|
||||
{
|
||||
g_assert (gst_cuvid_vtable.CuvidGetDecoderCaps != NULL);
|
||||
|
||||
return gst_cuvid_vtable.CuvidGetDecoderCaps (pdc);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ G_BEGIN_DECLS
|
|||
G_GNUC_INTERNAL
|
||||
gboolean gst_cuvid_load_library (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gst_cuvid_can_get_decoder_caps (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
CUresult CuvidCtxLockCreate (CUvideoctxlock * pLock, CUcontext ctx);
|
||||
|
||||
|
@ -75,6 +78,8 @@ CUresult CuvidMapVideoFrame (CUvideodecoder hDecoder,
|
|||
G_GNUC_INTERNAL
|
||||
CUresult CuvidUnmapVideoFrame (CUvideodecoder hDecoder,
|
||||
guintptr DevPtr);
|
||||
G_GNUC_INTERNAL
|
||||
CUresult CuvidGetDecoderCaps (CUVIDDECODECAPS * pdc);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GST_CUVID_LOADER_H__ */
|
||||
|
|
|
@ -207,25 +207,7 @@ static gboolean gst_nvdec_flush (GstVideoDecoder * decoder);
|
|||
static GstFlowReturn gst_nvdec_drain (GstVideoDecoder * decoder);
|
||||
static GstFlowReturn gst_nvdec_finish (GstVideoDecoder * decoder);
|
||||
|
||||
static GstStaticPadTemplate gst_nvdec_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
|
||||
GST_PAD_SINK, GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("video/x-h264, stream-format=byte-stream, alignment=au; "
|
||||
"video/x-h265, stream-format=byte-stream, alignment=au; "
|
||||
"video/mpeg, mpegversion={ 1, 2, 4 }, systemstream=false; "
|
||||
"image/jpeg; video/x-vp8; video/x-vp9")
|
||||
);
|
||||
|
||||
static GstStaticPadTemplate gst_nvdec_src_template =
|
||||
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME,
|
||||
GST_PAD_SRC, GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "NV12") ", texture-target=2D")
|
||||
);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstNvDec, gst_nvdec, GST_TYPE_VIDEO_DECODER,
|
||||
GST_DEBUG_CATEGORY_INIT (gst_nvdec_debug_category, "nvdec", 0,
|
||||
"Debug category for the nvdec element"));
|
||||
G_DEFINE_ABSTRACT_TYPE (GstNvDec, gst_nvdec, GST_TYPE_VIDEO_DECODER);
|
||||
|
||||
static void
|
||||
gst_nvdec_class_init (GstNvDecClass * klass)
|
||||
|
@ -233,15 +215,6 @@ gst_nvdec_class_init (GstNvDecClass * klass)
|
|||
GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&gst_nvdec_sink_template);
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&gst_nvdec_src_template);
|
||||
|
||||
gst_element_class_set_static_metadata (element_class, "NVDEC video decoder",
|
||||
"Codec/Decoder/Video/Hardware", "NVDEC video decoder",
|
||||
"Ericsson AB, http://www.ericsson.com");
|
||||
|
||||
video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_nvdec_start);
|
||||
video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_nvdec_stop);
|
||||
video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_nvdec_set_format);
|
||||
|
@ -696,9 +669,7 @@ static gboolean
|
|||
gst_nvdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
|
||||
{
|
||||
GstNvDec *nvdec = GST_NVDEC (decoder);
|
||||
GstStructure *s;
|
||||
const gchar *caps_name;
|
||||
gint mpegversion = 0;
|
||||
GstNvDecClass *klass = GST_NVDEC_GET_CLASS (decoder);
|
||||
CUVIDPARSERPARAMS parser_params = { 0, };
|
||||
|
||||
GST_DEBUG_OBJECT (nvdec, "set format");
|
||||
|
@ -711,43 +682,7 @@ gst_nvdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
|
|||
if (!maybe_destroy_decoder_and_parser (nvdec))
|
||||
return FALSE;
|
||||
|
||||
s = gst_caps_get_structure (state->caps, 0);
|
||||
caps_name = gst_structure_get_name (s);
|
||||
GST_DEBUG_OBJECT (nvdec, "codec is %s", caps_name);
|
||||
|
||||
if (!g_strcmp0 (caps_name, "video/mpeg")) {
|
||||
if (gst_structure_get_int (s, "mpegversion", &mpegversion)) {
|
||||
switch (mpegversion) {
|
||||
case 1:
|
||||
parser_params.CodecType = cudaVideoCodec_MPEG1;
|
||||
break;
|
||||
case 2:
|
||||
parser_params.CodecType = cudaVideoCodec_MPEG2;
|
||||
break;
|
||||
case 4:
|
||||
parser_params.CodecType = cudaVideoCodec_MPEG4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mpegversion) {
|
||||
GST_ERROR_OBJECT (nvdec, "could not get MPEG version");
|
||||
return FALSE;
|
||||
}
|
||||
} else if (!g_strcmp0 (caps_name, "video/x-h264")) {
|
||||
parser_params.CodecType = cudaVideoCodec_H264;
|
||||
} else if (!g_strcmp0 (caps_name, "image/jpeg")) {
|
||||
parser_params.CodecType = cudaVideoCodec_JPEG;
|
||||
} else if (!g_strcmp0 (caps_name, "video/x-h265")) {
|
||||
parser_params.CodecType = cudaVideoCodec_HEVC;
|
||||
} else if (!g_strcmp0 (caps_name, "video/x-vp8")) {
|
||||
parser_params.CodecType = cudaVideoCodec_VP8;
|
||||
} else if (!g_strcmp0 (caps_name, "video/x-vp9")) {
|
||||
parser_params.CodecType = cudaVideoCodec_VP9;
|
||||
} else {
|
||||
GST_ERROR_OBJECT (nvdec, "failed to determine codec type");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
parser_params.CodecType = klass->codec_type;
|
||||
parser_params.ulMaxNumDecodeSurfaces = 20;
|
||||
parser_params.ulErrorThreshold = 100;
|
||||
parser_params.ulMaxDisplayDelay = 0;
|
||||
|
@ -1032,3 +967,322 @@ gst_nvdec_set_context (GstElement * element, GstContext * context)
|
|||
|
||||
GST_ELEMENT_CLASS (gst_nvdec_parent_class)->set_context (element, context);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstCaps *sink_caps;
|
||||
GstCaps *src_caps;
|
||||
cudaVideoCodec codec_type;
|
||||
gchar *codec;
|
||||
guint cuda_device_id;
|
||||
gboolean is_default;
|
||||
} GstNvDecClassData;
|
||||
|
||||
static void
|
||||
gst_nvdec_subclass_init (gpointer g_class, gpointer data)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
GstNvDecClass *nvdec_class = GST_NVDEC_CLASS (g_class);
|
||||
GstNvDecClassData *cdata = data;
|
||||
gchar *long_name;
|
||||
|
||||
if (cdata->is_default) {
|
||||
long_name = g_strdup_printf ("NVDEC %s Video Decoder", cdata->codec);
|
||||
} else {
|
||||
long_name = g_strdup_printf ("NVDEC %s Video Decoder with devide-id %d",
|
||||
cdata->codec, cdata->cuda_device_id);
|
||||
}
|
||||
|
||||
gst_element_class_set_metadata (element_class, long_name,
|
||||
"Codec/Decoder/Video/Hardware", "NVDEC video decoder",
|
||||
"Ericsson AB, http://www.ericsson.com, "
|
||||
"Seungha Yang <seungha.yang@navercorp.com>");
|
||||
g_free (long_name);
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
|
||||
cdata->sink_caps));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
|
||||
cdata->src_caps));
|
||||
|
||||
nvdec_class->codec_type = cdata->codec_type;
|
||||
nvdec_class->cuda_device_id = cdata->cuda_device_id;
|
||||
|
||||
gst_caps_unref (cdata->sink_caps);
|
||||
gst_caps_unref (cdata->src_caps);
|
||||
g_free (cdata->codec);
|
||||
g_free (cdata);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_nvdec_subclass_register (GstPlugin * plugin, GType type,
|
||||
cudaVideoCodec codec_type, const gchar * codec, guint device_id, guint rank,
|
||||
GstCaps * sink_caps, GstCaps * src_caps)
|
||||
{
|
||||
GTypeQuery type_query;
|
||||
GTypeInfo type_info = { 0, };
|
||||
GType subtype;
|
||||
gchar *type_name;
|
||||
GstNvDecClassData *cdata;
|
||||
|
||||
cdata = g_new0 (GstNvDecClassData, 1);
|
||||
cdata->sink_caps = gst_caps_ref (sink_caps);
|
||||
cdata->src_caps = gst_caps_ref (src_caps);
|
||||
cdata->codec_type = codec_type;
|
||||
cdata->codec = g_strdup (codec);
|
||||
cdata->cuda_device_id = device_id;
|
||||
cdata->is_default = TRUE;
|
||||
|
||||
g_type_query (type, &type_query);
|
||||
memset (&type_info, 0, sizeof (type_info));
|
||||
type_info.class_size = type_query.class_size;
|
||||
type_info.instance_size = type_query.instance_size;
|
||||
type_info.class_init = gst_nvdec_subclass_init;
|
||||
type_info.class_data = cdata;
|
||||
|
||||
type_name = g_strdup_printf ("nv%sdec", codec);
|
||||
|
||||
if (g_type_from_name (type_name) != 0) {
|
||||
g_free (type_name);
|
||||
type_name = g_strdup_printf ("nv%sdevice%ddec", codec, device_id);
|
||||
cdata->is_default = FALSE;
|
||||
}
|
||||
|
||||
subtype = g_type_register_static (type, type_name, &type_info, 0);
|
||||
|
||||
/* make lower rank than default device */
|
||||
if (!gst_element_register (plugin, type_name, rank - 1, subtype))
|
||||
GST_WARNING ("Failed to register plugin '%s'", type_name);
|
||||
|
||||
g_free (type_name);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint idx;
|
||||
cudaVideoChromaFormat format;
|
||||
} GstNvdecChromaMap;
|
||||
|
||||
static gboolean
|
||||
gst_nvdec_register (GstPlugin * plugin, GType type, cudaVideoCodec codec_type,
|
||||
const gchar * codec, const gchar * sink_caps_string, guint rank,
|
||||
gint device_count)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < device_count; i++) {
|
||||
CUdevice cuda_device;
|
||||
CUcontext cuda_ctx;
|
||||
CUresult cuda_ret;
|
||||
gint max_width = 0, min_width = G_MAXINT;
|
||||
gint max_height = 0, min_height = G_MAXINT;
|
||||
GstCaps *sink_templ = NULL;
|
||||
GstCaps *src_templ = NULL;
|
||||
/* FIXME: support 10/12bits format */
|
||||
guint bitdepth_minus8[1] = { 0 };
|
||||
gint c_idx, b_idx;
|
||||
guint num_support = 0;
|
||||
cudaVideoChromaFormat chroma_list[] = {
|
||||
#if 0
|
||||
/* FIXME: support monochrome */
|
||||
cudaVideoChromaFormat_Monochrome,
|
||||
/* FIXME: Can our OpenGL support NV16 and its 10/12bits variant?? */
|
||||
cudaVideoChromaFormat_422,
|
||||
cudaVideoChromaFormat_444,
|
||||
#endif
|
||||
cudaVideoChromaFormat_420,
|
||||
};
|
||||
GValue format_list = G_VALUE_INIT;
|
||||
GValue format = G_VALUE_INIT;
|
||||
|
||||
if (CuDeviceGet (&cuda_device, i) != CUDA_SUCCESS)
|
||||
continue;
|
||||
|
||||
if (CuCtxCreate (&cuda_ctx, 0, cuda_device) != CUDA_SUCCESS)
|
||||
continue;
|
||||
|
||||
g_value_init (&format_list, GST_TYPE_LIST);
|
||||
g_value_init (&format, G_TYPE_STRING);
|
||||
|
||||
if (CuCtxPushCurrent (cuda_ctx) != CUDA_SUCCESS)
|
||||
goto cuda_free;
|
||||
|
||||
for (c_idx = 0; c_idx < G_N_ELEMENTS (chroma_list); c_idx++) {
|
||||
for (b_idx = 0; b_idx < G_N_ELEMENTS (bitdepth_minus8); b_idx++) {
|
||||
CUVIDDECODECAPS decoder_caps = { 0, };
|
||||
|
||||
decoder_caps.eCodecType = codec_type;
|
||||
decoder_caps.eChromaFormat = chroma_list[c_idx];
|
||||
decoder_caps.nBitDepthMinus8 = bitdepth_minus8[b_idx];
|
||||
|
||||
cuda_ret = CuvidGetDecoderCaps (&decoder_caps);
|
||||
if (cuda_ret != CUDA_SUCCESS) {
|
||||
GST_INFO ("could not query %s decoder capability, ret %d",
|
||||
codec, cuda_ret);
|
||||
continue;
|
||||
} else if (!decoder_caps.bIsSupported) {
|
||||
GST_LOG ("%s bit-depth %d with chroma format %d is not supported",
|
||||
codec, bitdepth_minus8[b_idx] + 8, c_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (min_width > decoder_caps.nMinWidth)
|
||||
min_width = decoder_caps.nMinWidth;
|
||||
if (min_height > decoder_caps.nMinHeight)
|
||||
min_height = decoder_caps.nMinHeight;
|
||||
if (max_width < decoder_caps.nMaxWidth)
|
||||
max_width = decoder_caps.nMaxWidth;
|
||||
if (max_height < decoder_caps.nMaxHeight)
|
||||
max_height = decoder_caps.nMaxHeight;
|
||||
|
||||
GST_INFO ("%s bit-depth %d with chroma format %d [%d - %d] x [%d - %d]",
|
||||
codec, bitdepth_minus8[b_idx] + 8, c_idx, min_width, max_width,
|
||||
min_height, max_height);
|
||||
|
||||
switch (chroma_list[c_idx]) {
|
||||
case cudaVideoChromaFormat_420:
|
||||
g_value_set_string (&format, "NV12");
|
||||
gst_value_list_append_value (&format_list, &format);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
num_support++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_support == 0) {
|
||||
GST_INFO ("device can not support %s", codec);
|
||||
goto cuda_free;
|
||||
}
|
||||
|
||||
src_templ = gst_caps_new_simple ("video/x-raw",
|
||||
"width", GST_TYPE_INT_RANGE, min_width, max_width,
|
||||
"height", GST_TYPE_INT_RANGE, min_height, max_height,
|
||||
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
|
||||
|
||||
gst_caps_set_value (src_templ, "format", &format_list);
|
||||
|
||||
/* OpenGL specific */
|
||||
gst_caps_set_features_simple (src_templ,
|
||||
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
|
||||
gst_caps_set_simple (src_templ,
|
||||
"texture-target", G_TYPE_STRING, "2D", NULL);
|
||||
|
||||
sink_templ = gst_caps_from_string (sink_caps_string);
|
||||
gst_caps_set_simple (sink_templ,
|
||||
"width", GST_TYPE_INT_RANGE, min_width, max_width,
|
||||
"height", GST_TYPE_INT_RANGE, min_height, max_height, NULL);
|
||||
|
||||
GST_DEBUG ("sink template caps %" GST_PTR_FORMAT, sink_templ);
|
||||
GST_DEBUG ("src template caps %" GST_PTR_FORMAT, src_templ);
|
||||
|
||||
CuCtxPopCurrent (NULL);
|
||||
|
||||
cuda_free:
|
||||
CuCtxDestroy (cuda_ctx);
|
||||
|
||||
g_value_unset (&format_list);
|
||||
g_value_unset (&format);
|
||||
|
||||
if (sink_templ && src_templ) {
|
||||
gst_nvdec_subclass_register (plugin, type, codec_type, codec, i, rank,
|
||||
sink_templ, src_templ);
|
||||
}
|
||||
|
||||
gst_clear_caps (&sink_templ);
|
||||
gst_clear_caps (&src_templ);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cudaVideoCodec codec;
|
||||
const gchar *codec_name;
|
||||
const gchar *sink_caps_string;
|
||||
} GstNvCodecMap;
|
||||
|
||||
const GstNvCodecMap codec_map[] = {
|
||||
{cudaVideoCodec_MPEG1, "mpegvideo",
|
||||
"video/mpeg, mpegversion = (int) 1, systemstream = (boolean) false"},
|
||||
{cudaVideoCodec_MPEG2, "mpeg2video",
|
||||
"video/mpeg, mpegversion = (int) 2, systemstream = (boolean) false"},
|
||||
{cudaVideoCodec_MPEG4, "mpeg4video",
|
||||
"video/mpeg, mpegversion = (int) 4, systemstream = (boolean) false"},
|
||||
#if 0
|
||||
/* FIXME: need verification */
|
||||
{cudaVideoCodec_VC1, "vc1"},
|
||||
#endif
|
||||
{cudaVideoCodec_H264, "h264",
|
||||
"video/x-h264, stream-format = (string) byte-stream"
|
||||
", alignment = (string) au"},
|
||||
{cudaVideoCodec_JPEG, "jpeg", "image/jpeg"},
|
||||
#if 0
|
||||
/* FIXME: need verification */
|
||||
{cudaVideoCodec_H264_SVC, "h264svc"},
|
||||
{cudaVideoCodec_H264_MVC, "h264mvc"},
|
||||
#endif
|
||||
{cudaVideoCodec_HEVC, "h265",
|
||||
"video/x-h265, stream-format = (string) byte-stream"
|
||||
", alignment = (string) au"},
|
||||
{cudaVideoCodec_VP8, "vp8", "video/x-vp8"},
|
||||
{cudaVideoCodec_VP9, "vp9", "video/x-vp9"}
|
||||
};
|
||||
|
||||
gboolean
|
||||
gst_nvdec_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
gint i;
|
||||
CUresult cuda_ret;
|
||||
gint dev_count = 0;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_nvdec_debug_category, "nvdec", 0,
|
||||
"Debug category for the nvdec element");
|
||||
|
||||
if (!gst_cuvid_can_get_decoder_caps ()) {
|
||||
GstCaps *src_templ;
|
||||
|
||||
GST_INFO ("Too old nvidia driver to query decoder capability");
|
||||
|
||||
src_templ =
|
||||
gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "NV12")
|
||||
", texture-target=2D");
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (codec_map); i++) {
|
||||
GstCaps *sink_templ;
|
||||
|
||||
sink_templ = gst_caps_from_string (codec_map[i].sink_caps_string);
|
||||
|
||||
gst_nvdec_subclass_register (plugin, GST_TYPE_NVDEC, codec_map[i].codec,
|
||||
codec_map[i].codec_name, 0, GST_RANK_PRIMARY, sink_templ, src_templ);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cuda_ret = CuInit (0);
|
||||
if (cuda_ret != CUDA_SUCCESS) {
|
||||
GST_ERROR ("Failed to initialize CUDA API");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cuda_ret = CuDeviceGetCount (&dev_count);
|
||||
if (cuda_ret != CUDA_SUCCESS || dev_count == 0) {
|
||||
GST_ERROR ("No CUDA devices detected");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (codec_map); i++) {
|
||||
ret &= gst_nvdec_register (plugin, GST_TYPE_NVDEC, codec_map[i].codec,
|
||||
codec_map[i].codec_name, codec_map[i].sink_caps_string,
|
||||
GST_RANK_PRIMARY, dev_count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ GType gst_nvdec_cuda_context_get_type (void);
|
|||
#define GST_TYPE_NVDEC (gst_nvdec_get_type())
|
||||
#define GST_NVDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NVDEC, GstNvDec))
|
||||
#define GST_NVDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_NVDEC, GstNvDecClass))
|
||||
#define GST_NVDEC_GET_CLASS(obj)(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_NVDEC,GstNvDecClass))
|
||||
#define GST_IS_NVDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_NVDEC))
|
||||
#define GST_IS_NVDEC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_NVDEC))
|
||||
|
||||
|
@ -96,10 +97,15 @@ struct _GstNvDec
|
|||
struct _GstNvDecClass
|
||||
{
|
||||
GstVideoDecoderClass parent_class;
|
||||
|
||||
cudaVideoCodec codec_type;
|
||||
guint cuda_device_id;
|
||||
};
|
||||
|
||||
GType gst_nvdec_get_type (void);
|
||||
|
||||
gboolean gst_nvdec_plugin_init (GstPlugin * plugin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_NVDEC_H__ */
|
||||
|
|
|
@ -46,8 +46,7 @@ plugin_init (GstPlugin * plugin)
|
|||
#if HAVE_NVCODEC_GST_GL
|
||||
/* FIXME: make nvdec usable without OpenGL dependency */
|
||||
if (gst_cuvid_load_library ()) {
|
||||
ret &= gst_element_register (plugin, "nvdec", GST_RANK_PRIMARY,
|
||||
GST_TYPE_NVDEC);
|
||||
ret &= gst_nvdec_plugin_init (plugin);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue