Jiyuan
Jiyuan

Reputation: 11

Use EVR to display frames captured by camera device directly using Media Foundation

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

Answers (1)

mofo77
mofo77

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

Related Questions