拓扑是代表着Media Session 中的管道,代表着数据流。 Media Session 用拓扑来控制着数据流的走向。
拓扑是由结点组成,结点是管道中的对象, 每一个节点可能是 Media Source, MFT, Media Sinks,节点之间用线连接起来,表示数据流的路径。 结点分为四种类型:
1. Source Node: 代表数据源, Media Source
2. Transform Node: 代表 MFT, 处理单元/对象
3. Output Node: 代码了数据的消耗者, Media Sink
4. Tee Node: 代表数据流的一份拷贝
可以通过调用函数MFCreateTopology 来创建拓扑, 这个函数返回一个指针,指向IMFTopology 接口。
刚刚创建的拓扑中是不包含任何结点的, 可以调用函数 MFCreateTopologyNode 来创建拓扑结点, 这个函数返回一个指针,指向 IMFTopologyNode 接口。 创建节点的时候,必须要指点结点类型。
对于不同的节点类型的创建,有些细节的区别:
1. Source Nodes
- 在调用函数MFCreateTopologyNode 时,需要传递参数MF_TOPOLOGY_SOURCESTREAM_NODE
- 必须有一个指针指向 Media Source。 hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource);
- 必须有一个指针指向 Presentation Descriptor。
- 必须有一个指针指向 Stream Descriptor
- 调用 IMFTopology::AddNode, 把新创建的所有拓扑结点加入拓扑中
参考代码如下:
// Add a source node to a topology.
HRESULT AddSourceNode(
IMFTopology *pTopology, // Topology.
IMFMediaSource *pSource, // Media source.
IMFPresentationDescriptor *pPD, // Presentation descriptor.
IMFStreamDescriptor *pSD, // Stream descriptor.
IMFTopologyNode **ppNode) // Receives the node pointer.
{
IMFTopologyNode *pNode = NULL;
// Create the node.
HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode);
if (FAILED(hr))
{
goto done;
}
// Set the attributes.
hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource);
if (FAILED(hr))
{
goto done;
}
hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD);
if (FAILED(hr))
{
goto done;
}
hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD);
if (FAILED(hr))
{
goto done;
}
// Add the node to the topology.
hr = pTopology->AddNode(pNode);
if (FAILED(hr))
{
goto done;
}
// Return the pointer to the caller.
*ppNode = pNode;
(*ppNode)->AddRef();
done:
SafeRelease(&pNode);
return hr;
}
2. Transform Nodes
- 创建 MFT 实例,得到 IMFTransform 接口
- 调用函数MFCreateTopologyNode, 传递参数 MF_TOPOLOGY_TRANSFORM_NODE
- 调用 IMFTopologyNode::SetObject 设置MFT 对象(传递 IMFTransform 指针)
- 调用 IMFTopology::AddNode 把结点加入拓扑中
参考代码如下:
HRESULT AddTransformNode(
IMFTopology *pTopology, // Topology.
IMFTransform *pMFT, // MFT.
IMFTopologyNode **ppNode // Receives the node pointer.
)
{
*ppNode = NULL;
IMFTopologyNode *pNode = NULL;
// Create the node.
HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pNode);
// Set the object pointer.
if (SUCCEEDED(hr))
{
hr = pNode->SetObject(pMFT);
}
// Add the node to the topology.
if (SUCCEEDED(hr))
{
hr = pTopology->AddNode(pNode);
}
// Return the pointer to the caller.
if (SUCCEEDED(hr))
{
*ppNode = pNode;
(*ppNode)->AddRef();
}
SafeRelease(&pNode);
return hr;
}
3. Output Nodes (创建节点从 stream Sink)
- 创建一个Media Sink 实例,通过 IMFMediaSink 接口得到想要的Stream Sink
- 调用函数MFCreateTopologyNode, 传递参数 MF_TOPOLOGY_OUTPUT_NODE
- IMFTopologyNode::SetObject, 设置Stream Sink 对象(传递 IMFStreamSink 指针)
- 设置属性 MF_TOPONODE_NOSHUTDOWN_ON_REMOVE 为 FALSE (推荐)
- 调用IMFTopology::AddNode 把结点加入拓扑中
参考代码如下:
HRESULT AddOutputNode(
IMFTopology *pTopology, // Topology.
IMFStreamSink *pStreamSink, // Stream sink.
IMFTopologyNode **ppNode // Receives the node pointer.
)
{
IMFTopologyNode *pNode = NULL;
HRESULT hr = S_OK;
// Create the node.
hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
// Set the object pointer.
if (SUCCEEDED(hr))
{
hr = pNode->SetObject(pStreamSink);
}
// Add the node to the topology.
if (SUCCEEDED(hr))
{
hr = pTopology->AddNode(pNode);
}
if (SUCCEEDED(hr))
{
hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, TRUE);
}
// Return the pointer to the caller.
if (SUCCEEDED(hr))
{
*ppNode = pNode;
(*ppNode)->AddRef();
}
if (pNode)
{
pNode->Release();
}
return hr;
}
4. Output Nodes (创建节点从 Activation Object)
- 创建 Activation Object ,得到 IMFActivate 接口
- 调用函数MFCreateTopologyNode, 传递参数 MF_TOPOLOGY_OUTPUT_NODE
- 设置属性 MF_TOPONODE_NOSHUTDOWN_ON_REMOVE 为 TRUE (推荐)
- IMFTopologyNode::SetObject 传递 IMFActivate 指针
- 调用IMFTopology::AddNode 把结点加入拓扑中
参考代码如下:
// Add an output node to a topology.
HRESULT AddOutputNode(
IMFTopology *pTopology, // Topology.
IMFActivate *pActivate, // Media sink activation object.
DWORD dwId, // Identifier of the stream sink.
IMFTopologyNode **ppNode) // Receives the node pointer.
{
IMFTopologyNode *pNode = NULL;
// Create the node.
HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
if (FAILED(hr))
{
goto done;
}
// Set the object pointer.
hr = pNode->SetObject(pActivate);
if (FAILED(hr))
{
goto done;
}
// Set the stream sink ID attribute.
hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId);
if (FAILED(hr))
{
goto done;
}
hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
if (FAILED(hr))
{
goto done;
}
// Add the node to the topology.
hr = pTopology->AddNode(pNode);
if (FAILED(hr))
{
goto done;
}
// Return the pointer to the caller.
*ppNode = pNode;
(*ppNode)->AddRef();
done:
SafeRelease(&pNode);
return hr;
}
拓扑结点之间相互连接关系是通过 IMFTopologyNode::ConnectOutput 函数来设置的,可以把上下游的关系建立起来。