When capturing from USB devices via DirectShow, video and audio are processed mostly by two separate filters. The reason why two filters are necessary instead of one, is the USB class model (there exist one video class and one audio class) and the accordant driver interfaces that are provided by the operating system. However, DirectShow does not provide a function or method that would return the two filters for a capture device.
But with some know-how it’s possible to write such a function by ourselves. Today, I want to show you how it works. For this article I assume that you’ve already worked with DirectShow for some time, so I won’t start at the very beginning.
1. Enumerating the video capture filters
First, we create a list of all available video capture filters using IEnumMoniker and CLSID_VideoInputDeviceCategory.
While enumerating we save the “display name” of each IMoniker. By removing the prefix “@device:pnp:” we get the device path that could be used in CreateFile for example.
2. Enumerating the audio capture filters
Similarly, we do the same with audio capture filters using CLSID_AudioInputCategory.
We remove the prefix “@device:cm:{33D9A762-90C8-11D0-BD43-00A0C911CE86}\” from the “display name”. But this does not give us the device path, yet. We will get it in the next step.
3. Enumerating the waveInxxx devices
All audio capture devices are now enumerated using the waveInxxx API. The number of devices can be retrieved through the waveInGetNumDevs function.
The device’s name can be found in the structure member WAVEINCAPS.szPname when calling waveInGetDevCaps. The associated audio capture filter can be found by comparing the strings.
Now we can retrieve the device path for each matching filter. For this, we call waveInMessage passing the messages DRV_QUERYDEVICEINTERFACESIZE and DRV_QUERYDEVICEINTERFACE.
4. Retrieving the device instance
All that’s left to do is to get the device instance for each device path found (audio and video). We will use the setup API for this:
First, we get a device information list via SetupDiGetClassDevs. For video we use the category KSCATEGORY_CAPTURE and for audio we use KSCATEGORY_AUDIO.
Going through the category’s available device interfaces via SetupDiEnumDeviceInterfaces, we can retrieve detailed information for an interface by calling SetupDiGetDeviceInterfaceDetail.
If the path in SP_DEVICE_INTERFACE_DETAIL_DATA.DevicePath matches with one of our saved paths, then we can find the device instance in SP_DEVINFO_DATA.devInst.
5. Find the parent device instance
The last step is to find the parent device instance of each device instance found. The parent device instance can be retrieved by calling the CM_Get_Parent function from the Configuration Manager API.
If a video capture filter an an audio capture filter have the same parent, then we’ve found the pair of filters for a device! That’s it!
It sounds very complex but it isn’t. Attached you will find sample code which is shorter than this article!
Download:
CaptureDevice.zip









