none
about DirectShow: automatic combine video capture device and audio capture device

    Question

  • I have a WebCam via usb.
    I am writing a library which uses DirectShow to preview video and audio.
    My system has additional DirectShow devices like a soundcard.
    How can I connect to the right video capture device and the right audio capture device from the WebCam automatically?

     

    sample code:

     

    ICreateDevEnum *pDevEnum = NULL;  

    IEnumMoniker *pEnum = NULL;  

    IMoniker * pMoniker = NULL;  

    IPropertyBag *pPropBag = NULL;  

    HRESULT hr = S_OK;  

     

    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum));  

     

    hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);  

     

    // Enumerate the monikers

    while (pEnum->Next(1, &pMoniker, NULL) == S_OK)

    {  

                // bind the moniker to an object

                hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);

     

                // get FriendlyName

                VARIANT varName;

                VariantInit(&varName);

     

                hr = pPropBag->Read(L"FriendlyName", &varName, 0);  

                …….

    }

     

    hr = pDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnum, 0);  

     

    // Enumerate the monikers

    while (pEnum->Next(1, &pMoniker, NULL) == S_OK)

    {  

                // bind the moniker to an object

                hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);

     

                // get FriendlyName

                VARIANT varName;

                VariantInit(&varName);

     

                hr = pPropBag->Read(L"FriendlyName", &varName, 0);  

                …….

    }

     

     

    • Moved by Mathias Schiffer Friday, June 19, 2009 1:05 PM English Language Post (From:Windows Vista)
    Friday, June 19, 2009 11:09 AM

Answers


  •  

    I don’t think you can do it with DirectShow.  Imho the DirectShow enumerators and device monikers are pathetically lacking in force and effectiveness.  I use the setup api to enumerate devices and find their properties.

     

    1) Find the DevNode (aka DevInst ) of the WebCam.

     

    2) Get the DevNode’s parent using CM_Get_Parent().

     

    3) Use the setup api to enumerate the audio capture devices,

     

    4) For each audio capture device get it’s parent DevNode.

     

    5) Compare parents.

     

    If the parent DevNodes match then they belong to the same device.

     

    You can also play with the device paths and device identification strings.


    ------
     
    Btw, the crossbars have the same problem (and the same solution).

    Friday, June 19, 2009 4:17 PM
  • I am curious about the answer to this question as well.   I looked at the WDM Capture Sources in GraphEdt for a TurtleBeach USB VideoAdvantage and looked at the Display name the Insert Filter dialog showed for the filters.  While the Display Names were very close, they are different:

    USB Audio Device:
    @device:pnp:\\?usb#vid_10f5&pid_0004&mi_01#6&edc7182&0&0001#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

    VideoAdvantage USB
    @device:pnp:\\?usb#vid_10f5&pid_0004&mi_00#6&edc7182&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global



    usb#vid_10f5&pid_0004&mi_00#6&edc7182&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

     

    usb is the bus.

     

    vid_10f5 is the USB vendor/ manufacturer

     

    pid_0004 is the manufacture's product id

     

    mi_00 is the USB composite device's "multiple interface" number.

     

    #6 is the distance (the number of DevNodes) between the root and the device.

     

    edc7182 is the device's serial number

     

    0 I forget

     

    0000 I forget - maybe it's also the multiple interface number

     

    {65e8773d-8f56-11d0-a3b9-00a0c9223196} is KSCATEGORY_CAPTURE
    Friday, June 19, 2009 7:39 PM

All replies


  •  

    I don’t think you can do it with DirectShow.  Imho the DirectShow enumerators and device monikers are pathetically lacking in force and effectiveness.  I use the setup api to enumerate devices and find their properties.

     

    1) Find the DevNode (aka DevInst ) of the WebCam.

     

    2) Get the DevNode’s parent using CM_Get_Parent().

     

    3) Use the setup api to enumerate the audio capture devices,

     

    4) For each audio capture device get it’s parent DevNode.

     

    5) Compare parents.

     

    If the parent DevNodes match then they belong to the same device.

     

    You can also play with the device paths and device identification strings.


    ------
     
    Btw, the crossbars have the same problem (and the same solution).

    Friday, June 19, 2009 4:17 PM
  • You can also query IMoniker::GetDisplayName and use returned value as a key to be able to lookup the device later in another enumeration.
    http://alax.info/blog/tag/directshow
    Friday, June 19, 2009 5:51 PM
  • I am curious about the answer to this question as well.   I looked at the WDM Capture Sources in GraphEdt for a TurtleBeach USB VideoAdvantage and looked at the Display name the Insert Filter dialog showed for the filters.  While the Display Names were very close, they are different:

    USB Audio Device:
    @device:pnp:\\?usb#vid_10f5&pid_0004&mi_01#6&edc7182&0&0001#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

    VideoAdvantage USB
    @device:pnp:\\?usb#vid_10f5&pid_0004&mi_00#6&edc7182&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global


    Friday, June 19, 2009 7:19 PM
  • I am curious about the answer to this question as well.   I looked at the WDM Capture Sources in GraphEdt for a TurtleBeach USB VideoAdvantage and looked at the Display name the Insert Filter dialog showed for the filters.  While the Display Names were very close, they are different:

    USB Audio Device:
    @device:pnp:\\?usb#vid_10f5&pid_0004&mi_01#6&edc7182&0&0001#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

    VideoAdvantage USB
    @device:pnp:\\?usb#vid_10f5&pid_0004&mi_00#6&edc7182&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global



    usb#vid_10f5&pid_0004&mi_00#6&edc7182&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global

     

    usb is the bus.

     

    vid_10f5 is the USB vendor/ manufacturer

     

    pid_0004 is the manufacture's product id

     

    mi_00 is the USB composite device's "multiple interface" number.

     

    #6 is the distance (the number of DevNodes) between the root and the device.

     

    edc7182 is the device's serial number

     

    0 I forget

     

    0000 I forget - maybe it's also the multiple interface number

     

    {65e8773d-8f56-11d0-a3b9-00a0c9223196} is KSCATEGORY_CAPTURE
    Friday, June 19, 2009 7:39 PM
  • You can also query IMoniker::GetDisplayName and use returned value as a key to be able to lookup the device later in another enumeration.
    http://alax.info/blog/tag/directshow

    So, Roman, given that the DisplayNames are not the same for the two capture devices exposed by the TB VideoAdvantage USB, how do you use IMoniker::GetDisplayName to find associated capture devices?  Or do you just continuously increment the  'mi_xx' and other field and attempt to match it up against monikers enumerated by the audio input device class enumerator?  I supposed you could also enumerate until you find a audio device that matches the Vendor ID, Product ID, and serial number of the video device as specified in the DisplayName.

    BTW, thanks David for that explanation of the moniker display name.
    Saturday, June 20, 2009 1:50 AM
  • You can also query IMoniker::GetDisplayName and use returned value as a key to be able to lookup the device later in another enumeration.
    http://alax.info/blog/tag/directshow

    So, Roman, given that the DisplayNames are not the same for the two capture devices exposed by the TB VideoAdvantage USB, how do you use IMoniker::GetDisplayName to find associated capture devices?  Or do you just continuously increment the  'mi_xx' and other field and attempt to match it up against monikers enumerated by the audio input device class enumerator?  I supposed you could also enumerate until you find a audio device that matches the Vendor ID, Product ID, and serial number of the video device as specified in the DisplayName.

     

    FYI the DisplayName is more or less the DevicePath with the “@device:pnp:” prefix.  It doesn’t really buy us anything except that we don’t need to instantiate an IPropertyBag.


    For what we are trying to do we can use the DisplayName, the DevicePath, or the InstanceID.  They all contain the vid_XXXX pid_XXXX  and mi_XX stuff.

    You could just blot out the multiple interface number with “XX” and do a string compare.

     

    LPTSTR pszMI = _tcsstr(szInstanceID, _T("&MI_"));
    if (pszMI)
    {
    	pszMI[4] = 'X';
    	pszMI[5] = 'X';
    }
     

     

     Fwiw, here’s how I find the interface number.

    ULONG uUsbInterfaceNumber = (-1);
    
    // If the USB device is a child of a composite device then its InstanceID
    // will contain the substring "&MI_".
    LPTSTR pszMI = _tcsstr(szInstanceID, _T("&MI_"));
    if (pszMI)
    {
    	// Convert the multiple interface number (two hex characters) to int.
    	uUsbInterfaceNumber = _tcstoul(&pszMI[4], NULL, 16);
    }

     

    The problem is that even though we know the multiple interface number, we still don’t know if it corresponds to a Video Control Interface, a Video Streaming Interface, an Audio Control Interface,  a Audio Streaming Interface, or whatever else.

     

    The best way to make sense of it all is to use the setup api.  And by the time you code it up it ends up being easier to use the DevNodes, and it has the added benefit of working with 1394 and PCI devices too,






    Saturday, June 20, 2009 3:02 AM
  • Is it just me? Or does this forum software suck? When I try to edit my posts I either get a blank form or else I get the HTML dump. And when I insert code it forwards to the next tab in IE7.
    Saturday, June 20, 2009 3:26 AM
  • Is it just me? Or does this forum software suck? When I try to edit my posts I either get a blank form or else I get the HTML dump. And when I insert code it forwards to the next tab in IE7.
    I can edit my post once only, when I try to edit it second time in a row, FireFox would show an edit box without rich text formatting and HTML contents. As I am already aware of this bug, if I need to edit the post again after I just edited it, I copy/paste an URL into a new tab, re-load the page there and click Edit link there in the new tab. And it works this way.

    http://alax.info/blog/tag/directshow
    Saturday, June 20, 2009 5:27 AM
  • OK.  That sucks that you have to use two different APIs to do this.   Seems like it would be a pretty common operation to want to use the audio capture source filter associated with a video capture source by default.

    Roman suggested there was an alternative to the Setup API and I was hoping he could flesh it out for us. 
    Monday, June 22, 2009 12:47 PM
  • OK.  That sucks that you have to use two different APIs to do this.   Seems like it would be a pretty common operation to want to use the audio capture source filter associated with a video capture source by default.

    Roman suggested there was an alternative to the Setup API and I was hoping he could flesh it out for us. 
    Moniker display names - as I suggested to take a look above - may be helpful it picking up the right device in sense when you need to stick to certain device and be independent on its index when you are enumerating the devices using system device enumerator. I did not mean that you can in some way infer correspondence between existing audio and video devices, at least as a general solution AFAIK (if you have some information about specific hardware such as those VID/PID codes in advance, such as from vendor - this may work fine for you though).

    I would consider an option to have some configuration GUI to choose devices from available and keep moniker display names in persistent settings so that you could initialize from them and pick proper pair of devices.

    http://alax.info/blog/tag/directshow
    Monday, June 22, 2009 12:57 PM
  • That sucks that you have to use two different APIs to do this.   Seems like it would be a pretty common operation to want to use the audio capture source filter associated with a video capture source by default. 

    If you are unwilling to use the Setup API then maybe you should try IMoniker::CommonPrefixWith().

     

    http://msdn.microsoft.com/en-us/library/ms694315(VS.85).aspx

     

    IMoniker* pmkVidCap = NULL;		// moniker for the video capture device
    IMoniker* pmkAudCap = NULL;		// moniker for an audio capture device to test
    IMoniker* pmkCommon = NULL;		// product of the comparison

     

    Use the system device enumerator with CLSID_VideoInputDeviceCategory to get pmkVidCap.  Then use another system device enumerator with CLSID_AudioInputDeviceCategory to walk through each audio capture device.


    Do this for each audio capture moniker ...

    hr = pmkVidCap->CommonPrefixWith(pmkAudCap, &pmkCommon);


    I haven’t tried this - so I have no idea if it will help.  But it looks like this is exactly what CommonPrefixWith() is supposed to do.

     

    If it succeeds then just release pmkCommon.

     

     

     

    Tuesday, June 23, 2009 4:10 AM
  • Never mind. I would have expected it to return a moniker to the parent DevNode.  But I just coded it and it returns E_NOTIMPL.

    Tuesday, June 23, 2009 4:27 AM