mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 11:10:37 +00:00
332 lines
9.3 KiB
C
332 lines
9.3 KiB
C
|
/*
|
||
|
* 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)
|