2 * Copyright 2017 Nikolay Sivov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/debug.h"
29 #include "wine/list.h"
31 #include "mf_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
35 struct topology_loader
37 IMFTopoLoader IMFTopoLoader_iface
;
41 static inline struct topology_loader
*impl_from_IMFTopoLoader(IMFTopoLoader
*iface
)
43 return CONTAINING_RECORD(iface
, struct topology_loader
, IMFTopoLoader_iface
);
46 static HRESULT WINAPI
topology_loader_QueryInterface(IMFTopoLoader
*iface
, REFIID riid
, void **out
)
48 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
50 if (IsEqualIID(riid
, &IID_IMFTopoLoader
)
51 || IsEqualIID(riid
, &IID_IUnknown
))
54 IMFTopoLoader_AddRef(iface
);
58 WARN("Unsupported %s.\n", debugstr_guid(riid
));
63 static ULONG WINAPI
topology_loader_AddRef(IMFTopoLoader
*iface
)
65 struct topology_loader
*loader
= impl_from_IMFTopoLoader(iface
);
66 ULONG refcount
= InterlockedIncrement(&loader
->refcount
);
67 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
71 static ULONG WINAPI
topology_loader_Release(IMFTopoLoader
*iface
)
73 struct topology_loader
*loader
= impl_from_IMFTopoLoader(iface
);
74 ULONG refcount
= InterlockedDecrement(&loader
->refcount
);
76 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
84 struct topoloader_context
86 IMFTopology
*input_topology
;
87 IMFTopology
*output_topology
;
90 static HRESULT
topology_loader_clone_node(struct topoloader_context
*context
, IMFTopologyNode
*node
, IMFTopologyNode
**clone
)
92 MF_TOPOLOGY_TYPE node_type
;
96 if (FAILED(hr
= IMFTopologyNode_GetTopoNodeID(node
, &id
)))
98 if (SUCCEEDED(hr
= IMFTopology_GetNodeByID(context
->output_topology
, id
, clone
)))
101 IMFTopologyNode_GetNodeType(node
, &node_type
);
102 if (FAILED(hr
= MFCreateTopologyNode(node_type
, clone
)))
105 hr
= IMFTopologyNode_CloneFrom(*clone
, node
);
107 hr
= IMFTopology_AddNode(context
->output_topology
, *clone
);
111 IMFTopologyNode_Release(*clone
);
117 struct transform_output_type
120 IMFTransform
*transform
;
121 IMFActivate
*activate
;
124 struct connect_context
126 struct topoloader_context
*context
;
127 IMFTopologyNode
*upstream_node
;
128 IMFTopologyNode
*sink
;
129 IMFMediaTypeHandler
*sink_handler
;
130 unsigned int output_index
;
131 unsigned int input_index
;
132 GUID converter_category
;
133 GUID decoder_category
;
136 struct topology_branch
140 IMFTopologyNode
*node
;
147 static const char *debugstr_topology_branch(struct topology_branch
*branch
)
149 return wine_dbg_sprintf("%p:%lu to %p:%lu", branch
->up
.node
, branch
->up
.stream
, branch
->down
.node
, branch
->down
.stream
);
152 static HRESULT
topology_branch_create(IMFTopologyNode
*source
, DWORD source_stream
,
153 IMFTopologyNode
*sink
, DWORD sink_stream
, struct topology_branch
**out
)
155 struct topology_branch
*branch
;
157 if (!(branch
= calloc(1, sizeof(*branch
))))
158 return E_OUTOFMEMORY
;
160 IMFTopologyNode_AddRef((branch
->up
.node
= source
));
161 branch
->up
.stream
= source_stream
;
162 IMFTopologyNode_AddRef((branch
->down
.node
= sink
));
163 branch
->down
.stream
= sink_stream
;
169 static void topology_branch_destroy(struct topology_branch
*branch
)
171 IMFTopologyNode_Release(branch
->up
.node
);
172 IMFTopologyNode_Release(branch
->down
.node
);
176 static HRESULT
topology_branch_clone_nodes(struct topoloader_context
*context
, struct topology_branch
*branch
)
178 IMFTopologyNode
*up
, *down
;
181 if (FAILED(hr
= topology_loader_clone_node(context
, branch
->up
.node
, &up
)))
183 if (FAILED(hr
= topology_loader_clone_node(context
, branch
->down
.node
, &down
)))
185 IMFTopologyNode_Release(up
);
189 IMFTopologyNode_Release(branch
->up
.node
);
190 IMFTopologyNode_Release(branch
->down
.node
);
191 branch
->up
.node
= up
;
192 branch
->down
.node
= down
;
196 static HRESULT
topology_node_list_branches(IMFTopologyNode
*node
, struct list
*branches
)
198 struct topology_branch
*branch
;
199 DWORD i
, count
, down_stream
;
200 IMFTopologyNode
*down_node
;
203 hr
= IMFTopologyNode_GetOutputCount(node
, &count
);
204 for (i
= 0; SUCCEEDED(hr
) && i
< count
; ++i
)
206 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &down_node
, &down_stream
)))
209 if (SUCCEEDED(hr
= topology_branch_create(node
, i
, down_node
, down_stream
, &branch
)))
210 list_add_tail(branches
, &branch
->entry
);
212 IMFTopologyNode_Release(down_node
);
218 static HRESULT
topology_branch_fill_media_type(IMFMediaType
*up_type
, IMFMediaType
*down_type
)
225 if (FAILED(hr
= IMFMediaType_GetCount(up_type
, &count
)))
230 PropVariantInit(&value
);
231 hr
= IMFMediaType_GetItemByIndex(up_type
, count
, &key
, &value
);
232 if (SUCCEEDED(hr
) && FAILED(IMFMediaType_GetItem(down_type
, &key
, NULL
)))
233 hr
= IMFMediaType_SetItem(down_type
, &key
, &value
);
234 PropVariantClear(&value
);
242 static HRESULT
topology_branch_connect(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
243 struct topology_branch
*branch
, BOOL enumerate_source_types
);
244 static HRESULT
topology_branch_connect_down(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
245 struct topology_branch
*branch
, IMFMediaType
*up_type
);
246 static HRESULT
topology_branch_connect_indirect(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
247 struct topology_branch
*branch
, IMFMediaType
*up_type
, IMFMediaType
*down_type
)
249 BOOL decoder
= (method_mask
& MF_CONNECT_ALLOW_DECODER
) == MF_CONNECT_ALLOW_DECODER
;
250 MFT_REGISTER_TYPE_INFO input_info
, output_info
;
251 IMFTransform
*transform
;
252 IMFActivate
**activates
;
253 IMFTopologyNode
*node
;
254 unsigned int i
, count
;
258 TRACE("topology %p, method_mask %#x, branch %s, up_type %p, down_type %p.\n",
259 topology
, method_mask
, debugstr_topology_branch(branch
), up_type
, down_type
);
261 if (FAILED(hr
= IMFMediaType_GetMajorType(up_type
, &input_info
.guidMajorType
)))
263 if (FAILED(hr
= IMFMediaType_GetGUID(up_type
, &MF_MT_SUBTYPE
, &input_info
.guidSubtype
)))
266 output_info
= input_info
;
269 if (FAILED(hr
= IMFMediaType_GetMajorType(down_type
, &output_info
.guidMajorType
)))
271 if (FAILED(hr
= IMFMediaType_GetGUID(down_type
, &MF_MT_SUBTYPE
, &output_info
.guidSubtype
)))
275 if (IsEqualGUID(&input_info
.guidMajorType
, &MFMediaType_Audio
))
276 category
= decoder
? MFT_CATEGORY_AUDIO_DECODER
: MFT_CATEGORY_AUDIO_EFFECT
;
277 else if (IsEqualGUID(&input_info
.guidMajorType
, &MFMediaType_Video
))
278 category
= decoder
? MFT_CATEGORY_VIDEO_DECODER
: MFT_CATEGORY_VIDEO_PROCESSOR
;
280 return MF_E_INVALIDMEDIATYPE
;
282 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE
, &node
)))
285 method_mask
= MF_CONNECT_DIRECT
;
288 IMFTopologyNode_SetUINT32(node
, &MF_TOPONODE_DECODER
, 1);
289 method_mask
= MF_CONNECT_ALLOW_CONVERTER
;
292 if (FAILED(hr
= MFTEnumEx(category
, MFT_ENUM_FLAG_ALL
, &input_info
, decoder
? NULL
: &output_info
, &activates
, &count
)))
295 for (i
= 0, hr
= MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION
; i
< count
; ++i
)
297 struct topology_branch down_branch
= {.up
.node
= node
, .down
= branch
->down
};
298 struct topology_branch up_branch
= {.up
= branch
->up
, .down
.node
= node
};
300 if (FAILED(IMFActivate_ActivateObject(activates
[i
], &IID_IMFTransform
, (void **)&transform
)))
303 IMFTopologyNode_SetObject(node
, (IUnknown
*)transform
);
304 IMFTopologyNode_DeleteItem(node
, &MF_TOPONODE_TRANSFORM_OBJECTID
);
305 if (SUCCEEDED(IMFActivate_GetGUID(activates
[i
], &MFT_TRANSFORM_CLSID_Attribute
, &guid
)))
306 IMFTopologyNode_SetGUID(node
, &MF_TOPONODE_TRANSFORM_OBJECTID
, &guid
);
308 hr
= topology_branch_connect_down(topology
, MF_CONNECT_DIRECT
, &up_branch
, up_type
);
312 hr
= topology_branch_fill_media_type(up_type
, down_type
);
314 hr
= IMFTransform_SetOutputType(transform
, 0, down_type
, 0);
316 method_mask
= MF_CONNECT_DIRECT
;
318 IMFTransform_Release(transform
);
321 hr
= topology_branch_connect(topology
, method_mask
, &down_branch
, !down_type
);
323 hr
= IMFTopology_AddNode(topology
, node
);
328 IMFTopologyNode_Release(node
);
329 for (i
= 0; i
< count
; ++i
)
330 IMFActivate_Release(activates
[i
]);
331 CoTaskMemFree(activates
);
334 return MF_E_TOPO_CODEC_NOT_FOUND
;
338 static HRESULT
topology_branch_get_current_type(IMFMediaTypeHandler
*handler
, IMFMediaType
**type
)
340 IMFMediaType
*media_type
;
344 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, type
);
345 if (hr
!= MF_E_NOT_INITIALIZED
)
348 for (i
= 0; SUCCEEDED(hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, i
, &media_type
)); i
++)
350 if (SUCCEEDED(hr
= IMFMediaTypeHandler_IsMediaTypeSupported(handler
, media_type
, NULL
)))
356 IMFMediaType_Release(media_type
);
362 static HRESULT
topology_branch_connect_down(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
363 struct topology_branch
*branch
, IMFMediaType
*up_type
)
365 IMFMediaTypeHandler
*down_handler
;
366 IMFMediaType
*down_type
= NULL
;
367 MF_CONNECT_METHOD method
;
371 TRACE("topology %p, method_mask %#x, branch %s, up_type %p.\n",
372 topology
, method_mask
, debugstr_topology_branch(branch
), up_type
);
374 if (FAILED(IMFTopologyNode_GetUINT32(branch
->down
.node
, &MF_TOPONODE_CONNECT_METHOD
, &method
)))
375 method
= MF_CONNECT_ALLOW_DECODER
;
377 if (FAILED(hr
= topology_node_get_type_handler(branch
->down
.node
, branch
->down
.stream
, FALSE
, &down_handler
)))
380 if (SUCCEEDED(hr
= topology_branch_get_current_type(down_handler
, &down_type
))
381 && IMFMediaType_IsEqual(up_type
, down_type
, &flags
) == S_OK
)
383 TRACE("Connecting branch %s with current type %p.\n", debugstr_topology_branch(branch
), up_type
);
384 hr
= IMFTopologyNode_ConnectOutput(branch
->up
.node
, branch
->up
.stream
, branch
->down
.node
, branch
->down
.stream
);
388 if (SUCCEEDED(hr
= IMFMediaTypeHandler_IsMediaTypeSupported(down_handler
, up_type
, NULL
))
389 && SUCCEEDED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(down_handler
, up_type
)))
391 TRACE("Connected branch %s with upstream type %p.\n", debugstr_topology_branch(branch
), up_type
);
392 hr
= IMFTopologyNode_ConnectOutput(branch
->up
.node
, branch
->up
.stream
, branch
->down
.node
, branch
->down
.stream
);
396 if (FAILED(hr
) && (method
& method_mask
& MF_CONNECT_ALLOW_CONVERTER
) == MF_CONNECT_ALLOW_CONVERTER
)
397 hr
= topology_branch_connect_indirect(topology
, MF_CONNECT_ALLOW_CONVERTER
,
398 branch
, up_type
, down_type
);
400 if (FAILED(hr
) && (method
& method_mask
& MF_CONNECT_ALLOW_DECODER
) == MF_CONNECT_ALLOW_DECODER
)
401 hr
= topology_branch_connect_indirect(topology
, MF_CONNECT_ALLOW_DECODER
,
402 branch
, up_type
, down_type
);
406 IMFMediaType_Release(down_type
);
407 IMFMediaTypeHandler_Release(down_handler
);
412 static HRESULT
topology_branch_foreach_up_types(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
413 struct topology_branch
*branch
)
415 IMFMediaTypeHandler
*handler
;
420 if (FAILED(hr
= topology_node_get_type_handler(branch
->up
.node
, branch
->up
.stream
, TRUE
, &handler
)))
423 while (SUCCEEDED(hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, index
++, &type
)))
425 hr
= topology_branch_connect_down(topology
, method_mask
, branch
, type
);
427 hr
= IMFMediaTypeHandler_SetCurrentMediaType(handler
, type
);
428 IMFMediaType_Release(type
);
433 IMFMediaTypeHandler_Release(handler
);
437 static HRESULT
topology_branch_connect(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
438 struct topology_branch
*branch
, BOOL enumerate_source_types
)
440 MF_CONNECT_METHOD method
;
443 TRACE("topology %p, method_mask %#x, branch %s.\n", topology
, method_mask
, debugstr_topology_branch(branch
));
445 if (FAILED(IMFTopologyNode_GetUINT32(branch
->up
.node
, &MF_TOPONODE_CONNECT_METHOD
, &method
)))
446 method
= MF_CONNECT_DIRECT
;
448 if (enumerate_source_types
)
450 if (method
& MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES
)
451 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_ALLOW_DECODER
, branch
);
454 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_DIRECT
, branch
);
456 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_ALLOW_CONVERTER
, branch
);
458 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_ALLOW_DECODER
, branch
);
463 IMFMediaTypeHandler
*up_handler
;
464 IMFMediaType
*up_type
;
466 if (FAILED(hr
= topology_node_get_type_handler(branch
->up
.node
, branch
->up
.stream
, TRUE
, &up_handler
)))
468 if (SUCCEEDED(hr
= IMFMediaTypeHandler_GetCurrentMediaType(up_handler
, &up_type
))
469 || SUCCEEDED(hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler
, 0, &up_type
)))
471 hr
= topology_branch_connect_down(topology
, method_mask
, branch
, up_type
);
472 IMFMediaType_Release(up_type
);
474 IMFMediaTypeHandler_Release(up_handler
);
477 TRACE("returning %#lx\n", hr
);
481 static HRESULT
topology_loader_resolve_branches(struct topoloader_context
*context
, struct list
*branches
,
482 BOOL enumerate_source_types
)
484 struct list new_branches
= LIST_INIT(new_branches
);
485 struct topology_branch
*branch
, *next
;
486 MF_TOPOLOGY_TYPE node_type
;
489 LIST_FOR_EACH_ENTRY_SAFE(branch
, next
, branches
, struct topology_branch
, entry
)
491 list_remove(&branch
->entry
);
493 if (FAILED(hr
= topology_node_list_branches(branch
->down
.node
, &new_branches
)))
494 WARN("Failed to list branches from branch %s\n", debugstr_topology_branch(branch
));
495 else if (FAILED(hr
= IMFTopologyNode_GetNodeType(branch
->up
.node
, &node_type
)))
496 WARN("Failed to get source node type for branch %s\n", debugstr_topology_branch(branch
));
497 else if (FAILED(hr
= topology_branch_clone_nodes(context
, branch
)))
498 WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch
));
500 hr
= topology_branch_connect(context
->output_topology
, MF_CONNECT_ALLOW_DECODER
,
501 branch
, enumerate_source_types
);
503 topology_branch_destroy(branch
);
508 list_move_tail(branches
, &new_branches
);
512 static BOOL
topology_loader_is_node_d3d_aware(IMFTopologyNode
*node
)
514 IMFAttributes
*attributes
;
515 unsigned int d3d_aware
= 0;
516 IMFTransform
*transform
;
518 if (FAILED(topology_node_get_object(node
, &IID_IMFAttributes
, (void **)&attributes
)))
521 IMFAttributes_GetUINT32(attributes
, &MF_SA_D3D_AWARE
, &d3d_aware
);
522 IMFAttributes_Release(attributes
);
524 if (!d3d_aware
&& SUCCEEDED(topology_node_get_object(node
, &IID_IMFTransform
, (void **)&transform
)))
526 d3d_aware
= mf_is_sample_copier_transform(transform
);
527 IMFTransform_Release(transform
);
533 static HRESULT
topology_loader_create_copier(IMFTopologyNode
*upstream_node
, DWORD upstream_output
,
534 IMFTopologyNode
*downstream_node
, unsigned int downstream_input
, IMFTransform
**copier
)
536 IMFMediaType
*input_type
= NULL
, *output_type
= NULL
;
537 IMFTransform
*transform
;
540 if (FAILED(hr
= MFCreateSampleCopierMFT(&transform
)))
543 if (FAILED(hr
= MFGetTopoNodeCurrentType(upstream_node
, upstream_output
, TRUE
, &input_type
)))
544 WARN("Failed to get upstream media type hr %#lx.\n", hr
);
546 if (SUCCEEDED(hr
) && FAILED(hr
= MFGetTopoNodeCurrentType(downstream_node
, downstream_input
, FALSE
, &output_type
)))
547 WARN("Failed to get downstream media type hr %#lx.\n", hr
);
549 if (SUCCEEDED(hr
) && FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
550 WARN("Input type wasn't accepted, hr %#lx.\n", hr
);
552 if (SUCCEEDED(hr
) && FAILED(hr
= IMFTransform_SetOutputType(transform
, 0, output_type
, 0)))
553 WARN("Output type wasn't accepted, hr %#lx.\n", hr
);
558 IMFTransform_AddRef(*copier
);
562 IMFMediaType_Release(input_type
);
564 IMFMediaType_Release(output_type
);
566 IMFTransform_Release(transform
);
571 static HRESULT
topology_loader_connect_copier(struct topoloader_context
*context
, IMFTopologyNode
*upstream_node
,
572 DWORD upstream_output
, IMFTopologyNode
*downstream_node
, DWORD downstream_input
, IMFTransform
*copier
)
574 IMFTopologyNode
*copier_node
;
577 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE
, &copier_node
)))
580 IMFTopologyNode_SetObject(copier_node
, (IUnknown
*)copier
);
581 IMFTopology_AddNode(context
->output_topology
, copier_node
);
582 IMFTopologyNode_ConnectOutput(upstream_node
, upstream_output
, copier_node
, 0);
583 IMFTopologyNode_ConnectOutput(copier_node
, 0, downstream_node
, downstream_input
);
585 IMFTopologyNode_Release(copier_node
);
590 /* Right now this should be used for output nodes only. */
591 static HRESULT
topology_loader_connect_d3d_aware_input(struct topoloader_context
*context
,
592 IMFTopologyNode
*node
)
594 IMFTopologyNode
*upstream_node
;
595 IMFTransform
*copier
= NULL
;
596 IMFStreamSink
*stream_sink
;
597 DWORD upstream_output
;
600 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
603 if (topology_loader_is_node_d3d_aware(node
))
605 if (SUCCEEDED(IMFTopologyNode_GetInput(node
, 0, &upstream_node
, &upstream_output
)))
607 if (!topology_loader_is_node_d3d_aware(upstream_node
))
609 if (SUCCEEDED(hr
= topology_loader_create_copier(upstream_node
, upstream_output
, node
, 0, &copier
)))
611 hr
= topology_loader_connect_copier(context
, upstream_node
, upstream_output
, node
, 0, copier
);
612 IMFTransform_Release(copier
);
615 IMFTopologyNode_Release(upstream_node
);
619 IMFStreamSink_Release(stream_sink
);
624 static void topology_loader_resolve_complete(struct topoloader_context
*context
)
626 MF_TOPOLOGY_TYPE node_type
;
627 IMFTopologyNode
*node
;
631 IMFTopology_GetNodeCount(context
->output_topology
, &node_count
);
633 for (i
= 0; i
< node_count
; ++i
)
635 if (SUCCEEDED(IMFTopology_GetNode(context
->output_topology
, i
, &node
)))
637 IMFTopologyNode_GetNodeType(node
, &node_type
);
639 if (node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
641 /* Set MF_TOPONODE_STREAMID for all outputs. */
642 if (FAILED(IMFTopologyNode_GetItem(node
, &MF_TOPONODE_STREAMID
, NULL
)))
643 IMFTopologyNode_SetUINT32(node
, &MF_TOPONODE_STREAMID
, 0);
645 if (FAILED(hr
= topology_loader_connect_d3d_aware_input(context
, node
)))
646 WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr
);
648 else if (node_type
== MF_TOPOLOGY_SOURCESTREAM_NODE
)
650 /* Set MF_TOPONODE_MEDIASTART for all sources. */
651 if (FAILED(IMFTopologyNode_GetItem(node
, &MF_TOPONODE_MEDIASTART
, NULL
)))
652 IMFTopologyNode_SetUINT64(node
, &MF_TOPONODE_MEDIASTART
, 0);
655 IMFTopologyNode_Release(node
);
660 static HRESULT WINAPI
topology_loader_Load(IMFTopoLoader
*iface
, IMFTopology
*input_topology
,
661 IMFTopology
**ret_topology
, IMFTopology
*current_topology
)
663 struct list branches
= LIST_INIT(branches
);
664 struct topoloader_context context
= { 0 };
665 struct topology_branch
*branch
, *next
;
666 UINT32 enumerate_source_types
;
667 IMFTopology
*output_topology
;
668 MF_TOPOLOGY_TYPE node_type
;
669 IMFTopologyNode
*node
;
670 unsigned short i
= 0;
675 FIXME("iface %p, input_topology %p, ret_topology %p, current_topology %p stub!\n",
676 iface
, input_topology
, ret_topology
, current_topology
);
678 if (current_topology
)
679 FIXME("Current topology instance is ignored.\n");
681 /* Basic sanity checks for input topology:
683 - source nodes must have stream descriptor set;
684 - sink nodes must be resolved to stream sink objects;
686 while (SUCCEEDED(IMFTopology_GetNode(input_topology
, i
++, &node
)))
688 IMFTopologyNode_GetNodeType(node
, &node_type
);
692 case MF_TOPOLOGY_OUTPUT_NODE
:
693 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
695 /* Sinks must be bound beforehand. */
696 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&sink
)))
697 hr
= MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED
;
699 IMFStreamSink_Release(sink
);
700 IUnknown_Release(object
);
703 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
704 hr
= IMFTopologyNode_GetItem(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, NULL
);
710 IMFTopologyNode_Release(node
);
715 if (FAILED(hr
= MFCreateTopology(&output_topology
)))
718 IMFTopology_CopyAllItems(input_topology
, (IMFAttributes
*)output_topology
);
720 context
.input_topology
= input_topology
;
721 context
.output_topology
= output_topology
;
723 for (i
= 0; SUCCEEDED(IMFTopology_GetNode(input_topology
, i
, &node
)); i
++)
725 hr
= topology_node_list_branches(node
, &branches
);
726 IMFTopologyNode_Release(node
);
730 if (SUCCEEDED(hr
) && list_empty(&branches
))
731 hr
= MF_E_TOPO_UNSUPPORTED
;
733 if (FAILED(IMFTopology_GetUINT32(input_topology
, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES
,
734 &enumerate_source_types
)))
735 enumerate_source_types
= 0;
737 while (SUCCEEDED(hr
) && !list_empty(&branches
))
738 hr
= topology_loader_resolve_branches(&context
, &branches
, enumerate_source_types
);
740 LIST_FOR_EACH_ENTRY_SAFE(branch
, next
, &branches
, struct topology_branch
, entry
)
742 WARN("Failed to resolve branch %s\n", debugstr_topology_branch(branch
));
743 list_remove(&branch
->entry
);
744 topology_branch_destroy(branch
);
748 IMFTopology_Release(output_topology
);
751 topology_loader_resolve_complete(&context
);
752 *ret_topology
= output_topology
;
758 static const IMFTopoLoaderVtbl topology_loader_vtbl
=
760 topology_loader_QueryInterface
,
761 topology_loader_AddRef
,
762 topology_loader_Release
,
763 topology_loader_Load
,
766 /***********************************************************************
767 * MFCreateTopoLoader (mf.@)
769 HRESULT WINAPI
MFCreateTopoLoader(IMFTopoLoader
**loader
)
771 struct topology_loader
*object
;
773 TRACE("loader %p.\n", loader
);
778 if (!(object
= calloc(1, sizeof(*object
))))
779 return E_OUTOFMEMORY
;
781 object
->IMFTopoLoader_iface
.lpVtbl
= &topology_loader_vtbl
;
782 object
->refcount
= 1;
784 *loader
= &object
->IMFTopoLoader_iface
;