Beim Capturen von USB-Geräten mit DirectShow werden Video und Audio meist separat von zwei verschiedenen Filtern eingelesen. Der Grund dafür, dass zwei und nicht ein Filter nötig sind, liegt am USB-Klassenmodell (es gibt je eine Klasse für Video und Audio) und den dazu entsprechenden Treiberschnittstellen, die vom System zur Verfügung gestellt werden. DirectShow bietet jedoch keine Funktion oder Methode an, mit der man die gemeinsamen Filter eines Capture-Geräts ermitteln könnte.
Mit ein bisschen Know-How kann man aber so eine Funktion selbst implementieren. Wie das geht, möchte ich Euch heute zeigen. Für den Artikel setze ich voraus, dass Ihr Euch schon einige Zeit mit DirectShow beschäftigt habt. Daher werde ich nicht bei 0 beginnen.
1. Auflisten der Video-Capture-Filter
Zunächst erzeugen wir eine Liste der verfügbaren Video-Capture-Filter mittels IEnumMoniker und CLSID_VideoInputDeviceCategory.
Während der Auflistung sichern wir uns für jeden IMoniker seinen “Display Name”. Wir entfernen jedoch das vorangestellte “@device:pnp:” und erhalten somit den Pfad auf das Gerät, den man z.B. in CreateFile verwenden könnte.
2. Auflisten der Audio-Capture-Filter
Ähnlich verfahren wir mit den Audio-Capture-Filtern mittels CLSID_AudioInputCategory.
Beim “Display Name” wird das vorangestellte “@device:cm:{33D9A762-90C8-11D0-BD43-00A0C911CE86}\” entfernt. Daraus erhalten wir jedoch noch nicht den Pfad zum Gerät. Den müssen wir als Nächstes ermitteln.
3. Auflisten der waveInxxx-Geräte
Mittels dem waveInxxx-API werden nun alle Audio-Capture-Geräte aufgelistet. Deren Anzahl erhält man über die waveInGetNumDevs-Funktion.
Über waveInGetDevCaps erhält man den Namen des Geräts im Struktur-Member WAVEINCAPS.szPname. Über einen String-Vergleich erhalten wir somit eine Verbindung zu seinem Audio-Capture-Filter.
Jetzt können wir für den jeweiligen Filter den Gerätepfad ermitteln. Dies machen wir mit waveInMessage und den Nachrichten DRV_QUERYDEVICEINTERFACESIZE und DRV_QUERYDEVICEINTERFACE.
4. Ermitteln der Geräte-Instanz
Für jeden gefundenen Gerätepfad (Video und Audio) müssen wir jetzt nur noch seine Geräte-Instanz ermitteln. Dies machen wir über das Setup API:
Zuerst holen wir uns eine Liste von Geräteinformationen über SetupDiGetClassDevs. Für Video vewenden wir als Kategorie KSCATEGORY_CAPTURE und für Audio KSCATEGORY_AUDIO.
Beim Durchgehen der zur Kategorie vorhandenen Geräteschnittstellen mittels SetupDiEnumDeviceInterfaces holen wir uns mit SetupDiGetDeviceInterfaceDetail Informationen über jede einzelne Schnittstelle.
Stimmt der Pfad in SP_DEVICE_INTERFACE_DETAIL_DATA.DevicePath mit einem unserer gespeicherten Pfade überein, so finden wir die Geräte-Instanz in SP_DEVINFO_DATA.devInst und können sie speichern.
5. Die übergeordnete Geräte-Instanz ermitteln
Im letzten Schritt wird für jede gefundene Geräte-Instanz ihre übergeordnete Geräte-Instanz ermittelt. Das machen wir mit der CM_Get_Parent-Funktion aus dem Configuration Manager API.
Findet man für Video und Audio diesselbe übergeordnete Geräte-Instanz, dann hat mein das Filter-Paar für ein Gerät gefunden! Fertig!
Das hört sich alles sehr kompliziert und aufwändig an, ist es aber nicht. Angehängt findet Ihr Beispielcode dazu, der kürzer als dieser Artikel ist!
Download:
CaptureDevice.zip