• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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