将 Visual C++ Media Foundation Capture 应用程序转换为 C++ Builder
Converting Visual C++ Media Foundation Capture application to C++ Builder
我正在尝试将 Microsoft "CaptureEngine video capture sample" 代码从 Visual C++ 转换为 Embarcadero C++ Builder。
https://code.msdn.microsoft.com/windowsdesktop/Media-Foundation-Capture-78504c83
代码在 Visual C++ 中运行良好,但我需要包含在 C++ Builder 应用程序中。我的代码基本上可以正常工作,但有几个问题我需要帮助。
我可以 select 视频源、预览视频源甚至开始捕捉到文件。然而,视频捕获文件仅包含视频长度重复的一帧,即使音频已正确录制。
我想知道这是否是由于事件处理不当造成的。
来自媒体基础捕获引擎的事件使用 windows 消息传递到主线程,然后调用媒体引擎事件处理程序。但是我注意到事件处理程序停止录制并停止预览使用 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;
}
问题是,这个 m_hEvent 是从 C++ Builder 事件处理程序触发的,它是等待事件处理的同一主线程的一部分,所以我在尝试时获得了线程锁停止视频录制。如果我注释掉该行,我不会锁定,但我也不会获得有效的录制视频文件。
我不确定 Visual C++ 如何将事件与捕获引擎代码分开,关于我如何为 C++ Builder 执行此操作有什么建议吗?
捕获引擎事件回调是在工作线程上调用的,而不是 "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);
这实质上改变了应用程序的行为。控制线程停止预览并阻塞,直到工作线程发送一个通知来设置我上面引用的事件。从那里控制线程从等待操作中唤醒并继续预览停止。
如果这不是您在应用程序中看到的,我建议您在回调函数的第一行设置一个断点,以确保您收到通知。如果收到,您可以单步执行代码并确保到达事件设置行。如果您没有收到,则说明有其他事情正在阻塞,您将不得不解决这个问题,例如,通过中断和检查应用程序的线程状态。
我找到问题的原因了。 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;
}
我正在尝试将 Microsoft "CaptureEngine video capture sample" 代码从 Visual C++ 转换为 Embarcadero C++ Builder。
https://code.msdn.microsoft.com/windowsdesktop/Media-Foundation-Capture-78504c83
代码在 Visual C++ 中运行良好,但我需要包含在 C++ Builder 应用程序中。我的代码基本上可以正常工作,但有几个问题我需要帮助。
我可以 select 视频源、预览视频源甚至开始捕捉到文件。然而,视频捕获文件仅包含视频长度重复的一帧,即使音频已正确录制。
我想知道这是否是由于事件处理不当造成的。 来自媒体基础捕获引擎的事件使用 windows 消息传递到主线程,然后调用媒体引擎事件处理程序。但是我注意到事件处理程序停止录制并停止预览使用 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;
}
问题是,这个 m_hEvent 是从 C++ Builder 事件处理程序触发的,它是等待事件处理的同一主线程的一部分,所以我在尝试时获得了线程锁停止视频录制。如果我注释掉该行,我不会锁定,但我也不会获得有效的录制视频文件。
我不确定 Visual C++ 如何将事件与捕获引擎代码分开,关于我如何为 C++ Builder 执行此操作有什么建议吗?
捕获引擎事件回调是在工作线程上调用的,而不是 "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);
这实质上改变了应用程序的行为。控制线程停止预览并阻塞,直到工作线程发送一个通知来设置我上面引用的事件。从那里控制线程从等待操作中唤醒并继续预览停止。
如果这不是您在应用程序中看到的,我建议您在回调函数的第一行设置一个断点,以确保您收到通知。如果收到,您可以单步执行代码并确保到达事件设置行。如果您没有收到,则说明有其他事情正在阻塞,您将不得不解决这个问题,例如,通过中断和检查应用程序的线程状态。
我找到问题的原因了。 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;
}