【问题标题】:Converting Visual C++ Media Foundation Capture application to C++ Builder将 Visual C++ Media Foundation Capture 应用程序转换为 C++ Builder
【发布时间】:2019-08-02 01:46:48
【问题描述】:

我正在尝试将 Microsoft“CaptureEngine 视频捕获示例”代码从 Visual C++ 转换为 Embarcadero C++ Builder。

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

代码在 Visual C++ 上运行良好,但我需要包含在 C++ Builder 应用程序中。我基本上可以运行代码,但有几个问题需要帮助。

我可以选择视频源,预览视频源,甚至开始捕获到文件。然而,即使音频被正确录制,视频捕获文件仅包含在视频长度内重复的一帧。

我想知道这是否是由于事件处理不当造成的。 来自媒体基础捕获引擎的事件使用 Windows 消息传递到主线程,然后调用媒体引擎事件处理程序。但是我注意到事件处理程序停止录制并停止预览使用等待结果

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;
}

问题是,这个 m_hEvent 是从 C++ Builder 事件处理程序触发的,它是等待处理事件的同一主线程的一部分,所以当我试图停止视频录制时,我得到了一个线程锁。如果我注释掉该行,我不会锁定,但我也不会得到有效的录制视频文件。

我不确定 Visual C++ 如何将事件与 Capture 引擎代码分开,有什么建议可以为 C++ Builder 做到这一点吗?

【问题讨论】:

    标签: c++ video-capture ms-media-foundation


    【解决方案1】:

    捕获引擎事件回调在工作线程上调用,它不是“同一主线程的一部分”。

    // 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);
    

    这实质上改变了应用程序的行为。控制线程停止预览并阻塞,直到工作线程传递一个通知,该通知设置了我上面引用的事件。从那里控制线程从等待操作中唤醒并继续预览停止。

    如果这不是您在应用程序中看到的,我建议您在回调函数的第一行设置一个断点,以确保您收到通知。如果您收到,您可以单步执行代码并确保您到达事件设置行。如果您没有收到,则说明有其他事情正在阻塞,您必须弄清楚这一点,例如,通过闯入并检查应用程序的线程状态。

    【讨论】:

    • 感谢您的回复,将进一步调查未收到媒体基金会事件的原因。没有命中断点,应用程序只是在等待时锁定,必须进一步了解为什么会这样。
    【解决方案2】:

    我找到了问题的原因。 Capture 引擎示例中的 OnEvent 例程肯定在它自己的线程中。问题是它随后将消息发布到主应用程序线程,而不是自己处理。这意味着主线程在等待互斥体时被冻结。

    // Callback method to receive events from the capture engine.
    STDMETHODIMP CaptureManager::CaptureEngineCB::OnEvent( _In_ IMFMediaEvent* pEvent)
    {
        // Post a message to the application window, so the event is handled
        // on the application's main thread.
    
        if (m_fSleeping && m_pManager != NULL)
        {
            // We're about to fall asleep, that means we've just asked the CE to stop the preview
            // and record.  We need to handle it here since our message pump may be gone.
            GUID    guidType;
            HRESULT hrStatus;
            HRESULT hr = pEvent->GetStatus(&hrStatus);
            if (FAILED(hr))
            {
                hrStatus = hr;
            }
    
            hr = pEvent->GetExtendedType(&guidType);
            if (SUCCEEDED(hr))
            {
                if (guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED)
                {
                    m_pManager->OnPreviewStopped(hrStatus);
                    SetEvent(m_pManager->m_hEvent);
                }
                else if (guidType == MF_CAPTURE_ENGINE_RECORD_STOPPED)
                {
                    m_pManager->OnRecordStopped(hrStatus);
                    SetEvent(m_pManager->m_hEvent);
                }
                else
                {
                    // This is an event we don't know about, we don't really care and there's
                    // no clean way to report the error so just set the event and fall through.
                    SetEvent(m_pManager->m_hEvent);
                }
            }
    
            return S_OK;
        }
        else
        {
            pEvent->AddRef();  // The application will release the pointer when it handles the message.
            PostMessage(m_hwnd, WM_APP_CAPTURE_EVENT, (WPARAM)pEvent, 0L);
        }
    
        return S_OK;
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-30
      • 1970-01-01
      相关资源
      最近更新 更多