在拓扑和显示混合视频中添加两个媒体源 - Windows Media Foundation

Add two media sources in topology and display mix video - Windows Media Foundation

我正在探索 windows 媒体基础。
我想将两个视频流混合显示在一个 window.
我正在关注 MS 提供的一些示例。

我正在尝试将多个媒体源添加到拓扑中,我想将两个媒体文件添加到拓扑中。

根据下面的 link,我按照以下代码在拓扑中添加媒体源:
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);
}

但是我无法在我的拓扑中添加多个媒体源。
我的单个文件播放正常,但我无法混合和显示两个文件。

我建议将您的任务分为五个步骤: 1. 编写播放一个视频文件的代码。在 MSDN 上有示例代码:How to Play Media Files with Media Foundation。 2.研究WORKABLE player for point的代码,其中从视频文件路径(URL)创建了MediaSource。 3. 从两个视频文件路径 (URL) 创建两个 MediaSource。 4. 通过函数 MFCreateAggregateSource 从两个 MediaSource 创建 - 一个 MediaSource 并从方法播放器 HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource) 返回 MediaSource 5. 调用 '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.

递增

想法是在创建 Topology 之前为视频渲染器创建代码 Activate - 没问题。然后这个 ONE 视频渲染器通过检查条件 if (MFMediaType_Video == guidMajorType) 在 MediaSource 中的所有视频流之间通过 ref 指针激活共享。每个视频流都通过递增全局变量 globalVideoIndex++ 从 0 获得唯一 ID - 此 ID 在方法 hr = AddOutputNode(pTopology, pSinkActivate, iStreamID, &pOutputNode); 中设置。因此,所有视频流将由一个视频渲染器绘制,iStreamID 为 0 的视频流将 reference background,而其他视频流将附加。