Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / sys / winks / kshelpers.c
1 /*
2  * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "kshelpers.h"
21
22 #include <ksmedia.h>
23 #include <setupapi.h>
24
25 GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
26 #define GST_CAT_DEFAULT gst_ks_debug
27
28 gboolean
29 ks_is_valid_handle (HANDLE h)
30 {
31   return (h != INVALID_HANDLE_VALUE && h != NULL);
32 }
33
34 GList *
35 ks_enumerate_devices (const GUID * category)
36 {
37   GList *result = NULL;
38   HDEVINFO devinfo;
39   gint i;
40
41   devinfo = SetupDiGetClassDevsW (category, NULL, NULL,
42       DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
43   if (!ks_is_valid_handle (devinfo))
44     return NULL;                /* no devices */
45
46   for (i = 0;; i++) {
47     BOOL success;
48     SP_DEVICE_INTERFACE_DATA if_data = { 0, };
49     SP_DEVICE_INTERFACE_DETAIL_DATA_W *if_detail_data;
50     DWORD if_detail_data_size;
51     SP_DEVINFO_DATA devinfo_data = { 0, };
52     DWORD req_size;
53
54     if_data.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
55
56     success = SetupDiEnumDeviceInterfaces (devinfo, NULL, category, i,
57         &if_data);
58     if (!success)               /* all devices enumerated? */
59       break;
60
61     if_detail_data_size = (MAX_PATH - 1) * sizeof (gunichar2);
62     if_detail_data = g_malloc0 (if_detail_data_size);
63     if_detail_data->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA_W);
64
65     devinfo_data.cbSize = sizeof (SP_DEVINFO_DATA);
66
67     success = SetupDiGetDeviceInterfaceDetailW (devinfo, &if_data,
68         if_detail_data, if_detail_data_size, &req_size, &devinfo_data);
69     if (success) {
70       KsDeviceEntry *entry;
71       WCHAR buf[512];
72
73       entry = g_new0 (KsDeviceEntry, 1);
74       entry->index = i;
75       entry->path =
76           g_utf16_to_utf8 (if_detail_data->DevicePath, -1, NULL, NULL, NULL);
77
78       if (SetupDiGetDeviceRegistryPropertyW (devinfo, &devinfo_data,
79               SPDRP_FRIENDLYNAME, NULL, (BYTE *) buf, sizeof (buf), NULL)) {
80         entry->name = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
81       }
82
83       if (entry->name == NULL) {
84         if (SetupDiGetDeviceRegistryPropertyW (devinfo, &devinfo_data,
85                 SPDRP_DEVICEDESC, NULL, (BYTE *) buf, sizeof (buf), NULL)) {
86           entry->name = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
87         }
88       }
89
90       if (entry->name != NULL)
91         result = g_list_prepend (result, entry);
92       else
93         ks_device_entry_free (entry);
94     }
95
96     g_free (if_detail_data);
97   }
98
99   SetupDiDestroyDeviceInfoList (devinfo);
100
101   return g_list_reverse (result);
102 }
103
104 void
105 ks_device_entry_free (KsDeviceEntry * entry)
106 {
107   if (entry == NULL)
108     return;
109
110   g_free (entry->path);
111   g_free (entry->name);
112
113   g_free (entry);
114 }
115
116 void
117 ks_device_list_free (GList * devices)
118 {
119   GList *cur;
120
121   for (cur = devices; cur != NULL; cur = cur->next)
122     ks_device_entry_free (cur->data);
123
124   g_list_free (devices);
125 }
126
127 static gboolean
128 ks_sync_device_io_control (HANDLE device, gulong io_control_code,
129     gpointer in_buffer, gulong in_buffer_size, gpointer out_buffer,
130     gulong out_buffer_size, gulong * bytes_returned, gulong * error)
131 {
132   OVERLAPPED overlapped = { 0, };
133   BOOL success;
134
135   overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
136
137   success = DeviceIoControl (device, io_control_code, in_buffer,
138       in_buffer_size, out_buffer, out_buffer_size, bytes_returned, &overlapped);
139   if (!success) {
140     DWORD err;
141
142     if ((err = GetLastError ()) == ERROR_IO_PENDING) {
143       success = GetOverlappedResult (device, &overlapped, bytes_returned, TRUE);
144       if (!success)
145         err = GetLastError ();
146     }
147
148     if (error != NULL)
149       *error = err;
150   }
151
152   CloseHandle (overlapped.hEvent);
153
154   return success ? TRUE : FALSE;
155 }
156
157 gboolean
158 ks_filter_get_pin_property (HANDLE filter_handle, gulong pin_id,
159     GUID prop_set, gulong prop_id, gpointer value, gulong value_size,
160     gulong * error)
161 {
162   KSP_PIN prop = { 0, };
163   DWORD bytes_returned = 0;
164
165   prop.PinId = pin_id;
166   prop.Property.Set = prop_set;
167   prop.Property.Id = prop_id;
168   prop.Property.Flags = KSPROPERTY_TYPE_GET;
169
170   return ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY, &prop,
171       sizeof (prop), value, value_size, &bytes_returned, error);
172 }
173
174 gboolean
175 ks_filter_get_pin_property_multi (HANDLE filter_handle, gulong pin_id,
176     GUID prop_set, gulong prop_id, KSMULTIPLE_ITEM ** items, gulong * error)
177 {
178   KSP_PIN prop = { 0, };
179   DWORD items_size = 0, bytes_written = 0;
180   gulong err;
181   gboolean ret;
182
183   *items = NULL;
184
185   prop.PinId = pin_id;
186   prop.Property.Set = prop_set;
187   prop.Property.Id = prop_id;
188   prop.Property.Flags = KSPROPERTY_TYPE_GET;
189
190   ret = ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY,
191       &prop.Property, sizeof (prop), NULL, 0, &items_size, &err);
192   if (!ret && err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
193     goto ioctl_failed;
194
195   *items = g_malloc0 (items_size);
196
197   ret = ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY, &prop,
198       sizeof (prop), *items, items_size, &bytes_written, &err);
199   if (!ret)
200     goto ioctl_failed;
201
202   return ret;
203
204 ioctl_failed:
205   if (error != NULL)
206     *error = err;
207
208   g_free (*items);
209   *items = NULL;
210
211   return FALSE;
212 }
213
214 gboolean
215 ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id,
216     gulong prop_flags, gpointer * value, gulong * value_size, gulong * error)
217 {
218   KSPROPERTY prop = { 0, };
219   DWORD req_value_size = 0, bytes_written = 0;
220   gulong err;
221   gboolean ret;
222
223   *value = NULL;
224
225   prop.Set = prop_set;
226   prop.Id = prop_id;
227   prop.Flags = prop_flags;
228
229   if (value_size == NULL || *value_size == 0) {
230     ret = ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY,
231         &prop, sizeof (prop), NULL, 0, &req_value_size, &err);
232     if (!ret && err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
233       goto ioctl_failed;
234   } else {
235     req_value_size = *value_size;
236   }
237
238   *value = g_malloc0 (req_value_size);
239
240   ret = ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY, &prop,
241       sizeof (prop), *value, req_value_size, &bytes_written, &err);
242   if (!ret)
243     goto ioctl_failed;
244
245   if (value_size != NULL)
246     *value_size = bytes_written;
247
248   return ret;
249
250 ioctl_failed:
251   if (error != NULL)
252     *error = err;
253
254   g_free (*value);
255   *value = NULL;
256
257   if (value_size != NULL)
258     *value_size = 0;
259
260   return FALSE;
261 }
262
263 gboolean
264 ks_object_get_property (HANDLE handle, GUID prop_set, gulong prop_id,
265     gpointer * value, gulong * value_size, gulong * error)
266 {
267   return ks_object_query_property (handle, prop_set, prop_id,
268       KSPROPERTY_TYPE_GET, value, value_size, error);
269 }
270
271 gboolean
272 ks_object_set_property (HANDLE handle, GUID prop_set, gulong prop_id,
273     gpointer value, gulong value_size, gulong * error)
274 {
275   KSPROPERTY prop = { 0, };
276   DWORD bytes_returned;
277
278   prop.Set = prop_set;
279   prop.Id = prop_id;
280   prop.Flags = KSPROPERTY_TYPE_SET;
281
282   return ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY, &prop,
283       sizeof (prop), value, value_size, &bytes_returned, error);
284 }
285
286 gboolean
287 ks_object_get_supported_property_sets (HANDLE handle, GUID ** propsets,
288     gulong * len)
289 {
290   gulong size = 0;
291   gulong error;
292
293   *propsets = NULL;
294   *len = 0;
295
296   if (ks_object_query_property (handle, GUID_NULL, 0,
297           KSPROPERTY_TYPE_SETSUPPORT, propsets, &size, &error)) {
298     if (size % sizeof (GUID) == 0) {
299       *len = size / sizeof (GUID);
300       return TRUE;
301     }
302   }
303
304   g_free (*propsets);
305   *propsets = NULL;
306   *len = 0;
307   return FALSE;
308 }
309
310 gboolean
311 ks_object_set_connection_state (HANDLE handle, KSSTATE state, gulong * error)
312 {
313   return ks_object_set_property (handle, KSPROPSETID_Connection,
314       KSPROPERTY_CONNECTION_STATE, &state, sizeof (state), error);
315 }
316
317 gchar *
318 ks_guid_to_string (const GUID * guid)
319 {
320   return g_strdup_printf ("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
321       guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
322       guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
323       guid->Data4[6], guid->Data4[7]);
324 }
325
326 const gchar *
327 ks_state_to_string (KSSTATE state)
328 {
329   switch (state) {
330     case KSSTATE_STOP:
331       return "KSSTATE_STOP";
332     case KSSTATE_ACQUIRE:
333       return "KSSTATE_ACQUIRE";
334     case KSSTATE_PAUSE:
335       return "KSSTATE_PAUSE";
336     case KSSTATE_RUN:
337       return "KSSTATE_RUN";
338     default:
339       g_assert_not_reached ();
340   }
341
342   return "UNKNOWN";
343 }
344
345 #define CHECK_OPTIONS_FLAG(flag) \
346   if (flags & KSSTREAM_HEADER_OPTIONSF_##flag)\
347   {\
348     if (str->len > 0)\
349       g_string_append (str, "|");\
350     g_string_append (str, G_STRINGIFY (flag));\
351     flags &= ~KSSTREAM_HEADER_OPTIONSF_##flag;\
352   }
353
354 gchar *
355 ks_options_flags_to_string (gulong flags)
356 {
357   gchar *ret;
358   GString *str;
359
360   str = g_string_sized_new (128);
361
362   CHECK_OPTIONS_FLAG (SPLICEPOINT);
363   CHECK_OPTIONS_FLAG (PREROLL);
364   CHECK_OPTIONS_FLAG (DATADISCONTINUITY);
365   CHECK_OPTIONS_FLAG (TYPECHANGED);
366   CHECK_OPTIONS_FLAG (TIMEVALID);
367   CHECK_OPTIONS_FLAG (TIMEDISCONTINUITY);
368   CHECK_OPTIONS_FLAG (FLUSHONPAUSE);
369   CHECK_OPTIONS_FLAG (DURATIONVALID);
370   CHECK_OPTIONS_FLAG (ENDOFSTREAM);
371   CHECK_OPTIONS_FLAG (BUFFEREDTRANSFER);
372   CHECK_OPTIONS_FLAG (VRAM_DATA_TRANSFER);
373   CHECK_OPTIONS_FLAG (LOOPEDDATA);
374
375   if (flags != 0)
376     g_string_append_printf (str, "|0x%08x", flags);
377
378   ret = str->str;
379   g_string_free (str, FALSE);
380
381   return ret;
382 }
383
384 typedef struct
385 {
386   const GUID guid;
387   const gchar *name;
388 } KsPropertySetMapping;
389
390 #ifndef STATIC_KSPROPSETID_GM
391 #define STATIC_KSPROPSETID_GM \
392     0xAF627536, 0xE719, 0x11D2, 0x8A, 0x1D, 0x00, 0x60, 0x97, 0xD2, 0xDF, 0x5D
393 #endif
394 #ifndef STATIC_KSPROPSETID_Jack
395 #define STATIC_KSPROPSETID_Jack \
396     0x4509F757, 0x2D46, 0x4637, 0x8E, 0x62, 0xCE, 0x7D, 0xB9, 0x44, 0xF5, 0x7B
397 #endif
398
399 #ifndef STATIC_PROPSETID_VIDCAP_SELECTOR
400 #define STATIC_PROPSETID_VIDCAP_SELECTOR \
401     0x1ABDAECA, 0x68B6, 0x4F83, 0x93, 0x71, 0xB4, 0x13, 0x90, 0x7C, 0x7B, 0x9F
402 #endif
403 #ifndef STATIC_PROPSETID_EXT_DEVICE
404 #define STATIC_PROPSETID_EXT_DEVICE \
405     0xB5730A90, 0x1A2C, 0x11cf, 0x8c, 0x23, 0x00, 0xAA, 0x00, 0x6B, 0x68, 0x14
406 #endif
407 #ifndef STATIC_PROPSETID_EXT_TRANSPORT
408 #define STATIC_PROPSETID_EXT_TRANSPORT \
409     0xA03CD5F0, 0x3045, 0x11cf, 0x8c, 0x44, 0x00, 0xAA, 0x00, 0x6B, 0x68, 0x14
410 #endif
411 #ifndef STATIC_PROPSETID_TIMECODE_READER
412 #define STATIC_PROPSETID_TIMECODE_READER \
413     0x9B496CE1, 0x811B, 0x11cf, 0x8C, 0x77, 0x00, 0xAA, 0x00, 0x6B, 0x68, 0x14
414 #endif
415
416 static const KsPropertySetMapping known_property_sets[] = {
417   {{STATIC_KSPROPSETID_General}, "General"},
418   {{STATIC_KSPROPSETID_MediaSeeking}, "MediaSeeking"},
419   {{STATIC_KSPROPSETID_Topology}, "Topology"},
420   {{STATIC_KSPROPSETID_GM}, "GM"},
421   {{STATIC_KSPROPSETID_Pin}, "Pin"},
422   {{STATIC_KSPROPSETID_Quality}, "Quality"},
423   {{STATIC_KSPROPSETID_Connection}, "Connection"},
424   {{STATIC_KSPROPSETID_MemoryTransport}, "MemoryTransport"},
425   {{STATIC_KSPROPSETID_StreamAllocator}, "StreamAllocator"},
426   {{STATIC_KSPROPSETID_StreamInterface}, "StreamInterface"},
427   {{STATIC_KSPROPSETID_Stream}, "Stream"},
428   {{STATIC_KSPROPSETID_Clock}, "Clock"},
429
430   {{STATIC_KSPROPSETID_DirectSound3DListener}, "DirectSound3DListener"},
431   {{STATIC_KSPROPSETID_DirectSound3DBuffer}, "DirectSound3DBuffer"},
432   {{STATIC_KSPROPSETID_Hrtf3d}, "Hrtf3d"},
433   {{STATIC_KSPROPSETID_Itd3d}, "Itd3d"},
434   {{STATIC_KSPROPSETID_Bibliographic}, "Bibliographic"},
435   {{STATIC_KSPROPSETID_TopologyNode}, "TopologyNode"},
436   {{STATIC_KSPROPSETID_RtAudio}, "RtAudio"},
437   {{STATIC_KSPROPSETID_DrmAudioStream}, "DrmAudioStream"},
438   {{STATIC_KSPROPSETID_Audio}, "Audio"},
439   {{STATIC_KSPROPSETID_Acoustic_Echo_Cancel}, "Acoustic_Echo_Cancel"},
440   {{STATIC_KSPROPSETID_Wave_Queued}, "Wave_Queued"},
441   {{STATIC_KSPROPSETID_Wave}, "Wave"},
442   {{STATIC_KSPROPSETID_WaveTable}, "WaveTable"},
443   {{STATIC_KSPROPSETID_Cyclic}, "Cyclic"},
444   {{STATIC_KSPROPSETID_Sysaudio}, "Sysaudio"},
445   {{STATIC_KSPROPSETID_Sysaudio_Pin}, "Sysaudio_Pin"},
446   {{STATIC_KSPROPSETID_AudioGfx}, "AudioGfx"},
447   {{STATIC_KSPROPSETID_Linear}, "Linear"},
448   {{STATIC_KSPROPSETID_Mpeg2Vid}, "Mpeg2Vid"},
449   {{STATIC_KSPROPSETID_AC3}, "AC3"},
450   {{STATIC_KSPROPSETID_AudioDecoderOut}, "AudioDecoderOut"},
451   {{STATIC_KSPROPSETID_DvdSubPic}, "DvdSubPic"},
452   {{STATIC_KSPROPSETID_CopyProt}, "CopyProt"},
453   {{STATIC_KSPROPSETID_VBICAP_PROPERTIES}, "VBICAP_PROPERTIES"},
454   {{STATIC_KSPROPSETID_VBICodecFiltering}, "VBICodecFiltering"},
455   {{STATIC_KSPROPSETID_VramCapture}, "VramCapture"},
456   {{STATIC_KSPROPSETID_OverlayUpdate}, "OverlayUpdate"},
457   {{STATIC_KSPROPSETID_VPConfig}, "VPConfig"},
458   {{STATIC_KSPROPSETID_VPVBIConfig}, "VPVBIConfig"},
459   {{STATIC_KSPROPSETID_TSRateChange}, "TSRateChange"},
460   {{STATIC_KSPROPSETID_Jack}, "Jack"},
461
462   {{STATIC_PROPSETID_ALLOCATOR_CONTROL}, "ALLOCATOR_CONTROL"},
463   {{STATIC_PROPSETID_VIDCAP_VIDEOPROCAMP}, "VIDCAP_VIDEOPROCAMP"},
464   {{STATIC_PROPSETID_VIDCAP_SELECTOR}, "VIDCAP_SELECTOR"},
465   {{STATIC_PROPSETID_TUNER}, "TUNER"},
466   {{STATIC_PROPSETID_VIDCAP_VIDEOENCODER}, "VIDCAP_VIDEOENCODER"},
467   {{STATIC_PROPSETID_VIDCAP_VIDEODECODER}, "VIDCAP_VIDEODECODER"},
468   {{STATIC_PROPSETID_VIDCAP_CAMERACONTROL}, "VIDCAP_CAMERACONTROL"},
469   {{STATIC_PROPSETID_EXT_DEVICE}, "EXT_DEVICE"},
470   {{STATIC_PROPSETID_EXT_TRANSPORT}, "EXT_TRANSPORT"},
471   {{STATIC_PROPSETID_TIMECODE_READER}, "TIMECODE_READER"},
472   {{STATIC_PROPSETID_VIDCAP_CROSSBAR}, "VIDCAP_CROSSBAR"},
473   {{STATIC_PROPSETID_VIDCAP_TVAUDIO}, "VIDCAP_TVAUDIO"},
474   {{STATIC_PROPSETID_VIDCAP_VIDEOCOMPRESSION}, "VIDCAP_VIDEOCOMPRESSION"},
475   {{STATIC_PROPSETID_VIDCAP_VIDEOCONTROL}, "VIDCAP_VIDEOCONTROL"},
476   {{STATIC_PROPSETID_VIDCAP_DROPPEDFRAMES}, "VIDCAP_DROPPEDFRAMES"},
477 };
478
479 gchar *
480 ks_property_set_to_string (const GUID * guid)
481 {
482   guint i;
483
484   for (i = 0;
485       i < sizeof (known_property_sets) / sizeof (known_property_sets[0]); i++) {
486     if (IsEqualGUID (guid, &known_property_sets[i].guid))
487       return g_strdup_printf ("KSPROPSETID_%s", known_property_sets[i].name);
488   }
489
490   return ks_guid_to_string (guid);
491 }