1 /* GStreamer
2 * Copyright (C) 2018 Joshua M. Doe <oss@nvl.army.mil>
3 *
4 * dshowdeviceprovider.cpp: DirectShow device probing
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "gstdshow.h"
27 #include "gstdshowvideosrc.h"
28 #include "dshowdeviceprovider.h"
29
30 #include <gst/gst.h>
31
32 #include <windows.h>
33
34 GST_DEBUG_CATEGORY_EXTERN (dshowsrcwrapper_debug);
35 #define GST_CAT_DEFAULT dshowsrcwrapper_debug
36
37
38 static GstDevice *gst_dshow_device_new (guint id,
39 const gchar * device_name, GstCaps * caps, const gchar * device_path,
40 GstDshowDeviceType type);
41
42 G_DEFINE_TYPE (GstDshowDeviceProvider, gst_dshow_device_provider,
43 GST_TYPE_DEVICE_PROVIDER);
44
45 static void gst_dshow_device_provider_dispose (GObject * gobject);
46
47 static GList *gst_dshow_device_provider_probe (GstDeviceProvider * provider);
48 static gboolean gst_dshow_device_provider_start (GstDeviceProvider * provider);
49 static void gst_dshow_device_provider_stop (GstDeviceProvider * provider);
50
51 static void
gst_dshow_device_provider_class_init(GstDshowDeviceProviderClass * klass)52 gst_dshow_device_provider_class_init (GstDshowDeviceProviderClass * klass)
53 {
54 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
55 GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
56
57 gobject_class->dispose = gst_dshow_device_provider_dispose;
58
59 dm_class->probe = gst_dshow_device_provider_probe;
60 dm_class->start = gst_dshow_device_provider_start;
61 dm_class->stop = gst_dshow_device_provider_stop;
62
63 gst_device_provider_class_set_static_metadata (dm_class,
64 "DirectShow Device Provider", "Source/Audio/Video",
65 "List and provide DirectShow source devices",
66 "Руслан Ижбулатов <lrn1986@gmail.com>");
67 }
68
69 static void
gst_dshow_device_provider_init(GstDshowDeviceProvider * self)70 gst_dshow_device_provider_init (GstDshowDeviceProvider * self)
71 {
72 CoInitializeEx (NULL, COINIT_MULTITHREADED);
73 }
74
75 static void
gst_dshow_device_provider_dispose(GObject * gobject)76 gst_dshow_device_provider_dispose (GObject * gobject)
77 {
78 CoUninitialize ();
79 }
80
81 static GstDevice *
new_video_source(const DshowDeviceEntry * info)82 new_video_source (const DshowDeviceEntry * info)
83 {
84 g_assert (info && info->device != NULL);
85
86 return gst_dshow_device_new (info->device_index, info->device_name,
87 info->caps, info->device, GST_DSHOW_DEVICE_TYPE_VIDEO_SOURCE);
88 }
89
90 static GList *
gst_dshow_device_provider_probe(GstDeviceProvider * provider)91 gst_dshow_device_provider_probe (GstDeviceProvider * provider)
92 {
93 /*GstDshowDeviceProvider *self = GST_DSHOW_DEVICE_PROVIDER (provider); */
94 GList *devices, *cur;
95 GList *result;
96
97 result = NULL;
98
99 devices = gst_dshow_enumerate_devices (&CLSID_VideoInputDeviceCategory, TRUE);
100 if (devices == NULL)
101 return result;
102
103 /* TODO: try and sort camera first like ksvideosrc? */
104
105 for (cur = devices; cur != NULL; cur = cur->next) {
106 GstDevice *source;
107 DshowDeviceEntry *entry = (DshowDeviceEntry *) cur->data;
108
109 source = new_video_source (entry);
110 if (source)
111 result = g_list_prepend (result, gst_object_ref_sink (source));
112 }
113
114 result = g_list_reverse (result);
115
116 gst_dshow_device_list_free (devices);
117
118 return result;
119 }
120
121 static gboolean
gst_dshow_device_provider_start(GstDeviceProvider * provider)122 gst_dshow_device_provider_start (GstDeviceProvider * provider)
123 {
124 GList *devs;
125 GList *dev;
126 GstDshowDeviceProvider *self = GST_DSHOW_DEVICE_PROVIDER (provider);
127
128 devs = gst_dshow_device_provider_probe (provider);
129 for (dev = devs; dev; dev = dev->next) {
130 if (dev->data)
131 gst_device_provider_device_add (provider, (GstDevice *) dev->data);
132 }
133 g_list_free (devs);
134
135 return TRUE;
136 }
137
138 static void
gst_dshow_device_provider_stop(GstDeviceProvider * provider)139 gst_dshow_device_provider_stop (GstDeviceProvider * provider)
140 {
141
142 }
143
144 enum
145 {
146 PROP_0,
147 PROP_DEVICE,
148 PROP_DEVICE_NAME,
149 PROP_DEVICE_INDEX
150 };
151
152 G_DEFINE_TYPE (GstDshowDevice, gst_dshow_device, GST_TYPE_DEVICE);
153
154 static void gst_dshow_device_get_property (GObject * object, guint prop_id,
155 GValue * value, GParamSpec * pspec);
156 static void gst_dshow_device_set_property (GObject * object, guint prop_id,
157 const GValue * value, GParamSpec * pspec);
158 static void gst_dshow_device_finalize (GObject * object);
159 static GstElement *gst_dshow_device_create_element (GstDevice * device,
160 const gchar * name);
161
162 static void
gst_dshow_device_class_init(GstDshowDeviceClass * klass)163 gst_dshow_device_class_init (GstDshowDeviceClass * klass)
164 {
165 GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
166 GObjectClass *object_class = G_OBJECT_CLASS (klass);
167
168 dev_class->create_element = gst_dshow_device_create_element;
169
170 object_class->get_property = gst_dshow_device_get_property;
171 object_class->set_property = gst_dshow_device_set_property;
172 object_class->finalize = gst_dshow_device_finalize;
173
174 g_object_class_install_property (object_class, PROP_DEVICE,
175 g_param_spec_string ("device", "Device",
176 "DirectShow device path (@..classID/name)", "",
177 (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE |
178 G_PARAM_CONSTRUCT_ONLY)));
179
180 g_object_class_install_property (object_class, PROP_DEVICE_NAME,
181 g_param_spec_string ("device-name", "Device name",
182 "Human-readable name of the audio/video device", "",
183 (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE |
184 G_PARAM_CONSTRUCT_ONLY)));
185
186 g_object_class_install_property (object_class, PROP_DEVICE_INDEX,
187 g_param_spec_int ("device-index", "Device index",
188 "Index of the enumerated audio/video device", 0, G_MAXINT, 0,
189 (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE |
190 G_PARAM_CONSTRUCT_ONLY)));
191 }
192
193 static void
gst_dshow_device_init(GstDshowDevice * device)194 gst_dshow_device_init (GstDshowDevice * device)
195 {
196 }
197
198 static void
gst_dshow_device_finalize(GObject * object)199 gst_dshow_device_finalize (GObject * object)
200 {
201 GstDshowDevice *device = GST_DSHOW_DEVICE (object);
202
203 g_free (device->device);
204 g_free (device->device_name);
205
206 G_OBJECT_CLASS (gst_dshow_device_parent_class)->finalize (object);
207 }
208
209 static GstElement *
gst_dshow_device_create_element(GstDevice * device,const gchar * name)210 gst_dshow_device_create_element (GstDevice * device, const gchar * name)
211 {
212 GstDshowDevice *dev = GST_DSHOW_DEVICE (device);
213 GstElement *elem;
214
215 elem = gst_element_factory_make (dev->element, name);
216 g_object_set (elem, "device", dev->device, NULL);
217 g_object_set (elem, "device-name", dev->device_name, NULL);
218
219 return elem;
220 }
221
222
223 static GstDevice *
gst_dshow_device_new(guint device_index,const gchar * device_name,GstCaps * caps,const gchar * device_path,GstDshowDeviceType type)224 gst_dshow_device_new (guint device_index, const gchar * device_name,
225 GstCaps * caps, const gchar * device_path, GstDshowDeviceType type)
226 {
227 GstDshowDevice *gstdev;
228 const gchar *element = NULL;
229 const gchar *klass = NULL;
230
231 g_return_val_if_fail (device_name, NULL);
232 g_return_val_if_fail (device_path, NULL);
233 g_return_val_if_fail (caps, NULL);
234
235 switch (type) {
236 case GST_DSHOW_DEVICE_TYPE_VIDEO_SOURCE:
237 element = "dshowvideosrc";
238 klass = "Video/Source";
239 break;
240 case GST_DSHOW_DEVICE_TYPE_AUDIO_SOURCE:
241 element = "dshowaudiosrc";
242 klass = "Audio/Source";
243 break;
244 default:
245 g_assert_not_reached ();
246 break;
247 }
248
249 /* set props of parent device class */
250 gstdev = (GstDshowDevice *) g_object_new (GST_TYPE_DSHOW_DEVICE,
251 "display-name", device_name, "caps", caps, "device-class", klass, NULL);
252
253 gstdev->type = type;
254 gstdev->device = g_strdup (device_path);
255 gstdev->device_name = g_strdup (device_name);
256 gstdev->device_index = device_index;
257 gstdev->element = element;
258
259 return GST_DEVICE (gstdev);
260 }
261
262
263 static void
gst_dshow_device_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)264 gst_dshow_device_get_property (GObject * object, guint prop_id,
265 GValue * value, GParamSpec * pspec)
266 {
267 GstDshowDevice *device;
268
269 device = GST_DSHOW_DEVICE_CAST (object);
270
271 switch (prop_id) {
272 case PROP_DEVICE:
273 g_value_set_string (value, device->device);
274 break;
275 case PROP_DEVICE_NAME:
276 g_value_set_string (value, device->device_name);
277 break;
278 case PROP_DEVICE_INDEX:
279 g_value_set_int (value, device->device_index);
280 break;
281 default:
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283 break;
284 }
285 }
286
287
288 static void
gst_dshow_device_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)289 gst_dshow_device_set_property (GObject * object, guint prop_id,
290 const GValue * value, GParamSpec * pspec)
291 {
292 GstDshowDevice *device;
293
294 device = GST_DSHOW_DEVICE_CAST (object);
295
296 switch (prop_id) {
297 case PROP_DEVICE:
298 device->device = g_value_dup_string (value);
299 break;
300 case PROP_DEVICE_NAME:
301 device->device_name = g_value_dup_string (value);
302 break;
303 case PROP_DEVICE_INDEX:
304 device->device_index = g_value_get_int (value);
305 break;
306 default:
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308 break;
309 }
310 }
311