kernelbase/tests: Use win_skip() for missing APIs.
[wine.git] / dlls / mf / topology_loader.c
blob6b6d39d76d18837a33f015e6dbe4d8d6891cc52e
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 get_first_supported_media_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 HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type)
364 IMFMediaTypeHandler *handler;
365 HRESULT hr;
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);
374 return hr;
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;
384 DWORD flags;
385 HRESULT hr;
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)))
394 return hr;
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);
401 goto done;
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);
414 goto done;
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);
425 done:
426 if (down_type)
427 IMFMediaType_Release(down_type);
428 IMFMediaTypeHandler_Release(down_handler);
430 return hr;
433 static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method_mask,
434 struct topology_branch *branch)
436 IMFMediaTypeHandler *handler;
437 IMFMediaType *type;
438 DWORD index = 0;
439 HRESULT hr;
441 if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &handler)))
442 return hr;
444 while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type)))
446 hr = topology_branch_connect_down(topology, method_mask, branch, type);
447 if (SUCCEEDED(hr))
448 hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type);
449 IMFMediaType_Release(type);
450 if (SUCCEEDED(hr))
451 break;
454 IMFMediaTypeHandler_Release(handler);
455 return hr;
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;
462 HRESULT hr;
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);
473 else
475 hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch);
476 if (FAILED(hr))
477 hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch);
478 if (FAILED(hr))
479 hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch);
482 else
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)))
488 return hr;
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);
499 return 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;
508 HRESULT hr = S_OK;
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));
520 else
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);
525 if (FAILED(hr))
526 break;
529 list_move_tail(branches, &new_branches);
530 return hr;
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)))
540 return FALSE;
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);
551 return !!d3d_aware;
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;
559 HRESULT hr;
561 if (FAILED(hr = MFCreateSampleCopierMFT(&transform)))
562 return hr;
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);
574 if (SUCCEEDED(hr))
576 *copier = transform;
577 IMFTransform_AddRef(*copier);
580 if (up_type)
581 IMFMediaType_Release(up_type);
583 IMFTransform_Release(transform);
585 return hr;
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;
592 HRESULT hr;
594 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &copier_node)))
595 return hr;
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);
604 return S_OK;
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;
615 HRESULT hr;
617 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
618 return hr;
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);
638 return hr;
641 static void topology_loader_resolve_complete(struct topoloader_context *context)
643 MF_TOPOLOGY_TYPE node_type;
644 IMFTopologyNode *node;
645 WORD i, node_count;
646 HRESULT hr;
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;
688 IMFStreamSink *sink;
689 IUnknown *object;
690 HRESULT hr = E_FAIL;
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);
707 switch (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;
715 else if (sink)
716 IMFStreamSink_Release(sink);
717 IUnknown_Release(object);
719 break;
720 case MF_TOPOLOGY_SOURCESTREAM_NODE:
721 hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL);
722 break;
723 default:
727 IMFTopologyNode_Release(node);
728 if (FAILED(hr))
729 return hr;
732 if (FAILED(hr = MFCreateTopology(&output_topology)))
733 return hr;
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);
744 if (FAILED(hr))
745 break;
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);
764 if (FAILED(hr))
765 IMFTopology_Release(output_topology);
766 else
768 topology_loader_resolve_complete(&context);
769 *ret_topology = output_topology;
772 return hr;
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);
792 if (!loader)
793 return E_POINTER;
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;
803 return S_OK;