在拓扑和显示混合视频中添加两个媒体源 - 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
,而其他视频流将附加。
我正在探索 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
,而其他视频流将附加。