Search code examples
c++ms-media-foundation

Detect USB camera disconnection using IMFSourceReaderCallback


I am using IMFSourceReaderCallback asynchroneous c++ implementation to read and process an USB Camera video stream

It is working fine, except that if the camera gets unplugged (which can happen often, since we are using many USB Repeaters), I am not being notified. Here is an extract of the code :

HRESULT CMFSourceReaderCallback::OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent)
{
    // I was hoping to get an Event here if I lost the camera, but no...
    // The break point nether hits, and from EvilCorp documentation, there is no such event type
    return S_OK;
}

HRESULT CMFSourceReaderCallback::OnReadSample(
    HRESULT hrStatus,
    DWORD dwStreamIndex,
    DWORD dwStreamFlags,
    LONGLONG llTimestamp,
    IMFSample *pSample)
{
    bool isGrabbing = false;
    try
    {
        if (SUCCEEDED(hrStatus))
        {
            if (pSample)
            {
                // Do something with the sample.
                IMFMediaBuffer * pMediaBuffer;
                HRESULT hr;
                hr = pSample->ConvertToContiguousBuffer(&pMediaBuffer);

                if (FAILED(hr))
                {
                   // Inform other thread of the disconnection
                   //...
                   return S_OK;
                }
                byte *imgBuff;
                DWORD buffCurrLen = 0;
                DWORD buffMaxLen = 0;
                pMediaBuffer->Lock(&imgBuff, &buffMaxLen, &buffCurrLen);

                // Process image byte buffer
                pMediaBuffer->Unlock();
                pMediaBuffer->Release();
            }
        }
        else
        {
            // Inform other thread of the disconnection
            //...
            return S_OK;
        }

        if ((MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags) ||
            (MF_SOURCE_READERF_ERROR & dwStreamFlags))
        {
            // Inform other thread of the disconnection
            //...
            return S_OK;
        }
    } catch (std::exception &ex )
    {
            // Inform other thread of the disconnection
            //...
            return S_OK;
    }

    // check if other thread has not requested a stop
    isGrabbing = ...;

    if (isGrabbing)
    {
        //Re-arm callback
        HRESULT hr = _dataStruct->Reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
                                0, NULL, NULL, NULL, NULL);

        if (FAILED(hr))
        {
            // Inform other thread of the disconnection
            //...
            return S_OK;
        }
    }

    return S_OK;
}

Is there a way to get such notification through IMFSourceReader without the headache of polling available devices with MFEnumDeviceSources from time to time, which can be time consuming... ?

Thanks In advance !


Solution

  • The recommended way to handle capture device loss is explained here : Handling Video Device Loss

    You need to register for device notification : RegisterDeviceNotification. You need a window handle (HWND).

    In the message loop, you will receive WM_DEVICECHANGE. You have to check the symbolic link (is it the USB camera ?).

    When you are done, call UnregisterDeviceNotification.