1 /*
2 * Copyright (C) 2019 Mathieu Duponchelle <mathieu@centricular.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 /* Simple device provider example.
20 *
21 * Usage:
22 *
23 * GST_PLUGIN_PATH=$GST_PLUGIN_PATH:/path/to/libexample_device_provider.so/folder gst-device-monitor-1.0 -f
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <gst/gst.h>
31
32 #define NEW_DEVICE_INTERVAL 1 /* seconds */
33
34 #define EXAMPLE_TYPE_DEVICE_PROVIDER example_device_provider_get_type()
35 #define EXAMPLE_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),EXAMPLE_TYPE_DEVICE_PROVIDER,ExampleDeviceProvider))
36
37 typedef struct _ExampleDeviceProvider ExampleDeviceProvider;
38 typedef struct _ExampleDeviceProviderClass ExampleDeviceProviderClass;
39
40 struct _ExampleDeviceProviderClass
41 {
42 GstDeviceProviderClass parent_class;
43 };
44
45 /**
46 * Our device provider instance.
47 *
48 * @factory: the videotestsrc factory
49 * @patterns: When started, the list of videotestsrc pattern
50 * (as strings) to iterate through when adding new devices,
51 * eg "smpte", "snow", ...
52 * @timeout_id: When started, we will add a new device every
53 * %NEW_DEVICE_INTERVAL seconds
54 */
55 struct _ExampleDeviceProvider
56 {
57 GstDeviceProvider parent;
58 GstElementFactory *factory;
59 GList *patterns;
60 guint timeout_id;
61 };
62
63 static GType example_device_provider_get_type (void);
64
65 G_DEFINE_TYPE (ExampleDeviceProvider, example_device_provider,
66 GST_TYPE_DEVICE_PROVIDER);
67
68 #define EXAMPLE_TYPE_DEVICE example_device_get_type()
69 #define EXAMPLE_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),EXAMPLE_TYPE_DEVICE,ExampleDevice))
70
71 typedef struct _ExampleDevice ExampleDevice;
72 typedef struct _ExampleDeviceClass ExampleDeviceClass;
73
74 struct _ExampleDeviceClass
75 {
76 GstDeviceClass parent_class;
77 };
78
79 /* Our example device, it simply exposes a videotestsrc with a specific
80 * pattern.
81 */
82 struct _ExampleDevice
83 {
84 GstDevice parent;
85
86 gchar *pattern;
87 GstElementFactory *factory;
88 };
89
90 static GType example_device_get_type (void);
91
92 G_DEFINE_TYPE (ExampleDevice, example_device, GST_TYPE_DEVICE);
93
94 static void
example_device_init(ExampleDevice * self)95 example_device_init (ExampleDevice * self)
96 {
97 }
98
99 static void
example_device_finalize(GObject * object)100 example_device_finalize (GObject * object)
101 {
102 ExampleDevice *self = EXAMPLE_DEVICE (object);
103
104 g_free (self->pattern);
105
106 G_OBJECT_CLASS (example_device_parent_class)->finalize (object);
107 }
108
109 static void
example_device_dispose(GObject * object)110 example_device_dispose (GObject * object)
111 {
112 ExampleDevice *self = EXAMPLE_DEVICE (object);
113
114 gst_object_replace ((GstObject **) & self->factory, NULL);
115
116 G_OBJECT_CLASS (example_device_parent_class)->dispose (object);
117 }
118
119 static GstElement *
example_device_create_element(GstDevice * device,const gchar * name)120 example_device_create_element (GstDevice * device, const gchar * name)
121 {
122 ExampleDevice *self = EXAMPLE_DEVICE (device);
123 GstElement *ret;
124
125 ret = gst_element_factory_create (self->factory, name);
126
127 gst_util_set_object_arg (G_OBJECT (ret), "pattern", self->pattern);
128
129 return ret;
130 }
131
132 static void
example_device_class_init(ExampleDeviceClass * klass)133 example_device_class_init (ExampleDeviceClass * klass)
134 {
135 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
136 GstDeviceClass *gst_device_class = GST_DEVICE_CLASS (klass);
137
138 gobject_class->finalize = GST_DEBUG_FUNCPTR (example_device_finalize);
139 gobject_class->dispose = GST_DEBUG_FUNCPTR (example_device_dispose);
140
141 gst_device_class->create_element =
142 GST_DEBUG_FUNCPTR (example_device_create_element);
143 }
144
145 static GstDevice *
example_device_new(GstElementFactory * factory,const gchar * pattern)146 example_device_new (GstElementFactory * factory, const gchar * pattern)
147 {
148 GstDevice *ret;
149 gchar *display_name;
150 GstCaps *caps;
151 const GList *templates;
152
153 templates = gst_element_factory_get_static_pad_templates (factory);
154 caps = gst_static_pad_template_get_caps ((GstStaticPadTemplate *)
155 templates->data);
156
157 display_name = g_strdup_printf ("example-device-%s", pattern);
158
159 ret = GST_DEVICE (g_object_new (EXAMPLE_TYPE_DEVICE,
160 "display-name", display_name,
161 "device-class", "Video/Source", "caps", caps, NULL));
162
163 g_free (display_name);
164 gst_caps_unref (caps);
165
166 EXAMPLE_DEVICE (ret)->pattern = g_strdup (pattern);
167 EXAMPLE_DEVICE (ret)->factory =
168 GST_ELEMENT_FACTORY (gst_object_ref (factory));
169
170 return ret;
171 }
172
173 static void
example_device_provider_init(ExampleDeviceProvider * self)174 example_device_provider_init (ExampleDeviceProvider * self)
175 {
176 self->factory = gst_element_factory_find ("videotestsrc");
177
178 /* Ensure we can introspect the factory */
179 gst_object_unref (gst_plugin_feature_load (GST_PLUGIN_FEATURE
180 (self->factory)));
181
182 }
183
184 /* Called when gst_device_provider_get_devices() is called on a provider that
185 * hasn't been started, or doesn't implement #GstDeviceProvider.start().
186 *
187 * In that case, let's return a single example device, with a snow pattern.
188 */
189 static GList *
example_device_provider_probe(GstDeviceProvider * provider)190 example_device_provider_probe (GstDeviceProvider * provider)
191 {
192 ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (provider);
193 GList *ret = NULL;
194
195 ret = g_list_prepend (ret, example_device_new (self->factory, "snow"));
196
197 return ret;
198 }
199
200 static gboolean
example_device_provider_next_device(ExampleDeviceProvider * self)201 example_device_provider_next_device (ExampleDeviceProvider * self)
202 {
203 GstDevice *device;
204 gboolean ret = G_SOURCE_CONTINUE;
205
206 if (!self->patterns)
207 goto no_more_patterns;
208
209 device = example_device_new (self->factory, (gchar *) self->patterns->data);
210 gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), device);
211 g_free (self->patterns->data);
212 self->patterns = g_list_delete_link (self->patterns, self->patterns);
213
214 done:
215 return ret;
216
217 no_more_patterns:
218 GST_DEBUG_OBJECT (self, "Went through all videotestsrc patterns!");
219 ret = G_SOURCE_REMOVE;
220 goto done;
221 }
222
223 /* Start adding devices every %NEW_DEVICE_INTERVAL seconds.
224 * We will stop once we have consumed all the available videotestsrc
225 * patterns, or when our #GstDeviceProvider.stop() implementation is
226 * called.
227 */
228 static gboolean
example_device_provider_start(GstDeviceProvider * provider)229 example_device_provider_start (GstDeviceProvider * provider)
230 {
231 ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (provider);
232 GType element_type;
233 GTypeClass *element_class;
234 GParamSpec *pspec;
235 GEnumClass *value_class;
236 guint i;
237
238 g_assert (!self->timeout_id);
239
240 element_type = gst_element_factory_get_element_type (self->factory);
241 element_class = (GTypeClass *) g_type_class_ref (element_type);
242 pspec =
243 g_object_class_find_property ((GObjectClass *) element_class, "pattern");
244 value_class = (GEnumClass *) g_type_class_ref (pspec->value_type);
245
246 for (i = 0; i < value_class->n_values; i++) {
247 GEnumValue *val = &value_class->values[i];
248
249 self->patterns = g_list_append (self->patterns, g_strdup (val->value_nick));
250 }
251
252 g_type_class_unref (value_class);
253 g_type_class_unref (element_class);
254
255 self->timeout_id =
256 g_timeout_add_seconds (NEW_DEVICE_INTERVAL,
257 (GSourceFunc) example_device_provider_next_device, self);
258
259 return TRUE;
260 }
261
262 /* Simply stop adding devices by removing our timeout. */
263 static void
example_device_provider_stop(GstDeviceProvider * provider)264 example_device_provider_stop (GstDeviceProvider * provider)
265 {
266 ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (provider);
267
268 g_assert (self->timeout_id);
269
270 if (self->patterns) {
271 g_list_free_full (self->patterns, g_free);
272 self->patterns = NULL;
273 }
274
275 g_source_remove (self->timeout_id);
276 self->timeout_id = 0;
277 }
278
279 static void
example_device_provider_dispose(GObject * object)280 example_device_provider_dispose (GObject * object)
281 {
282 ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (object);
283
284 gst_object_replace ((GstObject **) & self->factory, NULL);
285
286 G_OBJECT_CLASS (example_device_provider_parent_class)->dispose (object);
287 }
288
289 static void
example_device_provider_finalize(GObject * object)290 example_device_provider_finalize (GObject * object)
291 {
292 ExampleDeviceProvider *self = EXAMPLE_DEVICE_PROVIDER (object);
293
294 if (self->patterns)
295 g_list_free_full (self->patterns, g_free);
296
297 G_OBJECT_CLASS (example_device_provider_parent_class)->finalize (object);
298 }
299
300 static void
example_device_provider_class_init(ExampleDeviceProviderClass * klass)301 example_device_provider_class_init (ExampleDeviceProviderClass * klass)
302 {
303 GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
304 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
305
306 gobject_class->dispose = GST_DEBUG_FUNCPTR (example_device_provider_dispose);
307 gobject_class->finalize =
308 GST_DEBUG_FUNCPTR (example_device_provider_finalize);
309
310 dm_class->probe = GST_DEBUG_FUNCPTR (example_device_provider_probe);
311 dm_class->start = GST_DEBUG_FUNCPTR (example_device_provider_start);
312 dm_class->stop = GST_DEBUG_FUNCPTR (example_device_provider_stop);
313
314 gst_device_provider_class_set_static_metadata (dm_class,
315 "Example Device Provider", "Source/Video",
316 "List and provides example source devices",
317 "Mathieu Duponchelle <mathieu@centricular.com>");
318 }
319
320 static gboolean
plugin_init(GstPlugin * plugin)321 plugin_init (GstPlugin * plugin)
322 {
323 return gst_device_provider_register (plugin, "exampledeviceprovider",
324 GST_RANK_PRIMARY, EXAMPLE_TYPE_DEVICE_PROVIDER);
325 }
326
327 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
328 GST_VERSION_MINOR,
329 example_device_provider,
330 "Example device provider",
331 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
332