使用EVR直接使用Media Foundation

时间:2016-02-26 12:45:02

标签: c++ windows ms-media-foundation

我正在尝试编写一个小应用程序,将相机设备捕获的视频帧直接显示在窗口上。我正在使用“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)。 非常感谢,如果有人可以提供帮助! 最诚挚的问候

1 个答案:

答案 0 :(得分:0)

这似乎很困惑。

当您希望EVR显示来自多个来源的帧时,您必须使用AddStreamSink。

阅读你的帖子,你只想从你的相机(一个来源)显示帧。

所以你不需要使用AddStreamSink。

您从AddStreamSink收到错误,因为在向EVR添加流时要使用的媒体类型存在一些限制(这取决于您的GPU特性)。