2016-02-26 45 views
1

我正在嘗試編寫一個小應用程序,可以將由相機設備捕獲的視頻幀直接顯示在窗口上。我使用「Source Reader」+「Sink Writer」架構而不是「Media Session」,因爲我必須直接處理這些捕獲的樣本。我創建源讀取成功,但是當我試圖創建EVR顯示框架,我遇到了一些問題...以下是我的代碼:使用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,看起來我應該能夠添加一個新的媒體類型,我希望用於媒體鏈接;但是我嘗試了AddStreamSink函數,但它直接返回錯誤。 「CCapture」類繼承自IMFSourceReaderCallBack,如果我的理解正確,我應該在OnReadSample回調函數中使用m_pPreviewStream-> ProcessSample(pSample)。 非常感謝,如果有人能幫助這個! 最好的問候

+0

我以前沒有嘗試過同樣的事情。這裏是我的不工作代碼https://github.com/sipsorcery/mediafoundationsamples/blob/master/MFVideoEVR/MFVideoEVR.cpp(我正在播放一個mp4文件,但如果我能得到工作切換到網絡攝像頭會很容易) 。希望有人會提出你的問題的答案。 – sipwiz

+0

非常感謝您的代碼,我認爲我們現在處於相同的情況...... – Jiyuan

回答

0

這似乎很困惑。

當您希望EVR顯示來自多個來源的幀時,您必須使用AddStreamSink。

閱讀你的文章,你想只顯示你的相機(一個來源)幀。

所以你不需要使用AddStreamSink。

並且您從AddStreamSink中收到錯誤,因爲在向EVR添加流時(取決於您的GPU特性),要使用的媒體類型有一些限制。

+0

非常感謝您的回覆。我做了另一個試驗:如果我獲得IMFVideoRenderer接口並在派生active_object m_pPreviewSink之後調用InitializeRenderer(NULL,NULL),我可以將mediatype設置爲引用流。現在遇到的問題是,當我在OnReadSample回調函數中調用m_pPreviewStream-> ProcessSample(pSample)時,它返回E_NOTIMPL。這是否意味着我必須自己實現Mixer和Presenter,即使我選擇使用默認值(InitializeRenderer的輸入是兩個NULL)? – Jiyuan

+0

在這裏檢查:http://stackoverflow.com/questions/24856180/how-to-send-imfsample-to-evr-media-sink – mofo77

相關問題