我正在尝试编写一个小应用程序,将相机设备捕获的视频帧直接显示在窗口上。我正在使用“Source Reader”+“Sink Writer”架构而不是“Media Session”,因为我必须直接处理这些捕获的样本。我已成功创建了Source Reader,但当我尝试创建EVR来显示框架时,我遇到了一些问题......以下是我的代码:
HRESULT CCapture::CreatePreviewEVR(HWND hWindow)
{
// m_pPreviewSink, m_pPreviewStream, m_pPresentationClock, and m_pPresentationTimeSource
// are all defined as Class members
HRESULT hr = S_OK;
DWORD sinkCharacteristics = NULL;
IMFActivate *pPreviewSinkActive = NULL;
IMFClockStateSink *pClockStateSink = NULL;
hr = MFCreateVideoRendererActivate(hWindow, &pPreviewSinkActive);
if(SUCCEEDED(hr))
{
hr = pPreviewSinkActive->ActivateObject(IID_PPV_ARGS(&m_pPreviewSink));
}
if(SUCCEEDED(hr))
{
hr = m_pPreviewSink->GetCharacteristics(&sinkCharacteristics); // sinkCharacteristics is 0x18
}
if(SUCCEEDED(hr))
{
hr = m_pPreviewSink->GetStreamSinkByIndex(0, &m_pPreviewStream);
}
if(SUCCEEDED(hr))
{
hr = MFCreatePresentationClock(&m_pPresentationClock);
}
if(SUCCEEDED(hr))
{
hr = MFCreateSystemTimeSource(&m_pPresentationTimeSource);
}
if(SUCCEEDED(hr))
{
hr = m_pPresentationTimeSource->QueryInterface(__uuidof(IMFClockStateSink),(void**)&pClockStateSink);
}
if(SUCCEEDED(hr))
{
hr = m_pPresentationClock->SetTimeSource(m_pPresentationTimeSource);
}
if(SUCCEEDED(hr))
{
hr = m_pPresentationClock->AddClockStateSink(pClockStateSink);
}
if(SUCCEEDED(hr))
{
hr = m_pPreviewSink->SetPresentationClock(m_pPresentationClock);
}
return hr;
}
HRESULT CCapture::ConfigurePreviewEVR()
{
// This function is implemented trying to do EVR Media Type Negotiation
DWORD mediaTypeCount = 0;
HRESULT hr =S_OK;
IMFMediaType *pSourceReaderType = NULL;
IMFMediaType *pSourceReaderTypeValid = NULL;
IMFMediaType *pPreviewSinkMediaType = NULL;
IMFMediaTypeHandler *pPreviewSinkMediaTypeHandler = NULL;
hr = m_pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pSourceReaderType);
if(SUCCEEDED(hr))
{
hr = MFCreateMediaType(&pPreviewSinkMediaType);
}
if(SUCCEEDED(hr))
{
hr = pPreviewSinkMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
}
if(SUCCEEDED(hr))
{
hr = pPreviewSinkMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
}
if(SUCCEEDED(hr))
{
hr = pPreviewSinkMediaType->SetUINT32(MF_MT_AVG_BITRATE, 14000000);
}
if(SUCCEEDED(hr))
{
hr = CopyAttribute(pSourceReaderType, pPreviewSinkMediaType, MF_MT_FRAME_SIZE);
}
if(SUCCEEDED(hr))
{
hr = CopyAttribute(pSourceReaderType, pPreviewSinkMediaType, MF_MT_FRAME_RATE);
}
if(SUCCEEDED(hr))
{
hr = CopyAttribute(pSourceReaderType, pPreviewSinkMediaType, MF_MT_PIXEL_ASPECT_RATIO);
}
if(SUCCEEDED(hr))
{
hr = CopyAttribute(pSourceReaderType, pPreviewSinkMediaType, MF_MT_INTERLACE_MODE);
}
if(SUCCEEDED(hr))
{
hr = m_pPreviewStream->GetMediaTypeHandler(&pPreviewSinkMediaTypeHandler);
}
if(SUCCEEDED(hr))
{
hr = pPreviewSinkMediaTypeHandler->GetMediaTypeCount(&mediaTypeCount); // derived mediaTypeCount is 0
}
if(SUCCEEDED(hr))
{
hr = pPreviewSinkMediaTypeHandler->IsMediaTypeSupported(pSourceReaderType, &pSourceReaderTypeValid); // Failed to get supported Media Type
}
if(SUCCEEDED(hr))
{
hr = pPreviewSinkMediaTypeHandler->SetCurrentMediaType(pSourceReaderTypeValid); // This function still fails if I use pSourceReaderType directly
}
if(SUCCEEDED(hr))
{
SafeRelease(&pSourceReaderType);
SafeRelease(&pPreviewSinkMediaType);
SafeRelease(&pPreviewSinkMediaTypeHandler);
}
return hr;
}
函数“CopyAttribute”来自MFCaptureToFile示例代码,它可以正常工作。由于变量“sinkCharacteristics”给出0x18,我似乎应该能够将我希望使用的媒体类型的新流添加到mediasink;但我尝试了AddStreamSink函数,但它直接返回错误。 “CCapture”类继承自IMFSourceReaderCallBack,如果我的理解是正确的,我应该在OnReadSample回调函数中使用m_pPreviewStream-> ProcessSample(pSample)。 非常感谢,如果有人可以提供帮助! 最诚挚的问候
答案 0 :(得分:0)
这似乎很困惑。
当您希望EVR显示来自多个来源的帧时,您必须使用AddStreamSink。
阅读你的帖子,你只想从你的相机(一个来源)显示帧。
所以你不需要使用AddStreamSink。
您从AddStreamSink收到错误,因为在向EVR添加流时要使用的媒体类型存在一些限制(这取决于您的GPU特性)。