nvdec: Register elements per device/codec with capability check
authorSeungha Yang <seungha.yang@navercorp.com>
Thu, 11 Jul 2019 12:53:46 +0000 (21:53 +0900)
committerSebastian Dröge <slomo@coaxion.net>
Mon, 22 Jul 2019 17:39:45 +0000 (17:39 +0000)
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.

sys/nvcodec/gstcuvidloader.c
sys/nvcodec/gstcuvidloader.h
sys/nvcodec/gstnvdec.c
sys/nvcodec/gstnvdec.h
sys/nvcodec/plugin.c

index 9943acb..2eda7f1 100644 (file)
 #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)) { \
-    GST_ERROR ("Failed to load '%s' from %s, %s", G_STRINGIFY (name), filename, g_module_error()); \
-    goto error; \
+    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;
 
@@ -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);
+}
index 51d252a..f9ad6c5 100644 (file)
@@ -30,6 +30,9 @@ 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);
 
 G_GNUC_INTERNAL
@@ -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__ */
index 37fa5ba..1870942 100644 (file)
@@ -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;
+}
index ccc5727..72d263b 100644 (file)
@@ -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__ */
index ee55ff3..3dc27af 100644 (file)
@@ -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