【问题标题】:Add two media sources in topology and display mix video - Windows Media Foundation在拓扑中添加两个媒体源并显示混合视频 - Windows Media Foundation
【发布时间】:2017-03-03 08:09:55
【问题描述】:

我正在探索 Windows Media Foundation。
我想在一个窗口中混合和显示两个视频流。
我正在关注 MS 提供的一些示例。

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

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

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

【问题讨论】:

  • 实际如何添加源?您使用源解析器、聚合源还是排序器源?
  • @VuVirt:我正在使用源聚合器从多个视频源创建一个源。但现在使用 EVR 和显示控制在一个渲染器中显示两个视频时遇到了困难。
  • 我不确定标准 IMFMediaSession 是否支持 EVR 的多个视频输入。您可能需要实现自定义媒体会话。

标签: ms-media-foundation


【解决方案1】:

我建议将您的任务分为五个步骤: 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); 用于第二个视频流。

问候。

附:如果您将使用两个带有音频流的视频,那么您将在 Aggregate MediaSource 中有四个流 - 它可能需要 FIND 视频流的流 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;
    }
}

然后将这个 crated 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 中的所有视频流之间通过引用指针激活共享。每个 VIDEO 流都通过递增全局变量 globalVideoIndex++ 从 0 获得唯一 id - 此 id 在方法 hr = AddOutputNode(pTopology, pSinkActivate, iStreamID, &amp;pOutputNode); 中设置。这样一来,所有的视频流都会被ONE视频渲染器绘制出来,iStreamID为0的视频流将reference background,而其他视频流将额外添加。

【讨论】:

  • 感谢您提供详细信息,但很难消化。我正在使用 MediaSession,并且可以使用链接中提供的示例渲染一个视频流:msdn.microsoft.com/en-us/library/windows/desktop/… 但我想显示两个视频流(暂时没有音频),我该怎么做?
  • 我写过:从两个视频文件路径(URL)创建两个 MediaSource。 4. 通过函数 MFCreateAggregateSource 从两个 MediaSource - 一个 MediaSource 创建并从方法播放器 HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource) 返回 MediaSource;
  • 您必须使用两个 URL 字符串作为参数创建新版本 CreateMediaSource - 例如 HRESULT CreateMediaSource(PCWSTR sURL1, PCWSTR sURL2, IMFMediaSource **ppSource)。然后从原始CreateMediaSource 复制代码,为每个 URL 创建 MediaSource,但不要返回值。然后,虽然您将在代码中拥有两个不同的 MediaSource,但您必须通过函数 [MFCreateCollection](MFCreateCollection) 使用 IMFCollection 创建对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-06
  • 1970-01-01
相关资源
最近更新 更多