2017-03-02 71 views
1

我在探索windows媒體基礎。
我想在一個窗口中混合並顯示兩個視頻流。
我跟隨少數MS提供的樣本。在拓撲中添加兩個媒體源並顯示混合視頻 - Windows Media Foundation

我想添加多個媒體源到拓撲,我想添加兩個媒體文件到拓撲。

按下面的鏈接,我下面的代碼在拓撲添加媒體來源:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms701605(v=vs.85).aspx

下面是一個源節點添加到拓撲代碼:

HRESULT hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD); 
if (FAILED(hr)) 
{ 
    goto done; 
} 

if (fSelected) 
{ 
    // Create the media sink activation object. 
    hr = CreateMediaSinkActivate(pSD, hVideoWnd, &pSinkActivate); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    // Add a source node for this stream. 
    hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pSourceNode); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    // Create the output node for the renderer. 
    hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    // Connect the source node to the output node. 
    hr = pSourceNode->ConnectOutput(0, pOutputNode, 0); 
} 

但我無法在拓撲中添加多個媒體源。
我的單個文件播放工作正常,但我無法混合並顯示兩個文件。

+0

你如何添加實際的來源?你使用源解析器,聚合源還是序列源? – VuVirt

+0

@VuVirt:我正在使用源聚合器從多個視頻源創建一個源。但現在正努力在使用EVR和顯示控件的一個渲染器中顯示兩個視頻。 – User7723337

+0

我不確定標準IMFMediaSession支持EVR的多個視頻輸入。您可能需要實施自定義媒體會話。 – VuVirt

回答

1

我建議分五步完成你的任務: 1.編寫播放ONE視頻文件的代碼。在MSDN上有示例代碼:How to Play Media Files with Media Foundation。 2. WORKABLE播放器的研究代碼點,從視頻文件路徑(URL)創建MediaSource。 3.從兩個視頻文件路徑(URL)創建TWO MediaSource。 4.按功能MFCreateAggregateSource從兩個MediaSource創建 - ONE MediaSource並從方法播放器重新指定MediaSource HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource) 5. call'hr = AddOutputNode(pTopology,pSinkActivate,0,& pOutputNode);'兩次:'hr = AddOutputNode(pTopology,pSinkActivate,0,& pOutputNode);'用於第一視頻流並且用於第二視頻流的hr = AddOutputNode(pTopology, pSinkActivate, 1, &pOutputNode);

問候。

P.S.如果您將兩個視頻與音頻流一起使用,那麼您將在Aggregate MediaSource中擁有四個流 - 它可能需要查找視頻流的流ID。 P.S.S不容易推薦僅查看演示代碼,但在CreateMediaSinkActivate中您會找到代碼hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate);。在代碼中,你必須創建此Activate前:

// For each stream, create the topology nodes and add them to the topology. 
for (DWORD i = 0; i < cSourceStreams; i++) 
{ 
    hr = AddBranchToPartialTopology(pTopology, pSource, pPD, i, hVideoWnd); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 
} 

然後設置此裝箱Activate作爲論據AddBranchToPartialTopology

例如:

hr = MFCreateVideoRendererActivate(hVideoWindow, &pVideoRendererActivate); 
// For each stream, create the topology nodes and add them to the topology. 
for (DWORD i = 0; i < cSourceStreams; i++) 
{ 
    hr = AddBranchToPartialTopology(pTopology, pSource, pPD, i, pVideoRendererActivate); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 
} 

AddBranchToPartialTopology你必須寫是這樣的:

HRESULT AddBranchToPartialTopology(
IMFTopology *pTopology,   // Topology. 
IMFMediaSource *pSource,  // Media source. 
IMFPresentationDescriptor *pPD, // Presentation descriptor. 
DWORD iStream,     // Stream index. 
IMFActivate* aVideoRendererActivate)     // VideoRenderer for video playback. 
{ 
IMFStreamDescriptor *pSD = NULL; 
IMFActivate   *pSinkActivate = NULL; 
IMFTopologyNode  *pSourceNode = NULL; 
IMFTopologyNode  *pOutputNode = NULL; 

BOOL fSelected = FALSE; 

HRESULT hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD); 
if (FAILED(hr)) 
{ 
    goto done; 
} 

DWORD iStreamID = 0; 

if (fSelected) 
{ 
    // Create the media sink activation object. 
    hr = CreateMediaSinkActivate(pSD, iStreamID, aVideoRendererActivate, &pSinkActivate); 

在「CreateMediaSinkActivate」你必須寫這樣的事:

DWORD globalVideoIndex = 0; 

HRESULT CreateMediaSinkActivate(
IMFStreamDescriptor *pSourceSD,  // Pointer to the stream descriptor. 
DWORD& iStreamID, // ctream index 
IMFActivate *pVideoRendererActivate,     // Handle to the video  renderer activate. 
IMFActivate **ppActivate 
) 
{ 
IMFMediaTypeHandler *pHandler = NULL; 
IMFActivate *pActivate = NULL; 

// Get the media type handler for the stream. 
HRESULT hr = pSourceSD->GetMediaTypeHandler(&pHandler); 
if (FAILED(hr)) 
{ 
    goto done; 
} 

// Get the major media type. 
GUID guidMajorType; 
hr = pHandler->GetMajorType(&guidMajorType); 
if (FAILED(hr)) 
{ 
    goto done; 
} 

// Create an IMFActivate object for the renderer, based on the media type. 
if (MFMediaType_Audio == guidMajorType) 
{ 
    // Create the audio renderer. 
    hr = MFCreateAudioRendererActivate(&pActivate); 
} 
else if (MFMediaType_Video == guidMajorType) 
{ 
    // Share the video renderer. 

    hr = pVideoRendererActivate->QueryInterface(IID_PPV_ARG(pActivate)) 

    iStreamID = globalVideoIndex++; 
} 
else 
{ 
    // Unknown stream type. 
    hr = E_FAIL; 
    // Optionally, you could deselect this stream instead of failing. 
} 
if (FAILED(hr)) 
{ 
    goto done; 
} 

// Return IMFActivate pointer to caller. 
*ppActivate = pActivate; 
(*ppActivate)->AddRef(); 

done: 
SafeRelease(&pHandler); 
SafeRelease(&pActivate); 
return hr; 
} 

AddBranchToPartialTopology你必須寫:

// Create the output node for the renderer. 
hr = AddOutputNode(pTopology, pSinkActivate, iStreamID, &pOutputNode); 
if (FAILED(hr)) 
{ 
    goto done; 
} 

的音頻數據流iStreamID將爲零,但對於視頻流會從全局變量globalVideoIndex增加。

想法是代碼爲視頻渲染器創建Activate之前創建Topology - 它是確定的。然後,這一個視頻渲染器通過檢查條件if (MFMediaType_Video == guidMajorType)來激活MediaSource中所有視頻流之間的ref指針共享。通過遞增全局變量globalVideoIndex++,每個VIDEO流都得到了唯一的ID,這個ID在方法hr = AddOutputNode(pTopology, pSinkActivate, iStreamID, &pOutputNode);中設置。其結果是,所有視頻流將由一個視頻渲染器被吸入,並與iStreamID視頻流是0將reference background,而其他視頻流將附加。

+0

感謝細節,但很難消化。我使用MediaSession,我能夠呈現一個視頻流,使用例如在提供的鏈接:https://msdn.microsoft.com/en-us/library/windows/desktop/ms703190(v=vs.85)。 aspx但我想顯示兩個視頻流(現在沒有音頻),所以我該怎麼做? – User7723337

+1

我寫道:從兩個視頻文件路徑(URL)創建兩個MediaSource。 4.函數MFCreateAggregateSource從TWO MediaSource的創建 - ONE MediaSource的以及從方法播放HRESULT CreateMediaSource(PCWSTR SURL,IMFMediaSource ** ppSource)retuurn MediaSource的; –

+1

您必須創建新的版本'CreateMediaSource'有兩個URL字符串參數 - 例如'HRESULT CreateMediaSource(PCWSTR sURL1,PCWSTR sURL2,IMFMediaSource ** ppSource)'。然後從最初的'CreateMediaSource'複製代碼爲每個URL創建MediaSource,但不要返回值。然後,雖然在代碼TWO中有不同的MediaSource,但您必須通過函數[MFCreateCollection](MFCreateCollection)通過「IMFCollection」創建對象。 –

相關問題