wined3d: Handle VKD3D_SHADER_RESOURCE_DATA_MIXED in wined3d_data_type_from_vkd3d().
[wine.git] / dlls / mf / topology_loader.c
blobab6943792370fec1e5e5778bea159458599fe367
1 /*
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
19 #include <stdarg.h>
20 #include <stddef.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
26 #include "mfidl.h"
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;
38 LONG refcount;
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))
53 *out = iface;
54 IMFTopoLoader_AddRef(iface);
55 return S_OK;
58 WARN("Unsupported %s.\n", debugstr_guid(riid));
59 *out = NULL;
60 return E_NOINTERFACE;
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);
68 return 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);
78 if (!refcount)
79 free(loader);
81 return 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;
93 HRESULT hr;
94 TOPOID id;
96 if (FAILED(hr = IMFTopologyNode_GetTopoNodeID(node, &id)))
97 return hr;
98 if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->output_topology, id, clone)))
99 return hr;
101 IMFTopologyNode_GetNodeType(node, &node_type);
102 if (FAILED(hr = MFCreateTopologyNode(node_type, clone)))
103 return hr;
105 hr = IMFTopologyNode_CloneFrom(*clone, node);
106 if (SUCCEEDED(hr))
107 hr = IMFTopology_AddNode(context->output_topology, *clone);
109 if (FAILED(hr))
111 IMFTopologyNode_Release(*clone);
112 *clone = NULL;
114 return hr;
117 struct transform_output_type
119 IMFMediaType *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
138 struct
140 IMFTopologyNode *node;
141 DWORD stream;
142 } up, down;
144 struct list entry;
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;
165 *out = branch;
166 return S_OK;
169 static void topology_branch_destroy(struct topology_branch *branch)
171 IMFTopologyNode_Release(branch->up.node);
172 IMFTopologyNode_Release(branch->down.node);
173 free(branch);
176 static HRESULT topology_branch_clone_nodes(struct topoloader_context *context, struct topology_branch *branch)
178 IMFTopologyNode *up, *down;
179 HRESULT hr;
181 if (FAILED(hr = topology_loader_clone_node(context, branch->up.node, &up)))
182 return hr;
183 if (FAILED(hr = topology_loader_clone_node(context, branch->down.node, &down)))
185 IMFTopologyNode_Release(up);
186 return hr;
189 IMFTopologyNode_Release(branch->up.node);
190 IMFTopologyNode_Release(branch->down.node);
191 branch->up.node = up;
192 branch->down.node = down;
193 return hr;
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;
201 HRESULT hr;
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)))
207 continue;
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);
215 return hr;
218 static HRESULT topology_branch_fill_media_type(IMFMediaType *up_type, IMFMediaType *down_type)
220 HRESULT hr = S_OK;
221 PROPVARIANT value;
222 UINT32 count;
223 GUID key;
225 if (FAILED(hr = IMFMediaType_GetCount(up_type, &count)))
226 return hr;
228 while (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);
235 if (FAILED(hr))
236 return hr;
239 return hr;
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;
255 GUID category, guid;
256 HRESULT hr;
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)))
262 return hr;
263 if (FAILED(hr = IMFMediaType_GetGUID(up_type, &MF_MT_SUBTYPE, &input_info.guidSubtype)))
264 return hr;
265 if (!down_type)
266 output_info = input_info;
267 else
269 if (FAILED(hr = IMFMediaType_GetMajorType(down_type, &output_info.guidMajorType)))
270 return hr;
271 if (FAILED(hr = IMFMediaType_GetGUID(down_type, &MF_MT_SUBTYPE, &output_info.guidSubtype)))
272 return hr;
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;
279 else
280 return MF_E_INVALIDMEDIATYPE;
282 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
283 return hr;
284 if (!decoder)
285 method_mask = MF_CONNECT_DIRECT;
286 else
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)))
293 return hr;
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)))
301 continue;
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);
309 if (down_type)
311 if (SUCCEEDED(hr))
312 hr = topology_branch_fill_media_type(up_type, down_type);
313 if (SUCCEEDED(hr))
314 hr = IMFTransform_SetOutputType(transform, 0, down_type, 0);
315 if (SUCCEEDED(hr))
316 method_mask = MF_CONNECT_DIRECT;
318 IMFTransform_Release(transform);
320 if (SUCCEEDED(hr))
321 hr = topology_branch_connect(topology, method_mask, &down_branch, !down_type);
322 if (SUCCEEDED(hr))
323 hr = IMFTopology_AddNode(topology, node);
324 if (SUCCEEDED(hr))
325 break;
328 IMFTopologyNode_Release(node);
329 for (i = 0; i < count; ++i)
330 IMFActivate_Release(activates[i]);
331 CoTaskMemFree(activates);
333 if (!count)
334 return MF_E_TOPO_CODEC_NOT_FOUND;
335 return hr;
338 static HRESULT topology_branch_get_current_type(IMFMediaTypeHandler *handler, IMFMediaType **type)
340 IMFMediaType *media_type;
341 HRESULT hr;
342 DWORD i;
344 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, type);
345 if (hr != MF_E_NOT_INITIALIZED)
346 return hr;
348 for (i = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, i, &media_type)); i++)
350 if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, media_type, NULL)))
352 *type = media_type;
353 return hr;
356 IMFMediaType_Release(media_type);
359 return hr;
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;
368 DWORD flags;
369 HRESULT hr;
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)))
378 return hr;
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);
385 goto done;
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);
393 goto done;
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);
404 done:
405 if (down_type)
406 IMFMediaType_Release(down_type);
407 IMFMediaTypeHandler_Release(down_handler);
409 return hr;
412 static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method_mask,
413 struct topology_branch *branch)
415 IMFMediaTypeHandler *handler;
416 IMFMediaType *type;
417 DWORD index = 0;
418 HRESULT hr;
420 if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &handler)))
421 return hr;
423 while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type)))
425 hr = topology_branch_connect_down(topology, method_mask, branch, type);
426 if (SUCCEEDED(hr))
427 hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type);
428 IMFMediaType_Release(type);
429 if (SUCCEEDED(hr))
430 break;
433 IMFMediaTypeHandler_Release(handler);
434 return hr;
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;
441 HRESULT hr;
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);
452 else
454 hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch);
455 if (FAILED(hr))
456 hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch);
457 if (FAILED(hr))
458 hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch);
461 else
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)))
467 return hr;
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);
478 return 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;
487 HRESULT hr = S_OK;
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));
499 else
500 hr = topology_branch_connect(context->output_topology, MF_CONNECT_ALLOW_DECODER,
501 branch, enumerate_source_types);
503 topology_branch_destroy(branch);
504 if (FAILED(hr))
505 break;
508 list_move_tail(branches, &new_branches);
509 return hr;
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)))
519 return FALSE;
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);
530 return !!d3d_aware;
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;
538 HRESULT hr;
540 if (FAILED(hr = MFCreateSampleCopierMFT(&transform)))
541 return hr;
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);
555 if (SUCCEEDED(hr))
557 *copier = transform;
558 IMFTransform_AddRef(*copier);
561 if (input_type)
562 IMFMediaType_Release(input_type);
563 if (output_type)
564 IMFMediaType_Release(output_type);
566 IMFTransform_Release(transform);
568 return hr;
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;
575 HRESULT hr;
577 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &copier_node)))
578 return hr;
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);
587 return S_OK;
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;
598 HRESULT hr;
600 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
601 return hr;
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);
621 return hr;
624 static void topology_loader_resolve_complete(struct topoloader_context *context)
626 MF_TOPOLOGY_TYPE node_type;
627 IMFTopologyNode *node;
628 WORD i, node_count;
629 HRESULT hr;
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;
671 IMFStreamSink *sink;
672 IUnknown *object;
673 HRESULT hr = E_FAIL;
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);
690 switch (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;
698 else if (sink)
699 IMFStreamSink_Release(sink);
700 IUnknown_Release(object);
702 break;
703 case MF_TOPOLOGY_SOURCESTREAM_NODE:
704 hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL);
705 break;
706 default:
710 IMFTopologyNode_Release(node);
711 if (FAILED(hr))
712 return hr;
715 if (FAILED(hr = MFCreateTopology(&output_topology)))
716 return hr;
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);
727 if (FAILED(hr))
728 break;
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);
747 if (FAILED(hr))
748 IMFTopology_Release(output_topology);
749 else
751 topology_loader_resolve_complete(&context);
752 *ret_topology = output_topology;
755 return hr;
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);
775 if (!loader)
776 return E_POINTER;
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;
786 return S_OK;