Hi,
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:
HRESULTCCapture::CreatePreviewEVR(HWNDhWindow)
{
//m_pPreviewSink,m_pPreviewStream,m_pPresentationClock,andm_pPresentationTimeSource
//arealldefinedasClassmembers
HRESULThr=S_OK;
DWORDsinkCharacteristics=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);//sinkCharacteristicsis0x18
}
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);
}
returnhr;
}
HRESULTCCapture::ConfigurePreviewEVR()
{
//ThisfunctionisimplementedtryingtodoEVRMediaTypeNegotiation
DWORDmediaTypeCount=0;
HRESULThr=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);//derivedmediaTypeCountis0
}
if(SUCCEEDED(hr))
{
hr=pPreviewSinkMediaTypeHandler->IsMediaTypeSupported(pSourceReaderType,&pSourceReaderTypeValid);//FailedtogetsupportedMediaType
}
if(SUCCEEDED(hr))
{
hr=pPreviewSinkMediaTypeHandler->SetCurrentMediaType(pSourceReaderTypeValid);//ThisfunctionstillfailsifIusepSourceReaderTypedirectly
}
if(SUCCEEDED(hr))
{
SafeRelease(&pSourceReaderType);
SafeRelease(&pPreviewSinkMediaType);
SafeRelease(&pPreviewSinkMediaTypeHandler);
}
returnhr;
}
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