examples: add device provider example
authorMathieu Duponchelle <mathieu@centricular.com>
Sat, 7 Sep 2019 02:28:46 +0000 (04:28 +0200)
committerMathieu Duponchelle <mathieu@centricular.com>
Mon, 7 Oct 2019 22:34:13 +0000 (00:34 +0200)
tests/examples/device-provider/example-device-provider.c [new file with mode: 0644]
tests/examples/device-provider/meson.build [new file with mode: 0644]
tests/examples/meson.build

diff --git a/tests/examples/device-provider/example-device-provider.c b/tests/examples/device-provider/example-device-provider.c
new file mode 100644 (file)
index 0000000..77cdc6f
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2019 Mathieu Duponchelle <mathieu@centricular.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.
+ */
+
+/* Simple device provider example.
+ *
+ * Usage:
+ *
+ * GST_PLUGIN_PATH=$GST_PLUGIN_PATH:/path/to/libexample_device_provider.so/folder gst-device-monitor-1.0 -f
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#define NEW_DEVICE_INTERVAL 1   /* seconds */
+
+#define EXAMPLE_TYPE_DEVICE_PROVIDER example_device_provider_get_type()
+#define EXAMPLE_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),EXAMPLE_TYPE_DEVICE_PROVIDER,ExampleDeviceProvider))
+
+typedef struct _ExampleDeviceProvider ExampleDeviceProvider;
+typedef struct _ExampleDeviceProviderClass ExampleDeviceProviderClass;
+
+struct _ExampleDeviceProviderClass
+{
+  GstDeviceProviderClass parent_class;
+};
+
+/**
+ * Our device provider instance.
+ *
+ * @factory: the videotestsrc factory
+ * @patterns: When started, the list of videotestsrc pattern
+ *            (as strings) to iterate through when adding new devices,
+ *            eg "smpte", "snow", ...
+ * @timeout_id: When started, we will add a new device every
+ *            %NEW_DEVICE_INTERVAL seconds
+ */
+struct _ExampleDeviceProvider
+{
+  GstDeviceProvider parent;
+  GstElementFactory *factory;
+  GList *patterns;
+  guint timeout_id;
+};
+
+static GType example_device_provider_get_type (void);
+
+G_DEFINE_TYPE (ExampleDeviceProvider, example_device_provider,
+    GST_TYPE_DEVICE_PROVIDER);
+
+#define EXAMPLE_TYPE_DEVICE example_device_get_type()
+#define EXAMPLE_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),EXAMPLE_TYPE_DEVICE,ExampleDevice))
+
+typedef struct _ExampleDevice ExampleDevice;
+typedef struct _ExampleDeviceClass ExampleDeviceClass;
+
+struct _ExampleDeviceClass
+{
+  GstDeviceClass parent_class;
+};
+
+/* Our example device, it simply exposes a videotestsrc with a specific
+ * pattern.
+ */
+struct _ExampleDevice
+{
+  GstDevice parent;
+
+  gchar *pattern;
+  GstElementFactory *factory;
+};
+
+static GType example_device_get_type (void);
+
+G_DEFINE_TYPE (ExampleDevice, example_device, GST_TYPE_DEVICE);
+
+static void
+example_device_init (ExampleDevice * self)
+{
+}
+
+static void
+example_device_finalize (GObject * object)
+{
+  ExampleDevice *self = EXAMPLE_DEVICE (object);
+
+  g_free (self->pattern);
+
+  G_OBJECT_CLASS (example_device_parent_class)->finalize (object);
+}
+
+static void
+example_device_dispose (GObject * object)
+{
+  ExampleDevice *self = EXAMPLE_DEVICE (object);
+
+  gst_object_replace ((GstObject **) & self->factory, NULL);
+
+  G_OBJECT_CLASS (example_device_parent_class)->dispose (object);
+}
+
+static GstElement *
+example_device_create_element (GstDevice * device, const gchar * name)
+{
+  ExampleDevice *self = EXAMPLE_DEVICE (device);
+  GstElement *ret;
+
+  ret = gst_element_factory_create (self->factory, name);
+
+  gst_util_set_object_arg (G_OBJECT (ret), "pattern", self->pattern);
+
+  return ret;
+}
+
+static void
+example_device_class_init (ExampleDeviceClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstDeviceClass *gst_device_class = GST_DEVICE_CLASS (klass);
+
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (example_device_finalize);
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (example_device_dispose);
+
+  gst_device_class->create_element =
+      GST_DEBUG_FUNCPTR (example_device_create_element);
+}
+
+static GstDevice *
+example_device_new (GstElementFactory * factory, const gchar * pattern)
+{
+  GstDevice *ret;
+  gchar *display_name;
+  GstCaps *caps;
+  const GList *templates;
+
+  templates = gst_element_factory_get_static_pad_templates (factory);
+  caps = gst_static_pad_template_get_caps ((GstStaticPadTemplate *)
+      templates->data);
+
+  display_name = g_strdup_printf ("example-device-%s", pattern);
+
+  ret = GST_DEVICE (g_object_new (EXAMPLE_TYPE_DEVICE,
+          "display-name", display_name,
+          "device-class", "Video/Source", "caps", caps, NULL));
+
+  g_free (display_name);
+  gst_caps_unref (caps);
+
+  EXAMPLE_DEVICE (ret)->pattern = g_strdup (pattern);
+  EXAMPLE_DEVICE (ret)->factory =
+      GST_ELEMENT_FACTORY (gst_object_ref (factory));
+
+  return ret;
+}
+
+static void
+example_device_provider_init (ExampleDeviceProvider * self)
+{
+  self->factory = gst_element_factory_find ("videotestsrc");
+
+  /* Ensure we can introspect the factory */
+  gst_object_unref (gst_plugin_feature_load (GST_PLUGIN_FEATURE
+          (self->factory)));
+
+}
+
+/* Called when gst_device_provider_get_devices() is called on a provider that
+ * hasn't been started, or doesn't implement #GstDeviceProvider.start().
+ *
+ * In that case, let's return a single example device, with a snow pattern.
+ */
+static GList *
+example_device_provider_probe (GstDeviceProvider * provider)
+{
+  ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (provider);
+  GList *ret = NULL;
+
+  ret = g_list_prepend (ret, example_device_new (self->factory, "snow"));
+
+  return ret;
+}
+
+static gboolean
+example_device_provider_next_device (ExampleDeviceProvider * self)
+{
+  GstDevice *device;
+  gboolean ret = G_SOURCE_CONTINUE;
+
+  if (!self->patterns)
+    goto no_more_patterns;
+
+  device = example_device_new (self->factory, (gchar *) self->patterns->data);
+  gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), device);
+  g_free (self->patterns->data);
+  self->patterns = g_list_delete_link (self->patterns, self->patterns);
+
+done:
+  return ret;
+
+no_more_patterns:
+  GST_DEBUG_OBJECT (self, "Went through all videotestsrc patterns!");
+  ret = G_SOURCE_REMOVE;
+  goto done;
+}
+
+/* Start adding devices every %NEW_DEVICE_INTERVAL seconds.
+ * We will stop once we have consumed all the available videotestsrc
+ * patterns, or when our #GstDeviceProvider.stop() implementation is
+ * called.
+ */
+static gboolean
+example_device_provider_start (GstDeviceProvider * provider)
+{
+  ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (provider);
+  GType element_type;
+  GTypeClass *element_class;
+  GParamSpec *pspec;
+  GEnumClass *value_class;
+  guint i;
+
+  g_assert (!self->timeout_id);
+
+  element_type = gst_element_factory_get_element_type (self->factory);
+  element_class = (GTypeClass *) g_type_class_ref (element_type);
+  pspec =
+      g_object_class_find_property ((GObjectClass *) element_class, "pattern");
+  value_class = (GEnumClass *) g_type_class_ref (pspec->value_type);
+
+  for (i = 0; i < value_class->n_values; i++) {
+    GEnumValue *val = &value_class->values[i];
+
+    self->patterns = g_list_append (self->patterns, g_strdup (val->value_nick));
+  }
+
+  g_type_class_unref (value_class);
+  g_type_class_unref (element_class);
+
+  self->timeout_id =
+      g_timeout_add_seconds (NEW_DEVICE_INTERVAL,
+      (GSourceFunc) example_device_provider_next_device, self);
+
+  return TRUE;
+}
+
+/* Simply stop adding devices by removing our timeout. */
+static void
+example_device_provider_stop (GstDeviceProvider * provider)
+{
+  ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (provider);
+
+  g_assert (self->timeout_id);
+
+  if (self->patterns) {
+    g_list_free_full (self->patterns, g_free);
+    self->patterns = NULL;
+  }
+
+  g_source_remove (self->timeout_id);
+  self->timeout_id = 0;
+}
+
+static void
+example_device_provider_dispose (GObject * object)
+{
+  ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (object);
+
+  gst_object_replace ((GstObject **) & self->factory, NULL);
+
+  G_OBJECT_CLASS (example_device_provider_parent_class)->dispose (object);
+}
+
+static void
+example_device_provider_finalize (GObject * object)
+{
+  ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (object);
+
+  if (self->patterns)
+    g_list_free_full (self->patterns, g_free);
+
+  G_OBJECT_CLASS (example_device_provider_parent_class)->finalize (object);
+}
+
+static void
+example_device_provider_class_init (ExampleDeviceProviderClass * klass)
+{
+  GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (example_device_provider_dispose);
+  gobject_class->finalize =
+      GST_DEBUG_FUNCPTR (example_device_provider_finalize);
+
+  dm_class->probe = GST_DEBUG_FUNCPTR (example_device_provider_probe);
+  dm_class->start = GST_DEBUG_FUNCPTR (example_device_provider_start);
+  dm_class->stop = GST_DEBUG_FUNCPTR (example_device_provider_stop);
+
+  gst_device_provider_class_set_static_metadata (dm_class,
+      "Example Device Provider", "Source/Video",
+      "List and provides example source devices",
+      "Mathieu Duponchelle <mathieu@centricular.com>");
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_device_provider_register (plugin, "exampledeviceprovider",
+      GST_RANK_PRIMARY, EXAMPLE_TYPE_DEVICE_PROVIDER);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    example_device_provider,
+    "Example device provider",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/tests/examples/device-provider/meson.build b/tests/examples/device-provider/meson.build
new file mode 100644 (file)
index 0000000..b96d561
--- /dev/null
@@ -0,0 +1,6 @@
+library('example_device_provider', 'example-device-provider.c',
+  include_directories: [configinc],
+  c_args : gst_plugins_base_args,
+  install: false,
+  dependencies: [gst_dep],
+)
index 44d28e2..0cfc839 100644 (file)
@@ -1,6 +1,7 @@
 subdir('app')
 subdir('audio')
 subdir('compositor')
+subdir('device-provider')
 subdir('dynamic')
 subdir('decodebin_next')
 subdir('encoding')