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
get_first_supported_media_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 HRESULT
topology_node_init_media_type(IMFTopologyNode
*node
, DWORD stream
, BOOL output
, IMFMediaType
**type
)
364 IMFMediaTypeHandler
*handler
;
367 if (SUCCEEDED(hr
= topology_node_get_type_handler(node
, stream
, output
, &handler
)))
369 if (SUCCEEDED(hr
= get_first_supported_media_type(handler
, type
)))
370 hr
= IMFMediaTypeHandler_SetCurrentMediaType(handler
, *type
);
371 IMFMediaTypeHandler_Release(handler
);
377 static HRESULT
topology_branch_connect_down(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
378 struct topology_branch
*branch
, IMFMediaType
*up_type
)
380 IMFMediaTypeHandler
*down_handler
;
381 IMFMediaType
*down_type
= NULL
;
382 MF_CONNECT_METHOD method
;
383 MF_TOPOLOGY_TYPE type
;
387 TRACE("topology %p, method_mask %#x, branch %s, up_type %p.\n",
388 topology
, method_mask
, debugstr_topology_branch(branch
), up_type
);
390 if (FAILED(IMFTopologyNode_GetUINT32(branch
->down
.node
, &MF_TOPONODE_CONNECT_METHOD
, &method
)))
391 method
= MF_CONNECT_ALLOW_DECODER
;
393 if (FAILED(hr
= topology_node_get_type_handler(branch
->down
.node
, branch
->down
.stream
, FALSE
, &down_handler
)))
396 if (SUCCEEDED(hr
= get_first_supported_media_type(down_handler
, &down_type
))
397 && IMFMediaType_IsEqual(up_type
, down_type
, &flags
) == S_OK
)
399 TRACE("Connecting branch %s with current type %p.\n", debugstr_topology_branch(branch
), up_type
);
400 hr
= IMFTopologyNode_ConnectOutput(branch
->up
.node
, branch
->up
.stream
, branch
->down
.node
, branch
->down
.stream
);
404 if (SUCCEEDED(hr
= IMFMediaTypeHandler_IsMediaTypeSupported(down_handler
, up_type
, NULL
)))
406 TRACE("Connected branch %s with upstream type %p.\n", debugstr_topology_branch(branch
), up_type
);
408 if (SUCCEEDED(IMFTopologyNode_GetNodeType(branch
->down
.node
, &type
)) && type
== MF_TOPOLOGY_TRANSFORM_NODE
409 && FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(down_handler
, up_type
)))
410 WARN("Failed to set transform node media type, hr %#lx\n", hr
);
412 hr
= IMFTopologyNode_ConnectOutput(branch
->up
.node
, branch
->up
.stream
, branch
->down
.node
, branch
->down
.stream
);
417 if (FAILED(hr
) && (method
& method_mask
& MF_CONNECT_ALLOW_CONVERTER
) == MF_CONNECT_ALLOW_CONVERTER
)
418 hr
= topology_branch_connect_indirect(topology
, MF_CONNECT_ALLOW_CONVERTER
,
419 branch
, up_type
, down_type
);
421 if (FAILED(hr
) && (method
& method_mask
& MF_CONNECT_ALLOW_DECODER
) == MF_CONNECT_ALLOW_DECODER
)
422 hr
= topology_branch_connect_indirect(topology
, MF_CONNECT_ALLOW_DECODER
,
423 branch
, up_type
, down_type
);
427 IMFMediaType_Release(down_type
);
428 IMFMediaTypeHandler_Release(down_handler
);
433 static HRESULT
topology_branch_foreach_up_types(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
434 struct topology_branch
*branch
)
436 IMFMediaTypeHandler
*handler
;
441 if (FAILED(hr
= topology_node_get_type_handler(branch
->up
.node
, branch
->up
.stream
, TRUE
, &handler
)))
444 while (SUCCEEDED(hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, index
++, &type
)))
446 hr
= topology_branch_connect_down(topology
, method_mask
, branch
, type
);
448 hr
= IMFMediaTypeHandler_SetCurrentMediaType(handler
, type
);
449 IMFMediaType_Release(type
);
454 IMFMediaTypeHandler_Release(handler
);
458 static HRESULT
topology_branch_connect(IMFTopology
*topology
, MF_CONNECT_METHOD method_mask
,
459 struct topology_branch
*branch
, BOOL enumerate_source_types
)
461 MF_CONNECT_METHOD method
;
464 TRACE("topology %p, method_mask %#x, branch %s.\n", topology
, method_mask
, debugstr_topology_branch(branch
));
466 if (FAILED(IMFTopologyNode_GetUINT32(branch
->up
.node
, &MF_TOPONODE_CONNECT_METHOD
, &method
)))
467 method
= MF_CONNECT_DIRECT
;
469 if (enumerate_source_types
)
471 if (method
& MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES
)
472 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_ALLOW_DECODER
, branch
);
475 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_DIRECT
, branch
);
477 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_ALLOW_CONVERTER
, branch
);
479 hr
= topology_branch_foreach_up_types(topology
, method_mask
& MF_CONNECT_ALLOW_DECODER
, branch
);
484 IMFMediaTypeHandler
*up_handler
;
485 IMFMediaType
*up_type
;
487 if (FAILED(hr
= topology_node_get_type_handler(branch
->up
.node
, branch
->up
.stream
, TRUE
, &up_handler
)))
489 if (SUCCEEDED(hr
= IMFMediaTypeHandler_GetCurrentMediaType(up_handler
, &up_type
))
490 || SUCCEEDED(hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler
, 0, &up_type
)))
492 hr
= topology_branch_connect_down(topology
, method_mask
, branch
, up_type
);
493 IMFMediaType_Release(up_type
);
495 IMFMediaTypeHandler_Release(up_handler
);
498 TRACE("returning %#lx\n", hr
);
502 static HRESULT
topology_loader_resolve_branches(struct topoloader_context
*context
, struct list
*branches
,
503 BOOL enumerate_source_types
)
505 struct list new_branches
= LIST_INIT(new_branches
);
506 struct topology_branch
*branch
, *next
;
507 MF_TOPOLOGY_TYPE node_type
;
510 LIST_FOR_EACH_ENTRY_SAFE(branch
, next
, branches
, struct topology_branch
, entry
)
512 list_remove(&branch
->entry
);
514 if (FAILED(hr
= topology_node_list_branches(branch
->down
.node
, &new_branches
)))
515 WARN("Failed to list branches from branch %s\n", debugstr_topology_branch(branch
));
516 else if (FAILED(hr
= IMFTopologyNode_GetNodeType(branch
->up
.node
, &node_type
)))
517 WARN("Failed to get source node type for branch %s\n", debugstr_topology_branch(branch
));
518 else if (FAILED(hr
= topology_branch_clone_nodes(context
, branch
)))
519 WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch
));
521 hr
= topology_branch_connect(context
->output_topology
, MF_CONNECT_ALLOW_DECODER
,
522 branch
, enumerate_source_types
|| node_type
== MF_TOPOLOGY_TRANSFORM_NODE
);
524 topology_branch_destroy(branch
);
529 list_move_tail(branches
, &new_branches
);
533 static BOOL
topology_loader_is_node_d3d_aware(IMFTopologyNode
*node
)
535 IMFAttributes
*attributes
;
536 unsigned int d3d_aware
= 0;
537 IMFTransform
*transform
;
539 if (FAILED(topology_node_get_object(node
, &IID_IMFAttributes
, (void **)&attributes
)))
542 IMFAttributes_GetUINT32(attributes
, &MF_SA_D3D_AWARE
, &d3d_aware
);
543 IMFAttributes_Release(attributes
);
545 if (!d3d_aware
&& SUCCEEDED(topology_node_get_object(node
, &IID_IMFTransform
, (void **)&transform
)))
547 d3d_aware
= mf_is_sample_copier_transform(transform
);
548 IMFTransform_Release(transform
);
554 static HRESULT
topology_loader_create_copier(IMFTopologyNode
*upstream_node
, DWORD upstream_output
,
555 IMFTopologyNode
*downstream_node
, unsigned int downstream_input
, IMFTransform
**copier
)
557 IMFMediaType
*up_type
= NULL
;
558 IMFTransform
*transform
;
561 if (FAILED(hr
= MFCreateSampleCopierMFT(&transform
)))
564 if (FAILED(hr
= MFGetTopoNodeCurrentType(upstream_node
, upstream_output
, TRUE
, &up_type
)))
565 WARN("Failed to get upstream media type hr %#lx.\n", hr
);
567 if (SUCCEEDED(hr
) && FAILED(hr
= IMFTransform_SetInputType(transform
, 0, up_type
, 0)))
568 WARN("Input type wasn't accepted, hr %#lx.\n", hr
);
570 /* We assume, that up_type is set to a value compatible with the down node by the branch resolver. */
571 if (SUCCEEDED(hr
) && FAILED(hr
= IMFTransform_SetOutputType(transform
, 0, up_type
, 0)))
572 WARN("Output type wasn't accepted, hr %#lx.\n", hr
);
577 IMFTransform_AddRef(*copier
);
581 IMFMediaType_Release(up_type
);
583 IMFTransform_Release(transform
);
588 static HRESULT
topology_loader_connect_copier(struct topoloader_context
*context
, IMFTopologyNode
*upstream_node
,
589 DWORD upstream_output
, IMFTopologyNode
*downstream_node
, DWORD downstream_input
, IMFTransform
*copier
)
591 IMFTopologyNode
*copier_node
;
594 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE
, &copier_node
)))
597 IMFTopologyNode_SetObject(copier_node
, (IUnknown
*)copier
);
598 IMFTopology_AddNode(context
->output_topology
, copier_node
);
599 IMFTopologyNode_ConnectOutput(upstream_node
, upstream_output
, copier_node
, 0);
600 IMFTopologyNode_ConnectOutput(copier_node
, 0, downstream_node
, downstream_input
);
602 IMFTopologyNode_Release(copier_node
);
607 /* Right now this should be used for output nodes only. */
608 static HRESULT
topology_loader_connect_d3d_aware_input(struct topoloader_context
*context
,
609 IMFTopologyNode
*node
)
611 IMFTopologyNode
*upstream_node
;
612 IMFTransform
*copier
= NULL
;
613 IMFStreamSink
*stream_sink
;
614 DWORD upstream_output
;
617 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
620 if (topology_loader_is_node_d3d_aware(node
))
622 if (SUCCEEDED(IMFTopologyNode_GetInput(node
, 0, &upstream_node
, &upstream_output
)))
624 if (!topology_loader_is_node_d3d_aware(upstream_node
))
626 if (SUCCEEDED(hr
= topology_loader_create_copier(upstream_node
, upstream_output
, node
, 0, &copier
)))
628 hr
= topology_loader_connect_copier(context
, upstream_node
, upstream_output
, node
, 0, copier
);
629 IMFTransform_Release(copier
);
632 IMFTopologyNode_Release(upstream_node
);
636 IMFStreamSink_Release(stream_sink
);
641 static void topology_loader_resolve_complete(struct topoloader_context
*context
)
643 MF_TOPOLOGY_TYPE node_type
;
644 IMFTopologyNode
*node
;
648 IMFTopology_GetNodeCount(context
->output_topology
, &node_count
);
650 for (i
= 0; i
< node_count
; ++i
)
652 if (SUCCEEDED(IMFTopology_GetNode(context
->output_topology
, i
, &node
)))
654 IMFTopologyNode_GetNodeType(node
, &node_type
);
656 if (node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
658 /* Set MF_TOPONODE_STREAMID for all outputs. */
659 if (FAILED(IMFTopologyNode_GetItem(node
, &MF_TOPONODE_STREAMID
, NULL
)))
660 IMFTopologyNode_SetUINT32(node
, &MF_TOPONODE_STREAMID
, 0);
662 if (FAILED(hr
= topology_loader_connect_d3d_aware_input(context
, node
)))
663 WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr
);
665 else if (node_type
== MF_TOPOLOGY_SOURCESTREAM_NODE
)
667 /* Set MF_TOPONODE_MEDIASTART for all sources. */
668 if (FAILED(IMFTopologyNode_GetItem(node
, &MF_TOPONODE_MEDIASTART
, NULL
)))
669 IMFTopologyNode_SetUINT64(node
, &MF_TOPONODE_MEDIASTART
, 0);
672 IMFTopologyNode_Release(node
);
677 static HRESULT WINAPI
topology_loader_Load(IMFTopoLoader
*iface
, IMFTopology
*input_topology
,
678 IMFTopology
**ret_topology
, IMFTopology
*current_topology
)
680 struct list branches
= LIST_INIT(branches
);
681 struct topoloader_context context
= { 0 };
682 struct topology_branch
*branch
, *next
;
683 UINT32 enumerate_source_types
;
684 IMFTopology
*output_topology
;
685 MF_TOPOLOGY_TYPE node_type
;
686 IMFTopologyNode
*node
;
687 unsigned short i
= 0;
692 FIXME("iface %p, input_topology %p, ret_topology %p, current_topology %p stub!\n",
693 iface
, input_topology
, ret_topology
, current_topology
);
695 if (current_topology
)
696 FIXME("Current topology instance is ignored.\n");
698 /* Basic sanity checks for input topology:
700 - source nodes must have stream descriptor set;
701 - sink nodes must be resolved to stream sink objects;
703 while (SUCCEEDED(IMFTopology_GetNode(input_topology
, i
++, &node
)))
705 IMFTopologyNode_GetNodeType(node
, &node_type
);
709 case MF_TOPOLOGY_OUTPUT_NODE
:
710 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
712 /* Sinks must be bound beforehand. */
713 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&sink
)))
714 hr
= MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED
;
716 IMFStreamSink_Release(sink
);
717 IUnknown_Release(object
);
720 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
721 hr
= IMFTopologyNode_GetItem(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, NULL
);
727 IMFTopologyNode_Release(node
);
732 if (FAILED(hr
= MFCreateTopology(&output_topology
)))
735 IMFTopology_CopyAllItems(input_topology
, (IMFAttributes
*)output_topology
);
737 context
.input_topology
= input_topology
;
738 context
.output_topology
= output_topology
;
740 for (i
= 0; SUCCEEDED(IMFTopology_GetNode(input_topology
, i
, &node
)); i
++)
742 hr
= topology_node_list_branches(node
, &branches
);
743 IMFTopologyNode_Release(node
);
747 if (SUCCEEDED(hr
) && list_empty(&branches
))
748 hr
= MF_E_TOPO_UNSUPPORTED
;
750 if (FAILED(IMFTopology_GetUINT32(input_topology
, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES
,
751 &enumerate_source_types
)))
752 enumerate_source_types
= 0;
754 while (SUCCEEDED(hr
) && !list_empty(&branches
))
755 hr
= topology_loader_resolve_branches(&context
, &branches
, enumerate_source_types
);
757 LIST_FOR_EACH_ENTRY_SAFE(branch
, next
, &branches
, struct topology_branch
, entry
)
759 WARN("Failed to resolve branch %s\n", debugstr_topology_branch(branch
));
760 list_remove(&branch
->entry
);
761 topology_branch_destroy(branch
);
765 IMFTopology_Release(output_topology
);
768 topology_loader_resolve_complete(&context
);
769 *ret_topology
= output_topology
;
775 static const IMFTopoLoaderVtbl topology_loader_vtbl
=
777 topology_loader_QueryInterface
,
778 topology_loader_AddRef
,
779 topology_loader_Release
,
780 topology_loader_Load
,
783 /***********************************************************************
784 * MFCreateTopoLoader (mf.@)
786 HRESULT WINAPI
MFCreateTopoLoader(IMFTopoLoader
**loader
)
788 struct topology_loader
*object
;
790 TRACE("loader %p.\n", loader
);
795 if (!(object
= calloc(1, sizeof(*object
))))
796 return E_OUTOFMEMORY
;
798 object
->IMFTopoLoader_iface
.lpVtbl
= &topology_loader_vtbl
;
799 object
->refcount
= 1;
801 *loader
= &object
->IMFTopoLoader_iface
;