include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / quartz / filtergraph.c
blobcc66b17c75b37c207dbf1a8e78e8080ef96f638b
1 /* DirectShow FilterGraph object (QUARTZ.DLL)
3 * Copyright 2002 Lionel Ulmer
4 * Copyright 2004 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "shlwapi.h"
31 #include "dshow.h"
32 #include "wine/debug.h"
33 #include "quartz_private.h"
34 #include "ole2.h"
35 #include "olectl.h"
36 #include "strmif.h"
37 #include "vfwmsgs.h"
38 #include "evcode.h"
39 #include "wine/heap.h"
40 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45 DECLARE_CRITICAL_SECTION(message_cs);
47 struct filter_create_params
49 HRESULT hr;
50 IMoniker *moniker;
51 IBaseFilter *filter;
54 static HANDLE message_thread, message_thread_ret;
55 static DWORD message_thread_id;
56 static unsigned int message_thread_refcount;
58 struct media_event
60 struct list entry;
61 LONG code;
62 LONG_PTR param1, param2;
65 #define MAX_ITF_CACHE_ENTRIES 3
66 typedef struct _ITF_CACHE_ENTRY {
67 const IID* riid;
68 IBaseFilter* filter;
69 IUnknown* iface;
70 } ITF_CACHE_ENTRY;
72 struct filter
74 struct list entry;
75 IBaseFilter *filter;
76 IMediaSeeking *seeking;
77 WCHAR *name;
78 BOOL sorting;
81 struct filter_graph
83 IUnknown IUnknown_inner;
84 IFilterGraph2 IFilterGraph2_iface;
85 IMediaControl IMediaControl_iface;
86 IMediaSeeking IMediaSeeking_iface;
87 IBasicAudio IBasicAudio_iface;
88 IBasicVideo2 IBasicVideo2_iface;
89 IVideoWindow IVideoWindow_iface;
90 IMediaEventEx IMediaEventEx_iface;
91 IMediaFilter IMediaFilter_iface;
92 IMediaEventSink IMediaEventSink_iface;
93 IGraphConfig IGraphConfig_iface;
94 IMediaPosition IMediaPosition_iface;
95 IObjectWithSite IObjectWithSite_iface;
96 IGraphVersion IGraphVersion_iface;
97 /* IAMGraphStreams */
98 /* IAMStats */
99 /* IFilterChain */
100 /* IFilterMapper2 */
101 /* IQueueCommand */
102 /* IRegisterServiceProvider */
103 /* IResourceManager */
104 /* IServiceProvider */
105 IVideoFrameStep IVideoFrameStep_iface;
107 IUnknown *outer_unk;
108 LONG ref;
109 IUnknown *punkFilterMapper2;
111 struct list filters;
112 unsigned int name_index;
114 FILTER_STATE state;
115 TP_WORK *async_run_work;
117 IReferenceClock *refClock;
118 IBaseFilter *refClockProvider;
120 /* We may indirectly wait for streaming threads while holding graph->cs in
121 * IMediaFilter::Stop() or IMediaSeeking::SetPositions(). Since streaming
122 * threads call IMediaEventSink::Notify() to queue EC_COMPLETE, we must
123 * use a separate lock to avoid them deadlocking on graph->cs. */
124 CRITICAL_SECTION event_cs;
125 struct list media_events;
126 HANDLE media_event_handle;
127 HWND media_event_window;
128 UINT media_event_message;
129 LPARAM media_event_lparam;
130 HANDLE hEventCompletion;
131 int CompletionStatus;
132 int nRenderers;
133 int EcCompleteCount;
134 int HandleEcComplete;
135 int HandleEcRepaint;
136 int HandleEcClockChanged;
137 unsigned int got_ec_complete : 1;
138 unsigned int media_events_disabled : 1;
140 CRITICAL_SECTION cs;
141 ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
142 int nItfCacheEntries;
143 BOOL defaultclock;
144 GUID timeformatseek;
145 IUnknown *pSite;
146 LONG version;
148 /* Respectively: the last timestamp at which we started streaming, and the
149 * current offset within the stream. */
150 REFERENCE_TIME stream_start, stream_elapsed;
151 REFERENCE_TIME stream_stop;
152 LONGLONG current_pos;
154 unsigned int needs_async_run : 1;
155 unsigned int threaded : 1;
158 struct enum_filters
160 IEnumFilters IEnumFilters_iface;
161 LONG ref;
162 struct filter_graph *graph;
163 LONG version;
164 struct list *cursor;
167 static HRESULT create_enum_filters(struct filter_graph *graph, struct list *cursor, IEnumFilters **out);
169 static inline struct enum_filters *impl_from_IEnumFilters(IEnumFilters *iface)
171 return CONTAINING_RECORD(iface, struct enum_filters, IEnumFilters_iface);
174 static HRESULT WINAPI EnumFilters_QueryInterface(IEnumFilters *iface, REFIID iid, void **out)
176 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
177 TRACE("enum_filters %p, iid %s, out %p.\n", enum_filters, qzdebugstr_guid(iid), out);
179 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumFilters))
181 IEnumFilters_AddRef(*out = iface);
182 return S_OK;
185 WARN("%s not implemented, returning E_NOINTERFACE.\n", qzdebugstr_guid(iid));
186 *out = NULL;
187 return E_NOINTERFACE;
190 static ULONG WINAPI EnumFilters_AddRef(IEnumFilters *iface)
192 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
193 ULONG ref = InterlockedIncrement(&enum_filters->ref);
195 TRACE("%p increasing refcount to %lu.\n", enum_filters, ref);
197 return ref;
200 static ULONG WINAPI EnumFilters_Release(IEnumFilters *iface)
202 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
203 ULONG ref = InterlockedDecrement(&enum_filters->ref);
205 TRACE("%p decreasing refcount to %lu.\n", enum_filters, ref);
207 if (!ref)
209 IUnknown_Release(enum_filters->graph->outer_unk);
210 heap_free(enum_filters);
213 return ref;
216 static HRESULT WINAPI EnumFilters_Next(IEnumFilters *iface, ULONG count,
217 IBaseFilter **filters, ULONG *fetched)
219 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
220 unsigned int i = 0;
222 TRACE("enum_filters %p, count %lu, filters %p, fetched %p.\n",
223 enum_filters, count, filters, fetched);
225 if (enum_filters->version != enum_filters->graph->version)
226 return VFW_E_ENUM_OUT_OF_SYNC;
228 if (!filters)
229 return E_POINTER;
231 for (i = 0; i < count; ++i)
233 struct filter *filter = LIST_ENTRY(enum_filters->cursor, struct filter, entry);
235 if (!enum_filters->cursor)
236 break;
238 IBaseFilter_AddRef(filters[i] = filter->filter);
239 enum_filters->cursor = list_next(&enum_filters->graph->filters, enum_filters->cursor);
242 if (fetched)
243 *fetched = i;
245 return (i == count) ? S_OK : S_FALSE;
248 static HRESULT WINAPI EnumFilters_Skip(IEnumFilters *iface, ULONG count)
250 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
252 TRACE("enum_filters %p, count %lu.\n", enum_filters, count);
254 if (enum_filters->version != enum_filters->graph->version)
255 return VFW_E_ENUM_OUT_OF_SYNC;
257 if (!enum_filters->cursor)
258 return E_INVALIDARG;
260 while (count--)
262 if (!(enum_filters->cursor = list_next(&enum_filters->graph->filters, enum_filters->cursor)))
263 return count ? S_FALSE : S_OK;
266 return S_OK;
269 static HRESULT WINAPI EnumFilters_Reset(IEnumFilters *iface)
271 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
273 TRACE("enum_filters %p.\n", enum_filters);
275 enum_filters->cursor = list_head(&enum_filters->graph->filters);
276 enum_filters->version = enum_filters->graph->version;
277 return S_OK;
280 static HRESULT WINAPI EnumFilters_Clone(IEnumFilters *iface, IEnumFilters **out)
282 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
284 TRACE("enum_filters %p, out %p.\n", enum_filters, out);
286 return create_enum_filters(enum_filters->graph, enum_filters->cursor, out);
289 static const IEnumFiltersVtbl EnumFilters_vtbl =
291 EnumFilters_QueryInterface,
292 EnumFilters_AddRef,
293 EnumFilters_Release,
294 EnumFilters_Next,
295 EnumFilters_Skip,
296 EnumFilters_Reset,
297 EnumFilters_Clone,
300 static HRESULT create_enum_filters(struct filter_graph *graph, struct list *cursor, IEnumFilters **out)
302 struct enum_filters *enum_filters;
304 if (!(enum_filters = heap_alloc(sizeof(*enum_filters))))
305 return E_OUTOFMEMORY;
307 enum_filters->IEnumFilters_iface.lpVtbl = &EnumFilters_vtbl;
308 enum_filters->ref = 1;
309 enum_filters->cursor = cursor;
310 enum_filters->graph = graph;
311 IUnknown_AddRef(graph->outer_unk);
312 enum_filters->version = graph->version;
314 *out = &enum_filters->IEnumFilters_iface;
315 return S_OK;
318 static BOOL queue_media_event(struct filter_graph *graph, LONG code,
319 LONG_PTR param1, LONG_PTR param2)
321 struct media_event *event;
323 if (!(event = malloc(sizeof(*event))))
324 return FALSE;
326 event->code = code;
327 event->param1 = param1;
328 event->param2 = param2;
329 list_add_tail(&graph->media_events, &event->entry);
331 SetEvent(graph->media_event_handle);
332 if (graph->media_event_window)
333 PostMessageW(graph->media_event_window, graph->media_event_message, 0, graph->media_event_lparam);
335 return TRUE;
338 static void flush_media_events(struct filter_graph *graph)
340 struct list *cursor;
342 while ((cursor = list_head(&graph->media_events)))
344 struct media_event *event = LIST_ENTRY(cursor, struct media_event, entry);
346 list_remove(&event->entry);
347 free(event);
351 static struct filter_graph *impl_from_IUnknown(IUnknown *iface)
353 return CONTAINING_RECORD(iface, struct filter_graph, IUnknown_inner);
356 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown *iface, REFIID riid, void **ppvObj)
358 struct filter_graph *This = impl_from_IUnknown(iface);
359 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
361 if (IsEqualGUID(&IID_IUnknown, riid)) {
362 *ppvObj = &This->IUnknown_inner;
363 TRACE(" returning IUnknown interface (%p)\n", *ppvObj);
364 } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
365 IsEqualGUID(&IID_IFilterGraph2, riid) ||
366 IsEqualGUID(&IID_IGraphBuilder, riid)) {
367 *ppvObj = &This->IFilterGraph2_iface;
368 TRACE(" returning IGraphBuilder interface (%p)\n", *ppvObj);
369 } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
370 *ppvObj = &This->IMediaControl_iface;
371 TRACE(" returning IMediaControl interface (%p)\n", *ppvObj);
372 } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
373 *ppvObj = &This->IMediaSeeking_iface;
374 TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj);
375 } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
376 *ppvObj = &This->IBasicAudio_iface;
377 TRACE(" returning IBasicAudio interface (%p)\n", *ppvObj);
378 } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
379 IsEqualGUID(&IID_IBasicVideo2, riid)) {
380 *ppvObj = &This->IBasicVideo2_iface;
381 TRACE(" returning IBasicVideo2 interface (%p)\n", *ppvObj);
382 } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
383 *ppvObj = &This->IVideoWindow_iface;
384 TRACE(" returning IVideoWindow interface (%p)\n", *ppvObj);
385 } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
386 IsEqualGUID(&IID_IMediaEventEx, riid)) {
387 *ppvObj = &This->IMediaEventEx_iface;
388 TRACE(" returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
389 } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
390 IsEqualGUID(&IID_IPersist, riid)) {
391 *ppvObj = &This->IMediaFilter_iface;
392 TRACE(" returning IMediaFilter interface (%p)\n", *ppvObj);
393 } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
394 *ppvObj = &This->IMediaEventSink_iface;
395 TRACE(" returning IMediaEventSink interface (%p)\n", *ppvObj);
396 } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
397 *ppvObj = &This->IGraphConfig_iface;
398 TRACE(" returning IGraphConfig interface (%p)\n", *ppvObj);
399 } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
400 *ppvObj = &This->IMediaPosition_iface;
401 TRACE(" returning IMediaPosition interface (%p)\n", *ppvObj);
402 } else if (IsEqualGUID(&IID_IObjectWithSite, riid)) {
403 *ppvObj = &This->IObjectWithSite_iface;
404 TRACE(" returning IObjectWithSite interface (%p)\n", *ppvObj);
405 } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
406 TRACE(" requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
407 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
408 } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
409 TRACE(" returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
410 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
411 } else if (IsEqualGUID(&IID_IFilterMapper3, riid)) {
412 TRACE(" returning IFilterMapper3 interface from aggregated filtermapper (%p)\n", *ppvObj);
413 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
414 } else if (IsEqualGUID(&IID_IGraphVersion, riid)) {
415 *ppvObj = &This->IGraphVersion_iface;
416 TRACE(" returning IGraphVersion interface (%p)\n", *ppvObj);
417 } else if (IsEqualGUID(&IID_IVideoFrameStep, riid)) {
418 *ppvObj = &This->IVideoFrameStep_iface;
419 TRACE(" returning IVideoFrameStep interface (%p)\n", *ppvObj);
420 } else {
421 *ppvObj = NULL;
422 FIXME("unknown interface %s\n", debugstr_guid(riid));
423 return E_NOINTERFACE;
426 IUnknown_AddRef((IUnknown *)*ppvObj);
427 return S_OK;
430 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown *iface)
432 struct filter_graph *graph = impl_from_IUnknown(iface);
433 ULONG refcount = InterlockedIncrement(&graph->ref);
435 TRACE("%p increasing refcount to %lu.\n", graph, refcount);
437 return refcount;
440 static ULONG WINAPI FilterGraphInner_Release(IUnknown *iface)
442 struct filter_graph *This = impl_from_IUnknown(iface);
443 ULONG refcount = InterlockedDecrement(&This->ref);
444 struct list *cursor;
446 TRACE("%p decreasing refcount to %lu.\n", This, refcount);
448 if (!refcount)
450 int i;
452 This->ref = 1; /* guard against reentrancy (aggregation). */
454 IMediaControl_Stop(&This->IMediaControl_iface);
456 while ((cursor = list_head(&This->filters)))
458 struct filter *filter = LIST_ENTRY(cursor, struct filter, entry);
460 IFilterGraph2_RemoveFilter(&This->IFilterGraph2_iface, filter->filter);
463 if (This->refClock)
464 IReferenceClock_Release(This->refClock);
466 for (i = 0; i < This->nItfCacheEntries; i++)
468 if (This->ItfCacheEntries[i].iface)
469 IUnknown_Release(This->ItfCacheEntries[i].iface);
472 IUnknown_Release(This->punkFilterMapper2);
474 if (This->pSite) IUnknown_Release(This->pSite);
476 flush_media_events(This);
477 CloseHandle(This->media_event_handle);
479 EnterCriticalSection(&message_cs);
480 if (This->threaded && !--message_thread_refcount)
482 PostThreadMessageW(message_thread_id, WM_USER + 1, 0, 0);
483 WaitForSingleObject(message_thread, INFINITE);
484 CloseHandle(message_thread);
485 CloseHandle(message_thread_ret);
487 LeaveCriticalSection(&message_cs);
489 This->event_cs.DebugInfo->Spare[0] = 0;
490 DeleteCriticalSection(&This->event_cs);
491 This->cs.DebugInfo->Spare[0] = 0;
492 DeleteCriticalSection(&This->cs);
493 free(This);
495 return refcount;
498 static struct filter_graph *impl_from_IFilterGraph2(IFilterGraph2 *iface)
500 return CONTAINING_RECORD(iface, struct filter_graph, IFilterGraph2_iface);
503 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface, REFIID iid, void **out)
505 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
506 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
509 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface)
511 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
512 return IUnknown_AddRef(graph->outer_unk);
515 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface)
517 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
518 return IUnknown_Release(graph->outer_unk);
521 static IBaseFilter *find_filter_by_name(struct filter_graph *graph, const WCHAR *name)
523 struct filter *filter;
525 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
527 if (!wcscmp(filter->name, name))
528 return filter->filter;
531 return NULL;
534 static BOOL has_output_pins(IBaseFilter *filter)
536 IEnumPins *enumpins;
537 PIN_DIRECTION dir;
538 IPin *pin;
540 if (FAILED(IBaseFilter_EnumPins(filter, &enumpins)))
541 return FALSE;
543 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
545 IPin_QueryDirection(pin, &dir);
546 IPin_Release(pin);
547 if (dir == PINDIR_OUTPUT)
549 IEnumPins_Release(enumpins);
550 return TRUE;
554 IEnumPins_Release(enumpins);
555 return FALSE;
558 static void update_seeking(struct filter *filter)
560 IMediaSeeking *seeking;
562 if (!filter->seeking)
564 /* The Legend of Heroes: Trails of Cold Steel II destroys its filter when
565 * its IMediaSeeking interface is released, so cache the interface instead
566 * of querying for it every time.
567 * Some filters (e.g. MediaStreamFilter) can become seekable when they are
568 * already in the graph, so always try to query IMediaSeeking if it's not
569 * cached yet. */
570 if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaSeeking, (void **)&seeking)))
572 if (IMediaSeeking_IsFormatSupported(seeking, &TIME_FORMAT_MEDIA_TIME) == S_OK)
573 filter->seeking = seeking;
574 else
575 IMediaSeeking_Release(seeking);
580 static BOOL is_renderer(struct filter *filter)
582 IMediaPosition *media_position;
583 IAMFilterMiscFlags *flags;
584 BOOL ret = FALSE;
586 if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IAMFilterMiscFlags, (void **)&flags)))
588 if (IAMFilterMiscFlags_GetMiscFlags(flags) & AM_FILTER_MISC_FLAGS_IS_RENDERER)
589 ret = TRUE;
590 IAMFilterMiscFlags_Release(flags);
592 else if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&media_position)))
594 if (!has_output_pins(filter->filter))
595 ret = TRUE;
596 IMediaPosition_Release(media_position);
598 else
600 update_seeking(filter);
601 if (filter->seeking && !has_output_pins(filter->filter))
602 ret = TRUE;
604 return ret;
607 /*** IFilterGraph methods ***/
608 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
609 IBaseFilter *filter, const WCHAR *name)
611 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
612 BOOL duplicate_name = FALSE;
613 struct filter *entry;
614 unsigned int i;
615 HRESULT hr;
617 TRACE("graph %p, filter %p, name %s.\n", graph, filter, debugstr_w(name));
619 if (!filter)
620 return E_POINTER;
622 if (!(entry = heap_alloc(sizeof(*entry))))
623 return E_OUTOFMEMORY;
625 if (!(entry->name = CoTaskMemAlloc((name ? wcslen(name) + 6 : 5) * sizeof(WCHAR))))
627 heap_free(entry);
628 return E_OUTOFMEMORY;
631 if (name && find_filter_by_name(graph, name))
632 duplicate_name = TRUE;
634 if (!name || duplicate_name)
636 for (i = 0; i < 10000 ; ++i)
638 if (name)
639 swprintf(entry->name, name ? wcslen(name) + 6 : 5, L"%s %04u", name, graph->name_index);
640 else
641 swprintf(entry->name, name ? wcslen(name) + 6 : 5, L"%04u", graph->name_index);
643 graph->name_index = (graph->name_index + 1) % 10000;
645 if (!find_filter_by_name(graph, entry->name))
646 break;
649 if (i == 10000)
651 CoTaskMemFree(entry->name);
652 heap_free(entry);
653 return VFW_E_DUPLICATE_NAME;
656 else
657 wcscpy(entry->name, name);
659 if (FAILED(hr = IBaseFilter_JoinFilterGraph(filter,
660 (IFilterGraph *)&graph->IFilterGraph2_iface, entry->name)))
662 CoTaskMemFree(entry->name);
663 heap_free(entry);
664 return hr;
667 IBaseFilter_SetSyncSource(filter, graph->refClock);
669 IBaseFilter_AddRef(entry->filter = filter);
671 list_add_head(&graph->filters, &entry->entry);
672 entry->sorting = FALSE;
673 entry->seeking = NULL;
674 ++graph->version;
676 return duplicate_name ? VFW_S_DUPLICATE_NAME : hr;
679 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
681 struct filter_graph *This = impl_from_IFilterGraph2(iface);
682 struct filter *entry;
683 int i;
684 HRESULT hr = E_FAIL;
686 TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
688 LIST_FOR_EACH_ENTRY(entry, &This->filters, struct filter, entry)
690 if (entry->filter == pFilter)
692 IEnumPins *penumpins = NULL;
694 if (This->defaultclock && This->refClockProvider == pFilter)
696 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
697 This->defaultclock = TRUE;
700 TRACE("Removing filter %s.\n", debugstr_w(entry->name));
702 hr = IBaseFilter_EnumPins(pFilter, &penumpins);
703 if (SUCCEEDED(hr)) {
704 IPin *ppin;
705 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
707 IPin *peer = NULL;
708 HRESULT hr;
710 IPin_ConnectedTo(ppin, &peer);
711 if (peer)
713 if (FAILED(hr = IPin_Disconnect(peer)))
715 WARN("Failed to disconnect peer %p, hr %#lx.\n", peer, hr);
716 IPin_Release(peer);
717 IPin_Release(ppin);
718 IEnumPins_Release(penumpins);
719 return hr;
721 IPin_Release(peer);
723 if (FAILED(hr = IPin_Disconnect(ppin)))
725 WARN("Failed to disconnect pin %p, hr %#lx.\n", ppin, hr);
726 IPin_Release(ppin);
727 IEnumPins_Release(penumpins);
728 return hr;
731 IPin_Release(ppin);
733 IEnumPins_Release(penumpins);
736 hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, NULL);
737 if (SUCCEEDED(hr))
739 IBaseFilter_SetSyncSource(pFilter, NULL);
740 IBaseFilter_Release(pFilter);
741 if (entry->seeking)
742 IMediaSeeking_Release(entry->seeking);
743 list_remove(&entry->entry);
744 CoTaskMemFree(entry->name);
745 heap_free(entry);
746 This->version++;
747 /* Invalidate interfaces in the cache */
748 for (i = 0; i < This->nItfCacheEntries; i++)
749 if (pFilter == This->ItfCacheEntries[i].filter)
751 IUnknown_Release(This->ItfCacheEntries[i].iface);
752 This->ItfCacheEntries[i].iface = NULL;
753 This->ItfCacheEntries[i].filter = NULL;
755 return S_OK;
757 break;
761 return hr; /* FIXME: check this error code */
764 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface, IEnumFilters **out)
766 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
768 TRACE("graph %p, out %p.\n", graph, out);
770 return create_enum_filters(graph, list_head(&graph->filters), out);
773 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface,
774 const WCHAR *name, IBaseFilter **filter)
776 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
778 TRACE("graph %p, name %s, filter %p.\n", graph, debugstr_w(name), filter);
780 if (!filter)
781 return E_POINTER;
783 if ((*filter = find_filter_by_name(graph, name)))
785 IBaseFilter_AddRef(*filter);
786 return S_OK;
789 return VFW_E_NOT_FOUND;
792 static HRESULT check_cyclic_connection(IPin *source, IPin *sink)
794 IPin *upstream_source, *upstream_sink;
795 PIN_INFO source_info, sink_info;
796 IEnumPins *enumpins;
797 HRESULT hr;
799 hr = IPin_QueryPinInfo(sink, &sink_info);
800 if (FAILED(hr))
802 ERR("Failed to query pin, hr %#lx.\n", hr);
803 return hr;
805 IBaseFilter_Release(sink_info.pFilter);
807 hr = IPin_QueryPinInfo(source, &source_info);
808 if (FAILED(hr))
810 ERR("Failed to query pin, hr %#lx.\n", hr);
811 return hr;
814 if (sink_info.pFilter == source_info.pFilter)
816 WARN("Cyclic connection detected; returning VFW_E_CIRCULAR_GRAPH.\n");
817 IBaseFilter_Release(source_info.pFilter);
818 return VFW_E_CIRCULAR_GRAPH;
821 hr = IBaseFilter_EnumPins(source_info.pFilter, &enumpins);
822 if (FAILED(hr))
824 ERR("Failed to enumerate pins, hr %#lx.\n", hr);
825 IBaseFilter_Release(source_info.pFilter);
826 return hr;
829 while ((hr = IEnumPins_Next(enumpins, 1, &upstream_sink, NULL)) == S_OK)
831 PIN_DIRECTION dir = PINDIR_OUTPUT;
833 IPin_QueryDirection(upstream_sink, &dir);
834 if (dir == PINDIR_INPUT && IPin_ConnectedTo(upstream_sink, &upstream_source) == S_OK)
836 hr = check_cyclic_connection(upstream_source, sink);
837 IPin_Release(upstream_source);
838 if (FAILED(hr))
840 IPin_Release(upstream_sink);
841 IEnumPins_Release(enumpins);
842 IBaseFilter_Release(source_info.pFilter);
843 return hr;
846 IPin_Release(upstream_sink);
848 IEnumPins_Release(enumpins);
850 IBaseFilter_Release(source_info.pFilter);
851 return S_OK;
854 static struct filter *find_sorted_filter(struct filter_graph *graph, IBaseFilter *iface)
856 struct filter *filter;
858 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
860 if (filter->filter == iface)
861 return filter;
864 return NULL;
867 static void sort_filter_recurse(struct filter_graph *graph, struct filter *filter, struct list *sorted)
869 struct filter *peer_filter;
870 IEnumPins *enumpins;
871 PIN_DIRECTION dir;
872 IPin *pin, *peer;
873 PIN_INFO info;
875 TRACE("Sorting filter %p.\n", filter->filter);
877 /* Cyclic connections should be caught by check_cyclic_connection(). */
878 assert(!filter->sorting);
880 filter->sorting = TRUE;
882 IBaseFilter_EnumPins(filter->filter, &enumpins);
883 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
885 IPin_QueryDirection(pin, &dir);
887 if (dir == PINDIR_INPUT && IPin_ConnectedTo(pin, &peer) == S_OK)
889 IPin_QueryPinInfo(peer, &info);
890 /* Note that the filter may have already been sorted. */
891 if ((peer_filter = find_sorted_filter(graph, info.pFilter)))
892 sort_filter_recurse(graph, peer_filter, sorted);
893 IBaseFilter_Release(info.pFilter);
894 IPin_Release(peer);
896 IPin_Release(pin);
898 IEnumPins_Release(enumpins);
900 filter->sorting = FALSE;
902 list_remove(&filter->entry);
903 list_add_head(sorted, &filter->entry);
906 static void sort_filters(struct filter_graph *graph)
908 struct list sorted = LIST_INIT(sorted), *cursor;
910 while ((cursor = list_head(&graph->filters)))
912 struct filter *filter = LIST_ENTRY(cursor, struct filter, entry);
913 sort_filter_recurse(graph, filter, &sorted);
916 list_move_tail(&graph->filters, &sorted);
919 /* NOTE: despite the implication, it doesn't matter which
920 * way round you put in the input and output pins */
921 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppinIn, IPin *ppinOut,
922 const AM_MEDIA_TYPE *pmt)
924 struct filter_graph *This = impl_from_IFilterGraph2(iface);
925 PIN_DIRECTION dir;
926 HRESULT hr;
928 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
929 strmbase_dump_media_type(pmt);
931 /* FIXME: check pins are in graph */
933 if (TRACE_ON(quartz))
935 PIN_INFO PinInfo;
937 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
938 if (FAILED(hr))
939 return hr;
941 TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
942 IBaseFilter_Release(PinInfo.pFilter);
944 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
945 if (FAILED(hr))
946 return hr;
948 TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
949 IBaseFilter_Release(PinInfo.pFilter);
952 hr = IPin_QueryDirection(ppinIn, &dir);
953 if (SUCCEEDED(hr))
955 if (dir == PINDIR_INPUT)
957 hr = check_cyclic_connection(ppinOut, ppinIn);
958 if (SUCCEEDED(hr))
959 hr = IPin_Connect(ppinOut, ppinIn, pmt);
961 else
963 hr = check_cyclic_connection(ppinIn, ppinOut);
964 if (SUCCEEDED(hr))
965 hr = IPin_Connect(ppinIn, ppinOut, pmt);
969 return hr;
972 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface, IPin *pin)
974 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
976 TRACE("graph %p, pin %p.\n", graph, pin);
978 return IFilterGraph2_ReconnectEx(iface, pin, NULL);
981 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
983 struct filter_graph *This = impl_from_IFilterGraph2(iface);
985 TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
987 if (!ppin)
988 return E_POINTER;
990 return IPin_Disconnect(ppin);
993 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
995 struct filter_graph *This = impl_from_IFilterGraph2(iface);
996 IReferenceClock *pClock = NULL;
997 struct filter *filter;
998 HRESULT hr = S_OK;
1000 TRACE("(%p/%p)->() live sources not handled properly!\n", This, iface);
1002 EnterCriticalSection(&This->cs);
1004 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
1006 if (IBaseFilter_QueryInterface(filter->filter, &IID_IReferenceClock, (void **)&pClock) == S_OK)
1007 break;
1010 if (!pClock)
1012 hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
1013 This->refClockProvider = NULL;
1015 else
1017 filter = LIST_ENTRY(list_tail(&This->filters), struct filter, entry);
1018 This->refClockProvider = filter->filter;
1021 if (SUCCEEDED(hr))
1023 hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
1024 This->defaultclock = TRUE;
1025 IReferenceClock_Release(pClock);
1027 LeaveCriticalSection(&This->cs);
1029 return hr;
1032 static DWORD WINAPI message_thread_run(void *ctx)
1034 MSG msg;
1036 SetThreadDescription(GetCurrentThread(), L"wine_qz_graph_worker");
1038 /* Make sure we have a message queue. */
1039 PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
1040 SetEvent(message_thread_ret);
1042 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1044 for (;;)
1046 GetMessageW(&msg, NULL, 0, 0);
1048 if (!msg.hwnd && msg.message == WM_USER)
1050 struct filter_create_params *params = (struct filter_create_params *)msg.wParam;
1052 params->hr = IMoniker_BindToObject(params->moniker, NULL, NULL,
1053 &IID_IBaseFilter, (void **)&params->filter);
1054 SetEvent(message_thread_ret);
1056 else if (!msg.hwnd && msg.message == WM_USER + 1)
1058 break;
1060 else
1062 TranslateMessage(&msg);
1063 DispatchMessageW(&msg);
1067 CoUninitialize();
1068 return 0;
1071 static HRESULT create_filter(struct filter_graph *graph, IMoniker *moniker, IBaseFilter **filter)
1073 if (graph->threaded)
1075 struct filter_create_params params;
1077 params.moniker = moniker;
1079 EnterCriticalSection(&message_cs);
1080 PostThreadMessageW(message_thread_id, WM_USER, (WPARAM)&params, 0);
1081 WaitForSingleObject(message_thread_ret, INFINITE);
1082 LeaveCriticalSection(&message_cs);
1084 *filter = params.filter;
1085 return params.hr;
1087 else
1088 return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter);
1091 static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
1092 BOOL render_to_existing, unsigned int recursion_depth);
1094 static HRESULT autoplug_through_sink(struct filter_graph *graph, IPin *source,
1095 IBaseFilter *filter, IPin *middle_sink, IPin *sink,
1096 BOOL render_to_existing, unsigned int recursion_depth)
1098 BOOL any = FALSE, all = TRUE;
1099 IPin *middle_source, *peer;
1100 IEnumPins *source_enum;
1101 PIN_DIRECTION dir;
1102 PIN_INFO info;
1103 HRESULT hr;
1105 TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, middle_sink);
1107 IPin_QueryDirection(middle_sink, &dir);
1108 if (dir != PINDIR_INPUT)
1109 return E_FAIL;
1111 if (IPin_ConnectedTo(middle_sink, &peer) == S_OK)
1113 IPin_Release(peer);
1114 return E_FAIL;
1117 if (FAILED(hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, middle_sink, NULL)))
1118 return E_FAIL;
1120 if (FAILED(hr = IBaseFilter_EnumPins(filter, &source_enum)))
1121 goto err;
1123 while (IEnumPins_Next(source_enum, 1, &middle_source, NULL) == S_OK)
1125 IPin_QueryPinInfo(middle_source, &info);
1126 IBaseFilter_Release(info.pFilter);
1127 if (info.dir != PINDIR_OUTPUT)
1129 IPin_Release(middle_source);
1130 continue;
1132 if (info.achName[0] == '~')
1134 TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
1135 IPin_Release(middle_source);
1136 continue;
1138 if (IPin_ConnectedTo(middle_source, &peer) == S_OK)
1140 IPin_Release(peer);
1141 IPin_Release(middle_source);
1142 continue;
1145 hr = autoplug(graph, middle_source, sink, render_to_existing, recursion_depth + 1);
1146 IPin_Release(middle_source);
1147 if (SUCCEEDED(hr) && sink)
1149 IEnumPins_Release(source_enum);
1150 return hr;
1152 if (SUCCEEDED(hr))
1153 any = TRUE;
1154 if (hr != S_OK)
1155 all = FALSE;
1157 IEnumPins_Release(source_enum);
1159 if (!sink)
1161 if (all)
1162 return S_OK;
1163 if (any)
1164 return VFW_S_PARTIAL_RENDER;
1167 err:
1168 IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, source);
1169 IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, middle_sink);
1170 return E_FAIL;
1173 static HRESULT autoplug_through_filter(struct filter_graph *graph, IPin *source,
1174 IBaseFilter *filter, IPin *sink, BOOL render_to_existing,
1175 unsigned int recursion_depth)
1177 IEnumPins *sink_enum;
1178 IPin *filter_sink;
1179 HRESULT hr;
1181 TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, filter);
1183 if (FAILED(hr = IBaseFilter_EnumPins(filter, &sink_enum)))
1184 return hr;
1186 while (IEnumPins_Next(sink_enum, 1, &filter_sink, NULL) == S_OK)
1188 hr = autoplug_through_sink(graph, source, filter, filter_sink, sink,
1189 render_to_existing, recursion_depth);
1190 IPin_Release(filter_sink);
1191 if (SUCCEEDED(hr))
1193 IEnumPins_Release(sink_enum);
1194 return hr;
1197 IEnumPins_Release(sink_enum);
1198 return VFW_E_CANNOT_CONNECT;
1201 static HRESULT get_autoplug_types(IPin *source, unsigned int *ret_count, GUID **ret_types)
1203 unsigned int i, mt_count = 0, mt_capacity = 16;
1204 AM_MEDIA_TYPE **mts = NULL;
1205 IEnumMediaTypes *enummt;
1206 GUID *types = NULL;
1207 HRESULT hr;
1209 if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
1211 ERR("Failed to enumerate media types, hr %#lx.\n", hr);
1212 return hr;
1215 for (;;)
1217 ULONG count;
1219 if (!(mts = realloc(mts, mt_capacity * sizeof(*mts))))
1221 hr = E_OUTOFMEMORY;
1222 goto out;
1225 if (FAILED(hr = IEnumMediaTypes_Next(enummt, mt_capacity - mt_count, mts + mt_count, &count)))
1227 ERR("Failed to get media types, hr %#lx.\n", hr);
1228 goto out;
1231 mt_count += count;
1232 if (hr == S_FALSE)
1233 break;
1235 mt_capacity *= 2;
1238 if (!(types = malloc(mt_count * 2 * sizeof(*types))))
1240 hr = E_OUTOFMEMORY;
1241 goto out;
1244 for (i = 0; i < mt_count; ++i)
1246 types[i * 2] = mts[i]->majortype;
1247 types[i * 2 + 1] = mts[i]->subtype;
1248 DeleteMediaType(mts[i]);
1251 *ret_count = mt_count;
1252 *ret_types = types;
1254 hr = S_OK;
1255 out:
1256 free(mts);
1257 IEnumMediaTypes_Release(enummt);
1258 return hr;
1261 /* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which
1262 * share most of the same code. Render() calls this with a NULL sink. */
1263 static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
1264 BOOL render_to_existing, unsigned int recursion_depth)
1266 IAMGraphBuilderCallback *callback = NULL;
1267 struct filter *graph_filter;
1268 IEnumMoniker *enummoniker;
1269 unsigned int type_count;
1270 IFilterMapper2 *mapper;
1271 IBaseFilter *filter;
1272 GUID *types = NULL;
1273 IMoniker *moniker;
1274 HRESULT hr;
1276 TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
1278 if (recursion_depth >= 5)
1280 WARN("Recursion depth has reached 5; aborting.\n");
1281 return VFW_E_CANNOT_CONNECT;
1284 if (sink)
1286 /* Try to connect directly to this sink. */
1287 hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, sink, NULL);
1289 /* If direct connection succeeded, we should propagate that return value.
1290 * If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
1291 * even bother trying intermediate filters, since they won't succeed. */
1292 if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
1293 return hr;
1296 /* Always prefer filters in the graph. */
1297 LIST_FOR_EACH_ENTRY(graph_filter, &graph->filters, struct filter, entry)
1299 if (SUCCEEDED(hr = autoplug_through_filter(graph, source, graph_filter->filter,
1300 sink, render_to_existing, recursion_depth)))
1301 return hr;
1304 IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
1306 if (FAILED(hr = get_autoplug_types(source, &type_count, &types)))
1308 IFilterMapper2_Release(mapper);
1309 return hr;
1312 if (graph->pSite)
1313 IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
1315 if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker,
1316 0, FALSE, MERIT_UNLIKELY, TRUE, type_count, types, NULL, NULL, FALSE,
1317 render_to_existing, 0, NULL, NULL, NULL)))
1318 goto out;
1320 while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
1322 IPropertyBag *bag;
1323 VARIANT var;
1325 VariantInit(&var);
1326 IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&bag);
1327 hr = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
1328 IPropertyBag_Release(bag);
1329 if (FAILED(hr))
1331 IMoniker_Release(moniker);
1332 continue;
1335 if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
1337 TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#lx.\n", hr);
1338 IMoniker_Release(moniker);
1339 continue;
1342 hr = create_filter(graph, moniker, &filter);
1343 IMoniker_Release(moniker);
1344 if (FAILED(hr))
1346 ERR("Failed to create filter for %s, hr %#lx.\n", debugstr_w(V_BSTR(&var)), hr);
1347 VariantClear(&var);
1348 continue;
1351 if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
1353 TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#lx.\n", hr);
1354 IBaseFilter_Release(filter);
1355 continue;
1358 hr = IFilterGraph2_AddFilter(&graph->IFilterGraph2_iface, filter, V_BSTR(&var));
1359 VariantClear(&var);
1360 if (FAILED(hr))
1362 ERR("Failed to add filter, hr %#lx.\n", hr);
1363 IBaseFilter_Release(filter);
1364 continue;
1367 hr = autoplug_through_filter(graph, source, filter, sink, render_to_existing, recursion_depth);
1368 if (SUCCEEDED(hr))
1370 IBaseFilter_Release(filter);
1371 goto out;
1374 IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
1375 IBaseFilter_Release(filter);
1377 IEnumMoniker_Release(enummoniker);
1379 hr = VFW_E_CANNOT_CONNECT;
1381 out:
1382 free(types);
1383 if (callback) IAMGraphBuilderCallback_Release(callback);
1384 IFilterMapper2_Release(mapper);
1385 return hr;
1388 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *source, IPin *sink)
1390 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1391 PIN_DIRECTION dir;
1392 HRESULT hr;
1394 TRACE("graph %p, source %p, sink %p.\n", graph, source, sink);
1396 if (!source || !sink)
1397 return E_POINTER;
1399 if (FAILED(hr = IPin_QueryDirection(source, &dir)))
1400 return hr;
1402 if (dir == PINDIR_INPUT)
1404 IPin *temp;
1406 TRACE("Directions seem backwards, swapping pins\n");
1408 temp = sink;
1409 sink = source;
1410 source = temp;
1413 EnterCriticalSection(&graph->cs);
1415 hr = autoplug(graph, source, sink, TRUE, 0);
1417 LeaveCriticalSection(&graph->cs);
1419 TRACE("Returning %#lx.\n", hr);
1420 return hr;
1423 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *source)
1425 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1426 HRESULT hr;
1428 TRACE("graph %p, source %p.\n", graph, source);
1430 EnterCriticalSection(&graph->cs);
1431 hr = autoplug(graph, source, NULL, FALSE, 0);
1432 LeaveCriticalSection(&graph->cs);
1433 if (hr == VFW_E_CANNOT_CONNECT)
1434 hr = VFW_E_CANNOT_RENDER;
1436 TRACE("Returning %#lx.\n", hr);
1437 return hr;
1440 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, LPCWSTR lpcwstrFile,
1441 LPCWSTR lpcwstrPlayList)
1443 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1444 IBaseFilter* preader = NULL;
1445 IPin* ppinreader = NULL;
1446 IEnumPins* penumpins = NULL;
1447 struct filter *filter;
1448 HRESULT hr;
1449 BOOL partial = FALSE;
1450 BOOL any = FALSE;
1452 TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1454 if (lpcwstrPlayList != NULL)
1455 return E_INVALIDARG;
1457 hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, L"Reader", &preader);
1458 if (FAILED(hr))
1459 return hr;
1461 hr = IBaseFilter_EnumPins(preader, &penumpins);
1462 if (SUCCEEDED(hr))
1464 while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1466 PIN_DIRECTION dir;
1468 IPin_QueryDirection(ppinreader, &dir);
1469 if (dir == PINDIR_OUTPUT)
1471 hr = IFilterGraph2_Render(iface, ppinreader);
1473 TRACE("Filters in chain:\n");
1474 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
1475 TRACE("- %s.\n", debugstr_w(filter->name));
1477 if (SUCCEEDED(hr))
1478 any = TRUE;
1479 if (hr != S_OK)
1480 partial = TRUE;
1482 IPin_Release(ppinreader);
1484 IEnumPins_Release(penumpins);
1486 if (!any)
1488 if (FAILED(hr = IFilterGraph2_RemoveFilter(iface, preader)))
1489 ERR("Failed to remove source filter, hr %#lx.\n", hr);
1490 hr = VFW_E_CANNOT_RENDER;
1492 else if (partial)
1494 hr = VFW_S_PARTIAL_RENDER;
1496 else
1498 hr = S_OK;
1501 IBaseFilter_Release(preader);
1503 TRACE("Returning %#lx.\n", hr);
1504 return hr;
1507 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface,
1508 const WCHAR *filename, const WCHAR *filter_name, IBaseFilter **ret_filter)
1510 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1511 IFileSourceFilter *filesource;
1512 IBaseFilter *filter;
1513 HRESULT hr;
1514 GUID clsid;
1516 TRACE("graph %p, filename %s, filter_name %s, ret_filter %p.\n",
1517 graph, debugstr_w(filename), debugstr_w(filter_name), ret_filter);
1519 if (!*filename)
1520 return VFW_E_NOT_FOUND;
1522 if (!get_media_type(filename, NULL, NULL, &clsid))
1523 clsid = CLSID_AsyncReader;
1524 TRACE("Using source filter %s.\n", debugstr_guid(&clsid));
1526 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
1527 &IID_IBaseFilter, (void **)&filter)))
1529 WARN("Failed to create filter, hr %#lx.\n", hr);
1530 return hr;
1533 if (FAILED(hr = IBaseFilter_QueryInterface(filter, &IID_IFileSourceFilter, (void **)&filesource)))
1535 WARN("Failed to get IFileSourceFilter, hr %#lx.\n", hr);
1536 IBaseFilter_Release(filter);
1537 return hr;
1540 hr = IFileSourceFilter_Load(filesource, filename, NULL);
1541 IFileSourceFilter_Release(filesource);
1542 if (FAILED(hr))
1544 WARN("Failed to load file, hr %#lx.\n", hr);
1545 IBaseFilter_Release(filter);
1546 return hr;
1549 if (FAILED(hr = IFilterGraph2_AddFilter(iface, filter, filter_name)))
1551 IBaseFilter_Release(filter);
1552 return hr;
1555 if (ret_filter)
1556 *ret_filter = filter;
1557 return S_OK;
1560 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface, DWORD_PTR file)
1562 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1564 TRACE("graph %p, file %#Ix.\n", graph, file);
1566 return S_OK;
1569 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface)
1571 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1573 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1575 return S_OK;
1578 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface)
1580 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1582 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1584 return S_OK;
1587 /*** IFilterGraph2 methods ***/
1588 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1589 IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1591 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1592 HRESULT hr;
1593 IBaseFilter* pfilter;
1595 TRACE("(%p/%p)->(%p %p %s %p)\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1597 hr = IMoniker_BindToObject(pMoniker, pCtx, NULL, &IID_IBaseFilter, (void**)&pfilter);
1598 if(FAILED(hr)) {
1599 WARN("Failed to bind moniker, hr %#lx.\n", hr);
1600 return hr;
1603 hr = IFilterGraph2_AddFilter(iface, pfilter, lpcwstrFilterName);
1604 if (FAILED(hr)) {
1605 WARN("Failed to add filter, hr %#lx.\n", hr);
1606 IBaseFilter_Release(pfilter);
1607 return hr;
1610 if(ppFilter)
1611 *ppFilter = pfilter;
1612 else IBaseFilter_Release(pfilter);
1614 return S_OK;
1617 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *pin, const AM_MEDIA_TYPE *mt)
1619 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1620 PIN_DIRECTION dir;
1621 HRESULT hr;
1622 IPin *peer;
1624 TRACE("graph %p, pin %p, mt %p.\n", graph, pin, mt);
1626 if (FAILED(hr = IPin_ConnectedTo(pin, &peer)))
1627 return hr;
1629 IPin_QueryDirection(pin, &dir);
1630 IFilterGraph2_Disconnect(iface, peer);
1631 IFilterGraph2_Disconnect(iface, pin);
1633 if (dir == PINDIR_INPUT)
1634 hr = IFilterGraph2_ConnectDirect(iface, peer, pin, mt);
1635 else
1636 hr = IFilterGraph2_ConnectDirect(iface, pin, peer, mt);
1638 IPin_Release(peer);
1639 return hr;
1642 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *source, DWORD flags, DWORD *context)
1644 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1645 HRESULT hr;
1647 TRACE("graph %p, source %p, flags %#lx, context %p.\n", graph, source, flags, context);
1649 if (flags & ~AM_RENDEREX_RENDERTOEXISTINGRENDERERS)
1650 FIXME("Unknown flags %#lx.\n", flags);
1652 EnterCriticalSection(&graph->cs);
1653 hr = autoplug(graph, source, NULL, !!(flags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS), 0);
1654 LeaveCriticalSection(&graph->cs);
1655 if (hr == VFW_E_CANNOT_CONNECT)
1656 hr = VFW_E_CANNOT_RENDER;
1658 TRACE("Returning %#lx.\n", hr);
1659 return hr;
1663 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1665 FilterGraph2_QueryInterface,
1666 FilterGraph2_AddRef,
1667 FilterGraph2_Release,
1668 FilterGraph2_AddFilter,
1669 FilterGraph2_RemoveFilter,
1670 FilterGraph2_EnumFilters,
1671 FilterGraph2_FindFilterByName,
1672 FilterGraph2_ConnectDirect,
1673 FilterGraph2_Reconnect,
1674 FilterGraph2_Disconnect,
1675 FilterGraph2_SetDefaultSyncSource,
1676 FilterGraph2_Connect,
1677 FilterGraph2_Render,
1678 FilterGraph2_RenderFile,
1679 FilterGraph2_AddSourceFilter,
1680 FilterGraph2_SetLogFile,
1681 FilterGraph2_Abort,
1682 FilterGraph2_ShouldOperationContinue,
1683 FilterGraph2_AddSourceFilterForMoniker,
1684 FilterGraph2_ReconnectEx,
1685 FilterGraph2_RenderEx
1688 static struct filter_graph *impl_from_IMediaControl(IMediaControl *iface)
1690 return CONTAINING_RECORD(iface, struct filter_graph, IMediaControl_iface);
1693 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID iid, void **out)
1695 struct filter_graph *graph = impl_from_IMediaControl(iface);
1696 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
1699 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1701 struct filter_graph *graph = impl_from_IMediaControl(iface);
1702 return IUnknown_AddRef(graph->outer_unk);
1705 static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1707 struct filter_graph *graph = impl_from_IMediaControl(iface);
1708 return IUnknown_Release(graph->outer_unk);
1712 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *count)
1714 TRACE("iface %p, count %p.\n", iface, count);
1715 *count = 1;
1716 return S_OK;
1719 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT index,
1720 LCID lcid, ITypeInfo **typeinfo)
1722 TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo);
1723 return strmbase_get_typeinfo(IMediaControl_tid, typeinfo);
1726 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID iid,
1727 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
1729 ITypeInfo *typeinfo;
1730 HRESULT hr;
1732 TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n",
1733 iface, debugstr_guid(iid), names, count, lcid, ids);
1735 if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaControl_tid, &typeinfo)))
1737 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
1738 ITypeInfo_Release(typeinfo);
1740 return hr;
1743 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID id, REFIID iid, LCID lcid,
1744 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
1746 ITypeInfo *typeinfo;
1747 HRESULT hr;
1749 TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
1750 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
1752 if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaControl_tid, &typeinfo)))
1754 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
1755 ITypeInfo_Release(typeinfo);
1757 return hr;
1760 static void update_render_count(struct filter_graph *graph)
1762 /* Some filters (e.g. MediaStreamFilter) can become renderers when they are
1763 * already in the graph. */
1764 struct filter *filter;
1765 graph->nRenderers = 0;
1766 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1768 if (is_renderer(filter))
1769 ++graph->nRenderers;
1773 /* Perform the paused -> running transition. The caller must hold graph->cs. */
1774 static HRESULT graph_start(struct filter_graph *graph, REFERENCE_TIME stream_start)
1776 struct media_event *event, *next;
1777 REFERENCE_TIME stream_stop;
1778 struct filter *filter;
1779 HRESULT hr = S_OK;
1781 EnterCriticalSection(&graph->event_cs);
1782 graph->EcCompleteCount = 0;
1783 update_render_count(graph);
1784 LeaveCriticalSection(&graph->event_cs);
1786 LIST_FOR_EACH_ENTRY_SAFE(event, next, &graph->media_events, struct media_event, entry)
1788 if (event->code == EC_COMPLETE)
1790 list_remove(&event->entry);
1791 free(event);
1794 if (list_empty(&graph->media_events))
1795 ResetEvent(graph->media_event_handle);
1797 if (graph->defaultclock && !graph->refClock)
1798 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
1800 if (!stream_start && graph->refClock)
1802 IReferenceClock_GetTime(graph->refClock, &graph->stream_start);
1803 stream_start = graph->stream_start - graph->stream_elapsed;
1804 /* Delay presentation time by 200 ms, to give filters time to
1805 * initialize. */
1806 stream_start += 200 * 10000;
1809 if (SUCCEEDED(IMediaSeeking_GetStopPosition(&graph->IMediaSeeking_iface, &stream_stop)))
1810 graph->stream_stop = stream_stop;
1812 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1814 HRESULT filter_hr = IBaseFilter_Run(filter->filter, stream_start);
1815 if (hr == S_OK)
1816 hr = filter_hr;
1817 TRACE("Filter %p returned %#lx.\n", filter->filter, filter_hr);
1820 if (FAILED(hr))
1821 WARN("Failed to start stream, hr %#lx.\n", hr);
1823 return hr;
1826 static void CALLBACK async_run_cb(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work)
1828 struct filter_graph *graph = context;
1829 struct filter *filter;
1830 FILTER_STATE state;
1831 HRESULT hr;
1833 TRACE("Performing asynchronous state change.\n");
1835 /* We can't just call GetState(), since that will return State_Running and
1836 * VFW_S_STATE_INTERMEDIATE regardless of whether we're done pausing yet.
1837 * Instead replicate it here. */
1839 for (;;)
1841 IBaseFilter *async_filter = NULL;
1843 hr = S_OK;
1845 EnterCriticalSection(&graph->cs);
1847 if (!graph->needs_async_run)
1848 break;
1850 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1852 hr = IBaseFilter_GetState(filter->filter, 0, &state);
1854 if (hr == VFW_S_STATE_INTERMEDIATE)
1855 async_filter = filter->filter;
1857 if (SUCCEEDED(hr) && state != State_Paused)
1858 ERR("Filter %p reported incorrect state %u.\n", filter->filter, state);
1860 if (hr != S_OK)
1861 break;
1864 if (hr != VFW_S_STATE_INTERMEDIATE)
1865 break;
1867 LeaveCriticalSection(&graph->cs);
1869 IBaseFilter_GetState(async_filter, 10, &state);
1872 if (hr == S_OK && graph->needs_async_run)
1874 sort_filters(graph);
1875 graph_start(graph, 0);
1876 graph->needs_async_run = 0;
1879 LeaveCriticalSection(&graph->cs);
1882 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
1884 struct filter_graph *graph = impl_from_IMediaControl(iface);
1885 BOOL need_async_run = TRUE;
1886 struct filter *filter;
1887 FILTER_STATE state;
1888 HRESULT hr = S_OK;
1890 TRACE("graph %p.\n", graph);
1892 EnterCriticalSection(&graph->cs);
1894 if (graph->state == State_Running)
1896 LeaveCriticalSection(&graph->cs);
1897 return S_OK;
1900 sort_filters(graph);
1902 EnterCriticalSection(&graph->event_cs);
1903 update_render_count(graph);
1904 LeaveCriticalSection(&graph->event_cs);
1906 if (graph->state == State_Stopped)
1908 if (graph->defaultclock && !graph->refClock)
1909 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
1911 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1913 HRESULT filter_hr = IBaseFilter_Pause(filter->filter);
1914 if (hr == S_OK)
1915 hr = filter_hr;
1916 TRACE("Filter %p returned %#lx.\n", filter->filter, filter_hr);
1918 /* If a filter returns VFW_S_CANT_CUE, we shouldn't wait for a
1919 * paused state. */
1920 filter_hr = IBaseFilter_GetState(filter->filter, 0, &state);
1921 if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE)
1922 need_async_run = FALSE;
1925 if (FAILED(hr))
1927 LeaveCriticalSection(&graph->cs);
1928 WARN("Failed to pause, hr %#lx.\n", hr);
1929 return hr;
1933 graph->state = State_Running;
1935 if (SUCCEEDED(hr))
1937 if (hr != S_OK && need_async_run)
1939 if (!graph->async_run_work)
1940 graph->async_run_work = CreateThreadpoolWork(async_run_cb, graph, NULL);
1941 graph->needs_async_run = 1;
1942 SubmitThreadpoolWork(graph->async_run_work);
1944 else
1946 graph_start(graph, 0);
1950 LeaveCriticalSection(&graph->cs);
1951 return hr;
1954 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
1956 struct filter_graph *graph = impl_from_IMediaControl(iface);
1958 TRACE("graph %p.\n", graph);
1960 return IMediaFilter_Pause(&graph->IMediaFilter_iface);
1963 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
1965 struct filter_graph *graph = impl_from_IMediaControl(iface);
1967 TRACE("graph %p.\n", graph);
1969 return IMediaFilter_Stop(&graph->IMediaFilter_iface);
1972 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG timeout, OAFilterState *state)
1974 struct filter_graph *graph = impl_from_IMediaControl(iface);
1976 TRACE("graph %p, timeout %ld, state %p.\n", graph, timeout, state);
1978 if (timeout < 0) timeout = INFINITE;
1980 return IMediaFilter_GetState(&graph->IMediaFilter_iface, timeout, (FILTER_STATE *)state);
1983 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
1985 struct filter_graph *This = impl_from_IMediaControl(iface);
1987 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strFilename), strFilename);
1989 return IFilterGraph2_RenderFile(&This->IFilterGraph2_iface, strFilename, NULL);
1992 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
1993 IDispatch **ppUnk)
1995 struct filter_graph *This = impl_from_IMediaControl(iface);
1997 FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
1999 return S_OK;
2002 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2004 struct filter_graph *This = impl_from_IMediaControl(iface);
2006 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2008 return S_OK;
2011 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2013 struct filter_graph *This = impl_from_IMediaControl(iface);
2015 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2017 return S_OK;
2020 static void CALLBACK wait_pause_cb(TP_CALLBACK_INSTANCE *instance, void *context)
2022 IMediaControl *control = context;
2023 OAFilterState state;
2024 HRESULT hr;
2026 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
2027 ERR("Failed to get paused state, hr %#lx.\n", hr);
2029 if (FAILED(hr = IMediaControl_Stop(control)))
2030 ERR("Failed to stop, hr %#lx.\n", hr);
2032 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
2033 ERR("Failed to get paused state, hr %#lx.\n", hr);
2035 IMediaControl_Release(control);
2038 static void CALLBACK wait_stop_cb(TP_CALLBACK_INSTANCE *instance, void *context)
2040 IMediaControl *control = context;
2041 OAFilterState state;
2042 HRESULT hr;
2044 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
2045 ERR("Failed to get state, hr %#lx.\n", hr);
2047 IMediaControl_Release(control);
2050 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2052 struct filter_graph *graph = impl_from_IMediaControl(iface);
2053 HRESULT hr;
2055 TRACE("graph %p.\n", graph);
2057 /* Even if we are already stopped, we still pause. */
2058 hr = IMediaControl_Pause(iface);
2059 if (FAILED(hr))
2060 return hr;
2061 else if (hr == S_FALSE)
2063 IMediaControl_AddRef(iface);
2064 TrySubmitThreadpoolCallback(wait_pause_cb, iface, NULL);
2065 return S_FALSE;
2068 hr = IMediaControl_Stop(iface);
2069 if (FAILED(hr))
2070 return hr;
2071 else if (hr == S_FALSE)
2073 IMediaControl_AddRef(iface);
2074 TrySubmitThreadpoolCallback(wait_stop_cb, iface, NULL);
2075 return S_FALSE;
2078 return S_OK;
2082 static const IMediaControlVtbl IMediaControl_VTable =
2084 MediaControl_QueryInterface,
2085 MediaControl_AddRef,
2086 MediaControl_Release,
2087 MediaControl_GetTypeInfoCount,
2088 MediaControl_GetTypeInfo,
2089 MediaControl_GetIDsOfNames,
2090 MediaControl_Invoke,
2091 MediaControl_Run,
2092 MediaControl_Pause,
2093 MediaControl_Stop,
2094 MediaControl_GetState,
2095 MediaControl_RenderFile,
2096 MediaControl_AddSourceFilter,
2097 MediaControl_get_FilterCollection,
2098 MediaControl_get_RegFilterCollection,
2099 MediaControl_StopWhenReady
2102 static struct filter_graph *impl_from_IMediaSeeking(IMediaSeeking *iface)
2104 return CONTAINING_RECORD(iface, struct filter_graph, IMediaSeeking_iface);
2107 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface, REFIID iid, void **out)
2109 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2110 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2113 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
2115 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2116 return IUnknown_AddRef(graph->outer_unk);
2119 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
2121 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2122 return IUnknown_Release(graph->outer_unk);
2125 typedef HRESULT (WINAPI *fnFoundSeek)(struct filter_graph *This, IMediaSeeking*, DWORD_PTR arg);
2127 static HRESULT all_renderers_seek(struct filter_graph *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2128 BOOL allnotimpl = TRUE;
2129 HRESULT hr, hr_return = S_OK;
2130 struct filter *filter;
2132 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
2134 update_seeking(filter);
2135 if (!filter->seeking)
2136 continue;
2137 hr = FoundSeek(This, filter->seeking, arg);
2138 if (hr_return != E_NOTIMPL)
2139 allnotimpl = FALSE;
2140 if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2141 hr_return = hr;
2144 if (allnotimpl)
2145 return E_NOTIMPL;
2146 return hr_return;
2149 static HRESULT WINAPI FoundCapabilities(struct filter_graph *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2151 HRESULT hr;
2152 DWORD caps = 0;
2154 hr = IMediaSeeking_GetCapabilities(seek, &caps);
2155 if (FAILED(hr))
2156 return hr;
2158 /* Only add common capabilities everything supports */
2159 *(DWORD*)pcaps &= caps;
2161 return hr;
2164 /*** IMediaSeeking methods ***/
2165 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2167 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2168 HRESULT hr;
2170 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2172 if (!pCapabilities)
2173 return E_POINTER;
2175 EnterCriticalSection(&This->cs);
2176 *pCapabilities = 0xffffffff;
2178 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2179 LeaveCriticalSection(&This->cs);
2181 return hr;
2184 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2186 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2187 DWORD originalcaps;
2188 HRESULT hr;
2190 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2192 if (!pCapabilities)
2193 return E_POINTER;
2195 EnterCriticalSection(&This->cs);
2196 originalcaps = *pCapabilities;
2197 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2198 LeaveCriticalSection(&This->cs);
2200 if (FAILED(hr))
2201 return hr;
2203 if (!*pCapabilities)
2204 return E_FAIL;
2205 if (*pCapabilities != originalcaps)
2206 return S_FALSE;
2207 return S_OK;
2210 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface, const GUID *pFormat)
2212 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2214 if (!pFormat)
2215 return E_POINTER;
2217 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2219 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2221 WARN("Unhandled time format %s\n", debugstr_guid(pFormat));
2222 return S_FALSE;
2225 return S_OK;
2228 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *pFormat)
2230 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2232 if (!pFormat)
2233 return E_POINTER;
2235 FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2236 memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2238 return S_OK;
2241 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface, GUID *pFormat)
2243 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2245 if (!pFormat)
2246 return E_POINTER;
2248 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2249 memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2251 return S_OK;
2254 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2256 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2258 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2259 if (!pFormat)
2260 return E_POINTER;
2262 if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2263 return S_FALSE;
2265 return S_OK;
2268 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2270 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2272 if (!pFormat)
2273 return E_POINTER;
2275 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2277 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2279 FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2280 return E_INVALIDARG;
2283 return S_OK;
2286 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface, LONGLONG *duration)
2288 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2289 HRESULT hr = E_NOTIMPL, filter_hr;
2290 LONGLONG filter_duration;
2291 struct filter *filter;
2293 TRACE("graph %p, duration %p.\n", graph, duration);
2295 if (!duration)
2296 return E_POINTER;
2298 *duration = 0;
2300 EnterCriticalSection(&graph->cs);
2302 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2304 update_seeking(filter);
2305 if (!filter->seeking)
2306 continue;
2308 filter_hr = IMediaSeeking_GetDuration(filter->seeking, &filter_duration);
2309 if (SUCCEEDED(filter_hr))
2311 hr = S_OK;
2312 *duration = max(*duration, filter_duration);
2314 else if (filter_hr != E_NOTIMPL)
2316 LeaveCriticalSection(&graph->cs);
2317 return filter_hr;
2321 LeaveCriticalSection(&graph->cs);
2323 TRACE("Returning hr %#lx, duration %s (%s seconds).\n", hr,
2324 wine_dbgstr_longlong(*duration), debugstr_time(*duration));
2325 return hr;
2328 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *stop)
2330 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2331 HRESULT hr = E_NOTIMPL, filter_hr;
2332 struct filter *filter;
2333 LONGLONG filter_stop;
2335 TRACE("graph %p, stop %p.\n", graph, stop);
2337 if (!stop)
2338 return E_POINTER;
2340 *stop = 0;
2342 EnterCriticalSection(&graph->cs);
2344 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2346 update_seeking(filter);
2347 if (!filter->seeking)
2348 continue;
2350 filter_hr = IMediaSeeking_GetStopPosition(filter->seeking, &filter_stop);
2351 if (SUCCEEDED(filter_hr))
2353 hr = S_OK;
2354 *stop = max(*stop, filter_stop);
2356 else if (filter_hr != E_NOTIMPL)
2358 LeaveCriticalSection(&graph->cs);
2359 return filter_hr;
2363 LeaveCriticalSection(&graph->cs);
2365 TRACE("Returning %s (%s seconds).\n", wine_dbgstr_longlong(*stop), debugstr_time(*stop));
2366 return hr;
2369 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *current)
2371 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2372 LONGLONG ret = graph->current_pos;
2374 TRACE("graph %p, current %p.\n", graph, current);
2376 if (!current)
2377 return E_POINTER;
2379 EnterCriticalSection(&graph->cs);
2381 if (graph->got_ec_complete)
2383 ret = graph->stream_stop;
2385 else if (graph->state == State_Running && !graph->needs_async_run && graph->refClock)
2387 REFERENCE_TIME time;
2388 IReferenceClock_GetTime(graph->refClock, &time);
2389 if (time)
2390 ret += time - graph->stream_start;
2393 LeaveCriticalSection(&graph->cs);
2395 TRACE("Returning %s (%s seconds).\n", wine_dbgstr_longlong(ret), debugstr_time(ret));
2396 *current = ret;
2398 return S_OK;
2401 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
2402 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2404 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2406 TRACE("(%p/%p)->(%p, %s, 0x%s, %s)\n", This, iface, pTarget,
2407 debugstr_guid(pTargetFormat), wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
2409 if (!pSourceFormat)
2410 pSourceFormat = &This->timeformatseek;
2412 if (!pTargetFormat)
2413 pTargetFormat = &This->timeformatseek;
2415 if (IsEqualGUID(pTargetFormat, pSourceFormat))
2416 *pTarget = Source;
2417 else
2418 FIXME("conversion %s->%s not supported\n", debugstr_guid(pSourceFormat), debugstr_guid(pTargetFormat));
2420 return S_OK;
2423 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *current_ptr,
2424 DWORD current_flags, LONGLONG *stop_ptr, DWORD stop_flags)
2426 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2427 HRESULT hr = E_NOTIMPL, filter_hr;
2428 struct filter *filter;
2429 FILTER_STATE state;
2431 TRACE("graph %p, current %s, current_flags %#lx, stop %s, stop_flags %#lx.\n", graph,
2432 current_ptr ? wine_dbgstr_longlong(*current_ptr) : "<null>", current_flags,
2433 stop_ptr ? wine_dbgstr_longlong(*stop_ptr): "<null>", stop_flags);
2434 if (current_ptr)
2435 TRACE("Setting current position to %s (%s seconds).\n",
2436 wine_dbgstr_longlong(*current_ptr), debugstr_time(*current_ptr));
2437 if (stop_ptr)
2438 TRACE("Setting stop position to %s (%s seconds).\n",
2439 wine_dbgstr_longlong(*stop_ptr), debugstr_time(*stop_ptr));
2441 if ((current_flags & 0x7) != AM_SEEKING_AbsolutePositioning
2442 && (current_flags & 0x7) != AM_SEEKING_NoPositioning)
2443 FIXME("Unhandled current_flags %#lx.\n", current_flags & 0x7);
2445 if ((stop_flags & 0x7) != AM_SEEKING_NoPositioning
2446 && (stop_flags & 0x7) != AM_SEEKING_AbsolutePositioning)
2447 FIXME("Unhandled stop_flags %#lx.\n", stop_flags & 0x7);
2449 EnterCriticalSection(&graph->cs);
2451 state = graph->state;
2452 if (state == State_Running && !graph->needs_async_run)
2453 IMediaControl_Pause(&graph->IMediaControl_iface);
2455 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2457 LONGLONG current = current_ptr ? *current_ptr : 0, stop = stop_ptr ? *stop_ptr : 0;
2459 update_seeking(filter);
2460 if (!filter->seeking)
2461 continue;
2463 filter_hr = IMediaSeeking_SetPositions(filter->seeking, &current,
2464 current_flags | AM_SEEKING_ReturnTime, &stop, stop_flags);
2465 if (SUCCEEDED(filter_hr))
2467 hr = S_OK;
2469 if (current_ptr && (current_flags & AM_SEEKING_ReturnTime))
2470 *current_ptr = current;
2471 if (stop_ptr && (stop_flags & AM_SEEKING_ReturnTime))
2472 *stop_ptr = stop;
2473 graph->current_pos = current;
2475 else if (filter_hr != E_NOTIMPL)
2477 LeaveCriticalSection(&graph->cs);
2478 return filter_hr;
2482 if ((current_flags & 0x7) != AM_SEEKING_NoPositioning && graph->refClock)
2484 IReferenceClock_GetTime(graph->refClock, &graph->stream_start);
2485 graph->stream_elapsed = 0;
2488 if (state == State_Running && !graph->needs_async_run)
2489 IMediaControl_Run(&graph->IMediaControl_iface);
2491 LeaveCriticalSection(&graph->cs);
2492 return hr;
2495 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
2496 LONGLONG *current, LONGLONG *stop)
2498 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2499 HRESULT hr = S_OK;
2501 TRACE("graph %p, current %p, stop %p.\n", graph, current, stop);
2503 if (current)
2504 hr = IMediaSeeking_GetCurrentPosition(iface, current);
2505 if (SUCCEEDED(hr) && stop)
2506 hr = IMediaSeeking_GetStopPosition(iface, stop);
2508 return hr;
2511 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, LONGLONG *pEarliest,
2512 LONGLONG *pLatest)
2514 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2516 FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2518 return S_OK;
2521 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2523 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2525 FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2527 return S_OK;
2530 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2532 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2534 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2536 if (!pdRate)
2537 return E_POINTER;
2539 *pdRate = 1.0;
2541 return S_OK;
2544 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
2546 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2548 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2550 return S_OK;
2554 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2556 MediaSeeking_QueryInterface,
2557 MediaSeeking_AddRef,
2558 MediaSeeking_Release,
2559 MediaSeeking_GetCapabilities,
2560 MediaSeeking_CheckCapabilities,
2561 MediaSeeking_IsFormatSupported,
2562 MediaSeeking_QueryPreferredFormat,
2563 MediaSeeking_GetTimeFormat,
2564 MediaSeeking_IsUsingTimeFormat,
2565 MediaSeeking_SetTimeFormat,
2566 MediaSeeking_GetDuration,
2567 MediaSeeking_GetStopPosition,
2568 MediaSeeking_GetCurrentPosition,
2569 MediaSeeking_ConvertTimeFormat,
2570 MediaSeeking_SetPositions,
2571 MediaSeeking_GetPositions,
2572 MediaSeeking_GetAvailable,
2573 MediaSeeking_SetRate,
2574 MediaSeeking_GetRate,
2575 MediaSeeking_GetPreroll
2578 static struct filter_graph *impl_from_IMediaPosition(IMediaPosition *iface)
2580 return CONTAINING_RECORD(iface, struct filter_graph, IMediaPosition_iface);
2583 /*** IUnknown methods ***/
2584 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition *iface, REFIID iid, void **out)
2586 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2587 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2590 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2592 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2593 return IUnknown_AddRef(graph->outer_unk);
2596 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2598 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2599 return IUnknown_Release(graph->outer_unk);
2602 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT *count)
2604 TRACE("iface %p, count %p.\n", iface, count);
2605 *count = 1;
2606 return S_OK;
2609 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT index,
2610 LCID lcid, ITypeInfo **typeinfo)
2612 TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo);
2613 return strmbase_get_typeinfo(IMediaPosition_tid, typeinfo);
2616 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition *iface, REFIID iid,
2617 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
2619 ITypeInfo *typeinfo;
2620 HRESULT hr;
2622 TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n",
2623 iface, debugstr_guid(iid), names, count, lcid, ids);
2625 if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaPosition_tid, &typeinfo)))
2627 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
2628 ITypeInfo_Release(typeinfo);
2630 return hr;
2633 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition *iface, DISPID id, REFIID iid, LCID lcid,
2634 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
2636 ITypeInfo *typeinfo;
2637 HRESULT hr;
2639 TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
2640 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
2642 if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaPosition_tid, &typeinfo)))
2644 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
2645 ITypeInfo_Release(typeinfo);
2647 return hr;
2650 static HRESULT ConvertFromREFTIME(IMediaSeeking *seek, REFTIME time_in, LONGLONG *time_out)
2652 GUID time_format;
2653 HRESULT hr;
2655 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2656 if (FAILED(hr))
2657 return hr;
2658 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2660 FIXME("Unsupported time format.\n");
2661 return E_NOTIMPL;
2664 *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2665 return S_OK;
2668 static HRESULT ConvertToREFTIME(IMediaSeeking *seek, LONGLONG time_in, REFTIME *time_out)
2670 GUID time_format;
2671 HRESULT hr;
2673 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2674 if (FAILED(hr))
2675 return hr;
2676 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2678 FIXME("Unsupported time format.\n");
2679 return E_NOTIMPL;
2682 *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2683 return S_OK;
2686 /*** IMediaPosition methods ***/
2687 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2689 LONGLONG duration;
2690 struct filter_graph *This = impl_from_IMediaPosition( iface );
2691 HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2692 if (FAILED(hr))
2693 return hr;
2694 return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2697 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2699 struct filter_graph *This = impl_from_IMediaPosition( iface );
2700 LONGLONG reftime;
2701 HRESULT hr;
2703 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2704 if (FAILED(hr))
2705 return hr;
2706 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2707 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
2710 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2712 struct filter_graph *This = impl_from_IMediaPosition( iface );
2713 LONGLONG pos;
2714 HRESULT hr;
2716 hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2717 if (FAILED(hr))
2718 return hr;
2719 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2722 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2724 struct filter_graph *This = impl_from_IMediaPosition( iface );
2725 LONGLONG pos;
2726 HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2727 if (FAILED(hr))
2728 return hr;
2729 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2732 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2734 struct filter_graph *This = impl_from_IMediaPosition( iface );
2735 LONGLONG reftime;
2736 HRESULT hr;
2738 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2739 if (FAILED(hr))
2740 return hr;
2741 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2742 &reftime, AM_SEEKING_AbsolutePositioning);
2745 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime)
2747 FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2748 return E_NOTIMPL;
2751 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime)
2753 FIXME("(%p)->(%f) stub!\n", iface, llTime);
2754 return E_NOTIMPL;
2757 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2759 struct filter_graph *This = impl_from_IMediaPosition( iface );
2760 return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2763 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2765 struct filter_graph *This = impl_from_IMediaPosition( iface );
2766 return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2769 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward)
2771 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2772 return E_NOTIMPL;
2775 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward)
2777 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2778 return E_NOTIMPL;
2782 static const IMediaPositionVtbl IMediaPosition_VTable =
2784 MediaPosition_QueryInterface,
2785 MediaPosition_AddRef,
2786 MediaPosition_Release,
2787 MediaPosition_GetTypeInfoCount,
2788 MediaPosition_GetTypeInfo,
2789 MediaPosition_GetIDsOfNames,
2790 MediaPosition_Invoke,
2791 MediaPosition_get_Duration,
2792 MediaPosition_put_CurrentPosition,
2793 MediaPosition_get_CurrentPosition,
2794 MediaPosition_get_StopTime,
2795 MediaPosition_put_StopTime,
2796 MediaPosition_get_PrerollTime,
2797 MediaPosition_put_PrerollTime,
2798 MediaPosition_put_Rate,
2799 MediaPosition_get_Rate,
2800 MediaPosition_CanSeekForward,
2801 MediaPosition_CanSeekBackward
2804 static struct filter_graph *impl_from_IObjectWithSite(IObjectWithSite *iface)
2806 return CONTAINING_RECORD(iface, struct filter_graph, IObjectWithSite_iface);
2809 /*** IUnknown methods ***/
2810 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID iid, void **out)
2812 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2813 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2816 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
2818 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2819 return IUnknown_AddRef(graph->outer_unk);
2822 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
2824 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2825 return IUnknown_Release(graph->outer_unk);
2828 /*** IObjectWithSite methods ***/
2830 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
2832 struct filter_graph *This = impl_from_IObjectWithSite( iface );
2834 TRACE("(%p/%p)->()\n", This, iface);
2835 if (This->pSite) IUnknown_Release(This->pSite);
2836 This->pSite = pUnkSite;
2837 IUnknown_AddRef(This->pSite);
2838 return S_OK;
2841 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, PVOID *ppvSite)
2843 struct filter_graph *This = impl_from_IObjectWithSite( iface );
2845 TRACE("(%p/%p)->(%s)\n", This, iface,debugstr_guid(riid));
2847 *ppvSite = NULL;
2848 if (!This->pSite)
2849 return E_FAIL;
2850 else
2851 return IUnknown_QueryInterface(This->pSite, riid, ppvSite);
2854 static const IObjectWithSiteVtbl IObjectWithSite_VTable =
2856 ObjectWithSite_QueryInterface,
2857 ObjectWithSite_AddRef,
2858 ObjectWithSite_Release,
2859 ObjectWithSite_SetSite,
2860 ObjectWithSite_GetSite,
2863 static HRESULT GetTargetInterface(struct filter_graph* pGraph, REFIID riid, LPVOID* ppvObj)
2865 struct filter *filter;
2866 HRESULT hr;
2867 int entry;
2869 /* Check if the interface type is already registered */
2870 for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2871 if (riid == pGraph->ItfCacheEntries[entry].riid)
2873 if (pGraph->ItfCacheEntries[entry].iface)
2875 /* Return the interface if available */
2876 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2877 return S_OK;
2879 break;
2882 if (entry >= MAX_ITF_CACHE_ENTRIES)
2884 FIXME("Not enough space to store interface in the cache\n");
2885 return E_OUTOFMEMORY;
2888 /* Find a filter supporting the requested interface */
2889 LIST_FOR_EACH_ENTRY(filter, &pGraph->filters, struct filter, entry)
2891 hr = IBaseFilter_QueryInterface(filter->filter, riid, ppvObj);
2892 if (hr == S_OK)
2894 pGraph->ItfCacheEntries[entry].riid = riid;
2895 pGraph->ItfCacheEntries[entry].filter = filter->filter;
2896 pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2897 if (entry >= pGraph->nItfCacheEntries)
2898 pGraph->nItfCacheEntries++;
2899 return S_OK;
2901 if (hr != E_NOINTERFACE)
2902 return hr;
2905 return IsEqualGUID(riid, &IID_IBasicAudio) ? E_NOTIMPL : E_NOINTERFACE;
2908 static struct filter_graph *impl_from_IBasicAudio(IBasicAudio *iface)
2910 return CONTAINING_RECORD(iface, struct filter_graph, IBasicAudio_iface);
2913 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID iid, void **out)
2915 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2916 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2919 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
2921 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2922 return IUnknown_AddRef(graph->outer_unk);
2925 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
2927 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2928 return IUnknown_Release(graph->outer_unk);
2931 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *count)
2933 TRACE("iface %p, count %p.\n", iface, count);
2934 *count = 1;
2935 return S_OK;
2938 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface, UINT index,
2939 LCID lcid, ITypeInfo **typeinfo)
2941 TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo);
2942 return strmbase_get_typeinfo(IBasicAudio_tid, typeinfo);
2945 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface, REFIID iid,
2946 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
2948 ITypeInfo *typeinfo;
2949 HRESULT hr;
2951 TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n",
2952 iface, debugstr_guid(iid), names, count, lcid, ids);
2954 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo)))
2956 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
2957 ITypeInfo_Release(typeinfo);
2959 return hr;
2962 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface, DISPID id, REFIID iid, LCID lcid,
2963 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
2965 ITypeInfo *typeinfo;
2966 HRESULT hr;
2968 TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
2969 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
2971 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo)))
2973 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
2974 ITypeInfo_Release(typeinfo);
2976 return hr;
2979 /*** IBasicAudio methods ***/
2980 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface, LONG lVolume)
2982 struct filter_graph *This = impl_from_IBasicAudio(iface);
2983 IBasicAudio* pBasicAudio;
2984 HRESULT hr;
2986 TRACE("graph %p, volume %ld.\n", This, lVolume);
2988 EnterCriticalSection(&This->cs);
2990 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2992 if (hr == S_OK)
2993 hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2995 LeaveCriticalSection(&This->cs);
2997 return hr;
3000 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface, LONG *plVolume)
3002 struct filter_graph *This = impl_from_IBasicAudio(iface);
3003 IBasicAudio* pBasicAudio;
3004 HRESULT hr;
3006 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
3008 EnterCriticalSection(&This->cs);
3010 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3012 if (hr == S_OK)
3013 hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
3015 LeaveCriticalSection(&This->cs);
3017 return hr;
3020 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface, LONG lBalance)
3022 struct filter_graph *This = impl_from_IBasicAudio(iface);
3023 IBasicAudio* pBasicAudio;
3024 HRESULT hr;
3026 TRACE("graph %p, balance %ld.\n", This, lBalance);
3028 EnterCriticalSection(&This->cs);
3030 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3032 if (hr == S_OK)
3033 hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
3035 LeaveCriticalSection(&This->cs);
3037 return hr;
3040 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface, LONG *plBalance)
3042 struct filter_graph *This = impl_from_IBasicAudio(iface);
3043 IBasicAudio* pBasicAudio;
3044 HRESULT hr;
3046 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
3048 EnterCriticalSection(&This->cs);
3050 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3052 if (hr == S_OK)
3053 hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
3055 LeaveCriticalSection(&This->cs);
3057 return hr;
3060 static const IBasicAudioVtbl IBasicAudio_VTable =
3062 BasicAudio_QueryInterface,
3063 BasicAudio_AddRef,
3064 BasicAudio_Release,
3065 BasicAudio_GetTypeInfoCount,
3066 BasicAudio_GetTypeInfo,
3067 BasicAudio_GetIDsOfNames,
3068 BasicAudio_Invoke,
3069 BasicAudio_put_Volume,
3070 BasicAudio_get_Volume,
3071 BasicAudio_put_Balance,
3072 BasicAudio_get_Balance
3075 static struct filter_graph *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3077 return CONTAINING_RECORD(iface, struct filter_graph, IBasicVideo2_iface);
3080 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface, REFIID iid, void **out)
3082 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3083 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
3086 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface)
3088 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3089 return IUnknown_AddRef(graph->outer_unk);
3092 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface)
3094 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3095 return IUnknown_Release(graph->outer_unk);
3098 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface, UINT *count)
3100 TRACE("iface %p, count %p.\n", iface, count);
3101 *count = 1;
3102 return S_OK;
3105 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface, UINT index,
3106 LCID lcid, ITypeInfo **typeinfo)
3108 TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo);
3109 return strmbase_get_typeinfo(IBasicVideo_tid, typeinfo);
3112 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface, REFIID iid,
3113 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
3115 ITypeInfo *typeinfo;
3116 HRESULT hr;
3118 TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n",
3119 iface, debugstr_guid(iid), names, count, lcid, ids);
3121 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo)))
3123 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
3124 ITypeInfo_Release(typeinfo);
3126 return hr;
3129 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface, DISPID id, REFIID iid, LCID lcid,
3130 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
3132 ITypeInfo *typeinfo;
3133 HRESULT hr;
3135 TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
3136 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
3138 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo)))
3140 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
3141 ITypeInfo_Release(typeinfo);
3143 return hr;
3146 /*** IBasicVideo methods ***/
3147 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface, REFTIME *pAvgTimePerFrame)
3149 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3150 IBasicVideo *pBasicVideo;
3151 HRESULT hr;
3153 TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3155 EnterCriticalSection(&This->cs);
3157 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3159 if (hr == S_OK)
3160 hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3162 LeaveCriticalSection(&This->cs);
3164 return hr;
3167 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface, LONG *pBitRate)
3169 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3170 IBasicVideo *pBasicVideo;
3171 HRESULT hr;
3173 TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3175 EnterCriticalSection(&This->cs);
3177 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3179 if (hr == S_OK)
3180 hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3182 LeaveCriticalSection(&This->cs);
3184 return hr;
3187 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface, LONG *pBitErrorRate)
3189 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3190 IBasicVideo *pBasicVideo;
3191 HRESULT hr;
3193 TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3195 EnterCriticalSection(&This->cs);
3197 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3199 if (hr == S_OK)
3200 hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3202 LeaveCriticalSection(&This->cs);
3204 return hr;
3207 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface, LONG *pVideoWidth)
3209 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3210 IBasicVideo *pBasicVideo;
3211 HRESULT hr;
3213 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3215 EnterCriticalSection(&This->cs);
3217 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3219 if (hr == S_OK)
3220 hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3222 LeaveCriticalSection(&This->cs);
3224 return hr;
3227 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface, LONG *pVideoHeight)
3229 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3230 IBasicVideo *pBasicVideo;
3231 HRESULT hr;
3233 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3235 EnterCriticalSection(&This->cs);
3237 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3239 if (hr == S_OK)
3240 hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3242 LeaveCriticalSection(&This->cs);
3244 return hr;
3247 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface, LONG SourceLeft)
3249 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3250 IBasicVideo *pBasicVideo;
3251 HRESULT hr;
3253 TRACE("graph %p, left %ld.\n", This, SourceLeft);
3255 EnterCriticalSection(&This->cs);
3257 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3259 if (hr == S_OK)
3260 hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3262 LeaveCriticalSection(&This->cs);
3264 return hr;
3267 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface, LONG *pSourceLeft)
3269 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3270 IBasicVideo *pBasicVideo;
3271 HRESULT hr;
3273 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3275 EnterCriticalSection(&This->cs);
3277 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3279 if (hr == S_OK)
3280 hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3282 LeaveCriticalSection(&This->cs);
3284 return hr;
3287 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface, LONG SourceWidth)
3289 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3290 IBasicVideo *pBasicVideo;
3291 HRESULT hr;
3293 TRACE("graph %p, width %ld.\n", This, SourceWidth);
3295 EnterCriticalSection(&This->cs);
3297 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3299 if (hr == S_OK)
3300 hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3302 LeaveCriticalSection(&This->cs);
3304 return hr;
3307 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface, LONG *pSourceWidth)
3309 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3310 IBasicVideo *pBasicVideo;
3311 HRESULT hr;
3313 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3315 EnterCriticalSection(&This->cs);
3317 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3319 if (hr == S_OK)
3320 hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3322 LeaveCriticalSection(&This->cs);
3324 return hr;
3327 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface, LONG SourceTop)
3329 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3330 IBasicVideo *pBasicVideo;
3331 HRESULT hr;
3333 TRACE("graph %p, top %ld.\n", This, SourceTop);
3335 EnterCriticalSection(&This->cs);
3337 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3339 if (hr == S_OK)
3340 hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3342 LeaveCriticalSection(&This->cs);
3344 return hr;
3347 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface, LONG *pSourceTop)
3349 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3350 IBasicVideo *pBasicVideo;
3351 HRESULT hr;
3353 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3355 EnterCriticalSection(&This->cs);
3357 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3359 if (hr == S_OK)
3360 hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3362 LeaveCriticalSection(&This->cs);
3364 return hr;
3367 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface, LONG SourceHeight)
3369 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3370 IBasicVideo *pBasicVideo;
3371 HRESULT hr;
3373 TRACE("graph %p, height %ld.\n", This, SourceHeight);
3375 EnterCriticalSection(&This->cs);
3377 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3379 if (hr == S_OK)
3380 hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3382 LeaveCriticalSection(&This->cs);
3384 return hr;
3387 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface, LONG *pSourceHeight)
3389 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3390 IBasicVideo *pBasicVideo;
3391 HRESULT hr;
3393 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3395 EnterCriticalSection(&This->cs);
3397 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3399 if (hr == S_OK)
3400 hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3402 LeaveCriticalSection(&This->cs);
3404 return hr;
3407 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface, LONG DestinationLeft)
3409 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3410 IBasicVideo *pBasicVideo;
3411 HRESULT hr;
3413 TRACE("graph %p, left %ld.\n", This, DestinationLeft);
3415 EnterCriticalSection(&This->cs);
3417 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3419 if (hr == S_OK)
3420 hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3422 LeaveCriticalSection(&This->cs);
3424 return hr;
3427 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface, LONG *pDestinationLeft)
3429 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3430 IBasicVideo *pBasicVideo;
3431 HRESULT hr;
3433 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3435 EnterCriticalSection(&This->cs);
3437 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3439 if (hr == S_OK)
3440 hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3442 LeaveCriticalSection(&This->cs);
3444 return hr;
3447 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface, LONG DestinationWidth)
3449 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3450 IBasicVideo *pBasicVideo;
3451 HRESULT hr;
3453 TRACE("graph %p, width %ld.\n", This, DestinationWidth);
3455 EnterCriticalSection(&This->cs);
3457 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3459 if (hr == S_OK)
3460 hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3462 LeaveCriticalSection(&This->cs);
3464 return hr;
3467 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface, LONG *pDestinationWidth)
3469 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3470 IBasicVideo *pBasicVideo;
3471 HRESULT hr;
3473 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3475 EnterCriticalSection(&This->cs);
3477 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3479 if (hr == S_OK)
3480 hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3482 LeaveCriticalSection(&This->cs);
3484 return hr;
3487 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface, LONG DestinationTop)
3489 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3490 IBasicVideo *pBasicVideo;
3491 HRESULT hr;
3493 TRACE("graph %p, top %ld.\n", This, DestinationTop);
3495 EnterCriticalSection(&This->cs);
3497 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3499 if (hr == S_OK)
3500 hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3502 LeaveCriticalSection(&This->cs);
3504 return hr;
3507 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface, LONG *pDestinationTop)
3509 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3510 IBasicVideo *pBasicVideo;
3511 HRESULT hr;
3513 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3515 EnterCriticalSection(&This->cs);
3517 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3519 if (hr == S_OK)
3520 hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3522 LeaveCriticalSection(&This->cs);
3524 return hr;
3527 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface, LONG DestinationHeight)
3529 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3530 IBasicVideo *pBasicVideo;
3531 HRESULT hr;
3533 TRACE("graph %p, height %ld.\n", This, DestinationHeight);
3535 EnterCriticalSection(&This->cs);
3537 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3539 if (hr == S_OK)
3540 hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3542 LeaveCriticalSection(&This->cs);
3544 return hr;
3547 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3548 LONG *pDestinationHeight)
3550 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3551 IBasicVideo *pBasicVideo;
3552 HRESULT hr;
3554 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3556 EnterCriticalSection(&This->cs);
3558 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3560 if (hr == S_OK)
3561 hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3563 LeaveCriticalSection(&This->cs);
3565 return hr;
3568 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3569 LONG Width, LONG Height)
3571 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3572 IBasicVideo *pBasicVideo;
3573 HRESULT hr;
3575 TRACE("graph %p, left %ld, top %ld, width %ld, height %ld.\n", This, Left, Top, Width, Height);
3577 EnterCriticalSection(&This->cs);
3579 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3581 if (hr == S_OK)
3582 hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3584 LeaveCriticalSection(&This->cs);
3586 return hr;
3589 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface, LONG *pLeft, LONG *pTop,
3590 LONG *pWidth, LONG *pHeight)
3592 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3593 IBasicVideo *pBasicVideo;
3594 HRESULT hr;
3596 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3598 EnterCriticalSection(&This->cs);
3600 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3602 if (hr == S_OK)
3603 hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3605 LeaveCriticalSection(&This->cs);
3607 return hr;
3610 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface)
3612 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3613 IBasicVideo *pBasicVideo;
3614 HRESULT hr;
3616 TRACE("(%p/%p)->()\n", This, iface);
3618 EnterCriticalSection(&This->cs);
3620 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3622 if (hr == S_OK)
3623 hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3625 LeaveCriticalSection(&This->cs);
3627 return hr;
3630 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3631 LONG Width, LONG Height)
3633 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3634 IBasicVideo *pBasicVideo;
3635 HRESULT hr;
3637 TRACE("graph %p, left %ld, top %ld, width %ld, height %ld.\n", This, Left, Top, Width, Height);
3639 EnterCriticalSection(&This->cs);
3641 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3643 if (hr == S_OK)
3644 hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3646 LeaveCriticalSection(&This->cs);
3648 return hr;
3651 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface, LONG *pLeft,
3652 LONG *pTop, LONG *pWidth, LONG *pHeight)
3654 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3655 IBasicVideo *pBasicVideo;
3656 HRESULT hr;
3658 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3660 EnterCriticalSection(&This->cs);
3662 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3664 if (hr == S_OK)
3665 hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3667 LeaveCriticalSection(&This->cs);
3669 return hr;
3672 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface)
3674 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3675 IBasicVideo *pBasicVideo;
3676 HRESULT hr;
3678 TRACE("(%p/%p)->()\n", This, iface);
3680 EnterCriticalSection(&This->cs);
3682 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3684 if (hr == S_OK)
3685 hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3687 LeaveCriticalSection(&This->cs);
3689 return hr;
3692 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface, LONG *pWidth, LONG *pHeight)
3694 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3695 IBasicVideo *pBasicVideo;
3696 HRESULT hr;
3698 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3700 EnterCriticalSection(&This->cs);
3702 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3704 if (hr == S_OK)
3705 hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3707 LeaveCriticalSection(&This->cs);
3709 return hr;
3712 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface, LONG StartIndex,
3713 LONG Entries, LONG *pRetrieved, LONG *pPalette)
3715 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3716 IBasicVideo *pBasicVideo;
3717 HRESULT hr;
3719 TRACE("graph %p, start_index %ld, count %ld, ret_count %p, entries %p.\n",
3720 This, StartIndex, Entries, pRetrieved, pPalette);
3722 EnterCriticalSection(&This->cs);
3724 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3726 if (hr == S_OK)
3727 hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3729 LeaveCriticalSection(&This->cs);
3731 return hr;
3734 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface, LONG *pBufferSize,
3735 LONG *pDIBImage)
3737 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3738 IBasicVideo *pBasicVideo;
3739 HRESULT hr;
3741 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3743 EnterCriticalSection(&This->cs);
3745 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3747 if (hr == S_OK)
3748 hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3750 LeaveCriticalSection(&This->cs);
3752 return hr;
3755 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface)
3757 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3758 IBasicVideo *pBasicVideo;
3759 HRESULT hr;
3761 TRACE("(%p/%p)->()\n", This, iface);
3763 EnterCriticalSection(&This->cs);
3765 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3767 if (hr == S_OK)
3768 hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3770 LeaveCriticalSection(&This->cs);
3772 return hr;
3775 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface)
3777 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3778 IBasicVideo *pBasicVideo;
3779 HRESULT hr;
3781 TRACE("(%p/%p)->()\n", This, iface);
3783 EnterCriticalSection(&This->cs);
3785 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3787 if (hr == S_OK)
3788 hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3790 LeaveCriticalSection(&This->cs);
3792 return hr;
3795 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX,
3796 LONG *plAspectY)
3798 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3799 IBasicVideo2 *pBasicVideo2;
3800 HRESULT hr;
3802 TRACE("(%p/%p)->()\n", This, iface);
3804 EnterCriticalSection(&This->cs);
3806 hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3808 if (hr == S_OK)
3809 hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3811 LeaveCriticalSection(&This->cs);
3813 return hr;
3816 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3818 BasicVideo_QueryInterface,
3819 BasicVideo_AddRef,
3820 BasicVideo_Release,
3821 BasicVideo_GetTypeInfoCount,
3822 BasicVideo_GetTypeInfo,
3823 BasicVideo_GetIDsOfNames,
3824 BasicVideo_Invoke,
3825 BasicVideo_get_AvgTimePerFrame,
3826 BasicVideo_get_BitRate,
3827 BasicVideo_get_BitErrorRate,
3828 BasicVideo_get_VideoWidth,
3829 BasicVideo_get_VideoHeight,
3830 BasicVideo_put_SourceLeft,
3831 BasicVideo_get_SourceLeft,
3832 BasicVideo_put_SourceWidth,
3833 BasicVideo_get_SourceWidth,
3834 BasicVideo_put_SourceTop,
3835 BasicVideo_get_SourceTop,
3836 BasicVideo_put_SourceHeight,
3837 BasicVideo_get_SourceHeight,
3838 BasicVideo_put_DestinationLeft,
3839 BasicVideo_get_DestinationLeft,
3840 BasicVideo_put_DestinationWidth,
3841 BasicVideo_get_DestinationWidth,
3842 BasicVideo_put_DestinationTop,
3843 BasicVideo_get_DestinationTop,
3844 BasicVideo_put_DestinationHeight,
3845 BasicVideo_get_DestinationHeight,
3846 BasicVideo_SetSourcePosition,
3847 BasicVideo_GetSourcePosition,
3848 BasicVideo_SetDefaultSourcePosition,
3849 BasicVideo_SetDestinationPosition,
3850 BasicVideo_GetDestinationPosition,
3851 BasicVideo_SetDefaultDestinationPosition,
3852 BasicVideo_GetVideoSize,
3853 BasicVideo_GetVideoPaletteEntries,
3854 BasicVideo_GetCurrentImage,
3855 BasicVideo_IsUsingDefaultSource,
3856 BasicVideo_IsUsingDefaultDestination,
3857 BasicVideo2_GetPreferredAspectRatio
3860 static struct filter_graph *impl_from_IVideoWindow(IVideoWindow *iface)
3862 return CONTAINING_RECORD(iface, struct filter_graph, IVideoWindow_iface);
3865 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID iid, void **out)
3867 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3868 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
3871 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
3873 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3874 return IUnknown_AddRef(graph->outer_unk);
3877 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
3879 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3880 return IUnknown_Release(graph->outer_unk);
3883 HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface, UINT *count)
3885 TRACE("iface %p, count %p.\n", iface, count);
3886 *count = 1;
3887 return S_OK;
3890 HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface, UINT index,
3891 LCID lcid, ITypeInfo **typeinfo)
3893 TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo);
3894 return strmbase_get_typeinfo(IVideoWindow_tid, typeinfo);
3897 HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface, REFIID iid,
3898 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
3900 ITypeInfo *typeinfo;
3901 HRESULT hr;
3903 TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n",
3904 iface, debugstr_guid(iid), names, count, lcid, ids);
3906 if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo)))
3908 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
3909 ITypeInfo_Release(typeinfo);
3911 return hr;
3914 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface, DISPID id, REFIID iid, LCID lcid,
3915 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
3917 ITypeInfo *typeinfo;
3918 HRESULT hr;
3920 TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
3921 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
3923 if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo)))
3925 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
3926 ITypeInfo_Release(typeinfo);
3928 return hr;
3931 /*** IVideoWindow methods ***/
3932 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface, BSTR strCaption)
3934 struct filter_graph *This = impl_from_IVideoWindow(iface);
3935 IVideoWindow *pVideoWindow;
3936 HRESULT hr;
3938 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3940 EnterCriticalSection(&This->cs);
3942 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3944 if (hr == S_OK)
3945 hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3947 LeaveCriticalSection(&This->cs);
3949 return hr;
3952 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface, BSTR *strCaption)
3954 struct filter_graph *This = impl_from_IVideoWindow(iface);
3955 IVideoWindow *pVideoWindow;
3956 HRESULT hr;
3958 TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
3960 EnterCriticalSection(&This->cs);
3962 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3964 if (hr == S_OK)
3965 hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
3967 LeaveCriticalSection(&This->cs);
3969 return hr;
3972 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle)
3974 struct filter_graph *This = impl_from_IVideoWindow(iface);
3975 IVideoWindow *pVideoWindow;
3976 HRESULT hr;
3978 TRACE("graph %p, style %#lx.\n", This, WindowStyle);
3980 EnterCriticalSection(&This->cs);
3982 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3984 if (hr == S_OK)
3985 hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
3987 LeaveCriticalSection(&This->cs);
3989 return hr;
3992 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface, LONG *WindowStyle)
3994 struct filter_graph *This = impl_from_IVideoWindow(iface);
3995 IVideoWindow *pVideoWindow;
3996 HRESULT hr;
3998 TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
4000 EnterCriticalSection(&This->cs);
4002 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4004 if (hr == S_OK)
4005 hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
4007 LeaveCriticalSection(&This->cs);
4009 return hr;
4012 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx)
4014 struct filter_graph *This = impl_from_IVideoWindow(iface);
4015 IVideoWindow *pVideoWindow;
4016 HRESULT hr;
4018 TRACE("graph %p, style %#lx.\n", This, WindowStyleEx);
4020 EnterCriticalSection(&This->cs);
4022 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4024 if (hr == S_OK)
4025 hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
4027 LeaveCriticalSection(&This->cs);
4029 return hr;
4032 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx)
4034 struct filter_graph *This = impl_from_IVideoWindow(iface);
4035 IVideoWindow *pVideoWindow;
4036 HRESULT hr;
4038 TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
4040 EnterCriticalSection(&This->cs);
4042 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4044 if (hr == S_OK)
4045 hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
4047 LeaveCriticalSection(&This->cs);
4049 return hr;
4052 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow)
4054 struct filter_graph *This = impl_from_IVideoWindow(iface);
4055 IVideoWindow *pVideoWindow;
4056 HRESULT hr;
4058 TRACE("graph %p, show %#lx.\n", This, AutoShow);
4060 EnterCriticalSection(&This->cs);
4062 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4064 if (hr == S_OK)
4065 hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
4067 LeaveCriticalSection(&This->cs);
4069 return hr;
4072 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface, LONG *AutoShow)
4074 struct filter_graph *This = impl_from_IVideoWindow(iface);
4075 IVideoWindow *pVideoWindow;
4076 HRESULT hr;
4078 TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4080 EnterCriticalSection(&This->cs);
4082 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4084 if (hr == S_OK)
4085 hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4087 LeaveCriticalSection(&This->cs);
4089 return hr;
4092 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface, LONG WindowState)
4094 struct filter_graph *This = impl_from_IVideoWindow(iface);
4095 IVideoWindow *pVideoWindow;
4096 HRESULT hr;
4098 TRACE("graph %p, state %ld.\n", This, WindowState);
4100 EnterCriticalSection(&This->cs);
4102 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4104 if (hr == S_OK)
4105 hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4107 LeaveCriticalSection(&This->cs);
4109 return hr;
4112 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface, LONG *WindowState)
4114 struct filter_graph *This = impl_from_IVideoWindow(iface);
4115 IVideoWindow *pVideoWindow;
4116 HRESULT hr;
4118 TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4120 EnterCriticalSection(&This->cs);
4122 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4124 if (hr == S_OK)
4125 hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4127 LeaveCriticalSection(&This->cs);
4129 return hr;
4132 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette)
4134 struct filter_graph *This = impl_from_IVideoWindow(iface);
4135 IVideoWindow *pVideoWindow;
4136 HRESULT hr;
4138 TRACE("graph %p, palette %ld.\n", This, BackgroundPalette);
4140 EnterCriticalSection(&This->cs);
4142 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4144 if (hr == S_OK)
4145 hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4147 LeaveCriticalSection(&This->cs);
4149 return hr;
4152 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4153 LONG *pBackgroundPalette)
4155 struct filter_graph *This = impl_from_IVideoWindow(iface);
4156 IVideoWindow *pVideoWindow;
4157 HRESULT hr;
4159 TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4161 EnterCriticalSection(&This->cs);
4163 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4165 if (hr == S_OK)
4166 hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4168 LeaveCriticalSection(&This->cs);
4170 return hr;
4173 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface, LONG Visible)
4175 struct filter_graph *This = impl_from_IVideoWindow(iface);
4176 IVideoWindow *pVideoWindow;
4177 HRESULT hr;
4179 TRACE("graph %p, visible %ld.\n", This, Visible);
4181 EnterCriticalSection(&This->cs);
4183 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4185 if (hr == S_OK)
4186 hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4188 LeaveCriticalSection(&This->cs);
4190 return hr;
4193 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface, LONG *pVisible)
4195 struct filter_graph *This = impl_from_IVideoWindow(iface);
4196 IVideoWindow *pVideoWindow;
4197 HRESULT hr;
4199 TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4201 EnterCriticalSection(&This->cs);
4203 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4205 if (hr == S_OK)
4206 hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4208 LeaveCriticalSection(&This->cs);
4210 return hr;
4213 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface, LONG Left)
4215 struct filter_graph *This = impl_from_IVideoWindow(iface);
4216 IVideoWindow *pVideoWindow;
4217 HRESULT hr;
4219 TRACE("graph %p, left %ld.\n", This, Left);
4221 EnterCriticalSection(&This->cs);
4223 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4225 if (hr == S_OK)
4226 hr = IVideoWindow_put_Left(pVideoWindow, Left);
4228 LeaveCriticalSection(&This->cs);
4230 return hr;
4233 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface, LONG *pLeft)
4235 struct filter_graph *This = impl_from_IVideoWindow(iface);
4236 IVideoWindow *pVideoWindow;
4237 HRESULT hr;
4239 TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4241 EnterCriticalSection(&This->cs);
4243 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4245 if (hr == S_OK)
4246 hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4248 LeaveCriticalSection(&This->cs);
4250 return hr;
4253 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface, LONG Width)
4255 struct filter_graph *This = impl_from_IVideoWindow(iface);
4256 IVideoWindow *pVideoWindow;
4257 HRESULT hr;
4259 TRACE("graph %p, width %ld.\n", This, Width);
4261 EnterCriticalSection(&This->cs);
4263 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4265 if (hr == S_OK)
4266 hr = IVideoWindow_put_Width(pVideoWindow, Width);
4268 LeaveCriticalSection(&This->cs);
4270 return hr;
4273 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface, LONG *pWidth)
4275 struct filter_graph *This = impl_from_IVideoWindow(iface);
4276 IVideoWindow *pVideoWindow;
4277 HRESULT hr;
4279 TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4281 EnterCriticalSection(&This->cs);
4283 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4285 if (hr == S_OK)
4286 hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4288 LeaveCriticalSection(&This->cs);
4290 return hr;
4293 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface, LONG Top)
4295 struct filter_graph *This = impl_from_IVideoWindow(iface);
4296 IVideoWindow *pVideoWindow;
4297 HRESULT hr;
4299 TRACE("graph %p, top %ld.\n", This, Top);
4301 EnterCriticalSection(&This->cs);
4303 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4305 if (hr == S_OK)
4306 hr = IVideoWindow_put_Top(pVideoWindow, Top);
4308 LeaveCriticalSection(&This->cs);
4310 return hr;
4313 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface, LONG *pTop)
4315 struct filter_graph *This = impl_from_IVideoWindow(iface);
4316 IVideoWindow *pVideoWindow;
4317 HRESULT hr;
4319 TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4321 EnterCriticalSection(&This->cs);
4323 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4325 if (hr == S_OK)
4326 hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4328 LeaveCriticalSection(&This->cs);
4330 return hr;
4333 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface, LONG Height)
4335 struct filter_graph *This = impl_from_IVideoWindow(iface);
4336 IVideoWindow *pVideoWindow;
4337 HRESULT hr;
4339 TRACE("graph %p, height %ld.\n", This, Height);
4341 EnterCriticalSection(&This->cs);
4343 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4345 if (hr == S_OK)
4346 hr = IVideoWindow_put_Height(pVideoWindow, Height);
4348 LeaveCriticalSection(&This->cs);
4350 return hr;
4353 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface, LONG *pHeight)
4355 struct filter_graph *This = impl_from_IVideoWindow(iface);
4356 IVideoWindow *pVideoWindow;
4357 HRESULT hr;
4359 TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4361 EnterCriticalSection(&This->cs);
4363 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4365 if (hr == S_OK)
4366 hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4368 LeaveCriticalSection(&This->cs);
4370 return hr;
4373 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface, OAHWND Owner)
4375 struct filter_graph *This = impl_from_IVideoWindow(iface);
4376 IVideoWindow *pVideoWindow;
4377 HRESULT hr;
4379 TRACE("graph %p, owner %#Ix.\n", This, Owner);
4381 EnterCriticalSection(&This->cs);
4383 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4385 if (hr == S_OK)
4386 hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4388 LeaveCriticalSection(&This->cs);
4390 return hr;
4393 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface, OAHWND *Owner)
4395 struct filter_graph *This = impl_from_IVideoWindow(iface);
4396 IVideoWindow *pVideoWindow;
4397 HRESULT hr;
4399 TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4401 EnterCriticalSection(&This->cs);
4403 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4405 if (hr == S_OK)
4406 hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4408 LeaveCriticalSection(&This->cs);
4410 return hr;
4413 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface, OAHWND Drain)
4415 struct filter_graph *This = impl_from_IVideoWindow(iface);
4416 IVideoWindow *pVideoWindow;
4417 HRESULT hr;
4419 TRACE("graph %p, drain %#Ix.\n", This, Drain);
4421 EnterCriticalSection(&This->cs);
4423 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4425 if (hr == S_OK)
4426 hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4428 LeaveCriticalSection(&This->cs);
4430 return hr;
4433 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface, OAHWND *Drain)
4435 struct filter_graph *This = impl_from_IVideoWindow(iface);
4436 IVideoWindow *pVideoWindow;
4437 HRESULT hr;
4439 TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4441 EnterCriticalSection(&This->cs);
4443 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4445 if (hr == S_OK)
4446 hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4448 LeaveCriticalSection(&This->cs);
4450 return hr;
4453 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface, LONG *Color)
4455 struct filter_graph *This = impl_from_IVideoWindow(iface);
4456 IVideoWindow *pVideoWindow;
4457 HRESULT hr;
4459 TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4461 EnterCriticalSection(&This->cs);
4463 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4465 if (hr == S_OK)
4466 hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4468 LeaveCriticalSection(&This->cs);
4470 return hr;
4473 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface, LONG Color)
4475 struct filter_graph *This = impl_from_IVideoWindow(iface);
4476 IVideoWindow *pVideoWindow;
4477 HRESULT hr;
4479 TRACE("graph %p, colour %#lx.\n", This, Color);
4481 EnterCriticalSection(&This->cs);
4483 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4485 if (hr == S_OK)
4486 hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4488 LeaveCriticalSection(&This->cs);
4490 return hr;
4493 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface, LONG *FullScreenMode)
4495 struct filter_graph *This = impl_from_IVideoWindow(iface);
4496 IVideoWindow *pVideoWindow;
4497 HRESULT hr;
4499 TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4501 EnterCriticalSection(&This->cs);
4503 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4505 if (hr == S_OK)
4506 hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4507 if (hr == E_NOTIMPL)
4509 *FullScreenMode = OAFALSE;
4510 hr = S_OK;
4513 LeaveCriticalSection(&This->cs);
4515 return hr;
4518 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, LONG FullScreenMode)
4520 struct filter_graph *This = impl_from_IVideoWindow(iface);
4521 IVideoWindow *pVideoWindow;
4522 HRESULT hr;
4524 TRACE("graph %p, fullscreen %ld.\n", This, FullScreenMode);
4526 EnterCriticalSection(&This->cs);
4528 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4530 if (hr == S_OK)
4531 hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4532 if (hr == E_NOTIMPL && FullScreenMode == OAFALSE)
4533 hr = S_FALSE;
4535 LeaveCriticalSection(&This->cs);
4537 return hr;
4540 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface, LONG Focus)
4542 struct filter_graph *This = impl_from_IVideoWindow(iface);
4543 IVideoWindow *pVideoWindow;
4544 HRESULT hr;
4546 TRACE("graph %p, focus %ld.\n", This, Focus);
4548 EnterCriticalSection(&This->cs);
4550 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4552 if (hr == S_OK)
4553 hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4555 LeaveCriticalSection(&This->cs);
4557 return hr;
4560 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface, OAHWND hwnd, LONG uMsg,
4561 LONG_PTR wParam, LONG_PTR lParam)
4563 struct filter_graph *This = impl_from_IVideoWindow(iface);
4564 IVideoWindow *pVideoWindow;
4565 HRESULT hr;
4567 TRACE("graph %p, hwnd %#Ix, message %#lx, wparam %#Ix, lparam %#Ix.\n", This, hwnd, uMsg, wParam, lParam);
4569 EnterCriticalSection(&This->cs);
4571 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4573 if (hr == S_OK)
4574 hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4576 LeaveCriticalSection(&This->cs);
4578 return hr;
4581 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface, LONG Left, LONG Top,
4582 LONG Width, LONG Height)
4584 struct filter_graph *This = impl_from_IVideoWindow(iface);
4585 IVideoWindow *pVideoWindow;
4586 HRESULT hr;
4588 TRACE("graph %p, left %ld, top %ld, width %ld, height %ld.\n", This, Left, Top, Width, Height);
4590 EnterCriticalSection(&This->cs);
4592 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4594 if (hr == S_OK)
4595 hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4597 LeaveCriticalSection(&This->cs);
4599 return hr;
4602 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4603 LONG *pWidth, LONG *pHeight)
4605 struct filter_graph *This = impl_from_IVideoWindow(iface);
4606 IVideoWindow *pVideoWindow;
4607 HRESULT hr;
4609 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4611 EnterCriticalSection(&This->cs);
4613 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4615 if (hr == S_OK)
4616 hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4618 LeaveCriticalSection(&This->cs);
4620 return hr;
4623 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4624 LONG *pHeight)
4626 struct filter_graph *This = impl_from_IVideoWindow(iface);
4627 IVideoWindow *pVideoWindow;
4628 HRESULT hr;
4630 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4632 EnterCriticalSection(&This->cs);
4634 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4636 if (hr == S_OK)
4637 hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4639 LeaveCriticalSection(&This->cs);
4641 return hr;
4644 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4645 LONG *pHeight)
4647 struct filter_graph *This = impl_from_IVideoWindow(iface);
4648 IVideoWindow *pVideoWindow;
4649 HRESULT hr;
4651 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4653 EnterCriticalSection(&This->cs);
4655 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4657 if (hr == S_OK)
4658 hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4660 LeaveCriticalSection(&This->cs);
4662 return hr;
4665 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4666 LONG *pWidth, LONG *pHeight)
4668 struct filter_graph *This = impl_from_IVideoWindow(iface);
4669 IVideoWindow *pVideoWindow;
4670 HRESULT hr;
4672 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4674 EnterCriticalSection(&This->cs);
4676 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4678 if (hr == S_OK)
4679 hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4681 LeaveCriticalSection(&This->cs);
4683 return hr;
4686 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface, LONG HideCursor)
4688 struct filter_graph *This = impl_from_IVideoWindow(iface);
4689 IVideoWindow *pVideoWindow;
4690 HRESULT hr;
4692 TRACE("graph %p, hide %ld.\n", This, HideCursor);
4694 EnterCriticalSection(&This->cs);
4696 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4698 if (hr == S_OK)
4699 hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4701 LeaveCriticalSection(&This->cs);
4703 return hr;
4706 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden)
4708 struct filter_graph *This = impl_from_IVideoWindow(iface);
4709 IVideoWindow *pVideoWindow;
4710 HRESULT hr;
4712 TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4714 EnterCriticalSection(&This->cs);
4716 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4718 if (hr == S_OK)
4719 hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4721 LeaveCriticalSection(&This->cs);
4723 return hr;
4727 static const IVideoWindowVtbl IVideoWindow_VTable =
4729 VideoWindow_QueryInterface,
4730 VideoWindow_AddRef,
4731 VideoWindow_Release,
4732 VideoWindow_GetTypeInfoCount,
4733 VideoWindow_GetTypeInfo,
4734 VideoWindow_GetIDsOfNames,
4735 VideoWindow_Invoke,
4736 VideoWindow_put_Caption,
4737 VideoWindow_get_Caption,
4738 VideoWindow_put_WindowStyle,
4739 VideoWindow_get_WindowStyle,
4740 VideoWindow_put_WindowStyleEx,
4741 VideoWindow_get_WindowStyleEx,
4742 VideoWindow_put_AutoShow,
4743 VideoWindow_get_AutoShow,
4744 VideoWindow_put_WindowState,
4745 VideoWindow_get_WindowState,
4746 VideoWindow_put_BackgroundPalette,
4747 VideoWindow_get_BackgroundPalette,
4748 VideoWindow_put_Visible,
4749 VideoWindow_get_Visible,
4750 VideoWindow_put_Left,
4751 VideoWindow_get_Left,
4752 VideoWindow_put_Width,
4753 VideoWindow_get_Width,
4754 VideoWindow_put_Top,
4755 VideoWindow_get_Top,
4756 VideoWindow_put_Height,
4757 VideoWindow_get_Height,
4758 VideoWindow_put_Owner,
4759 VideoWindow_get_Owner,
4760 VideoWindow_put_MessageDrain,
4761 VideoWindow_get_MessageDrain,
4762 VideoWindow_get_BorderColor,
4763 VideoWindow_put_BorderColor,
4764 VideoWindow_get_FullScreenMode,
4765 VideoWindow_put_FullScreenMode,
4766 VideoWindow_SetWindowForeground,
4767 VideoWindow_NotifyOwnerMessage,
4768 VideoWindow_SetWindowPosition,
4769 VideoWindow_GetWindowPosition,
4770 VideoWindow_GetMinIdealImageSize,
4771 VideoWindow_GetMaxIdealImageSize,
4772 VideoWindow_GetRestorePosition,
4773 VideoWindow_HideCursor,
4774 VideoWindow_IsCursorHidden
4777 static struct filter_graph *impl_from_IMediaEventEx(IMediaEventEx *iface)
4779 return CONTAINING_RECORD(iface, struct filter_graph, IMediaEventEx_iface);
4782 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface, REFIID iid, void **out)
4784 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4785 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
4788 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface)
4790 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4791 return IUnknown_AddRef(graph->outer_unk);
4794 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface)
4796 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4797 return IUnknown_Release(graph->outer_unk);
4800 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface, UINT *count)
4802 TRACE("iface %p, count %p.\n", iface, count);
4803 *count = 1;
4804 return S_OK;
4807 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface, UINT index,
4808 LCID lcid, ITypeInfo **typeinfo)
4810 TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo);
4811 return strmbase_get_typeinfo(IMediaEvent_tid, typeinfo);
4814 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface, REFIID iid,
4815 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
4817 ITypeInfo *typeinfo;
4818 HRESULT hr;
4820 TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n",
4821 iface, debugstr_guid(iid), names, count, lcid, ids);
4823 if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaEvent_tid, &typeinfo)))
4825 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
4826 ITypeInfo_Release(typeinfo);
4828 return hr;
4831 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface, DISPID id, REFIID iid, LCID lcid,
4832 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
4834 ITypeInfo *typeinfo;
4835 HRESULT hr;
4837 TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
4838 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
4840 if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaEvent_tid, &typeinfo)))
4842 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
4843 ITypeInfo_Release(typeinfo);
4845 return hr;
4848 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface, OAEVENT *event)
4850 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4852 TRACE("graph %p, event %p.\n", graph, event);
4854 *event = (OAEVENT)graph->media_event_handle;
4855 return S_OK;
4858 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface, LONG *code,
4859 LONG_PTR *param1, LONG_PTR *param2, LONG timeout)
4861 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4862 struct media_event *event;
4863 struct list *entry;
4865 TRACE("graph %p, code %p, param1 %p, param2 %p, timeout %ld.\n", graph, code, param1, param2, timeout);
4867 *code = 0;
4869 if (WaitForSingleObject(graph->media_event_handle, timeout))
4870 return E_ABORT;
4872 EnterCriticalSection(&graph->event_cs);
4874 if (!(entry = list_head(&graph->media_events)))
4876 ResetEvent(graph->media_event_handle);
4877 LeaveCriticalSection(&graph->event_cs);
4878 return E_ABORT;
4880 event = LIST_ENTRY(entry, struct media_event, entry);
4881 list_remove(&event->entry);
4882 *code = event->code;
4883 *param1 = event->param1;
4884 *param2 = event->param2;
4885 free(event);
4887 LeaveCriticalSection(&graph->event_cs);
4888 return S_OK;
4891 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface, LONG msTimeout,
4892 LONG *pEvCode)
4894 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4896 TRACE("graph %p, timeout %ld, code %p.\n", This, msTimeout, pEvCode);
4898 if (This->state != State_Running)
4899 return VFW_E_WRONG_STATE;
4901 if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4903 *pEvCode = This->CompletionStatus;
4904 return S_OK;
4907 *pEvCode = 0;
4908 return E_ABORT;
4911 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4913 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4915 TRACE("graph %p, code %#lx.\n", This, lEvCode);
4917 if (lEvCode == EC_COMPLETE)
4918 This->HandleEcComplete = FALSE;
4919 else if (lEvCode == EC_REPAINT)
4920 This->HandleEcRepaint = FALSE;
4921 else if (lEvCode == EC_CLOCK_CHANGED)
4922 This->HandleEcClockChanged = FALSE;
4923 else
4924 return S_FALSE;
4926 return S_OK;
4929 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4931 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4933 TRACE("graph %p, code %#lx.\n", This, lEvCode);
4935 if (lEvCode == EC_COMPLETE)
4936 This->HandleEcComplete = TRUE;
4937 else if (lEvCode == EC_REPAINT)
4938 This->HandleEcRepaint = TRUE;
4939 else if (lEvCode == EC_CLOCK_CHANGED)
4940 This->HandleEcClockChanged = TRUE;
4941 else
4942 return S_FALSE;
4944 return S_OK;
4947 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface, LONG code,
4948 LONG_PTR param1, LONG_PTR param2)
4950 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4952 WARN("graph %p, code %#lx, param1 %Id, param2 %Id, stub!\n", graph, code, param1, param2);
4954 return S_OK;
4957 /*** IMediaEventEx methods ***/
4958 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface,
4959 OAHWND window, LONG message, LONG_PTR lparam)
4961 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4963 TRACE("graph %p, window %#Ix, message %#lx, lparam %#Ix.\n", graph, window, message, lparam);
4965 graph->media_event_window = (HWND)window;
4966 graph->media_event_message = message;
4967 graph->media_event_lparam = lparam;
4969 return S_OK;
4972 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface, LONG flags)
4974 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4976 TRACE("graph %p, flags %#lx.\n", graph, flags);
4978 if (flags & ~AM_MEDIAEVENT_NONOTIFY)
4980 WARN("Invalid flags %#lx, returning E_INVALIDARG.\n", flags);
4981 return E_INVALIDARG;
4984 graph->media_events_disabled = flags;
4986 if (flags)
4988 flush_media_events(graph);
4989 ResetEvent(graph->media_event_handle);
4992 return S_OK;
4995 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface, LONG *flags)
4997 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4999 TRACE("graph %p, flags %p.\n", graph, flags);
5001 if (!flags)
5002 return E_POINTER;
5004 *flags = graph->media_events_disabled;
5006 return S_OK;
5010 static const IMediaEventExVtbl IMediaEventEx_VTable =
5012 MediaEvent_QueryInterface,
5013 MediaEvent_AddRef,
5014 MediaEvent_Release,
5015 MediaEvent_GetTypeInfoCount,
5016 MediaEvent_GetTypeInfo,
5017 MediaEvent_GetIDsOfNames,
5018 MediaEvent_Invoke,
5019 MediaEvent_GetEventHandle,
5020 MediaEvent_GetEvent,
5021 MediaEvent_WaitForCompletion,
5022 MediaEvent_CancelDefaultHandling,
5023 MediaEvent_RestoreDefaultHandling,
5024 MediaEvent_FreeEventParams,
5025 MediaEvent_SetNotifyWindow,
5026 MediaEvent_SetNotifyFlags,
5027 MediaEvent_GetNotifyFlags
5031 static struct filter_graph *impl_from_IMediaFilter(IMediaFilter *iface)
5033 return CONTAINING_RECORD(iface, struct filter_graph, IMediaFilter_iface);
5036 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID iid, void **out)
5038 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5040 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5043 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
5045 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5047 return IUnknown_AddRef(graph->outer_unk);
5050 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
5052 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5054 return IUnknown_Release(graph->outer_unk);
5057 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
5059 FIXME("(%p): stub\n", pClassID);
5061 return E_NOTIMPL;
5064 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
5066 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5067 HRESULT hr = S_OK, filter_hr;
5068 struct filter *filter;
5069 TP_WORK *work;
5071 TRACE("graph %p.\n", graph);
5073 EnterCriticalSection(&graph->cs);
5075 if (graph->state == State_Stopped)
5077 LeaveCriticalSection(&graph->cs);
5078 return S_OK;
5081 sort_filters(graph);
5083 if (graph->state == State_Running)
5085 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5087 filter_hr = IBaseFilter_Pause(filter->filter);
5088 if (hr == S_OK)
5089 hr = filter_hr;
5093 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5095 filter_hr = IBaseFilter_Stop(filter->filter);
5096 if (hr == S_OK)
5097 hr = filter_hr;
5100 graph->state = State_Stopped;
5101 graph->needs_async_run = 0;
5102 work = graph->async_run_work;
5103 graph->got_ec_complete = 0;
5105 /* Update the current position, probably to synchronize multiple streams. */
5106 IMediaSeeking_SetPositions(&graph->IMediaSeeking_iface, &graph->current_pos,
5107 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
5109 LeaveCriticalSection(&graph->cs);
5111 if (work)
5112 WaitForThreadpoolWorkCallbacks(work, TRUE);
5114 return hr;
5117 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
5119 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5120 HRESULT hr = S_OK, filter_hr;
5121 struct filter *filter;
5122 TP_WORK *work;
5124 TRACE("graph %p.\n", graph);
5126 EnterCriticalSection(&graph->cs);
5128 if (graph->state == State_Paused)
5130 LeaveCriticalSection(&graph->cs);
5131 return S_OK;
5134 sort_filters(graph);
5136 EnterCriticalSection(&graph->event_cs);
5137 update_render_count(graph);
5138 LeaveCriticalSection(&graph->event_cs);
5140 if (graph->defaultclock && !graph->refClock)
5141 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
5143 if (graph->state == State_Running && !graph->needs_async_run && graph->refClock)
5145 REFERENCE_TIME time;
5146 IReferenceClock_GetTime(graph->refClock, &time);
5147 graph->stream_elapsed += time - graph->stream_start;
5148 graph->current_pos += graph->stream_elapsed;
5151 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5153 filter_hr = IBaseFilter_Pause(filter->filter);
5154 if (hr == S_OK)
5155 hr = filter_hr;
5158 graph->state = State_Paused;
5159 graph->needs_async_run = 0;
5160 work = graph->async_run_work;
5162 LeaveCriticalSection(&graph->cs);
5164 if (work)
5165 WaitForThreadpoolWorkCallbacks(work, TRUE);
5167 return hr;
5170 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
5172 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5173 HRESULT hr;
5175 TRACE("graph %p, start %s.\n", graph, debugstr_time(start));
5177 EnterCriticalSection(&graph->cs);
5179 if (graph->state == State_Running)
5181 LeaveCriticalSection(&graph->cs);
5182 return S_OK;
5185 sort_filters(graph);
5187 hr = graph_start(graph, start);
5189 graph->state = State_Running;
5190 graph->needs_async_run = 0;
5192 LeaveCriticalSection(&graph->cs);
5193 return hr;
5196 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, FILTER_STATE *state)
5198 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5199 DWORD end = GetTickCount() + timeout;
5200 HRESULT hr;
5202 TRACE("graph %p, timeout %lu, state %p.\n", graph, timeout, state);
5204 if (!state)
5205 return E_POINTER;
5207 /* Thread safety is a little tricky here. GetState() shouldn't block other
5208 * functions from being called on the filter graph. However, we can't just
5209 * call IBaseFilter::GetState() in one loop and drop the lock on every
5210 * iteration, since the filter list might change beneath us. So instead we
5211 * do what native does, and poll for it every 10 ms. */
5213 EnterCriticalSection(&graph->cs);
5214 *state = graph->state;
5216 for (;;)
5218 IBaseFilter *async_filter = NULL;
5219 FILTER_STATE filter_state;
5220 struct filter *filter;
5222 hr = S_OK;
5224 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5226 HRESULT filter_hr = IBaseFilter_GetState(filter->filter, 0, &filter_state);
5228 TRACE("Filter %p returned hr %#lx, state %u.\n", filter->filter, filter_hr, filter_state);
5230 if (filter_hr == VFW_S_STATE_INTERMEDIATE)
5231 async_filter = filter->filter;
5233 if (hr == S_OK && filter_hr == VFW_S_STATE_INTERMEDIATE)
5234 hr = VFW_S_STATE_INTERMEDIATE;
5235 else if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE)
5236 hr = filter_hr;
5238 if (hr == S_OK && filter_state == State_Paused && graph->state != State_Paused)
5240 async_filter = filter->filter;
5241 hr = VFW_S_STATE_INTERMEDIATE;
5243 else if (filter_state != graph->state && filter_state != State_Paused)
5244 hr = E_FAIL;
5246 if (graph->needs_async_run)
5248 if (filter_state != State_Paused && filter_state != State_Running)
5249 ERR("Filter %p reported incorrect state %u (expected %u or %u).\n",
5250 filter->filter, filter_state, State_Paused, State_Running);
5252 else
5254 if (filter_state != graph->state)
5255 ERR("Filter %p reported incorrect state %u (expected %u).\n",
5256 filter->filter, filter_state, graph->state);
5260 LeaveCriticalSection(&graph->cs);
5262 if (hr != VFW_S_STATE_INTERMEDIATE || (timeout != INFINITE && GetTickCount() >= end))
5263 break;
5265 IBaseFilter_GetState(async_filter, 10, &filter_state);
5267 EnterCriticalSection(&graph->cs);
5270 TRACE("Returning %#lx, state %u.\n", hr, *state);
5271 return hr;
5274 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
5276 struct filter_graph *This = impl_from_IMediaFilter(iface);
5277 struct filter *filter;
5278 HRESULT hr = S_OK;
5280 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
5282 EnterCriticalSection(&This->cs);
5284 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
5286 hr = IBaseFilter_SetSyncSource(filter->filter, pClock);
5287 if (FAILED(hr))
5288 break;
5291 if (FAILED(hr))
5293 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
5294 IBaseFilter_SetSyncSource(filter->filter, This->refClock);
5296 else
5298 if (This->refClock)
5299 IReferenceClock_Release(This->refClock);
5300 This->refClock = pClock;
5301 if (This->refClock)
5302 IReferenceClock_AddRef(This->refClock);
5303 This->defaultclock = FALSE;
5305 if (This->HandleEcClockChanged)
5307 IMediaEventSink *pEventSink;
5308 HRESULT eshr;
5310 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (void **)&pEventSink);
5311 if (SUCCEEDED(eshr))
5313 IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5314 IMediaEventSink_Release(pEventSink);
5319 LeaveCriticalSection(&This->cs);
5321 return hr;
5324 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5326 struct filter_graph *This = impl_from_IMediaFilter(iface);
5328 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
5330 if (!ppClock)
5331 return E_POINTER;
5333 EnterCriticalSection(&This->cs);
5335 *ppClock = This->refClock;
5336 if (*ppClock)
5337 IReferenceClock_AddRef(*ppClock);
5339 LeaveCriticalSection(&This->cs);
5341 return S_OK;
5344 static const IMediaFilterVtbl IMediaFilter_VTable =
5346 MediaFilter_QueryInterface,
5347 MediaFilter_AddRef,
5348 MediaFilter_Release,
5349 MediaFilter_GetClassID,
5350 MediaFilter_Stop,
5351 MediaFilter_Pause,
5352 MediaFilter_Run,
5353 MediaFilter_GetState,
5354 MediaFilter_SetSyncSource,
5355 MediaFilter_GetSyncSource
5358 static struct filter_graph *impl_from_IMediaEventSink(IMediaEventSink *iface)
5360 return CONTAINING_RECORD(iface, struct filter_graph, IMediaEventSink_iface);
5363 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID iid, void **out)
5365 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5367 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5370 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5372 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5374 return IUnknown_AddRef(graph->outer_unk);
5377 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5379 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5381 return IUnknown_Release(graph->outer_unk);
5384 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG code,
5385 LONG_PTR param1, LONG_PTR param2)
5387 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5389 TRACE("graph %p, code %#lx, param1 %#Ix, param2 %#Ix.\n", graph, code, param1, param2);
5391 EnterCriticalSection(&graph->event_cs);
5393 if (code == EC_COMPLETE && graph->HandleEcComplete)
5395 if (++graph->EcCompleteCount == graph->nRenderers)
5397 if (graph->media_events_disabled)
5398 SetEvent(graph->media_event_handle);
5399 else
5400 queue_media_event(graph, EC_COMPLETE, S_OK, 0);
5401 graph->CompletionStatus = EC_COMPLETE;
5402 graph->got_ec_complete = 1;
5403 SetEvent(graph->hEventCompletion);
5406 else if ((code == EC_REPAINT) && graph->HandleEcRepaint)
5408 FIXME("EC_REPAINT is not handled.\n");
5410 else if (!graph->media_events_disabled)
5412 queue_media_event(graph, code, param1, param2);
5415 LeaveCriticalSection(&graph->event_cs);
5416 return S_OK;
5419 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5421 MediaEventSink_QueryInterface,
5422 MediaEventSink_AddRef,
5423 MediaEventSink_Release,
5424 MediaEventSink_Notify
5427 static struct filter_graph *impl_from_IGraphConfig(IGraphConfig *iface)
5429 return CONTAINING_RECORD(iface, struct filter_graph, IGraphConfig_iface);
5432 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID iid, void **out)
5434 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5436 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5439 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5441 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5443 return IUnknown_AddRef(graph->outer_unk);
5446 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5448 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5450 return IUnknown_Release(graph->outer_unk);
5453 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface, IPin *source, IPin *sink,
5454 const AM_MEDIA_TYPE *mt, IBaseFilter *filter, HANDLE abort_event, DWORD flags)
5456 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5458 FIXME("graph %p, source %p, sink %p, mt %p, filter %p, abort_event %p, flags %#lx, stub!\n",
5459 graph, source, sink, mt, filter, abort_event, flags);
5460 strmbase_dump_media_type(mt);
5462 return E_NOTIMPL;
5465 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface,
5466 IGraphConfigCallback *callback, void *context, DWORD flags, HANDLE abort_event)
5468 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5469 HRESULT hr;
5471 TRACE("graph %p, callback %p, context %p, flags %#lx, abort_event %p.\n",
5472 graph, callback, context, flags, abort_event);
5474 if (abort_event)
5475 FIXME("The parameter hAbortEvent is not handled!\n");
5477 EnterCriticalSection(&graph->cs);
5479 hr = IGraphConfigCallback_Reconfigure(callback, context, flags);
5481 LeaveCriticalSection(&graph->cs);
5483 return hr;
5486 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface, IBaseFilter *pFilter)
5488 struct filter_graph *This = impl_from_IGraphConfig(iface);
5490 FIXME("(%p)->(%p): stub!\n", This, pFilter);
5492 return E_NOTIMPL;
5495 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface, IEnumFilters **pEnum)
5497 struct filter_graph *This = impl_from_IGraphConfig(iface);
5499 FIXME("(%p)->(%p): stub!\n", This, pEnum);
5501 return E_NOTIMPL;
5504 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface, IBaseFilter *pFilter)
5506 struct filter_graph *This = impl_from_IGraphConfig(iface);
5508 FIXME("(%p)->(%p): stub!\n", This, pFilter);
5510 return E_NOTIMPL;
5513 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface, REFERENCE_TIME *prtStart)
5515 struct filter_graph *This = impl_from_IGraphConfig(iface);
5517 FIXME("(%p)->(%p): stub!\n", This, prtStart);
5519 return E_NOTIMPL;
5522 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface, IPin *pOutputPin,
5523 IPinConnection *pConnection, HANDLE hEventAbort)
5525 struct filter_graph *This = impl_from_IGraphConfig(iface);
5527 FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5529 return E_NOTIMPL;
5532 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface, IBaseFilter *filter, DWORD flags)
5534 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5536 FIXME("graph %p, filter %p, flags %#lx, stub!\n", graph, filter, flags);
5538 return E_NOTIMPL;
5541 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5542 DWORD *dwFlags)
5544 struct filter_graph *This = impl_from_IGraphConfig(iface);
5546 FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5548 return E_NOTIMPL;
5551 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface, IBaseFilter *filter, DWORD flags)
5553 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5555 FIXME("graph %p, filter %p, flags %#lx, stub!\n", graph, filter, flags);
5557 return E_NOTIMPL;
5560 static const IGraphConfigVtbl IGraphConfig_VTable =
5562 GraphConfig_QueryInterface,
5563 GraphConfig_AddRef,
5564 GraphConfig_Release,
5565 GraphConfig_Reconnect,
5566 GraphConfig_Reconfigure,
5567 GraphConfig_AddFilterToCache,
5568 GraphConfig_EnumCacheFilter,
5569 GraphConfig_RemoveFilterFromCache,
5570 GraphConfig_GetStartTime,
5571 GraphConfig_PushThroughData,
5572 GraphConfig_SetFilterFlags,
5573 GraphConfig_GetFilterFlags,
5574 GraphConfig_RemoveFilterEx
5577 static struct filter_graph *impl_from_IGraphVersion(IGraphVersion *iface)
5579 return CONTAINING_RECORD(iface, struct filter_graph, IGraphVersion_iface);
5582 static HRESULT WINAPI GraphVersion_QueryInterface(IGraphVersion *iface, REFIID iid, void **out)
5584 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5586 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5589 static ULONG WINAPI GraphVersion_AddRef(IGraphVersion *iface)
5591 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5593 return IUnknown_AddRef(graph->outer_unk);
5596 static ULONG WINAPI GraphVersion_Release(IGraphVersion *iface)
5598 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5600 return IUnknown_Release(graph->outer_unk);
5603 static HRESULT WINAPI GraphVersion_QueryVersion(IGraphVersion *iface, LONG *version)
5605 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5607 TRACE("graph %p, version %p, returning %ld.\n", graph, version, graph->version);
5609 if (!version)
5610 return E_POINTER;
5612 *version = graph->version;
5613 return S_OK;
5616 static const IGraphVersionVtbl IGraphVersion_VTable =
5618 GraphVersion_QueryInterface,
5619 GraphVersion_AddRef,
5620 GraphVersion_Release,
5621 GraphVersion_QueryVersion,
5624 static struct filter_graph *impl_from_IVideoFrameStep(IVideoFrameStep *iface)
5626 return CONTAINING_RECORD(iface, struct filter_graph, IVideoFrameStep_iface);
5629 static HRESULT WINAPI VideoFrameStep_QueryInterface(IVideoFrameStep *iface, REFIID iid, void **out)
5631 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5632 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5635 static ULONG WINAPI VideoFrameStep_AddRef(IVideoFrameStep *iface)
5637 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5638 return IUnknown_AddRef(graph->outer_unk);
5641 static ULONG WINAPI VideoFrameStep_Release(IVideoFrameStep *iface)
5643 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5644 return IUnknown_Release(graph->outer_unk);
5647 static HRESULT WINAPI VideoFrameStep_Step(IVideoFrameStep *iface, DWORD frame_count, IUnknown *filter)
5649 FIXME("iface %p, frame_count %lu, filter %p, stub!\n", iface, frame_count, filter);
5650 return E_NOTIMPL;
5653 static HRESULT WINAPI VideoFrameStep_CanStep(IVideoFrameStep *iface, LONG multiple, IUnknown *filter)
5655 FIXME("iface %p, multiple %ld, filter %p, stub!\n", iface, multiple, filter);
5656 return E_NOTIMPL;
5659 static HRESULT WINAPI VideoFrameStep_CancelStep(IVideoFrameStep *iface)
5661 FIXME("iface %p, stub!\n", iface);
5662 return E_NOTIMPL;
5665 static const IVideoFrameStepVtbl VideoFrameStep_vtbl =
5667 VideoFrameStep_QueryInterface,
5668 VideoFrameStep_AddRef,
5669 VideoFrameStep_Release,
5670 VideoFrameStep_Step,
5671 VideoFrameStep_CanStep,
5672 VideoFrameStep_CancelStep
5675 static const IUnknownVtbl IInner_VTable =
5677 FilterGraphInner_QueryInterface,
5678 FilterGraphInner_AddRef,
5679 FilterGraphInner_Release
5682 static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded)
5684 struct filter_graph *object;
5685 HRESULT hr;
5687 *out = NULL;
5689 if (!(object = calloc(1, sizeof(*object))))
5690 return E_OUTOFMEMORY;
5692 object->IBasicAudio_iface.lpVtbl = &IBasicAudio_VTable;
5693 object->IBasicVideo2_iface.lpVtbl = &IBasicVideo_VTable;
5694 object->IFilterGraph2_iface.lpVtbl = &IFilterGraph2_VTable;
5695 object->IGraphConfig_iface.lpVtbl = &IGraphConfig_VTable;
5696 object->IGraphVersion_iface.lpVtbl = &IGraphVersion_VTable;
5697 object->IMediaControl_iface.lpVtbl = &IMediaControl_VTable;
5698 object->IMediaEventEx_iface.lpVtbl = &IMediaEventEx_VTable;
5699 object->IMediaEventSink_iface.lpVtbl = &IMediaEventSink_VTable;
5700 object->IMediaFilter_iface.lpVtbl = &IMediaFilter_VTable;
5701 object->IMediaPosition_iface.lpVtbl = &IMediaPosition_VTable;
5702 object->IMediaSeeking_iface.lpVtbl = &IMediaSeeking_VTable;
5703 object->IObjectWithSite_iface.lpVtbl = &IObjectWithSite_VTable;
5704 object->IUnknown_inner.lpVtbl = &IInner_VTable;
5705 object->IVideoFrameStep_iface.lpVtbl = &VideoFrameStep_vtbl;
5706 object->IVideoWindow_iface.lpVtbl = &IVideoWindow_VTable;
5707 object->ref = 1;
5708 object->outer_unk = outer ? outer : &object->IUnknown_inner;
5710 if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, object->outer_unk,
5711 CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&object->punkFilterMapper2)))
5713 ERR("Failed to create filter mapper, hr %#lx.\n", hr);
5714 free(object);
5715 return hr;
5718 InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
5719 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": filter_graph.cs");
5720 InitializeCriticalSectionEx(&object->event_cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
5721 object->event_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": filter_graph.event_cs");
5723 object->defaultclock = TRUE;
5725 object->media_event_handle = CreateEventW(NULL, TRUE, FALSE, NULL);
5726 list_init(&object->media_events);
5727 list_init(&object->filters);
5728 object->HandleEcClockChanged = TRUE;
5729 object->HandleEcComplete = TRUE;
5730 object->HandleEcRepaint = TRUE;
5731 object->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5733 object->name_index = 1;
5734 object->timeformatseek = TIME_FORMAT_MEDIA_TIME;
5736 object->threaded = !!threaded;
5738 EnterCriticalSection(&message_cs);
5739 if (threaded && !message_thread_refcount++)
5741 message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL);
5742 message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &message_thread_id);
5743 WaitForSingleObject(message_thread_ret, INFINITE);
5745 LeaveCriticalSection(&message_cs);
5747 TRACE("Created %sthreaded filter graph %p.\n", threaded ? "" : "non-", object);
5748 *out = &object->IUnknown_inner;
5749 return S_OK;
5752 HRESULT filter_graph_create(IUnknown *outer, IUnknown **out)
5754 return filter_graph_common_create(outer, out, TRUE);
5757 HRESULT filter_graph_no_thread_create(IUnknown *outer, IUnknown **out)
5759 return filter_graph_common_create(outer, out, FALSE);