【发布时间】:2017-07-05 18:21:33
【问题描述】:
我正在使用 MediaFoundation SourceReader 技术开发 USB 摄像头流式桌面应用程序。该相机支持 USB3.0,1080p MJPG 视频格式分辨率为 60fps。
我使用 Software MJPEG Decoder MFT 将 MJPG 转换为 YUY2 帧,然后转换为 RGB32 帧在窗口上绘制。使用此软件解码器时,我只能在窗口上渲染 30fps,而不是 60fps。我在这个网站上发布了一个问题,并得到了一些使用英特尔硬件 MJPEG 解码器 MFT 来解决丢帧问题的建议。
为了使用这个硬件 MJPEG 解码器,我已经解决了异步 MFT 处理模型,并通过 IMFTransform 接口为 IMFMediaEventGenerator 配置了异步回调。
使用 ProcessMessage 方法调用 MFT_MESSAGE_NOTIFY_START_OF_STREAM 后,我收到了两次 MFTransfromNeedInput 事件,但没有收到来自 MFT 的 MFTransformHaveOutput 事件。
我在这里分享了我的代码供您参考:
IMFTransform* m_pTransform = NULL;
HRESULT EnumDecoderMFT ()
{
HRESULT hr;
IMFActivate** ppActivate;
UINT32 numDecodersMJPG = 0;
LPWSTR lpMFTName = 0;
MFT_REGISTER_TYPE_INFO inputFilter = {MFMediaType_Video,MFVideoFormat_MJPG};
MFT_REGISTER_TYPE_INFO outputFilter = {MFMediaType_Video,MFVideoFormat_YUY2};
UINT32 unFlags = MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
hr = MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, unFlags, &inputFilter, &outputFilter, &ppActivate, &numDecodersMJPG);
if (FAILED(hr)) return hr;
hr = ppActivate[0]->GetAllocatedString(MFT_FRIENDLY_NAME_Attribute,&lpMFTName,0);
if (FAILED(hr)) return hr;
// Activate transform
hr = ppActivate[0]->ActivateObject(__uuidof(IMFTransform), (void**)&m_pTransform);
if (FAILED(hr)) return hr;
hr = hr = m_pTransform->GetAttributes(&pAttributes);
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
if(FAILED(hr)) return hr;
hr = pAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE,TRUE);
if(FAILED(hr)) return hr;
hr = pAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
if(FAILED(hr)) return hr;
hr = m_pTransform->QueryInterface(IID_IMFMediaEventGenerator,(void**)&m_pEventGenerator);
if(FAILED(hr)) return hr;
hr = m_pEventGenerator->BeginGetEvent((IMFAsyncCallback*)this,NULL);
if(FAILED(hr)) return hr;
pAttributes->Release();
}
SafeRelease(&ppActivate[0]);
CoTaskMemFree(ppActivate);
return hr;
}
HRESULT Invoke(IMFAsyncResult *pResult)
{
HRESULT hr = S_OK,hrStatus;
MediaEventType meType = MEUnknown; // Event type
IMFMediaEvent *pEvent = NULL;
// Get the event from the event queue.
hr = m_pEventGenerator->EndGetEvent(pResult, &pEvent); //Completes an asynchronous request for the next event in the queue.
if(FAILED(hr)) return hr;
// Get the event type.
hr = pEvent->GetType(&meType);
if(FAILED(hr)) return hr;
hr = pEvent->GetStatus(&hrStatus);
if(FAILED(hr)) return hr;
if(SUCCEEDED(hrStatus))
{
if(meType == METransformNeedInput)
{
SetEvent(m_hNeedInputEvent);
}
else if(meType == METransformHaveOutput)
{
SetEvent(m_hHaveOutputEvent);
}
else if(meType == METransformDrainComplete)
{
hr = m_pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH,0);
if(FAILED(hr)) return hr;
}
else if(meType == MEError)
{
PROPVARIANT pValue;
hr = pEvent->GetValue(&pValue);
if(FAILED(hr)) return hr;
}
hr = m_pEventGenerator->BeginGetEvent((IMFAsyncCallback*)this,NULL);
if(FAILED(hr)) return hr;
}
done:
SafeRelease(&pEvent);
return S_OK;
}
HRESULT CMFSourceReader::OnReadSample(
HRESULT hrStatus,
DWORD dwStreamIndex ,
DWORD dwStreamFlags ,
LONGLONG llTimestamp ,
IMFSample *pSample // Can be NULL
)
{
HRESULT hr = S_OK;
IMFMediaBuffer *pBuffer = NULL;
DWORD dwcbTotLen = 0;
IMFSample *mftOutSample = NULL;
EnterCriticalSection(&m_critsec);
if (FAILED(hrStatus))
{
hr = hrStatus;
}
if (SUCCEEDED(hr))
{
if (pSample != NULL)
{
if(dwStreamIndex == 0) //VideoStream
{
if(m_pTransform)
{
hr = m_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
if(FAILED(hr)) return hr;
m_dwWaitObj = WaitForSingleObject(m_hNeedInputEvent,INFINITE);
if(m_dwWaitObj == WAIT_OBJECT_0)
{
hr = ProcessInputSample(pSample);
if(FAILED(hr)) return hr;
}
m_dwWaitObj = WaitForSingleObject(m_hHaveOutputEvent,INFINITE);
if(m_dwWaitObj == WAIT_OBJECT_0)
{
hr = ProcessOutputSample(&mftOutSample);
if(FAILED(hr)) return hr;
}
}
}
}
}
if(SUCCEEDED(hr))
{
if(m_pReader != NULL)
{
hr = m_pReader->ReadSample(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
NULL, // actual
NULL, // flags
NULL, // timestamp
NULL // sample
);
if(FAILED(hr)) return hr;
}
}
SafeRelease(&mftOutSample);
LeaveCriticalSection(&m_critsec);
return hr;
}
HRESULT ProcessOutputSample(IMFSample **pOutSample)
{
HRESULT hr = S_OK;
MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
DWORD processOutputStatus = 0,mftOutFlags = 0;
MFT_OUTPUT_STREAM_INFO StreamInfo;
IMFSample *mftOutSample = NULL;
IMFMediaBuffer *pOutBuffer = NULL;
if(m_pTransform != NULL)
{
hr = m_pTransform->GetOutputStreamInfo(0, &StreamInfo);
if(FAILED(hr)) return hr;
DWORD status = 0;
hr = m_pTransform->GetOutputStatus(&status);
if (FAILED(hr)) return hr;
hr = MFCreateSample(&mftOutSample);
if(FAILED(hr)) return hr;
hr = MFCreateMemoryBuffer(StreamInfo.cbSize, &pOutBuffer);
if(FAILED(hr)) return hr;
hr = mftOutSample->AddBuffer(pOutBuffer);
if(FAILED(hr)) return hr;
outputDataBuffer.dwStreamID = 0;
outputDataBuffer.dwStatus = 0;
outputDataBuffer.pEvents = NULL;
outputDataBuffer.pSample = mftOutSample;
hr = m_pTransform->ProcessOutput(0, 1, &outputDataBuffer, &processOutputStatus);
if(FAILED(hr)) return hr;
hr = m_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
if (FAILED(hr)) return hr;
hr = m_pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
if (FAILED(hr)) return hr;
if(mftOutSample)
{
*pOutSample = mftOutSample;
(*pOutSample)->AddRef();
}
ResetEvent(m_hHaveOutputEvent);
}
SafeRelease(&mftOutSample);
SafeRelease(&pOutBuffer);
return hr;
}
HRESULT ProcessInputSample(IMFSample *pInputSample)
{
HRESULT hr;
if(m_pTransform != NULL)
{
hr = m_pTransform->ProcessInput(0, pInputSample, 0);
if(FAILED(hr)) return hr;
hr = m_pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM,0);
if(FAILED(hr)) return hr;
ResetEvent(m_hNeedInputEvent);
}
return hr;
}
我在我的代码中注释了 ProcessOutputSample() 方法并检查了,连续 MFT 发送 MFTransformNeedInput 事件类型。在 ProcessInput 示例之后,我有 ProcessOutput 方法,但它返回了 E_UNEXPECTED 错误。我在 MSDN 中读到过这个错误,他们提到我不应该调用 IMFTransform:: ProcessOutput 方法而不接收 MFTransformHaveOutput 事件。
我有什么遗漏吗?我可以在 MediaFoundation 中使用英特尔硬件 MJPEG 解码器 MFT 吗?有人提供使用此解码器的示例吗?过去 4 天,我一直在努力解决这个问题。
提前致谢。
【问题讨论】:
-
那是什么网络摄像头? (只是好奇)
-
我正在使用此链接中提到的相机:e-consystems.com/13mp-autofocus-usb-camera.asp
-
@Abi,我也面临同样的问题。你能解决问题吗?如果是的话,你能指导我看任何样品吗?
标签: video visual-c++ media ms-media-foundation