Reputation: 11
I am trying to write a small app that display video frames captured by camera device directly onto a window. I am using "Source Reader" + "Sink Writer" architecture rather than "Media Session" as I have to deal with those captured samples directly. I have created Source Reader successfully but when I tried to create EVR to display frames, I met some problems... following is my code:
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;
}
The function "CopyAttribute" is from MFCaptureToFile Sample Code, it can work normally. As the variable "sinkCharacteristics" gives 0x18, it seems I should be able to add a new stream with the media type I wish to use to the mediasink; however I tried AddStreamSink function but it returned error directly. The "CCapture" Class inherits from IMFSourceReaderCallBack, and If my understanding is correct, I should use m_pPreviewStream->ProcessSample(pSample) in OnReadSample callback function. Thanks a lot if anyone can help on this! Best Regards
Upvotes: 1
Views: 559
Reputation: 1515
This seems very confused.
You have to use AddStreamSink, when you want EVR to display frames from several sources.
Reading your post, you want to display frames only from your camera (one source).
So you don't need to use AddStreamSink.
And you get error from AddStreamSink, because there are some limitations about media types to use when adding streams to EVR (it depends on your GPU characteristics).
Upvotes: 0