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