nvcodec: Add cuda-device-id read-only property to stateless decoders
authorSeungha Yang <seungha@centricular.com>
Sun, 26 Jun 2022 13:26:29 +0000 (22:26 +0900)
committerSeungha Yang <seungha@centricular.com>
Wed, 29 Jun 2022 16:54:17 +0000 (01:54 +0900)
... and remove unnecessary intermediate subclass from class hierarchy

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2665>

subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.c
subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h
subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.c
subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.h
subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.c
subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.h
subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.c
subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.h
subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.c
subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.h

index 0c6c8af..bf717ec 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
+/**
+ * SECTION:element-nvav1dec
+ * @title: nvav1dec
+ *
+ * GstCodecs based NVIDIA AV1 video decoder
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 filesrc location=/path/to/av1/file ! parsebin ! nvav1dec ! videoconvert ! autovideosink
+ * ```
+ *
+ * Since: 1.22
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -66,12 +81,11 @@ typedef struct _GstNvAV1DecClass
   guint cuda_device_id;
 } GstNvAV1DecClass;
 
-typedef struct
+enum
 {
-  GstCaps *sink_caps;
-  GstCaps *src_caps;
-  guint cuda_device_id;
-} GstNvAV1DecClassData;
+  PROP_0,
+  PROP_CUDA_DEVICE_ID,
+};
 
 static GTypeClass *parent_class = NULL;
 
@@ -79,6 +93,9 @@ static GTypeClass *parent_class = NULL;
 #define GST_NV_AV1_DEC_GET_CLASS(object) \
     (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvAV1DecClass))
 
+static void gst_nv_av1_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
 static void gst_nv_av1_dec_set_context (GstElement * element,
     GstContext * context);
 static gboolean gst_nv_av1_dec_open (GstVideoDecoder * decoder);
@@ -108,12 +125,20 @@ static guint gst_nv_av1_dec_get_preferred_output_delay (GstAV1Decoder * decoder,
 
 static void
 gst_nv_av1_dec_class_init (GstNvAV1DecClass * klass,
-    GstNvAV1DecClassData * cdata)
+    GstNvDecoderClassData * cdata)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
   GstAV1DecoderClass *av1decoder_class = GST_AV1_DECODER_CLASS (klass);
 
+  object_class->get_property = gst_nv_av1_dec_get_property;
+
+  g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
+      g_param_spec_uint ("cuda-device-id", "CUDA device id",
+          "Assigned CUDA device id", 0, G_MAXINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_av1_dec_set_context);
 
   parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
@@ -165,6 +190,22 @@ gst_nv_av1_dec_init (GstNvAV1Dec * self)
 }
 
 static void
+gst_nv_av1_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstNvAV1DecClass *klass = GST_NV_AV1_DEC_GET_CLASS (object);
+
+  switch (prop_id) {
+    case PROP_CUDA_DEVICE_ID:
+      g_value_set_uint (value, klass->cuda_device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_nv_av1_dec_set_context (GstElement * element, GstContext * context)
 {
   GstNvAV1Dec *self = GST_NV_AV1_DEC (element);
@@ -874,11 +915,11 @@ gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, guint rank,
     0,
     (GInstanceInitFunc) gst_nv_av1_dec_init,
   };
-  GstNvAV1DecClassData *cdata;
+  GstNvDecoderClassData *cdata;
 
   GST_DEBUG_CATEGORY_INIT (gst_nv_av1_dec_debug, "nvav1dec", 0, "nvav1dec");
 
-  cdata = g_new0 (GstNvAV1DecClassData, 1);
+  cdata = g_new0 (GstNvDecoderClassData, 1);
   cdata->sink_caps = gst_caps_ref (sink_caps);
   cdata->src_caps = gst_caps_ref (src_caps);
   cdata->cuda_device_id = device_id;
index 635d63d..635b301 100644 (file)
@@ -49,6 +49,13 @@ typedef struct _GstNvDecoderFrame
   gint ref_count;
 } GstNvDecoderFrame;
 
+typedef struct _GstNvDecoderClassData
+{
+  GstCaps *sink_caps;
+  GstCaps *src_caps;
+  guint cuda_device_id;
+} GstNvDecoderClassData;
+
 GstNvDecoder * gst_nv_decoder_new (GstCudaContext * context);
 
 gboolean       gst_nv_decoder_is_configured (GstNvDecoder * decoder);
index 3f5c335..61e9296 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/**
+ * SECTION:element-nvh264sldec
+ * @title: nvh264sldec
+ *
+ * GstCodecs based NVIDIA H.264 video decoder
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 filesrc location=/path/to/h264/file ! parsebin ! nvh264sldec ! videoconvert ! autovideosink
+ * ```
+ *
+ * Since: 1.18
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -84,7 +99,7 @@
 GST_DEBUG_CATEGORY_STATIC (gst_nv_h264_dec_debug);
 #define GST_CAT_DEFAULT gst_nv_h264_dec_debug
 
-struct _GstNvH264Dec
+typedef struct _GstNvH264Dec
 {
   GstH264Decoder parent;
 
@@ -114,18 +129,30 @@ struct _GstNvH264Dec
   gboolean interlaced;
 
   GArray *ref_list;
-};
+} GstNvH264Dec;
 
-struct _GstNvH264DecClass
+typedef struct _GstNvH264DecClass
 {
   GstH264DecoderClass parent_class;
   guint cuda_device_id;
+} GstNvH264DecClass;
+
+enum
+{
+  PROP_0,
+  PROP_CUDA_DEVICE_ID,
 };
 
-#define gst_nv_h264_dec_parent_class parent_class
-G_DEFINE_TYPE (GstNvH264Dec, gst_nv_h264_dec, GST_TYPE_H264_DECODER);
+static GTypeClass *parent_class = NULL;
+
+#define GST_NV_H264_DEC(object) ((GstNvH264Dec *) (object))
+#define GST_NV_H264_DEC_GET_CLASS(object) \
+    (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvH264DecClass))
 
 static void gst_nv_h264_decoder_dispose (GObject * object);
+static void gst_nv_h264_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
 static void gst_nv_h264_dec_set_context (GstElement * element,
     GstContext * context);
 static gboolean gst_nv_h264_dec_open (GstVideoDecoder * decoder);
@@ -158,23 +185,44 @@ gst_nv_h264_dec_get_preferred_output_delay (GstH264Decoder * decoder,
     gboolean live);
 
 static void
-gst_nv_h264_dec_class_init (GstNvH264DecClass * klass)
+gst_nv_h264_dec_class_init (GstNvH264DecClass * klass,
+    GstNvDecoderClassData * cdata)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
   GstH264DecoderClass *h264decoder_class = GST_H264_DECODER_CLASS (klass);
 
+  object_class->dispose = gst_nv_h264_decoder_dispose;
+  object_class->get_property = gst_nv_h264_dec_get_property;
+
   /**
-   * GstNvH264Dec
+   * GstNvH264SLDec:cuda-device-id:
+   *
+   * Assigned CUDA device id
    *
-   * Since: 1.18
+   * Since: 1.22
    */
-
-  object_class->dispose = gst_nv_h264_decoder_dispose;
+  g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
+      g_param_spec_uint ("cuda-device-id", "CUDA device id",
+          "Assigned CUDA device id", 0, G_MAXINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_set_context);
 
+  parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
+  gst_element_class_set_static_metadata (element_class,
+      "NVDEC H.264 Stateless Decoder",
+      "Codec/Decoder/Video/Hardware",
+      "NVIDIA H.264 video decoder", "Seungha Yang <seungha@centricular.com>");
+
+  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));
+
   decoder_class->open = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_open);
   decoder_class->close = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_close);
   decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_negotiate);
@@ -199,10 +247,11 @@ gst_nv_h264_dec_class_init (GstNvH264DecClass * klass)
   h264decoder_class->get_preferred_output_delay =
       GST_DEBUG_FUNCPTR (gst_nv_h264_dec_get_preferred_output_delay);
 
-  GST_DEBUG_CATEGORY_INIT (gst_nv_h264_dec_debug,
-      "nvh264dec", 0, "Nvidia H.264 Decoder");
+  klass->cuda_device_id = cdata->cuda_device_id;
 
-  gst_type_mark_as_plugin_api (GST_TYPE_NV_H264_DEC, 0);
+  gst_caps_unref (cdata->sink_caps);
+  gst_caps_unref (cdata->src_caps);
+  g_free (cdata);
 }
 
 static void
@@ -225,6 +274,22 @@ gst_nv_h264_decoder_dispose (GObject * object)
 }
 
 static void
+gst_nv_h264_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstNvH264DecClass *klass = GST_NV_H264_DEC_GET_CLASS (object);
+
+  switch (prop_id) {
+    case PROP_CUDA_DEVICE_ID:
+      g_value_set_uint (value, klass->cuda_device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_nv_h264_dec_set_context (GstElement * element, GstContext * context)
 {
   GstNvH264Dec *self = GST_NV_H264_DEC (element);
@@ -885,68 +950,32 @@ gst_nv_h264_dec_get_preferred_output_delay (GstH264Decoder * decoder,
   return 4;
 }
 
-typedef struct
-{
-  GstCaps *sink_caps;
-  GstCaps *src_caps;
-  guint cuda_device_id;
-  gboolean is_default;
-} GstNvH264DecClassData;
-
-static void
-gst_nv_h264_dec_subclass_init (gpointer klass, GstNvH264DecClassData * cdata)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  GstNvH264DecClass *nvdec_class = (GstNvH264DecClass *) (klass);
-  gchar *long_name;
-
-  if (cdata->is_default) {
-    long_name = g_strdup_printf ("NVDEC H.264 Stateless Decoder");
-  } else {
-    long_name = g_strdup_printf ("NVDEC H.264 Stateless Decoder with device %d",
-        cdata->cuda_device_id);
-  }
-
-  gst_element_class_set_metadata (element_class, long_name,
-      "Codec/Decoder/Video/Hardware",
-      "Nvidia H.264 video decoder", "Seungha Yang <seungha@centricular.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->cuda_device_id = cdata->cuda_device_id;
-
-  gst_caps_unref (cdata->sink_caps);
-  gst_caps_unref (cdata->src_caps);
-  g_free (cdata);
-}
-
 void
 gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, guint rank,
     GstCaps * sink_caps, GstCaps * src_caps, gboolean is_primary)
 {
-  GTypeQuery type_query;
-  GTypeInfo type_info = { 0, };
-  GType subtype;
+  GType type;
   gchar *type_name;
   gchar *feature_name;
-  GstNvH264DecClassData *cdata;
-  gboolean is_default = TRUE;
+  GstNvDecoderClassData *cdata;
+  gint index = 0;
   const GValue *value;
   GstStructure *s;
-
-  /**
-   * element-nvh264sldec
-   *
-   * Since: 1.18
-   */
-
-  cdata = g_new0 (GstNvH264DecClassData, 1);
+  GTypeInfo type_info = {
+    sizeof (GstNvH264DecClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) gst_nv_h264_dec_class_init,
+    NULL,
+    NULL,
+    sizeof (GstNvH264Dec),
+    0,
+    (GInstanceInitFunc) gst_nv_h264_dec_init,
+  };
+
+  GST_DEBUG_CATEGORY_INIT (gst_nv_h264_dec_debug, "nvh264dec", 0, "nvh264dec");
+
+  cdata = g_new0 (GstNvDecoderClassData, 1);
   cdata->sink_caps = gst_caps_from_string ("video/x-h264, "
       "stream-format= (string) { avc, avc3, byte-stream }, "
       "alignment= (string) au, "
@@ -965,45 +994,37 @@ gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, guint rank,
   cdata->src_caps = gst_caps_ref (src_caps);
   cdata->cuda_device_id = device_id;
 
-  g_type_query (GST_TYPE_NV_H264_DEC, &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 = (GClassInitFunc) gst_nv_h264_dec_subclass_init;
-  type_info.class_data = cdata;
-
   if (is_primary) {
-    type_name = g_strdup ("GstNvH264StatelessPrimaryDec");
+    type_name = g_strdup ("GstNvH264Dec");
     feature_name = g_strdup ("nvh264dec");
   } else {
-    type_name = g_strdup ("GstNvH264StatelessDec");
+    type_name = g_strdup ("GstNvH264SLDec");
     feature_name = g_strdup ("nvh264sldec");
   }
 
-  if (g_type_from_name (type_name) != 0) {
+  while (g_type_from_name (type_name)) {
+    index++;
     g_free (type_name);
     g_free (feature_name);
     if (is_primary) {
-      type_name =
-          g_strdup_printf ("GstNvH264StatelessPrimaryDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvh264device%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvH264Device%dDec", index);
+      feature_name = g_strdup_printf ("nvh264device%ddec", index);
     } else {
-      type_name = g_strdup_printf ("GstNvH264StatelessDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvh264sldevice%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvH264SLDevice%dDec", index);
+      feature_name = g_strdup_printf ("nvh264sldevice%ddec", index);
     }
-
-    is_default = FALSE;
   }
 
-  cdata->is_default = is_default;
-  subtype = g_type_register_static (GST_TYPE_NV_H264_DEC,
+  type_info.class_data = cdata;
+
+  type = g_type_register_static (GST_TYPE_H264_DECODER,
       type_name, &type_info, 0);
 
   /* make lower rank than default device */
-  if (rank > 0 && !is_default)
+  if (rank > 0 && index > 0)
     rank--;
 
-  if (!gst_element_register (plugin, feature_name, rank, subtype))
+  if (!gst_element_register (plugin, feature_name, rank, type))
     GST_WARNING ("Failed to register plugin '%s'", type_name);
 
   g_free (type_name);
index bc2e956..69d209a 100644 (file)
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_NV_H264_DEC            (gst_nv_h264_dec_get_type())
-#define GST_NV_H264_DEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NV_H264_DEC, GstNvH264Dec))
-#define GST_NV_H264_DEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  GST_TYPE_NV_H264_DEC, GstNvH264DecClass))
-#define GST_NV_H264_DEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  GST_TYPE_NV_H264_DEC, GstNvH264DecClass))
-
-typedef struct _GstNvH264Dec GstNvH264Dec;
-typedef struct _GstNvH264DecClass GstNvH264DecClass;
-
-GType gst_nv_h264_dec_get_type (void);
-
 void gst_nv_h264_dec_register (GstPlugin * plugin,
                                guint device_id,
                                guint rank,
index 75dae1d..2770db9 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/**
+ * SECTION:element-nvh265sldec
+ * @title: nvh265sldec
+ *
+ * GstCodecs based NVIDIA H.265 video decoder
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 filesrc location=/path/to/h265/file ! parsebin ! nvh265sldec ! videoconvert ! autovideosink
+ * ```
+ *
+ * Since: 1.18
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -83,7 +98,7 @@
 GST_DEBUG_CATEGORY_STATIC (gst_nv_h265_dec_debug);
 #define GST_CAT_DEFAULT gst_nv_h265_dec_debug
 
-struct _GstNvH265Dec
+typedef struct _GstNvH265Dec
 {
   GstH265Decoder parent;
 
@@ -108,16 +123,28 @@ struct _GstNvH265Dec
   guint coded_width, coded_height;
   guint bitdepth;
   guint chroma_format_idc;
-};
+} GstNvH265Dec;
 
-struct _GstNvH265DecClass
+typedef struct _GstNvH265DecClass
 {
   GstH265DecoderClass parent_class;
   guint cuda_device_id;
+} GstNvH265DecClass;
+
+enum
+{
+  PROP_0,
+  PROP_CUDA_DEVICE_ID,
 };
 
-#define gst_nv_h265_dec_parent_class parent_class
-G_DEFINE_TYPE (GstNvH265Dec, gst_nv_h265_dec, GST_TYPE_H265_DECODER);
+static GTypeClass *parent_class = NULL;
+
+#define GST_NV_H265_DEC(object) ((GstNvH265Dec *) (object))
+#define GST_NV_H265_DEC_GET_CLASS(object) \
+    (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvH265DecClass))
+
+static void gst_nv_h265_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
 
 static void gst_nv_h265_dec_set_context (GstElement * element,
     GstContext * context);
@@ -148,20 +175,43 @@ gst_nv_h265_dec_get_preferred_output_delay (GstH265Decoder * decoder,
     gboolean live);
 
 static void
-gst_nv_h265_dec_class_init (GstNvH265DecClass * klass)
+gst_nv_h265_dec_class_init (GstNvH265DecClass * klass,
+    GstNvDecoderClassData * cdata)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
   GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (klass);
 
+  object_class->get_property = gst_nv_h265_dec_get_property;
+
   /**
-   * GstNvH265Dec
+   * GstNvH265SLDec:cuda-device-id:
+   *
+   * Assigned CUDA device id
    *
-   * Since: 1.18
+   * Since: 1.22
    */
+  g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
+      g_param_spec_uint ("cuda-device-id", "CUDA device id",
+          "Assigned CUDA device id", 0, G_MAXINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h265_dec_set_context);
 
+  parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
+  gst_element_class_set_static_metadata (element_class,
+      "NVDEC H.265 Stateless Decoder",
+      "Codec/Decoder/Video/Hardware",
+      "NVIDIA H.265 video decoder", "Seungha Yang <seungha@centricular.com>");
+
+  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));
+
   decoder_class->open = GST_DEBUG_FUNCPTR (gst_nv_h265_dec_open);
   decoder_class->close = GST_DEBUG_FUNCPTR (gst_nv_h265_dec_close);
   decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_nv_h265_dec_negotiate);
@@ -184,10 +234,11 @@ gst_nv_h265_dec_class_init (GstNvH265DecClass * klass)
   h265decoder_class->get_preferred_output_delay =
       GST_DEBUG_FUNCPTR (gst_nv_h265_dec_get_preferred_output_delay);
 
-  GST_DEBUG_CATEGORY_INIT (gst_nv_h265_dec_debug,
-      "nvh265dec", 0, "Nvidia H.265 Decoder");
+  klass->cuda_device_id = cdata->cuda_device_id;
 
-  gst_type_mark_as_plugin_api (GST_TYPE_NV_H265_DEC, 0);
+  gst_caps_unref (cdata->sink_caps);
+  gst_caps_unref (cdata->src_caps);
+  g_free (cdata);
 }
 
 static void
@@ -196,6 +247,22 @@ gst_nv_h265_dec_init (GstNvH265Dec * self)
 }
 
 static void
+gst_nv_h265_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstNvH265DecClass *klass = GST_NV_H265_DEC_GET_CLASS (object);
+
+  switch (prop_id) {
+    case PROP_CUDA_DEVICE_ID:
+      g_value_set_uint (value, klass->cuda_device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_nv_h265_dec_set_context (GstElement * element, GstContext * context)
 {
   GstNvH265Dec *self = GST_NV_H265_DEC (element);
@@ -931,68 +998,32 @@ gst_nv_h265_dec_get_preferred_output_delay (GstH265Decoder * decoder,
   return 4;
 }
 
-typedef struct
-{
-  GstCaps *sink_caps;
-  GstCaps *src_caps;
-  guint cuda_device_id;
-  gboolean is_default;
-} GstNvH265DecClassData;
-
-static void
-gst_nv_h265_dec_subclass_init (gpointer klass, GstNvH265DecClassData * cdata)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  GstNvH265DecClass *nvdec_class = (GstNvH265DecClass *) (klass);
-  gchar *long_name;
-
-  if (cdata->is_default) {
-    long_name = g_strdup_printf ("NVDEC H.265 Stateless Decoder");
-  } else {
-    long_name = g_strdup_printf ("NVDEC H.265 Stateless Decoder with device %d",
-        cdata->cuda_device_id);
-  }
-
-  gst_element_class_set_metadata (element_class, long_name,
-      "Codec/Decoder/Video/Hardware",
-      "Nvidia H.265 video decoder", "Seungha Yang <seungha@centricular.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->cuda_device_id = cdata->cuda_device_id;
-
-  gst_caps_unref (cdata->sink_caps);
-  gst_caps_unref (cdata->src_caps);
-  g_free (cdata);
-}
-
 void
 gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank,
     GstCaps * sink_caps, GstCaps * src_caps, gboolean is_primary)
 {
-  GTypeQuery type_query;
-  GTypeInfo type_info = { 0, };
-  GType subtype;
+  GType type;
   gchar *type_name;
   gchar *feature_name;
-  GstNvH265DecClassData *cdata;
-  gboolean is_default = TRUE;
+  GstNvDecoderClassData *cdata;
+  gint index = 0;
   GValue value_list = G_VALUE_INIT;
   GValue value = G_VALUE_INIT;
-
-  /**
-   * element-nvh265sldec
-   *
-   * Since: 1.18
-   */
-
-  cdata = g_new0 (GstNvH265DecClassData, 1);
+  GTypeInfo type_info = {
+    sizeof (GstNvH265DecClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) gst_nv_h265_dec_class_init,
+    NULL,
+    NULL,
+    sizeof (GstNvH265Dec),
+    0,
+    (GInstanceInitFunc) gst_nv_h265_dec_init,
+  };
+
+  GST_DEBUG_CATEGORY_INIT (gst_nv_h265_dec_debug, "nvh265dec", 0, "nvh265dec");
+
+  cdata = g_new0 (GstNvDecoderClassData, 1);
   cdata->sink_caps = gst_caps_copy (sink_caps);
 
   /* Update stream-format since we support packetized format as well */
@@ -1017,45 +1048,36 @@ gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank,
   cdata->src_caps = gst_caps_ref (src_caps);
   cdata->cuda_device_id = device_id;
 
-  g_type_query (GST_TYPE_NV_H265_DEC, &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 = (GClassInitFunc) gst_nv_h265_dec_subclass_init;
-  type_info.class_data = cdata;
-
   if (is_primary) {
-    type_name = g_strdup ("GstNvH265StatelessPrimaryDec");
+    type_name = g_strdup ("GstNvH265Dec");
     feature_name = g_strdup ("nvh265dec");
   } else {
-    type_name = g_strdup ("GstNvH265StatelessDec");
+    type_name = g_strdup ("GstNvH265SLDec");
     feature_name = g_strdup ("nvh265sldec");
   }
 
-  if (g_type_from_name (type_name) != 0) {
+  while (g_type_from_name (type_name)) {
+    index++;
     g_free (type_name);
     g_free (feature_name);
     if (is_primary) {
-      type_name =
-          g_strdup_printf ("GstNvH265StatelessPrimaryDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvh265device%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvH265Device%dDec", index);
+      feature_name = g_strdup_printf ("nvh265device%ddec", index);
     } else {
-      type_name = g_strdup_printf ("GstNvH265StatelessDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvh265sldevice%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvH265SLDevice%dDec", index);
+      feature_name = g_strdup_printf ("nvh265sldevice%ddec", index);
     }
-
-    is_default = FALSE;
   }
 
-  cdata->is_default = is_default;
-  subtype = g_type_register_static (GST_TYPE_NV_H265_DEC,
+  type_info.class_data = cdata;
+  type = g_type_register_static (GST_TYPE_H265_DECODER,
       type_name, &type_info, 0);
 
   /* make lower rank than default device */
-  if (rank > 0 && !is_default)
+  if (rank > 0 && index > 0)
     rank--;
 
-  if (!gst_element_register (plugin, feature_name, rank, subtype))
+  if (!gst_element_register (plugin, feature_name, rank, type))
     GST_WARNING ("Failed to register plugin '%s'", type_name);
 
   g_free (type_name);
index afca7f9..7dffa3e 100644 (file)
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_NV_H265_DEC            (gst_nv_h265_dec_get_type())
-#define GST_NV_H265_DEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NV_H265_DEC, GstNvH265Dec))
-#define GST_NV_H265_DEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  GST_TYPE_NV_H265_DEC, GstNvH265DecClass))
-#define GST_NV_H265_DEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  GST_TYPE_NV_H265_DEC, GstNvH265DecClass))
-
-typedef struct _GstNvH265Dec GstNvH265Dec;
-typedef struct _GstNvH265DecClass GstNvH265DecClass;
-
-GType gst_nv_h265_dec_get_type (void);
-
 void gst_nv_h265_dec_register (GstPlugin * plugin,
                                guint device_id,
                                guint rank,
index 3cbfe51..520c169 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
+/**
+ * SECTION:element-nvvp8sldec
+ * @title: nvvp8sldec
+ *
+ * GstCodecs based NVIDIA VP8 video decoder
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 filesrc location=/path/to/vp8/file ! parsebin ! nvvp8sldec ! videoconvert ! autovideosink
+ * ```
+ *
+ * Since: 1.20
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -31,7 +46,7 @@
 GST_DEBUG_CATEGORY_STATIC (gst_nv_vp8_dec_debug);
 #define GST_CAT_DEFAULT gst_nv_vp8_dec_debug
 
-struct _GstNvVp8Dec
+typedef struct _GstNvVp8Dec
 {
   GstVp8Decoder parent;
 
@@ -42,22 +57,28 @@ struct _GstNvVp8Dec
   CUVIDPICPARAMS params;
 
   guint width, height;
-};
+} GstNvVp8Dec;
 
-struct _GstNvVp8DecClass
+typedef struct _GstNvVp8DecClass
 {
   GstVp8DecoderClass parent_class;
   guint cuda_device_id;
+} GstNvVp8DecClass;
+
+enum
+{
+  PROP_0,
+  PROP_CUDA_DEVICE_ID,
 };
 
-#define gst_nv_vp8_dec_parent_class parent_class
+static GTypeClass *parent_class = NULL;
 
-/**
- * GstNvVp8Dec:
- *
- * Since: 1.20
- */
-G_DEFINE_TYPE (GstNvVp8Dec, gst_nv_vp8_dec, GST_TYPE_VP8_DECODER);
+#define GST_NV_VP8_DEC(object) ((GstNvVp8Dec *) (object))
+#define GST_NV_VP8_DEC_GET_CLASS(object) \
+    (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvVp8DecClass))
+
+static void gst_nv_vp8_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
 
 static void gst_nv_vp8_dec_set_context (GstElement * element,
     GstContext * context);
@@ -82,14 +103,43 @@ static guint gst_nv_vp8_dec_get_preferred_output_delay (GstVp8Decoder * decoder,
     gboolean is_live);
 
 static void
-gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass)
+gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass,
+    GstNvDecoderClassData * cdata)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
   GstVp8DecoderClass *vp8decoder_class = GST_VP8_DECODER_CLASS (klass);
 
+  object_class->get_property = gst_nv_vp8_dec_get_property;
+
+  /**
+   * GstNvVp8SLDec:cuda-device-id:
+   *
+   * Assigned CUDA device id
+   *
+   * Since: 1.22
+   */
+  g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
+      g_param_spec_uint ("cuda-device-id", "CUDA device id",
+          "Assigned CUDA device id", 0, G_MAXINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_set_context);
 
+  parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
+  gst_element_class_set_metadata (element_class,
+      "NVDEC VP8 Stateless Decoder",
+      "Codec/Decoder/Video/Hardware",
+      "NVIDIA VP8 video decoder", "Seungha Yang <seungha@centricular.com>");
+
+  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));
+
   decoder_class->open = GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_open);
   decoder_class->close = GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_close);
   decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_negotiate);
@@ -108,10 +158,11 @@ gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass)
   vp8decoder_class->get_preferred_output_delay =
       GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_get_preferred_output_delay);
 
-  GST_DEBUG_CATEGORY_INIT (gst_nv_vp8_dec_debug,
-      "nvvp8dec", 0, "NVIDIA VP8 Decoder");
+  klass->cuda_device_id = cdata->cuda_device_id;
 
-  gst_type_mark_as_plugin_api (GST_TYPE_NV_VP8_DEC, 0);
+  gst_caps_unref (cdata->sink_caps);
+  gst_caps_unref (cdata->src_caps);
+  g_free (cdata);
 }
 
 static void
@@ -120,6 +171,22 @@ gst_nv_vp8_dec_init (GstNvVp8Dec * self)
 }
 
 static void
+gst_nv_vp8_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstNvVp8DecClass *klass = GST_NV_VP8_DEC_GET_CLASS (object);
+
+  switch (prop_id) {
+    case PROP_CUDA_DEVICE_ID:
+      g_value_set_uint (value, klass->cuda_device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_nv_vp8_dec_set_context (GstElement * element, GstContext * context)
 {
   GstNvVp8Dec *self = GST_NV_VP8_DEC (element);
@@ -444,109 +511,64 @@ gst_nv_vp8_dec_get_preferred_output_delay (GstVp8Decoder * decoder,
   return 4;
 }
 
-typedef struct
-{
-  GstCaps *sink_caps;
-  GstCaps *src_caps;
-  guint cuda_device_id;
-  gboolean is_default;
-} GstNvVp8DecClassData;
-
-static void
-gst_nv_vp8_dec_subclass_init (gpointer klass, GstNvVp8DecClassData * cdata)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  GstNvVp8DecClass *nvdec_class = (GstNvVp8DecClass *) (klass);
-  gchar *long_name;
-
-  if (cdata->is_default) {
-    long_name = g_strdup_printf ("NVDEC VP8 Stateless Decoder");
-  } else {
-    long_name = g_strdup_printf ("NVDEC VP8 Stateless Decoder with device %d",
-        cdata->cuda_device_id);
-  }
-
-  gst_element_class_set_metadata (element_class, long_name,
-      "Codec/Decoder/Video/Hardware",
-      "NVIDIA VP8 video decoder", "Seungha Yang <seungha@centricular.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->cuda_device_id = cdata->cuda_device_id;
-
-  gst_caps_unref (cdata->sink_caps);
-  gst_caps_unref (cdata->src_caps);
-  g_free (cdata);
-}
-
 void
 gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, guint rank,
     GstCaps * sink_caps, GstCaps * src_caps, gboolean is_primary)
 {
-  GTypeQuery type_query;
-  GTypeInfo type_info = { 0, };
-  GType subtype;
+  GType type;
   gchar *type_name;
   gchar *feature_name;
-  GstNvVp8DecClassData *cdata;
-  gboolean is_default = TRUE;
-
-  /**
-   * element-nvvp8sldec:
-   *
-   * Since: 1.20
-   */
-
-  cdata = g_new0 (GstNvVp8DecClassData, 1);
+  GstNvDecoderClassData *cdata;
+  gint index = 0;
+  GTypeInfo type_info = {
+    sizeof (GstNvVp8DecClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) gst_nv_vp8_dec_class_init,
+    NULL,
+    NULL,
+    sizeof (GstNvVp8Dec),
+    0,
+    (GInstanceInitFunc) gst_nv_vp8_dec_init,
+  };
+
+  GST_DEBUG_CATEGORY_INIT (gst_nv_vp8_dec_debug, "nvvp8dec", 0, "nvvp8dec");
+
+  cdata = g_new0 (GstNvDecoderClassData, 1);
   cdata->sink_caps = gst_caps_ref (sink_caps);
   cdata->src_caps = gst_caps_ref (src_caps);
   cdata->cuda_device_id = device_id;
 
-  g_type_query (GST_TYPE_NV_VP8_DEC, &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 = (GClassInitFunc) gst_nv_vp8_dec_subclass_init;
-  type_info.class_data = cdata;
-
   if (is_primary) {
-    type_name = g_strdup ("GstNvVP8StatelessPrimaryDec");
+    type_name = g_strdup ("GstNvVp8Dec");
     feature_name = g_strdup ("nvvp8dec");
   } else {
-    type_name = g_strdup ("GstNvVP8StatelessDec");
+    type_name = g_strdup ("GstNvVp8SLDec");
     feature_name = g_strdup ("nvvp8sldec");
   }
 
-  if (g_type_from_name (type_name) != 0) {
+  while (g_type_from_name (type_name)) {
+    index++;
     g_free (type_name);
     g_free (feature_name);
     if (is_primary) {
-      type_name =
-          g_strdup_printf ("GstNvVP8StatelessPrimaryDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvvp8device%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvVp8Device%dDec", index);
+      feature_name = g_strdup_printf ("nvvp8device%ddec", index);
     } else {
-      type_name = g_strdup_printf ("GstNvVP8StatelessDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvvp8sldevice%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvVp8SLDevice%dDec", index);
+      feature_name = g_strdup_printf ("nvvp8sldevice%ddec", index);
     }
-
-    is_default = FALSE;
   }
 
-  cdata->is_default = is_default;
-  subtype = g_type_register_static (GST_TYPE_NV_VP8_DEC,
+  type_info.class_data = cdata;
+  type = g_type_register_static (GST_TYPE_VP8_DECODER,
       type_name, &type_info, 0);
 
   /* make lower rank than default device */
-  if (rank > 0 && !is_default)
+  if (rank > 0 && index > 0)
     rank--;
 
-  if (!gst_element_register (plugin, feature_name, rank, subtype))
+  if (!gst_element_register (plugin, feature_name, rank, type))
     GST_WARNING ("Failed to register plugin '%s'", type_name);
 
   g_free (type_name);
index df55f2e..3bc6c30 100644 (file)
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_NV_VP8_DEC            (gst_nv_vp8_dec_get_type())
-#define GST_NV_VP8_DEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NV_VP8_DEC, GstNvVp8Dec))
-#define GST_NV_VP8_DEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  GST_TYPE_NV_VP8_DEC, GstNvVp8DecClass))
-#define GST_NV_VP8_DEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  GST_TYPE_NV_VP8_DEC, GstNvVp8DecClass))
-
-typedef struct _GstNvVp8Dec GstNvVp8Dec;
-typedef struct _GstNvVp8DecClass GstNvVp8DecClass;
-
-GType gst_nv_vp8_dec_get_type (void);
-
 void gst_nv_vp8_dec_register (GstPlugin * plugin,
                               guint device_id,
                               guint rank,
index fe2a9fa..c21fbd3 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
+/**
+ * SECTION:element-nvvp9sldec
+ * @title: nvvp9sldec
+ *
+ * GstCodecs based NVIDIA VP9 video decoder
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 filesrc location=/path/to/vp9/file ! parsebin ! nvvp9sldec ! videoconvert ! autovideosink
+ * ```
+ *
+ * Since: 1.20
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -31,7 +46,7 @@
 GST_DEBUG_CATEGORY_STATIC (gst_nv_vp9_dec_debug);
 #define GST_CAT_DEFAULT gst_nv_vp9_dec_debug
 
-struct _GstNvVp9Dec
+typedef struct _GstNvVp9Dec
 {
   GstVp9Decoder parent;
 
@@ -43,22 +58,28 @@ struct _GstNvVp9Dec
 
   guint width, height;
   GstVP9Profile profile;
-};
+} GstNvVp9Dec;
 
-struct _GstNvVp9DecClass
+typedef struct _GstNvVp9DecClass
 {
   GstVp9DecoderClass parent_class;
   guint cuda_device_id;
+} GstNvVp9DecClass;
+
+enum
+{
+  PROP_0,
+  PROP_CUDA_DEVICE_ID,
 };
 
-#define gst_nv_vp9_dec_parent_class parent_class
+static GTypeClass *parent_class = NULL;
 
-/**
- * GstNvVp9Dec:
- *
- * Since: 1.20
- */
-G_DEFINE_TYPE (GstNvVp9Dec, gst_nv_vp9_dec, GST_TYPE_VP9_DECODER);
+#define GST_NV_VP9_DEC(object) ((GstNvVp9Dec *) (object))
+#define GST_NV_VP9_DEC_GET_CLASS(object) \
+    (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvVp9DecClass))
+
+static void gst_nv_vp9_dec_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
 
 static void gst_nv_vp9_dec_set_context (GstElement * element,
     GstContext * context);
@@ -85,14 +106,43 @@ static guint gst_nv_vp9_dec_get_preferred_output_delay (GstVp9Decoder * decoder,
     gboolean is_live);
 
 static void
-gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass)
+gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass,
+    GstNvDecoderClassData * cdata)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
   GstVp9DecoderClass *vp9decoder_class = GST_VP9_DECODER_CLASS (klass);
 
+  object_class->get_property = gst_nv_vp9_dec_get_property;
+
+  /**
+   * GstNvVp9SLDec:cuda-device-id:
+   *
+   * Assigned CUDA device id
+   *
+   * Since: 1.22
+   */
+  g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
+      g_param_spec_uint ("cuda-device-id", "CUDA device id",
+          "Assigned CUDA device id", 0, G_MAXINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_set_context);
 
+  parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
+  gst_element_class_set_metadata (element_class,
+      "NVDEC VP9 Stateless Decoder",
+      "Codec/Decoder/Video/Hardware",
+      "NVIDIA VP9 video decoder", "Seungha Yang <seungha@centricular.com>");
+
+  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));
+
   decoder_class->open = GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_open);
   decoder_class->close = GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_close);
   decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_negotiate);
@@ -113,10 +163,11 @@ gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass)
   vp9decoder_class->get_preferred_output_delay =
       GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_get_preferred_output_delay);
 
-  GST_DEBUG_CATEGORY_INIT (gst_nv_vp9_dec_debug,
-      "nvvp9dec", 0, "NVIDIA VP9 Decoder");
+  klass->cuda_device_id = cdata->cuda_device_id;
 
-  gst_type_mark_as_plugin_api (GST_TYPE_NV_VP9_DEC, 0);
+  gst_caps_unref (cdata->sink_caps);
+  gst_caps_unref (cdata->src_caps);
+  g_free (cdata);
 }
 
 static void
@@ -125,6 +176,22 @@ gst_nv_vp9_dec_init (GstNvVp9Dec * self)
 }
 
 static void
+gst_nv_vp9_dec_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstNvVp9DecClass *klass = GST_NV_VP9_DEC_GET_CLASS (object);
+
+  switch (prop_id) {
+    case PROP_CUDA_DEVICE_ID:
+      g_value_set_uint (value, klass->cuda_device_id);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_nv_vp9_dec_set_context (GstElement * element, GstContext * context)
 {
   GstNvVp9Dec *self = GST_NV_VP9_DEC (element);
@@ -539,66 +606,30 @@ gst_nv_vp9_dec_get_preferred_output_delay (GstVp9Decoder * decoder,
   return 4;
 }
 
-typedef struct
-{
-  GstCaps *sink_caps;
-  GstCaps *src_caps;
-  guint cuda_device_id;
-  gboolean is_default;
-} GstNvVp9DecClassData;
-
-static void
-gst_nv_vp9_dec_subclass_init (gpointer klass, GstNvVp9DecClassData * cdata)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  GstNvVp9DecClass *nvdec_class = (GstNvVp9DecClass *) (klass);
-  gchar *long_name;
-
-  if (cdata->is_default) {
-    long_name = g_strdup_printf ("NVDEC VP9 Stateless Decoder");
-  } else {
-    long_name = g_strdup_printf ("NVDEC VP9 Stateless Decoder with device %d",
-        cdata->cuda_device_id);
-  }
-
-  gst_element_class_set_metadata (element_class, long_name,
-      "Codec/Decoder/Video/Hardware",
-      "NVIDIA VP9 video decoder", "Seungha Yang <seungha@centricular.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->cuda_device_id = cdata->cuda_device_id;
-
-  gst_caps_unref (cdata->sink_caps);
-  gst_caps_unref (cdata->src_caps);
-  g_free (cdata);
-}
-
 void
 gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank,
     GstCaps * sink_caps, GstCaps * src_caps, gboolean is_primary)
 {
-  GTypeQuery type_query;
-  GTypeInfo type_info = { 0, };
-  GType subtype;
+  GType type;
   gchar *type_name;
   gchar *feature_name;
-  GstNvVp9DecClassData *cdata;
-  gboolean is_default = TRUE;
-
-  /**
-   * element-nvvp9sldec:
-   *
-   * Since: 1.20
-   */
-
-  cdata = g_new0 (GstNvVp9DecClassData, 1);
+  GstNvDecoderClassData *cdata;
+  gint index = 0;
+  GTypeInfo type_info = {
+    sizeof (GstNvVp9DecClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) gst_nv_vp9_dec_class_init,
+    NULL,
+    NULL,
+    sizeof (GstNvVp9Dec),
+    0,
+    (GInstanceInitFunc) gst_nv_vp9_dec_init,
+  };
+
+  GST_DEBUG_CATEGORY_INIT (gst_nv_vp9_dec_debug, "nvvp9dec", 0, "nvvp9dec");
+
+  cdata = g_new0 (GstNvDecoderClassData, 1);
   cdata->sink_caps = gst_caps_copy (sink_caps);
   gst_caps_set_simple (cdata->sink_caps,
       "alignment", G_TYPE_STRING, "frame", NULL);
@@ -607,45 +638,37 @@ gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank,
   cdata->src_caps = gst_caps_ref (src_caps);
   cdata->cuda_device_id = device_id;
 
-  g_type_query (GST_TYPE_NV_VP9_DEC, &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 = (GClassInitFunc) gst_nv_vp9_dec_subclass_init;
-  type_info.class_data = cdata;
-
   if (is_primary) {
-    type_name = g_strdup ("GstNvVP9StatelessPrimaryDec");
+    type_name = g_strdup ("GstNvVp9Dec");
     feature_name = g_strdup ("nvvp9dec");
   } else {
-    type_name = g_strdup ("GstNvVP9StatelessDec");
+    type_name = g_strdup ("GstNvVp9SLDec");
     feature_name = g_strdup ("nvvp9sldec");
   }
 
-  if (g_type_from_name (type_name) != 0) {
+  while (g_type_from_name (type_name)) {
+    index++;
     g_free (type_name);
     g_free (feature_name);
     if (is_primary) {
-      type_name =
-          g_strdup_printf ("GstNvVP9StatelessPrimaryDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvvp9device%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvVp9Device%dDec", index);
+      feature_name = g_strdup_printf ("nvvp9device%ddec", index);
     } else {
-      type_name = g_strdup_printf ("GstNvVP9StatelessDevice%dDec", device_id);
-      feature_name = g_strdup_printf ("nvvp9sldevice%ddec", device_id);
+      type_name = g_strdup_printf ("GstNvVp9SLDevice%dDec", index);
+      feature_name = g_strdup_printf ("nvvp9sldevice%ddec", index);
     }
-
-    is_default = FALSE;
   }
 
-  cdata->is_default = is_default;
-  subtype = g_type_register_static (GST_TYPE_NV_VP9_DEC,
+  type_info.class_data = cdata;
+
+  type = g_type_register_static (GST_TYPE_VP9_DECODER,
       type_name, &type_info, 0);
 
   /* make lower rank than default device */
-  if (rank > 0 && !is_default)
+  if (rank > 0 && index > 0)
     rank--;
 
-  if (!gst_element_register (plugin, feature_name, rank, subtype))
+  if (!gst_element_register (plugin, feature_name, rank, type))
     GST_WARNING ("Failed to register plugin '%s'", type_name);
 
   g_free (type_name);
index 1a5051f..9d53972 100644 (file)
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_NV_VP9_DEC            (gst_nv_vp9_dec_get_type())
-#define GST_NV_VP9_DEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NV_VP9_DEC, GstNvVp9Dec))
-#define GST_NV_VP9_DEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  GST_TYPE_NV_VP9_DEC, GstNvVp9DecClass))
-#define GST_NV_VP9_DEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  GST_TYPE_NV_VP9_DEC, GstNvVp9DecClass))
-
-typedef struct _GstNvVp9Dec GstNvVp9Dec;
-typedef struct _GstNvVp9DecClass GstNvVp9DecClass;
-
-GType gst_nv_vp9_dec_get_type (void);
-
 void gst_nv_vp9_dec_register (GstPlugin * plugin,
                               guint device_id,
                               guint rank,