Search code examples
video-capturems-media-foundation

MediaFoundation with multi-input device?


I have a project where the source device has an SVideo and a Composite connector available for capture. In DirectShow, I can use IAMCrossbar to set which one to capture from, but in MediaFoundation I only get a single video stream and a C00D3704 status when I try to start streaming (using a SourceReader). Is there any way to select the input in MediaFoundation?

NB: LEADTOOLS claims to be able to do this, but I don't know how. Nothing else I've found says how to do it.

Pointers to the correct interface and/or attributes would be enough...


Solution

  • The answer depends on the specific capture card, but nevertheless pretty simple. Some capture cards (like a dual head Datapath card), will appear as two separate devices (for each card in the system). Therefore, you will activate them separately, following the enumeration (error checking omitted for brevity):

    UINT32 deviceCount = 0;
    IMFActivate** devices = nullptr;
    Microsoft::WRL::ComPtr<IMFAttributes> attributes = nullptr;
    hr = ::MFCreateAttributes(attributes.GetAddressOf(), 1);
    hr = ::attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, 
                               MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
    hr = ::MFEnumDeviceSources(attributes.Get(), &devices, &deviceCount);
    

    And then activation of the device using GetMediaFoundationActivator and the member function ActivateObject.

    This makes sense for a card like the one referenced above since it has separate hardware on the card for each input. And you can concurrently activate each as a result.

    However it is possible for the driver to report your SVideo and Composite as one device since it will likely be using the same hardware. In that case, you will find the separate streams types on a single IMFSourceReader.

    IMFMediaType* mediaType = nullptr;
    
    HRESULT hr = S_OK;
    while (hr == S_OK)
    {
        hr = reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, index, &mediaType);
        if (hr == MF_E_NO_MORE_TYPES)
            break;
    
        // ... [ process media type ]
        ++index;
    }
    

    In this case, you set the stream selection (IMFSourceReader::SetStreamSelection). I go into some detail on that topic here.

    If you are intending to concurrently capture audio, you will have to build an aggregate source, which I wrote a bit about here;

    Assuming that your capture card has fairly recent drivers, I am certain that you will locate and read from your available streams without much trouble. Good luck.