Search code examples
c++video-capturems-media-foundation

Converting Visual C++ Media Foundation Capture application to C++ Builder


I am trying to convert the Microsoft "CaptureEngine video capture sample" code from Visual C++ to Embarcadero C++ Builder.

https://code.msdn.microsoft.com/windowsdesktop/Media-Foundation-Capture-78504c83

The code runs fine with Visual C++, but I need to include in a C++ Builder application. I basically have the code working, but there are a couple of issues I need help with.

I can select the video source, preview the video source and even start capture to file. However the video capture file just contains the one frame repeated for the length of the video, even though Audio is correctly recorded.

I am wondering if this is due to events not being handled properly. The events from the media foundation capture engine are passed to the main thread using windows messaging which then calls the media engine event handler. However I have noticed the event handler to stop the recording and to stop the preview uses wait for result

void WaitForResult()
{
    WaitForSingleObject(m_hEvent, INFINITE);
}

HRESULT CaptureManager::StopPreview()
{
  HRESULT hr = S_OK;

  if (m_pEngine == NULL)
  {
    return MF_E_NOT_INITIALIZED;
  }

  if (!m_bPreviewing)
  {
    return S_OK;
  }
  hr = m_pEngine->StopPreview();
  if (FAILED(hr))
  {
    goto done;
  }
  WaitForResult();

  if (m_fPowerRequestSet && m_hpwrRequest != INVALID_HANDLE_VALUE)
  {
    PowerClearRequest(m_hpwrRequest, PowerRequestExecutionRequired);
    m_fPowerRequestSet = false;
  }
  done:
    return hr;
}

The trouble is, this m_hEvent is triggered from the C++ Builder event handler which is part of the same main thread which is waiting for the event to be handled, so I get a thread lock when trying to stop the video recording. If I comment out the line, I don't lock but I also don't get valid recorded video file.

I am not sure how the Visual C++ separates the events from the Capture engine code, any suggestion as to how I can do this for C++ Builder?


Solution

  • Capture engine event callback is called on a worker thread and it is not "a part of same main thread".

    // Callback method to receive events from the capture engine.
    STDMETHODIMP CaptureManager::CaptureEngineCB::OnEvent( _In_ IMFMediaEvent* pEvent)
    {
    ...
                if (guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED)
                {
                    m_pManager->OnPreviewStopped(hrStatus);
                    SetEvent(m_pManager->m_hEvent);
    

    This essentially changes the behavior of the application. The controlling thread stops preview and blocks until worker thread delivers a notification which sets the event as I quoted above. From there controlling thread wakes up from wait operation and continues with preview stopped.

    If this is not what you are seeing in your application I would suggest setting a breakpoint at the first line of callback function to make sure you receive the notification. If you receive, you can step the code and make sure you reach the event setting line. If you don't receive, something else is blocking and you will have to figure that out, such as for example, by breaking in and examining thread states of the application.