summaryrefslogtreecommitdiffstats
path: root/sys/winks/kshelpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/winks/kshelpers.c')
-rw-r--r--sys/winks/kshelpers.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/sys/winks/kshelpers.c b/sys/winks/kshelpers.c
new file mode 100644
index 00000000..d1aa274e
--- /dev/null
+++ b/sys/winks/kshelpers.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "kshelpers.h"
+
+#include <ksmedia.h>
+#include <setupapi.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
+#define GST_CAT_DEFAULT gst_ks_debug
+
+gboolean
+ks_is_valid_handle (HANDLE h)
+{
+ return (h != INVALID_HANDLE_VALUE && h != NULL);
+}
+
+GList *
+ks_enumerate_devices (const GUID * category)
+{
+ GList *result = NULL;
+ HDEVINFO devinfo;
+ gint i;
+
+ devinfo = SetupDiGetClassDevsW (category, NULL, NULL,
+ DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (!ks_is_valid_handle (devinfo))
+ return NULL; /* no devices */
+
+ for (i = 0;; i++) {
+ BOOL success;
+ SP_DEVICE_INTERFACE_DATA if_data = { 0, };
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *if_detail_data;
+ DWORD if_detail_data_size;
+ SP_DEVINFO_DATA devinfo_data = { 0, };
+ DWORD req_size;
+
+ if_data.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
+
+ success = SetupDiEnumDeviceInterfaces (devinfo, NULL, category, i,
+ &if_data);
+ if (!success) /* all devices enumerated? */
+ break;
+
+ if_detail_data_size = (MAX_PATH - 1) * sizeof (gunichar2);
+ if_detail_data = g_malloc0 (if_detail_data_size);
+ if_detail_data->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+
+ devinfo_data.cbSize = sizeof (SP_DEVINFO_DATA);
+
+ success = SetupDiGetDeviceInterfaceDetailW (devinfo, &if_data,
+ if_detail_data, if_detail_data_size, &req_size, &devinfo_data);
+ if (success) {
+ KsDeviceEntry *entry;
+ WCHAR buf[512];
+
+ entry = g_new0 (KsDeviceEntry, 1);
+ entry->index = i;
+ entry->path =
+ g_utf16_to_utf8 (if_detail_data->DevicePath, -1, NULL, NULL, NULL);
+
+ if (SetupDiGetDeviceRegistryPropertyW (devinfo, &devinfo_data,
+ SPDRP_FRIENDLYNAME, NULL, (BYTE *) buf, sizeof (buf), NULL)) {
+ entry->name = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
+ }
+
+ if (entry->name == NULL) {
+ if (SetupDiGetDeviceRegistryPropertyW (devinfo, &devinfo_data,
+ SPDRP_DEVICEDESC, NULL, (BYTE *) buf, sizeof (buf), NULL)) {
+ entry->name = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
+ }
+ }
+
+ if (entry->name != NULL)
+ result = g_list_prepend (result, entry);
+ else
+ ks_device_entry_free (entry);
+ }
+
+ g_free (if_detail_data);
+ }
+
+ SetupDiDestroyDeviceInfoList (devinfo);
+
+ return g_list_reverse (result);
+}
+
+void
+ks_device_entry_free (KsDeviceEntry * entry)
+{
+ if (entry == NULL)
+ return;
+
+ g_free (entry->path);
+ g_free (entry->name);
+
+ g_free (entry);
+}
+
+void
+ks_device_list_free (GList * devices)
+{
+ GList *cur;
+
+ for (cur = devices; cur != NULL; cur = cur->next)
+ ks_device_entry_free (cur->data);
+
+ g_list_free (devices);
+}
+
+static gboolean
+ks_sync_device_io_control (HANDLE device, gulong io_control_code,
+ gpointer in_buffer, gulong in_buffer_size, gpointer out_buffer,
+ gulong out_buffer_size, gulong * bytes_returned)
+{
+ OVERLAPPED overlapped = { 0, };
+ BOOL success;
+
+ overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+
+ success = DeviceIoControl (device, io_control_code, in_buffer,
+ in_buffer_size, out_buffer, out_buffer_size, bytes_returned, &overlapped);
+ if (!success && GetLastError () == ERROR_IO_PENDING)
+ success = GetOverlappedResult (device, &overlapped, bytes_returned, TRUE);
+
+ CloseHandle (overlapped.hEvent);
+
+ return success ? TRUE : FALSE;
+}
+
+gboolean
+ks_filter_get_pin_property (HANDLE filter_handle, gulong pin_id,
+ GUID prop_set, gulong prop_id, gpointer value, gulong value_size)
+{
+ KSP_PIN prop = { 0, };
+ DWORD bytes_returned = 0;
+
+ prop.PinId = pin_id;
+ prop.Property.Set = prop_set;
+ prop.Property.Id = prop_id;
+ prop.Property.Flags = KSPROPERTY_TYPE_GET;
+
+ return ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY, &prop,
+ sizeof (prop), value, value_size, &bytes_returned);
+}
+
+gboolean
+ks_filter_get_pin_property_multi (HANDLE filter_handle, gulong pin_id,
+ GUID prop_set, gulong prop_id, KSMULTIPLE_ITEM ** items)
+{
+ KSP_PIN prop = { 0, };
+ DWORD items_size = 0, bytes_written = 0;
+ gboolean ret;
+
+ *items = NULL;
+
+ prop.PinId = pin_id;
+ prop.Property.Set = prop_set;
+ prop.Property.Id = prop_id;
+ prop.Property.Flags = KSPROPERTY_TYPE_GET;
+
+ ret = ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY,
+ &prop.Property, sizeof (prop), NULL, 0, &items_size);
+ if (!ret) {
+ DWORD err = GetLastError ();
+ if (err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
+ goto error;
+ }
+
+ *items = g_malloc0 (items_size);
+
+ ret = ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY, &prop,
+ sizeof (prop), *items, items_size, &bytes_written);
+ if (!ret)
+ goto error;
+
+ return ret;
+
+error:
+ g_free (*items);
+ *items = NULL;
+
+ return FALSE;
+}
+
+gboolean
+ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id,
+ gulong prop_flags, gpointer * value, gulong * value_size)
+{
+ KSPROPERTY prop = { 0, };
+ DWORD req_value_size = 0, bytes_written = 0;
+ gboolean ret;
+
+ *value = NULL;
+
+ prop.Set = prop_set;
+ prop.Id = prop_id;
+ prop.Flags = prop_flags;
+
+ if (value_size == NULL || *value_size == 0) {
+ ret = ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY,
+ &prop, sizeof (prop), NULL, 0, &req_value_size);
+ if (!ret) {
+ DWORD err = GetLastError ();
+ if (err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
+ goto error;
+ }
+ } else {
+ req_value_size = *value_size;
+ }
+
+ *value = g_malloc0 (req_value_size);
+
+ ret = ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY, &prop,
+ sizeof (prop), *value, req_value_size, &bytes_written);
+ if (!ret)
+ goto error;
+
+ if (value_size != NULL)
+ *value_size = bytes_written;
+
+ return ret;
+
+error:
+ g_free (*value);
+ *value = NULL;
+
+ if (value_size != NULL)
+ *value_size = 0;
+
+ return FALSE;
+}
+
+gboolean
+ks_object_get_property (HANDLE handle, GUID prop_set, gulong prop_id,
+ gpointer * value, gulong * value_size)
+{
+ return ks_object_query_property (handle, prop_set, prop_id,
+ KSPROPERTY_TYPE_GET, value, value_size);
+}
+
+gboolean
+ks_object_set_property (HANDLE handle, GUID prop_set, gulong prop_id,
+ gpointer value, gulong value_size)
+{
+ KSPROPERTY prop = { 0, };
+ DWORD bytes_returned;
+
+ prop.Set = prop_set;
+ prop.Id = prop_id;
+ prop.Flags = KSPROPERTY_TYPE_SET;
+
+ return ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY, &prop,
+ sizeof (prop), value, value_size, &bytes_returned);
+}
+
+gboolean
+ks_object_get_supported_property_sets (HANDLE handle, GUID ** propsets,
+ gulong * len)
+{
+ gulong size = 0;
+
+ *propsets = NULL;
+ *len = 0;
+
+ if (ks_object_query_property (handle, GUID_NULL, 0,
+ KSPROPERTY_TYPE_SETSUPPORT, propsets, &size)) {
+ if (size % sizeof (GUID) == 0) {
+ *len = size / sizeof (GUID);
+ return TRUE;
+ }
+ }
+
+ g_free (*propsets);
+ *propsets = NULL;
+ *len = 0;
+ return FALSE;
+}
+
+gboolean
+ks_object_set_connection_state (HANDLE handle, KSSTATE state)
+{
+ return ks_object_set_property (handle, KSPROPSETID_Connection,
+ KSPROPERTY_CONNECTION_STATE, &state, sizeof (state));
+}
+
+const gchar *
+ks_state_to_string (KSSTATE state)
+{
+ switch (state) {
+ case KSSTATE_STOP:
+ return "KSSTATE_STOP";
+ case KSSTATE_ACQUIRE:
+ return "KSSTATE_ACQUIRE";
+ case KSSTATE_PAUSE:
+ return "KSSTATE_PAUSE";
+ case KSSTATE_RUN:
+ return "KSSTATE_RUN";
+ default:
+ g_assert_not_reached ();
+ }
+
+ return "UNKNOWN";
+}
+
+#define CHECK_OPTIONS_FLAG(flag) \
+ if (flags & KSSTREAM_HEADER_OPTIONSF_##flag)\
+ {\
+ if (str->len > 0)\
+ g_string_append (str, " | ");\
+ g_string_append (str, G_STRINGIFY (flag));\
+ flags &= ~KSSTREAM_HEADER_OPTIONSF_##flag;\
+ }
+
+gchar *
+ks_options_flags_to_string (gulong flags)
+{
+ gchar *ret;
+ GString *str;
+
+ str = g_string_sized_new (128);
+
+ CHECK_OPTIONS_FLAG (DATADISCONTINUITY);
+ CHECK_OPTIONS_FLAG (DURATIONVALID);
+ CHECK_OPTIONS_FLAG (ENDOFSTREAM);
+ CHECK_OPTIONS_FLAG (FLUSHONPAUSE);
+ CHECK_OPTIONS_FLAG (LOOPEDDATA);
+ CHECK_OPTIONS_FLAG (PREROLL);
+ CHECK_OPTIONS_FLAG (SPLICEPOINT);
+ CHECK_OPTIONS_FLAG (TIMEDISCONTINUITY);
+ CHECK_OPTIONS_FLAG (TIMEVALID);
+ CHECK_OPTIONS_FLAG (TYPECHANGED);
+ CHECK_OPTIONS_FLAG (VRAM_DATA_TRANSFER);
+ CHECK_OPTIONS_FLAG (BUFFEREDTRANSFER);
+
+ if (flags != 0)
+ g_string_append_printf (str, " | 0x%08x", flags);
+
+ ret = str->str;
+ g_string_free (str, FALSE);
+
+ return ret;
+}
+
+typedef struct
+{
+ const GUID guid;
+ const gchar *name;
+} KsPropertySetMapping;
+
+#ifndef STATIC_KSPROPSETID_GM
+#define STATIC_KSPROPSETID_GM \
+ 0xAF627536, 0xE719, 0x11D2, 0x8A, 0x1D, 0x00, 0x60, 0x97, 0xD2, 0xDF, 0x5D
+#endif
+#ifndef STATIC_KSPROPSETID_Jack
+#define STATIC_KSPROPSETID_Jack \
+ 0x4509F757, 0x2D46, 0x4637, 0x8E, 0x62, 0xCE, 0x7D, 0xB9, 0x44, 0xF5, 0x7B
+#endif
+
+#ifndef STATIC_PROPSETID_VIDCAP_SELECTOR
+#define STATIC_PROPSETID_VIDCAP_SELECTOR \
+ 0x1ABDAECA, 0x68B6, 0x4F83, 0x93, 0x71, 0xB4, 0x13, 0x90, 0x7C, 0x7B, 0x9F
+#endif
+#ifndef STATIC_PROPSETID_EXT_DEVICE
+#define STATIC_PROPSETID_EXT_DEVICE \
+ 0xB5730A90, 0x1A2C, 0x11cf, 0x8c, 0x23, 0x00, 0xAA, 0x00, 0x6B, 0x68, 0x14
+#endif
+#ifndef STATIC_PROPSETID_EXT_TRANSPORT
+#define STATIC_PROPSETID_EXT_TRANSPORT \
+ 0xA03CD5F0, 0x3045, 0x11cf, 0x8c, 0x44, 0x00, 0xAA, 0x00, 0x6B, 0x68, 0x14
+#endif
+#ifndef STATIC_PROPSETID_TIMECODE_READER
+#define STATIC_PROPSETID_TIMECODE_READER \
+ 0x9B496CE1, 0x811B, 0x11cf, 0x8C, 0x77, 0x00, 0xAA, 0x00, 0x6B, 0x68, 0x14
+#endif
+
+static const KsPropertySetMapping known_property_sets[] = {
+ {{STATIC_KSPROPSETID_General}, "General"},
+ {{STATIC_KSPROPSETID_MediaSeeking}, "MediaSeeking"},
+ {{STATIC_KSPROPSETID_Topology}, "Topology"},
+ {{STATIC_KSPROPSETID_GM}, "GM"},
+ {{STATIC_KSPROPSETID_Pin}, "Pin"},
+ {{STATIC_KSPROPSETID_Quality}, "Quality"},
+ {{STATIC_KSPROPSETID_Connection}, "Connection"},
+ {{STATIC_KSPROPSETID_MemoryTransport}, "MemoryTransport"},
+ {{STATIC_KSPROPSETID_StreamAllocator}, "StreamAllocator"},
+ {{STATIC_KSPROPSETID_StreamInterface}, "StreamInterface"},
+ {{STATIC_KSPROPSETID_Stream}, "Stream"},
+ {{STATIC_KSPROPSETID_Clock}, "Clock"},
+
+ {{STATIC_KSPROPSETID_DirectSound3DListener}, "DirectSound3DListener"},
+ {{STATIC_KSPROPSETID_DirectSound3DBuffer}, "DirectSound3DBuffer"},
+ {{STATIC_KSPROPSETID_Hrtf3d}, "Hrtf3d"},
+ {{STATIC_KSPROPSETID_Itd3d}, "Itd3d"},
+ {{STATIC_KSPROPSETID_Bibliographic}, "Bibliographic"},
+ {{STATIC_KSPROPSETID_TopologyNode}, "TopologyNode"},
+ {{STATIC_KSPROPSETID_RtAudio}, "RtAudio"},
+ {{STATIC_KSPROPSETID_DrmAudioStream}, "DrmAudioStream"},
+ {{STATIC_KSPROPSETID_Audio}, "Audio"},
+ {{STATIC_KSPROPSETID_Acoustic_Echo_Cancel}, "Acoustic_Echo_Cancel"},
+ {{STATIC_KSPROPSETID_Wave_Queued}, "Wave_Queued"},
+ {{STATIC_KSPROPSETID_Wave}, "Wave"},
+ {{STATIC_KSPROPSETID_WaveTable}, "WaveTable"},
+ {{STATIC_KSPROPSETID_Cyclic}, "Cyclic"},
+ {{STATIC_KSPROPSETID_Sysaudio}, "Sysaudio"},
+ {{STATIC_KSPROPSETID_Sysaudio_Pin}, "Sysaudio_Pin"},
+ {{STATIC_KSPROPSETID_AudioGfx}, "AudioGfx"},
+ {{STATIC_KSPROPSETID_Linear}, "Linear"},
+ {{STATIC_KSPROPSETID_Mpeg2Vid}, "Mpeg2Vid"},
+ {{STATIC_KSPROPSETID_AC3}, "AC3"},
+ {{STATIC_KSPROPSETID_AudioDecoderOut}, "AudioDecoderOut"},
+ {{STATIC_KSPROPSETID_DvdSubPic}, "DvdSubPic"},
+ {{STATIC_KSPROPSETID_CopyProt}, "CopyProt"},
+ {{STATIC_KSPROPSETID_VBICAP_PROPERTIES}, "VBICAP_PROPERTIES"},
+ {{STATIC_KSPROPSETID_VBICodecFiltering}, "VBICodecFiltering"},
+ {{STATIC_KSPROPSETID_VramCapture}, "VramCapture"},
+ {{STATIC_KSPROPSETID_OverlayUpdate}, "OverlayUpdate"},
+ {{STATIC_KSPROPSETID_VPConfig}, "VPConfig"},
+ {{STATIC_KSPROPSETID_VPVBIConfig}, "VPVBIConfig"},
+ {{STATIC_KSPROPSETID_TSRateChange}, "TSRateChange"},
+ {{STATIC_KSPROPSETID_Jack}, "Jack"},
+
+ {{STATIC_PROPSETID_ALLOCATOR_CONTROL}, "ALLOCATOR_CONTROL"},
+ {{STATIC_PROPSETID_VIDCAP_VIDEOPROCAMP}, "VIDCAP_VIDEOPROCAMP"},
+ {{STATIC_PROPSETID_VIDCAP_SELECTOR}, "VIDCAP_SELECTOR"},
+ {{STATIC_PROPSETID_TUNER}, "TUNER"},
+ {{STATIC_PROPSETID_VIDCAP_VIDEOENCODER}, "VIDCAP_VIDEOENCODER"},
+ {{STATIC_PROPSETID_VIDCAP_VIDEODECODER}, "VIDCAP_VIDEODECODER"},
+ {{STATIC_PROPSETID_VIDCAP_CAMERACONTROL}, "VIDCAP_CAMERACONTROL"},
+ {{STATIC_PROPSETID_EXT_DEVICE}, "EXT_DEVICE"},
+ {{STATIC_PROPSETID_EXT_TRANSPORT}, "EXT_TRANSPORT"},
+ {{STATIC_PROPSETID_TIMECODE_READER}, "TIMECODE_READER"},
+ {{STATIC_PROPSETID_VIDCAP_CROSSBAR}, "VIDCAP_CROSSBAR"},
+ {{STATIC_PROPSETID_VIDCAP_TVAUDIO}, "VIDCAP_TVAUDIO"},
+ {{STATIC_PROPSETID_VIDCAP_VIDEOCOMPRESSION}, "VIDCAP_VIDEOCOMPRESSION"},
+ {{STATIC_PROPSETID_VIDCAP_VIDEOCONTROL}, "VIDCAP_VIDEOCONTROL"},
+ {{STATIC_PROPSETID_VIDCAP_DROPPEDFRAMES}, "VIDCAP_DROPPEDFRAMES"},
+};
+
+gchar *
+ks_property_set_to_string (const GUID * guid)
+{
+ guint i;
+
+ for (i = 0;
+ i < sizeof (known_property_sets) / sizeof (known_property_sets[0]); i++) {
+ if (IsEqualGUID (guid, &known_property_sets[i].guid))
+ return g_strdup_printf ("KSPROPSETID_%s", known_property_sets[i].name);
+ }
+
+ return g_strdup_printf ("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
+ guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
+ guid->Data4[6], guid->Data4[7]);
+}