quartz: Correct return value handling in IMediaSeeking::GetDuration().
[wine.git] / dlls / quartz / filtergraph.c
blobfb0890fda1faa1c102666e6156dff7ed86def89e
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 typedef struct {
46 HWND hWnd; /* Target window */
47 UINT msg; /* User window message */
48 LONG_PTR instance; /* User data */
49 int disabled; /* Disabled messages posting */
50 } WndNotify;
52 typedef struct {
53 LONG lEventCode; /* Event code */
54 LONG_PTR lParam1; /* Param1 */
55 LONG_PTR lParam2; /* Param2 */
56 } Event;
58 /* messages ring implementation for queuing events (taken from winmm) */
59 #define EVENTS_RING_BUFFER_INCREMENT 64
60 typedef struct {
61 Event* messages;
62 int ring_buffer_size;
63 int msg_tosave;
64 int msg_toget;
65 CRITICAL_SECTION msg_crst;
66 HANDLE msg_event; /* Signaled for no empty queue */
67 } EventsQueue;
69 static int EventsQueue_Init(EventsQueue* omr)
71 omr->msg_toget = 0;
72 omr->msg_tosave = 0;
73 omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
74 omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
75 omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
76 ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
78 InitializeCriticalSection(&omr->msg_crst);
79 omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
80 return TRUE;
83 static int EventsQueue_Destroy(EventsQueue* omr)
85 CloseHandle(omr->msg_event);
86 CoTaskMemFree(omr->messages);
87 omr->msg_crst.DebugInfo->Spare[0] = 0;
88 DeleteCriticalSection(&omr->msg_crst);
89 return TRUE;
92 static BOOL EventsQueue_PutEvent(EventsQueue* omr, const Event* evt)
94 EnterCriticalSection(&omr->msg_crst);
95 if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
97 int old_ring_buffer_size = omr->ring_buffer_size;
98 omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
99 TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
100 omr->messages = CoTaskMemRealloc(omr->messages, omr->ring_buffer_size * sizeof(Event));
101 /* Now we need to rearrange the ring buffer so that the new
102 buffers just allocated are in between omr->msg_tosave and
103 omr->msg_toget.
105 if (omr->msg_tosave < omr->msg_toget)
107 memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
108 &(omr->messages[omr->msg_toget]),
109 sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
111 omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
114 omr->messages[omr->msg_tosave] = *evt;
115 SetEvent(omr->msg_event);
116 omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
117 LeaveCriticalSection(&omr->msg_crst);
118 return TRUE;
121 static BOOL EventsQueue_GetEvent(EventsQueue* omr, Event* evt, LONG msTimeOut)
123 if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
124 return FALSE;
126 EnterCriticalSection(&omr->msg_crst);
128 if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
130 LeaveCriticalSection(&omr->msg_crst);
131 return FALSE;
134 *evt = omr->messages[omr->msg_toget];
135 omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
137 /* Mark the buffer as empty if needed */
138 if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
139 ResetEvent(omr->msg_event);
141 LeaveCriticalSection(&omr->msg_crst);
142 return TRUE;
145 #define MAX_ITF_CACHE_ENTRIES 3
146 typedef struct _ITF_CACHE_ENTRY {
147 const IID* riid;
148 IBaseFilter* filter;
149 IUnknown* iface;
150 } ITF_CACHE_ENTRY;
152 struct filter
154 struct list entry;
155 IBaseFilter *filter;
156 IMediaSeeking *seeking;
157 WCHAR *name;
158 BOOL sorting;
161 struct filter_graph
163 IUnknown IUnknown_inner;
164 IFilterGraph2 IFilterGraph2_iface;
165 IMediaControl IMediaControl_iface;
166 IMediaSeeking IMediaSeeking_iface;
167 IBasicAudio IBasicAudio_iface;
168 IBasicVideo2 IBasicVideo2_iface;
169 IVideoWindow IVideoWindow_iface;
170 IMediaEventEx IMediaEventEx_iface;
171 IMediaFilter IMediaFilter_iface;
172 IMediaEventSink IMediaEventSink_iface;
173 IGraphConfig IGraphConfig_iface;
174 IMediaPosition IMediaPosition_iface;
175 IObjectWithSite IObjectWithSite_iface;
176 IGraphVersion IGraphVersion_iface;
177 /* IAMGraphStreams */
178 /* IAMStats */
179 /* IFilterChain */
180 /* IFilterMapper2 */
181 /* IQueueCommand */
182 /* IRegisterServiceProvider */
183 /* IResourceManager */
184 /* IServiceProvider */
185 IVideoFrameStep IVideoFrameStep_iface;
187 IUnknown *outer_unk;
188 LONG ref;
189 IUnknown *punkFilterMapper2;
191 struct list filters;
192 unsigned int name_index;
194 OAFilterState state;
195 TP_WORK *async_run_work;
197 IReferenceClock *refClock;
198 IBaseFilter *refClockProvider;
199 EventsQueue evqueue;
200 HANDLE hEventCompletion;
201 int CompletionStatus;
202 WndNotify notif;
203 int nRenderers;
204 int EcCompleteCount;
205 int HandleEcComplete;
206 int HandleEcRepaint;
207 int HandleEcClockChanged;
208 CRITICAL_SECTION cs;
209 ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
210 int nItfCacheEntries;
211 BOOL defaultclock;
212 GUID timeformatseek;
213 IUnknown *pSite;
214 LONG version;
216 HANDLE message_thread, message_thread_ret;
217 DWORD message_thread_id;
219 /* Respectively: the last timestamp at which we started streaming, and the
220 * current offset within the stream. */
221 REFERENCE_TIME stream_start, stream_elapsed;
222 REFERENCE_TIME stream_stop;
223 LONGLONG current_pos;
225 unsigned int needs_async_run : 1;
226 unsigned int got_ec_complete : 1;
229 struct enum_filters
231 IEnumFilters IEnumFilters_iface;
232 LONG ref;
233 struct filter_graph *graph;
234 LONG version;
235 struct list *cursor;
238 static HRESULT create_enum_filters(struct filter_graph *graph, struct list *cursor, IEnumFilters **out);
240 static inline struct enum_filters *impl_from_IEnumFilters(IEnumFilters *iface)
242 return CONTAINING_RECORD(iface, struct enum_filters, IEnumFilters_iface);
245 static HRESULT WINAPI EnumFilters_QueryInterface(IEnumFilters *iface, REFIID iid, void **out)
247 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
248 TRACE("enum_filters %p, iid %s, out %p.\n", enum_filters, qzdebugstr_guid(iid), out);
250 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumFilters))
252 IEnumFilters_AddRef(*out = iface);
253 return S_OK;
256 WARN("%s not implemented, returning E_NOINTERFACE.\n", qzdebugstr_guid(iid));
257 *out = NULL;
258 return E_NOINTERFACE;
261 static ULONG WINAPI EnumFilters_AddRef(IEnumFilters *iface)
263 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
264 ULONG ref = InterlockedIncrement(&enum_filters->ref);
266 TRACE("%p increasing refcount to %u.\n", enum_filters, ref);
268 return ref;
271 static ULONG WINAPI EnumFilters_Release(IEnumFilters *iface)
273 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
274 ULONG ref = InterlockedDecrement(&enum_filters->ref);
276 TRACE("%p decreasing refcount to %u.\n", enum_filters, ref);
278 if (!ref)
280 IUnknown_Release(enum_filters->graph->outer_unk);
281 heap_free(enum_filters);
284 return ref;
287 static HRESULT WINAPI EnumFilters_Next(IEnumFilters *iface, ULONG count,
288 IBaseFilter **filters, ULONG *fetched)
290 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
291 unsigned int i = 0;
293 TRACE("enum_filters %p, count %u, filters %p, fetched %p.\n",
294 enum_filters, count, filters, fetched);
296 if (enum_filters->version != enum_filters->graph->version)
297 return VFW_E_ENUM_OUT_OF_SYNC;
299 if (!filters)
300 return E_POINTER;
302 for (i = 0; i < count; ++i)
304 struct filter *filter = LIST_ENTRY(enum_filters->cursor, struct filter, entry);
306 if (!enum_filters->cursor)
307 break;
309 IBaseFilter_AddRef(filters[i] = filter->filter);
310 enum_filters->cursor = list_next(&enum_filters->graph->filters, enum_filters->cursor);
313 if (fetched)
314 *fetched = i;
316 return (i == count) ? S_OK : S_FALSE;
319 static HRESULT WINAPI EnumFilters_Skip(IEnumFilters *iface, ULONG count)
321 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
323 TRACE("enum_filters %p, count %u.\n", enum_filters, count);
325 if (!enum_filters->cursor)
326 return S_FALSE;
328 while (count--)
330 if (!(enum_filters->cursor = list_next(&enum_filters->graph->filters, enum_filters->cursor)))
331 return S_FALSE;
334 return S_OK;
337 static HRESULT WINAPI EnumFilters_Reset(IEnumFilters *iface)
339 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
341 TRACE("enum_filters %p.\n", enum_filters);
343 enum_filters->cursor = list_head(&enum_filters->graph->filters);
344 enum_filters->version = enum_filters->graph->version;
345 return S_OK;
348 static HRESULT WINAPI EnumFilters_Clone(IEnumFilters *iface, IEnumFilters **out)
350 struct enum_filters *enum_filters = impl_from_IEnumFilters(iface);
352 TRACE("enum_filters %p, out %p.\n", enum_filters, out);
354 return create_enum_filters(enum_filters->graph, enum_filters->cursor, out);
357 static const IEnumFiltersVtbl EnumFilters_vtbl =
359 EnumFilters_QueryInterface,
360 EnumFilters_AddRef,
361 EnumFilters_Release,
362 EnumFilters_Next,
363 EnumFilters_Skip,
364 EnumFilters_Reset,
365 EnumFilters_Clone,
368 static HRESULT create_enum_filters(struct filter_graph *graph, struct list *cursor, IEnumFilters **out)
370 struct enum_filters *enum_filters;
372 if (!(enum_filters = heap_alloc(sizeof(*enum_filters))))
373 return E_OUTOFMEMORY;
375 enum_filters->IEnumFilters_iface.lpVtbl = &EnumFilters_vtbl;
376 enum_filters->ref = 1;
377 enum_filters->cursor = cursor;
378 enum_filters->graph = graph;
379 IUnknown_AddRef(graph->outer_unk);
380 enum_filters->version = graph->version;
382 *out = &enum_filters->IEnumFilters_iface;
383 return S_OK;
386 static struct filter_graph *impl_from_IUnknown(IUnknown *iface)
388 return CONTAINING_RECORD(iface, struct filter_graph, IUnknown_inner);
391 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown *iface, REFIID riid, void **ppvObj)
393 struct filter_graph *This = impl_from_IUnknown(iface);
394 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
396 if (IsEqualGUID(&IID_IUnknown, riid)) {
397 *ppvObj = &This->IUnknown_inner;
398 TRACE(" returning IUnknown interface (%p)\n", *ppvObj);
399 } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
400 IsEqualGUID(&IID_IFilterGraph2, riid) ||
401 IsEqualGUID(&IID_IGraphBuilder, riid)) {
402 *ppvObj = &This->IFilterGraph2_iface;
403 TRACE(" returning IGraphBuilder interface (%p)\n", *ppvObj);
404 } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
405 *ppvObj = &This->IMediaControl_iface;
406 TRACE(" returning IMediaControl interface (%p)\n", *ppvObj);
407 } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
408 *ppvObj = &This->IMediaSeeking_iface;
409 TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj);
410 } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
411 *ppvObj = &This->IBasicAudio_iface;
412 TRACE(" returning IBasicAudio interface (%p)\n", *ppvObj);
413 } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
414 IsEqualGUID(&IID_IBasicVideo2, riid)) {
415 *ppvObj = &This->IBasicVideo2_iface;
416 TRACE(" returning IBasicVideo2 interface (%p)\n", *ppvObj);
417 } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
418 *ppvObj = &This->IVideoWindow_iface;
419 TRACE(" returning IVideoWindow interface (%p)\n", *ppvObj);
420 } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
421 IsEqualGUID(&IID_IMediaEventEx, riid)) {
422 *ppvObj = &This->IMediaEventEx_iface;
423 TRACE(" returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
424 } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
425 IsEqualGUID(&IID_IPersist, riid)) {
426 *ppvObj = &This->IMediaFilter_iface;
427 TRACE(" returning IMediaFilter interface (%p)\n", *ppvObj);
428 } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
429 *ppvObj = &This->IMediaEventSink_iface;
430 TRACE(" returning IMediaEventSink interface (%p)\n", *ppvObj);
431 } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
432 *ppvObj = &This->IGraphConfig_iface;
433 TRACE(" returning IGraphConfig interface (%p)\n", *ppvObj);
434 } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
435 *ppvObj = &This->IMediaPosition_iface;
436 TRACE(" returning IMediaPosition interface (%p)\n", *ppvObj);
437 } else if (IsEqualGUID(&IID_IObjectWithSite, riid)) {
438 *ppvObj = &This->IObjectWithSite_iface;
439 TRACE(" returning IObjectWithSite interface (%p)\n", *ppvObj);
440 } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
441 TRACE(" requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
442 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
443 } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
444 TRACE(" returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
445 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
446 } else if (IsEqualGUID(&IID_IFilterMapper3, riid)) {
447 TRACE(" returning IFilterMapper3 interface from aggregated filtermapper (%p)\n", *ppvObj);
448 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
449 } else if (IsEqualGUID(&IID_IGraphVersion, riid)) {
450 *ppvObj = &This->IGraphVersion_iface;
451 TRACE(" returning IGraphVersion interface (%p)\n", *ppvObj);
452 } else if (IsEqualGUID(&IID_IVideoFrameStep, riid)) {
453 *ppvObj = &This->IVideoFrameStep_iface;
454 TRACE(" returning IVideoFrameStep interface (%p)\n", *ppvObj);
455 } else {
456 *ppvObj = NULL;
457 FIXME("unknown interface %s\n", debugstr_guid(riid));
458 return E_NOINTERFACE;
461 IUnknown_AddRef((IUnknown *)*ppvObj);
462 return S_OK;
465 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown *iface)
467 struct filter_graph *This = impl_from_IUnknown(iface);
468 ULONG ref = InterlockedIncrement(&This->ref);
470 TRACE("(%p)->(): new ref = %d\n", This, ref);
472 return ref;
475 static ULONG WINAPI FilterGraphInner_Release(IUnknown *iface)
477 struct filter_graph *This = impl_from_IUnknown(iface);
478 ULONG ref = InterlockedDecrement(&This->ref);
479 struct filter *filter, *next;
481 TRACE("(%p)->(): new ref = %d\n", This, ref);
483 if (ref == 0) {
484 int i;
486 This->ref = 1; /* guard against reentrancy (aggregation). */
488 IMediaControl_Stop(&This->IMediaControl_iface);
490 LIST_FOR_EACH_ENTRY_SAFE(filter, next, &This->filters, struct filter, entry)
492 IFilterGraph2_RemoveFilter(&This->IFilterGraph2_iface, filter->filter);
495 if (This->refClock)
496 IReferenceClock_Release(This->refClock);
498 for (i = 0; i < This->nItfCacheEntries; i++)
500 if (This->ItfCacheEntries[i].iface)
501 IUnknown_Release(This->ItfCacheEntries[i].iface);
504 IUnknown_Release(This->punkFilterMapper2);
506 if (This->pSite) IUnknown_Release(This->pSite);
508 CloseHandle(This->hEventCompletion);
509 EventsQueue_Destroy(&This->evqueue);
510 This->cs.DebugInfo->Spare[0] = 0;
511 if (This->message_thread)
513 PostThreadMessageW(This->message_thread_id, WM_USER + 1, 0, 0);
514 WaitForSingleObject(This->message_thread, INFINITE);
515 CloseHandle(This->message_thread);
516 CloseHandle(This->message_thread_ret);
518 DeleteCriticalSection(&This->cs);
519 free(This);
521 InterlockedDecrement(&object_locks);
523 return ref;
526 static struct filter_graph *impl_from_IFilterGraph2(IFilterGraph2 *iface)
528 return CONTAINING_RECORD(iface, struct filter_graph, IFilterGraph2_iface);
531 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface, REFIID iid, void **out)
533 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
534 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
537 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface)
539 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
540 return IUnknown_AddRef(graph->outer_unk);
543 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface)
545 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
546 return IUnknown_Release(graph->outer_unk);
549 static IBaseFilter *find_filter_by_name(struct filter_graph *graph, const WCHAR *name)
551 struct filter *filter;
553 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
555 if (!wcscmp(filter->name, name))
556 return filter->filter;
559 return NULL;
562 static BOOL has_output_pins(IBaseFilter *filter)
564 IEnumPins *enumpins;
565 PIN_DIRECTION dir;
566 IPin *pin;
568 if (FAILED(IBaseFilter_EnumPins(filter, &enumpins)))
569 return FALSE;
571 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
573 IPin_QueryDirection(pin, &dir);
574 IPin_Release(pin);
575 if (dir == PINDIR_OUTPUT)
577 IEnumPins_Release(enumpins);
578 return TRUE;
582 IEnumPins_Release(enumpins);
583 return FALSE;
586 static void update_seeking(struct filter *filter)
588 IMediaSeeking *seeking;
590 if (!filter->seeking)
592 /* The Legend of Heroes: Trails of Cold Steel II destroys its filter when
593 * its IMediaSeeking interface is released, so cache the interface instead
594 * of querying for it every time.
595 * Some filters (e.g. MediaStreamFilter) can become seekable when they are
596 * already in the graph, so always try to query IMediaSeeking if it's not
597 * cached yet. */
598 if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaSeeking, (void **)&seeking)))
600 if (IMediaSeeking_IsFormatSupported(seeking, &TIME_FORMAT_MEDIA_TIME) == S_OK)
601 filter->seeking = seeking;
602 else
603 IMediaSeeking_Release(seeking);
608 static BOOL is_renderer(struct filter *filter)
610 IAMFilterMiscFlags *flags;
611 BOOL ret = FALSE;
613 if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IAMFilterMiscFlags, (void **)&flags)))
615 if (IAMFilterMiscFlags_GetMiscFlags(flags) & AM_FILTER_MISC_FLAGS_IS_RENDERER)
616 ret = TRUE;
617 IAMFilterMiscFlags_Release(flags);
619 else
621 update_seeking(filter);
622 if (filter->seeking && !has_output_pins(filter->filter))
623 ret = TRUE;
625 return ret;
628 /*** IFilterGraph methods ***/
629 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
630 IBaseFilter *filter, const WCHAR *name)
632 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
633 BOOL duplicate_name = FALSE;
634 struct filter *entry;
635 unsigned int i;
636 HRESULT hr;
638 TRACE("graph %p, filter %p, name %s.\n", graph, filter, debugstr_w(name));
640 if (!filter)
641 return E_POINTER;
643 if (!(entry = heap_alloc(sizeof(*entry))))
644 return E_OUTOFMEMORY;
646 if (!(entry->name = CoTaskMemAlloc((name ? wcslen(name) + 6 : 5) * sizeof(WCHAR))))
648 heap_free(entry);
649 return E_OUTOFMEMORY;
652 if (name && find_filter_by_name(graph, name))
653 duplicate_name = TRUE;
655 if (!name || duplicate_name)
657 for (i = 0; i < 10000 ; ++i)
659 if (name)
660 swprintf(entry->name, name ? wcslen(name) + 6 : 5, L"%s %04u", name, graph->name_index);
661 else
662 swprintf(entry->name, name ? wcslen(name) + 6 : 5, L"%04u", graph->name_index);
664 graph->name_index = (graph->name_index + 1) % 10000;
666 if (!find_filter_by_name(graph, entry->name))
667 break;
670 if (i == 10000)
672 CoTaskMemFree(entry->name);
673 heap_free(entry);
674 return VFW_E_DUPLICATE_NAME;
677 else
678 wcscpy(entry->name, name);
680 if (FAILED(hr = IBaseFilter_JoinFilterGraph(filter,
681 (IFilterGraph *)&graph->IFilterGraph2_iface, entry->name)))
683 CoTaskMemFree(entry->name);
684 heap_free(entry);
685 return hr;
688 IBaseFilter_AddRef(entry->filter = filter);
690 list_add_head(&graph->filters, &entry->entry);
691 entry->sorting = FALSE;
692 entry->seeking = NULL;
693 ++graph->version;
695 return duplicate_name ? VFW_S_DUPLICATE_NAME : hr;
698 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
700 struct filter_graph *This = impl_from_IFilterGraph2(iface);
701 struct filter *entry;
702 int i;
703 HRESULT hr = E_FAIL;
705 TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
707 LIST_FOR_EACH_ENTRY(entry, &This->filters, struct filter, entry)
709 if (entry->filter == pFilter)
711 IEnumPins *penumpins = NULL;
713 if (This->defaultclock && This->refClockProvider == pFilter)
715 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
716 This->defaultclock = TRUE;
719 TRACE("Removing filter %s.\n", debugstr_w(entry->name));
721 hr = IBaseFilter_EnumPins(pFilter, &penumpins);
722 if (SUCCEEDED(hr)) {
723 IPin *ppin;
724 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
726 IPin *peer = NULL;
727 HRESULT hr;
729 IPin_ConnectedTo(ppin, &peer);
730 if (peer)
732 if (FAILED(hr = IPin_Disconnect(peer)))
734 WARN("Failed to disconnect peer %p, hr %#x.\n", peer, hr);
735 IPin_Release(peer);
736 IPin_Release(ppin);
737 IEnumPins_Release(penumpins);
738 return hr;
740 IPin_Release(peer);
742 if (FAILED(hr = IPin_Disconnect(ppin)))
744 WARN("Failed to disconnect pin %p, hr %#x.\n", ppin, hr);
745 IPin_Release(ppin);
746 IEnumPins_Release(penumpins);
747 return hr;
750 IPin_Release(ppin);
752 IEnumPins_Release(penumpins);
755 hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, NULL);
756 if (SUCCEEDED(hr))
758 IBaseFilter_SetSyncSource(pFilter, NULL);
759 IBaseFilter_Release(pFilter);
760 if (entry->seeking)
761 IMediaSeeking_Release(entry->seeking);
762 list_remove(&entry->entry);
763 CoTaskMemFree(entry->name);
764 heap_free(entry);
765 This->version++;
766 /* Invalidate interfaces in the cache */
767 for (i = 0; i < This->nItfCacheEntries; i++)
768 if (pFilter == This->ItfCacheEntries[i].filter)
770 IUnknown_Release(This->ItfCacheEntries[i].iface);
771 This->ItfCacheEntries[i].iface = NULL;
772 This->ItfCacheEntries[i].filter = NULL;
774 return S_OK;
776 break;
780 return hr; /* FIXME: check this error code */
783 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface, IEnumFilters **out)
785 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
787 TRACE("graph %p, out %p.\n", graph, out);
789 return create_enum_filters(graph, list_head(&graph->filters), out);
792 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface,
793 const WCHAR *name, IBaseFilter **filter)
795 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
797 TRACE("graph %p, name %s, filter %p.\n", graph, debugstr_w(name), filter);
799 if (!filter)
800 return E_POINTER;
802 if ((*filter = find_filter_by_name(graph, name)))
804 IBaseFilter_AddRef(*filter);
805 return S_OK;
808 return VFW_E_NOT_FOUND;
811 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
812 * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
814 static HRESULT CheckCircularConnection(struct filter_graph *This, IPin *out, IPin *in)
816 #if 1
817 HRESULT hr;
818 PIN_INFO info_out, info_in;
820 hr = IPin_QueryPinInfo(out, &info_out);
821 if (FAILED(hr))
822 return hr;
823 if (info_out.dir != PINDIR_OUTPUT)
825 IBaseFilter_Release(info_out.pFilter);
826 return VFW_E_CANNOT_CONNECT;
829 hr = IPin_QueryPinInfo(in, &info_in);
830 if (SUCCEEDED(hr))
831 IBaseFilter_Release(info_in.pFilter);
832 if (FAILED(hr))
833 goto out;
834 if (info_in.dir != PINDIR_INPUT)
836 hr = VFW_E_CANNOT_CONNECT;
837 goto out;
840 if (info_out.pFilter == info_in.pFilter)
841 hr = VFW_E_CIRCULAR_GRAPH;
842 else
844 IEnumPins *enumpins;
845 IPin *test;
847 hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
848 if (FAILED(hr))
849 goto out;
851 IEnumPins_Reset(enumpins);
852 while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
854 PIN_DIRECTION dir = PINDIR_OUTPUT;
855 IPin_QueryDirection(test, &dir);
856 if (dir == PINDIR_INPUT)
858 IPin *victim = NULL;
859 IPin_ConnectedTo(test, &victim);
860 if (victim)
862 hr = CheckCircularConnection(This, victim, in);
863 IPin_Release(victim);
864 if (FAILED(hr))
866 IPin_Release(test);
867 break;
871 IPin_Release(test);
873 IEnumPins_Release(enumpins);
876 out:
877 IBaseFilter_Release(info_out.pFilter);
878 if (FAILED(hr))
879 ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
880 return hr;
881 #else
882 /* Debugging filtergraphs not enabled */
883 return S_OK;
884 #endif
887 static struct filter *find_sorted_filter(struct filter_graph *graph, IBaseFilter *iface)
889 struct filter *filter;
891 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
893 if (filter->filter == iface)
894 return filter;
897 return NULL;
900 static void sort_filter_recurse(struct filter_graph *graph, struct filter *filter, struct list *sorted)
902 struct filter *peer_filter;
903 IEnumPins *enumpins;
904 PIN_DIRECTION dir;
905 IPin *pin, *peer;
906 PIN_INFO info;
908 TRACE("Sorting filter %p.\n", filter->filter);
910 /* Cyclic connections should be caught by CheckCircularConnection(). */
911 assert(!filter->sorting);
913 filter->sorting = TRUE;
915 IBaseFilter_EnumPins(filter->filter, &enumpins);
916 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
918 IPin_QueryDirection(pin, &dir);
920 if (dir == PINDIR_INPUT && IPin_ConnectedTo(pin, &peer) == S_OK)
922 IPin_QueryPinInfo(peer, &info);
923 /* Note that the filter may have already been sorted. */
924 if ((peer_filter = find_sorted_filter(graph, info.pFilter)))
925 sort_filter_recurse(graph, peer_filter, sorted);
926 IBaseFilter_Release(info.pFilter);
927 IPin_Release(peer);
929 IPin_Release(pin);
931 IEnumPins_Release(enumpins);
933 filter->sorting = FALSE;
935 list_remove(&filter->entry);
936 list_add_head(sorted, &filter->entry);
939 static void sort_filters(struct filter_graph *graph)
941 struct list sorted = LIST_INIT(sorted), *cursor;
943 while ((cursor = list_head(&graph->filters)))
945 struct filter *filter = LIST_ENTRY(cursor, struct filter, entry);
946 sort_filter_recurse(graph, filter, &sorted);
949 list_move_tail(&graph->filters, &sorted);
952 /* NOTE: despite the implication, it doesn't matter which
953 * way round you put in the input and output pins */
954 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppinIn, IPin *ppinOut,
955 const AM_MEDIA_TYPE *pmt)
957 struct filter_graph *This = impl_from_IFilterGraph2(iface);
958 PIN_DIRECTION dir;
959 HRESULT hr;
961 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
962 strmbase_dump_media_type(pmt);
964 /* FIXME: check pins are in graph */
966 if (TRACE_ON(quartz))
968 PIN_INFO PinInfo;
970 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
971 if (FAILED(hr))
972 return hr;
974 TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
975 IBaseFilter_Release(PinInfo.pFilter);
977 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
978 if (FAILED(hr))
979 return hr;
981 TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
982 IBaseFilter_Release(PinInfo.pFilter);
985 hr = IPin_QueryDirection(ppinIn, &dir);
986 if (SUCCEEDED(hr))
988 if (dir == PINDIR_INPUT)
990 hr = CheckCircularConnection(This, ppinOut, ppinIn);
991 if (SUCCEEDED(hr))
992 hr = IPin_Connect(ppinOut, ppinIn, pmt);
994 else
996 hr = CheckCircularConnection(This, ppinIn, ppinOut);
997 if (SUCCEEDED(hr))
998 hr = IPin_Connect(ppinIn, ppinOut, pmt);
1002 return hr;
1005 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface, IPin *pin)
1007 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1009 TRACE("graph %p, pin %p.\n", graph, pin);
1011 return IFilterGraph2_ReconnectEx(iface, pin, NULL);
1014 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
1016 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1018 TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
1020 if (!ppin)
1021 return E_POINTER;
1023 return IPin_Disconnect(ppin);
1026 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
1028 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1029 IReferenceClock *pClock = NULL;
1030 struct filter *filter;
1031 HRESULT hr = S_OK;
1033 TRACE("(%p/%p)->() live sources not handled properly!\n", This, iface);
1035 EnterCriticalSection(&This->cs);
1037 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
1039 if (IBaseFilter_QueryInterface(filter->filter, &IID_IReferenceClock, (void **)&pClock) == S_OK)
1040 break;
1043 if (!pClock)
1045 hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
1046 This->refClockProvider = NULL;
1048 else
1050 filter = LIST_ENTRY(list_tail(&This->filters), struct filter, entry);
1051 This->refClockProvider = filter->filter;
1054 if (SUCCEEDED(hr))
1056 hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
1057 This->defaultclock = TRUE;
1058 IReferenceClock_Release(pClock);
1060 LeaveCriticalSection(&This->cs);
1062 return hr;
1065 struct filter_create_params
1067 HRESULT hr;
1068 IMoniker *moniker;
1069 IBaseFilter *filter;
1072 static DWORD WINAPI message_thread_run(void *ctx)
1074 struct filter_graph *graph = ctx;
1075 MSG msg;
1077 /* Make sure we have a message queue. */
1078 PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
1079 SetEvent(graph->message_thread_ret);
1081 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1083 for (;;)
1085 GetMessageW(&msg, NULL, 0, 0);
1087 if (!msg.hwnd && msg.message == WM_USER)
1089 struct filter_create_params *params = (struct filter_create_params *)msg.wParam;
1091 params->hr = IMoniker_BindToObject(params->moniker, NULL, NULL,
1092 &IID_IBaseFilter, (void **)&params->filter);
1093 SetEvent(graph->message_thread_ret);
1095 else if (!msg.hwnd && msg.message == WM_USER + 1)
1097 break;
1099 else
1101 TranslateMessage(&msg);
1102 DispatchMessageW(&msg);
1106 CoUninitialize();
1107 return 0;
1110 static HRESULT create_filter(struct filter_graph *graph, IMoniker *moniker, IBaseFilter **filter)
1112 if (graph->message_thread)
1114 struct filter_create_params params;
1116 params.moniker = moniker;
1117 PostThreadMessageW(graph->message_thread_id, WM_USER, (WPARAM)&params, 0);
1118 WaitForSingleObject(graph->message_thread_ret, INFINITE);
1119 *filter = params.filter;
1120 return params.hr;
1122 else
1123 return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter);
1126 static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
1127 BOOL render_to_existing, unsigned int recursion_depth);
1129 static HRESULT autoplug_through_sink(struct filter_graph *graph, IPin *source,
1130 IBaseFilter *filter, IPin *middle_sink, IPin *sink,
1131 BOOL render_to_existing, unsigned int recursion_depth)
1133 BOOL any = FALSE, all = TRUE;
1134 IPin *middle_source, *peer;
1135 IEnumPins *source_enum;
1136 PIN_DIRECTION dir;
1137 PIN_INFO info;
1138 HRESULT hr;
1140 TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, middle_sink);
1142 IPin_QueryDirection(middle_sink, &dir);
1143 if (dir != PINDIR_INPUT)
1144 return E_FAIL;
1146 if (IPin_ConnectedTo(middle_sink, &peer) == S_OK)
1148 IPin_Release(peer);
1149 return E_FAIL;
1152 if (FAILED(hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, middle_sink, NULL)))
1153 return E_FAIL;
1155 if (FAILED(hr = IBaseFilter_EnumPins(filter, &source_enum)))
1156 goto err;
1158 while (IEnumPins_Next(source_enum, 1, &middle_source, NULL) == S_OK)
1160 IPin_QueryPinInfo(middle_source, &info);
1161 IBaseFilter_Release(info.pFilter);
1162 if (info.dir != PINDIR_OUTPUT)
1164 IPin_Release(middle_source);
1165 continue;
1167 if (info.achName[0] == '~')
1169 TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
1170 IPin_Release(middle_source);
1171 continue;
1173 if (IPin_ConnectedTo(middle_source, &peer) == S_OK)
1175 IPin_Release(peer);
1176 IPin_Release(middle_source);
1177 continue;
1180 hr = autoplug(graph, middle_source, sink, render_to_existing, recursion_depth + 1);
1181 IPin_Release(middle_source);
1182 if (SUCCEEDED(hr) && sink)
1184 IEnumPins_Release(source_enum);
1185 return hr;
1187 if (SUCCEEDED(hr))
1188 any = TRUE;
1189 if (hr != S_OK)
1190 all = FALSE;
1192 IEnumPins_Release(source_enum);
1194 if (!sink)
1196 if (all)
1197 return S_OK;
1198 if (any)
1199 return VFW_S_PARTIAL_RENDER;
1202 err:
1203 IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, source);
1204 IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, middle_sink);
1205 return E_FAIL;
1208 static HRESULT autoplug_through_filter(struct filter_graph *graph, IPin *source,
1209 IBaseFilter *filter, IPin *sink, BOOL render_to_existing,
1210 unsigned int recursion_depth)
1212 IEnumPins *sink_enum;
1213 IPin *filter_sink;
1214 HRESULT hr;
1216 TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, filter);
1218 if (FAILED(hr = IBaseFilter_EnumPins(filter, &sink_enum)))
1219 return hr;
1221 while (IEnumPins_Next(sink_enum, 1, &filter_sink, NULL) == S_OK)
1223 hr = autoplug_through_sink(graph, source, filter, filter_sink, sink,
1224 render_to_existing, recursion_depth);
1225 IPin_Release(filter_sink);
1226 if (SUCCEEDED(hr))
1228 IEnumPins_Release(sink_enum);
1229 return hr;
1232 IEnumPins_Release(sink_enum);
1233 return VFW_E_CANNOT_CONNECT;
1236 /* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which
1237 * share most of the same code. Render() calls this with a NULL sink. */
1238 static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
1239 BOOL render_to_existing, unsigned int recursion_depth)
1241 IAMGraphBuilderCallback *callback = NULL;
1242 IEnumMediaTypes *enummt;
1243 IFilterMapper2 *mapper;
1244 struct filter *filter;
1245 AM_MEDIA_TYPE *mt;
1246 HRESULT hr;
1248 TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
1250 if (recursion_depth >= 5)
1252 WARN("Recursion depth has reached 5; aborting.\n");
1253 return VFW_E_CANNOT_CONNECT;
1256 if (sink)
1258 /* Try to connect directly to this sink. */
1259 hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, sink, NULL);
1261 /* If direct connection succeeded, we should propagate that return value.
1262 * If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
1263 * even bother trying intermediate filters, since they won't succeed. */
1264 if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
1265 return hr;
1268 /* Always prefer filters in the graph. */
1269 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1271 if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter,
1272 sink, render_to_existing, recursion_depth)))
1273 return hr;
1276 IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
1278 if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
1280 IFilterMapper2_Release(mapper);
1281 return hr;
1284 if (graph->pSite)
1285 IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
1287 while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
1289 GUID types[2] = {mt->majortype, mt->subtype};
1290 IEnumMoniker *enummoniker;
1291 IBaseFilter *filter;
1292 IMoniker *moniker;
1294 DeleteMediaType(mt);
1296 if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker,
1297 0, FALSE, MERIT_UNLIKELY, TRUE, 1, types, NULL, NULL, FALSE,
1298 render_to_existing, 0, NULL, NULL, NULL)))
1299 goto out;
1301 while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
1303 IPropertyBag *bag;
1304 VARIANT var;
1306 VariantInit(&var);
1307 IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&bag);
1308 hr = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
1309 IPropertyBag_Release(bag);
1310 if (FAILED(hr))
1312 IMoniker_Release(moniker);
1313 continue;
1316 if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
1318 TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#x.\n", hr);
1319 IMoniker_Release(moniker);
1320 continue;
1323 hr = create_filter(graph, moniker, &filter);
1324 IMoniker_Release(moniker);
1325 if (FAILED(hr))
1327 ERR("Failed to create filter for %s, hr %#x.\n", debugstr_w(V_BSTR(&var)), hr);
1328 VariantClear(&var);
1329 continue;
1332 if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
1334 TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#x.\n", hr);
1335 IBaseFilter_Release(filter);
1336 continue;
1339 hr = IFilterGraph2_AddFilter(&graph->IFilterGraph2_iface, filter, V_BSTR(&var));
1340 VariantClear(&var);
1341 if (FAILED(hr))
1343 ERR("Failed to add filter, hr %#x.\n", hr);
1344 IBaseFilter_Release(filter);
1345 continue;
1348 hr = autoplug_through_filter(graph, source, filter, sink, render_to_existing, recursion_depth);
1349 if (SUCCEEDED(hr))
1351 IBaseFilter_Release(filter);
1352 goto out;
1355 IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
1356 IBaseFilter_Release(filter);
1358 IEnumMoniker_Release(enummoniker);
1361 hr = VFW_E_CANNOT_CONNECT;
1363 out:
1364 if (callback) IAMGraphBuilderCallback_Release(callback);
1365 IEnumMediaTypes_Release(enummt);
1366 IFilterMapper2_Release(mapper);
1367 return hr;
1370 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *source, IPin *sink)
1372 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1373 PIN_DIRECTION dir;
1374 HRESULT hr;
1376 TRACE("graph %p, source %p, sink %p.\n", graph, source, sink);
1378 if (!source || !sink)
1379 return E_POINTER;
1381 if (FAILED(hr = IPin_QueryDirection(source, &dir)))
1382 return hr;
1384 if (dir == PINDIR_INPUT)
1386 IPin *temp;
1388 TRACE("Directions seem backwards, swapping pins\n");
1390 temp = sink;
1391 sink = source;
1392 source = temp;
1395 EnterCriticalSection(&graph->cs);
1397 hr = autoplug(graph, source, sink, FALSE, 0);
1399 LeaveCriticalSection(&graph->cs);
1401 TRACE("Returning %#x.\n", hr);
1402 return hr;
1405 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *source)
1407 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1408 HRESULT hr;
1410 TRACE("graph %p, source %p.\n", graph, source);
1412 EnterCriticalSection(&graph->cs);
1413 hr = autoplug(graph, source, NULL, FALSE, 0);
1414 LeaveCriticalSection(&graph->cs);
1415 if (hr == VFW_E_CANNOT_CONNECT)
1416 hr = VFW_E_CANNOT_RENDER;
1418 TRACE("Returning %#x.\n", hr);
1419 return hr;
1422 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, LPCWSTR lpcwstrFile,
1423 LPCWSTR lpcwstrPlayList)
1425 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1426 IBaseFilter* preader = NULL;
1427 IPin* ppinreader = NULL;
1428 IEnumPins* penumpins = NULL;
1429 struct filter *filter;
1430 HRESULT hr;
1431 BOOL partial = FALSE;
1432 BOOL any = FALSE;
1434 TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1436 if (lpcwstrPlayList != NULL)
1437 return E_INVALIDARG;
1439 hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, L"Reader", &preader);
1440 if (FAILED(hr))
1441 return hr;
1443 hr = IBaseFilter_EnumPins(preader, &penumpins);
1444 if (SUCCEEDED(hr))
1446 while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1448 PIN_DIRECTION dir;
1450 IPin_QueryDirection(ppinreader, &dir);
1451 if (dir == PINDIR_OUTPUT)
1453 hr = IFilterGraph2_Render(iface, ppinreader);
1455 TRACE("Filters in chain:\n");
1456 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
1457 TRACE("- %s.\n", debugstr_w(filter->name));
1459 if (SUCCEEDED(hr))
1460 any = TRUE;
1461 if (hr != S_OK)
1462 partial = TRUE;
1464 IPin_Release(ppinreader);
1466 IEnumPins_Release(penumpins);
1468 if (!any)
1469 hr = VFW_E_CANNOT_RENDER;
1470 else if (partial)
1471 hr = VFW_S_PARTIAL_RENDER;
1472 else
1473 hr = S_OK;
1475 IBaseFilter_Release(preader);
1477 TRACE("--> %08x\n", hr);
1478 return hr;
1481 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface,
1482 const WCHAR *filename, const WCHAR *filter_name, IBaseFilter **ret_filter)
1484 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1485 IFileSourceFilter *filesource;
1486 IBaseFilter *filter;
1487 HRESULT hr;
1488 GUID clsid;
1490 TRACE("graph %p, filename %s, filter_name %s, ret_filter %p.\n",
1491 graph, debugstr_w(filename), debugstr_w(filter_name), ret_filter);
1493 if (!get_media_type(filename, NULL, NULL, &clsid))
1494 clsid = CLSID_AsyncReader;
1495 TRACE("Using source filter %s.\n", debugstr_guid(&clsid));
1497 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
1498 &IID_IBaseFilter, (void **)&filter)))
1500 WARN("Failed to create filter, hr %#x.\n", hr);
1501 return hr;
1504 if (FAILED(hr = IBaseFilter_QueryInterface(filter, &IID_IFileSourceFilter, (void **)&filesource)))
1506 WARN("Failed to get IFileSourceFilter, hr %#x.\n", hr);
1507 IBaseFilter_Release(filter);
1508 return hr;
1511 hr = IFileSourceFilter_Load(filesource, filename, NULL);
1512 IFileSourceFilter_Release(filesource);
1513 if (FAILED(hr))
1515 WARN("Failed to load file, hr %#x.\n", hr);
1516 return hr;
1519 if (FAILED(hr = IFilterGraph2_AddFilter(iface, filter, filter_name)))
1521 IBaseFilter_Release(filter);
1522 return hr;
1525 if (ret_filter)
1526 *ret_filter = filter;
1527 return S_OK;
1530 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface, DWORD_PTR hFile)
1532 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1534 TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1536 return S_OK;
1539 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface)
1541 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1543 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1545 return S_OK;
1548 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface)
1550 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1552 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1554 return S_OK;
1557 /*** IFilterGraph2 methods ***/
1558 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1559 IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1561 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1562 HRESULT hr;
1563 IBaseFilter* pfilter;
1565 TRACE("(%p/%p)->(%p %p %s %p)\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1567 hr = IMoniker_BindToObject(pMoniker, pCtx, NULL, &IID_IBaseFilter, (void**)&pfilter);
1568 if(FAILED(hr)) {
1569 WARN("Unable to bind moniker to filter object (%x)\n", hr);
1570 return hr;
1573 hr = IFilterGraph2_AddFilter(iface, pfilter, lpcwstrFilterName);
1574 if (FAILED(hr)) {
1575 WARN("Unable to add filter (%x)\n", hr);
1576 IBaseFilter_Release(pfilter);
1577 return hr;
1580 if(ppFilter)
1581 *ppFilter = pfilter;
1582 else IBaseFilter_Release(pfilter);
1584 return S_OK;
1587 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *pin, const AM_MEDIA_TYPE *mt)
1589 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1590 PIN_DIRECTION dir;
1591 HRESULT hr;
1592 IPin *peer;
1594 TRACE("graph %p, pin %p, mt %p.\n", graph, pin, mt);
1596 if (FAILED(hr = IPin_ConnectedTo(pin, &peer)))
1597 return hr;
1599 IPin_QueryDirection(pin, &dir);
1600 IFilterGraph2_Disconnect(iface, peer);
1601 IFilterGraph2_Disconnect(iface, pin);
1603 if (dir == PINDIR_INPUT)
1604 hr = IFilterGraph2_ConnectDirect(iface, peer, pin, mt);
1605 else
1606 hr = IFilterGraph2_ConnectDirect(iface, pin, peer, mt);
1608 IPin_Release(peer);
1609 return hr;
1612 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *source, DWORD flags, DWORD *context)
1614 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1615 HRESULT hr;
1617 TRACE("graph %p, source %p, flags %#x, context %p.\n", graph, source, flags, context);
1619 if (flags & ~AM_RENDEREX_RENDERTOEXISTINGRENDERERS)
1620 FIXME("Unknown flags %#x.\n", flags);
1622 EnterCriticalSection(&graph->cs);
1623 hr = autoplug(graph, source, NULL, !!(flags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS), 0);
1624 LeaveCriticalSection(&graph->cs);
1625 if (hr == VFW_E_CANNOT_CONNECT)
1626 hr = VFW_E_CANNOT_RENDER;
1628 TRACE("Returning %#x.\n", hr);
1629 return hr;
1633 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1635 FilterGraph2_QueryInterface,
1636 FilterGraph2_AddRef,
1637 FilterGraph2_Release,
1638 FilterGraph2_AddFilter,
1639 FilterGraph2_RemoveFilter,
1640 FilterGraph2_EnumFilters,
1641 FilterGraph2_FindFilterByName,
1642 FilterGraph2_ConnectDirect,
1643 FilterGraph2_Reconnect,
1644 FilterGraph2_Disconnect,
1645 FilterGraph2_SetDefaultSyncSource,
1646 FilterGraph2_Connect,
1647 FilterGraph2_Render,
1648 FilterGraph2_RenderFile,
1649 FilterGraph2_AddSourceFilter,
1650 FilterGraph2_SetLogFile,
1651 FilterGraph2_Abort,
1652 FilterGraph2_ShouldOperationContinue,
1653 FilterGraph2_AddSourceFilterForMoniker,
1654 FilterGraph2_ReconnectEx,
1655 FilterGraph2_RenderEx
1658 static struct filter_graph *impl_from_IMediaControl(IMediaControl *iface)
1660 return CONTAINING_RECORD(iface, struct filter_graph, IMediaControl_iface);
1663 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID iid, void **out)
1665 struct filter_graph *graph = impl_from_IMediaControl(iface);
1666 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
1669 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1671 struct filter_graph *graph = impl_from_IMediaControl(iface);
1672 return IUnknown_AddRef(graph->outer_unk);
1675 static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1677 struct filter_graph *graph = impl_from_IMediaControl(iface);
1678 return IUnknown_Release(graph->outer_unk);
1682 /*** IDispatch methods ***/
1683 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *pctinfo)
1685 struct filter_graph *This = impl_from_IMediaControl(iface);
1687 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1689 return S_OK;
1692 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT iTInfo, LCID lcid,
1693 ITypeInfo **ppTInfo)
1695 struct filter_graph *This = impl_from_IMediaControl(iface);
1697 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1699 return S_OK;
1702 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID riid,
1703 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1705 struct filter_graph *This = impl_from_IMediaControl(iface);
1707 TRACE("(%p/%p)->(%s, %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), rgszNames,
1708 cNames, lcid, rgDispId);
1710 return S_OK;
1713 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMember, REFIID riid,
1714 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
1715 UINT *puArgErr)
1717 struct filter_graph *This = impl_from_IMediaControl(iface);
1719 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember,
1720 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1722 return S_OK;
1725 static void update_render_count(struct filter_graph *graph)
1727 /* Some filters (e.g. MediaStreamFilter) can become renderers when they are
1728 * already in the graph. */
1729 struct filter *filter;
1730 graph->nRenderers = 0;
1731 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1733 if (is_renderer(filter))
1734 ++graph->nRenderers;
1738 /* Perform the paused -> running transition. The caller must hold graph->cs. */
1739 static HRESULT graph_start(struct filter_graph *graph, REFERENCE_TIME stream_start)
1741 REFERENCE_TIME stream_stop;
1742 struct filter *filter;
1743 HRESULT hr = S_OK;
1745 graph->EcCompleteCount = 0;
1746 update_render_count(graph);
1748 if (graph->defaultclock && !graph->refClock)
1749 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
1751 if (!stream_start && graph->refClock)
1753 IReferenceClock_GetTime(graph->refClock, &graph->stream_start);
1754 stream_start = graph->stream_start - graph->stream_elapsed;
1755 /* Delay presentation time by 200 ms, to give filters time to
1756 * initialize. */
1757 stream_start += 200 * 10000;
1760 if (SUCCEEDED(IMediaSeeking_GetStopPosition(&graph->IMediaSeeking_iface, &stream_stop)))
1761 graph->stream_stop = stream_stop;
1763 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1765 HRESULT filter_hr = IBaseFilter_Run(filter->filter, stream_start);
1766 if (hr == S_OK)
1767 hr = filter_hr;
1768 TRACE("Filter %p returned %#x.\n", filter->filter, filter_hr);
1771 if (FAILED(hr))
1772 WARN("Failed to start stream, hr %#x.\n", hr);
1774 return hr;
1777 static void CALLBACK async_run_cb(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work)
1779 struct filter_graph *graph = context;
1780 struct filter *filter;
1781 FILTER_STATE state;
1782 HRESULT hr;
1784 TRACE("Performing asynchronous state change.\n");
1786 /* We can't just call GetState(), since that will return State_Running and
1787 * VFW_S_STATE_INTERMEDIATE regardless of whether we're done pausing yet.
1788 * Instead replicate it here. */
1790 for (;;)
1792 IBaseFilter *async_filter = NULL;
1794 hr = S_OK;
1796 EnterCriticalSection(&graph->cs);
1798 if (!graph->needs_async_run)
1799 break;
1801 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1803 hr = IBaseFilter_GetState(filter->filter, 0, &state);
1805 if (hr == VFW_S_STATE_INTERMEDIATE)
1806 async_filter = filter->filter;
1808 if (SUCCEEDED(hr) && state != State_Paused)
1809 ERR("Filter %p reported incorrect state %u.\n", filter->filter, state);
1811 if (hr != S_OK)
1812 break;
1815 if (hr != VFW_S_STATE_INTERMEDIATE)
1816 break;
1818 LeaveCriticalSection(&graph->cs);
1820 IBaseFilter_GetState(async_filter, 10, &state);
1823 if (hr == S_OK && graph->needs_async_run)
1825 sort_filters(graph);
1826 graph_start(graph, 0);
1827 graph->needs_async_run = 0;
1830 LeaveCriticalSection(&graph->cs);
1833 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
1835 struct filter_graph *graph = impl_from_IMediaControl(iface);
1836 BOOL need_async_run = TRUE;
1837 struct filter *filter;
1838 FILTER_STATE state;
1839 HRESULT hr = S_OK;
1841 TRACE("graph %p.\n", graph);
1843 EnterCriticalSection(&graph->cs);
1845 if (graph->state == State_Running)
1847 LeaveCriticalSection(&graph->cs);
1848 return S_OK;
1851 sort_filters(graph);
1852 update_render_count(graph);
1854 if (graph->state == State_Stopped)
1856 if (graph->defaultclock && !graph->refClock)
1857 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
1859 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1861 HRESULT filter_hr = IBaseFilter_Pause(filter->filter);
1862 if (hr == S_OK)
1863 hr = filter_hr;
1864 TRACE("Filter %p returned %#x.\n", filter->filter, filter_hr);
1866 /* If a filter returns VFW_S_CANT_CUE, we shouldn't wait for a
1867 * paused state. */
1868 filter_hr = IBaseFilter_GetState(filter->filter, 0, &state);
1869 if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE)
1870 need_async_run = FALSE;
1873 if (FAILED(hr))
1875 LeaveCriticalSection(&graph->cs);
1876 WARN("Failed to pause, hr %#x.\n", hr);
1877 return hr;
1881 graph->state = State_Running;
1883 if (SUCCEEDED(hr))
1885 if (hr != S_OK && need_async_run)
1887 if (!graph->async_run_work)
1888 graph->async_run_work = CreateThreadpoolWork(async_run_cb, graph, NULL);
1889 graph->needs_async_run = 1;
1890 SubmitThreadpoolWork(graph->async_run_work);
1892 else
1894 graph_start(graph, 0);
1898 LeaveCriticalSection(&graph->cs);
1899 return hr;
1902 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
1904 struct filter_graph *graph = impl_from_IMediaControl(iface);
1906 TRACE("graph %p.\n", graph);
1908 return IMediaFilter_Pause(&graph->IMediaFilter_iface);
1911 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
1913 struct filter_graph *graph = impl_from_IMediaControl(iface);
1915 TRACE("graph %p.\n", graph);
1917 return IMediaFilter_Stop(&graph->IMediaFilter_iface);
1920 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG timeout, OAFilterState *state)
1922 struct filter_graph *graph = impl_from_IMediaControl(iface);
1924 TRACE("graph %p, timeout %u, state %p.\n", graph, timeout, state);
1926 if (timeout < 0) timeout = INFINITE;
1928 return IMediaFilter_GetState(&graph->IMediaFilter_iface, timeout, (FILTER_STATE *)state);
1931 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
1933 struct filter_graph *This = impl_from_IMediaControl(iface);
1935 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strFilename), strFilename);
1937 return IFilterGraph2_RenderFile(&This->IFilterGraph2_iface, strFilename, NULL);
1940 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
1941 IDispatch **ppUnk)
1943 struct filter_graph *This = impl_from_IMediaControl(iface);
1945 FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
1947 return S_OK;
1950 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
1952 struct filter_graph *This = impl_from_IMediaControl(iface);
1954 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1956 return S_OK;
1959 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
1961 struct filter_graph *This = impl_from_IMediaControl(iface);
1963 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1965 return S_OK;
1968 static void CALLBACK wait_pause_cb(TP_CALLBACK_INSTANCE *instance, void *context)
1970 IMediaControl *control = context;
1971 OAFilterState state;
1972 HRESULT hr;
1974 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
1975 ERR("Failed to get paused state, hr %#x.\n", hr);
1977 if (FAILED(hr = IMediaControl_Stop(control)))
1978 ERR("Failed to stop, hr %#x.\n", hr);
1980 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
1981 ERR("Failed to get paused state, hr %#x.\n", hr);
1983 IMediaControl_Release(control);
1986 static void CALLBACK wait_stop_cb(TP_CALLBACK_INSTANCE *instance, void *context)
1988 IMediaControl *control = context;
1989 OAFilterState state;
1990 HRESULT hr;
1992 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
1993 ERR("Failed to get state, hr %#x.\n", hr);
1995 IMediaControl_Release(control);
1998 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2000 struct filter_graph *graph = impl_from_IMediaControl(iface);
2001 HRESULT hr;
2003 TRACE("graph %p.\n", graph);
2005 /* Even if we are already stopped, we still pause. */
2006 hr = IMediaControl_Pause(iface);
2007 if (FAILED(hr))
2008 return hr;
2009 else if (hr == S_FALSE)
2011 IMediaControl_AddRef(iface);
2012 TrySubmitThreadpoolCallback(wait_pause_cb, iface, NULL);
2013 return S_FALSE;
2016 hr = IMediaControl_Stop(iface);
2017 if (FAILED(hr))
2018 return hr;
2019 else if (hr == S_FALSE)
2021 IMediaControl_AddRef(iface);
2022 TrySubmitThreadpoolCallback(wait_stop_cb, iface, NULL);
2023 return S_FALSE;
2026 return S_OK;
2030 static const IMediaControlVtbl IMediaControl_VTable =
2032 MediaControl_QueryInterface,
2033 MediaControl_AddRef,
2034 MediaControl_Release,
2035 MediaControl_GetTypeInfoCount,
2036 MediaControl_GetTypeInfo,
2037 MediaControl_GetIDsOfNames,
2038 MediaControl_Invoke,
2039 MediaControl_Run,
2040 MediaControl_Pause,
2041 MediaControl_Stop,
2042 MediaControl_GetState,
2043 MediaControl_RenderFile,
2044 MediaControl_AddSourceFilter,
2045 MediaControl_get_FilterCollection,
2046 MediaControl_get_RegFilterCollection,
2047 MediaControl_StopWhenReady
2050 static struct filter_graph *impl_from_IMediaSeeking(IMediaSeeking *iface)
2052 return CONTAINING_RECORD(iface, struct filter_graph, IMediaSeeking_iface);
2055 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface, REFIID iid, void **out)
2057 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2058 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2061 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
2063 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2064 return IUnknown_AddRef(graph->outer_unk);
2067 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
2069 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2070 return IUnknown_Release(graph->outer_unk);
2073 typedef HRESULT (WINAPI *fnFoundSeek)(struct filter_graph *This, IMediaSeeking*, DWORD_PTR arg);
2075 static HRESULT all_renderers_seek(struct filter_graph *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2076 BOOL allnotimpl = TRUE;
2077 HRESULT hr, hr_return = S_OK;
2078 struct filter *filter;
2080 TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2081 /* Send a message to all renderers, they are responsible for broadcasting it further */
2083 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
2085 update_seeking(filter);
2086 if (!filter->seeking)
2087 continue;
2088 hr = FoundSeek(This, filter->seeking, arg);
2089 if (hr_return != E_NOTIMPL)
2090 allnotimpl = FALSE;
2091 if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2092 hr_return = hr;
2095 if (allnotimpl)
2096 return E_NOTIMPL;
2097 return hr_return;
2100 static HRESULT WINAPI FoundCapabilities(struct filter_graph *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2102 HRESULT hr;
2103 DWORD caps = 0;
2105 hr = IMediaSeeking_GetCapabilities(seek, &caps);
2106 if (FAILED(hr))
2107 return hr;
2109 /* Only add common capabilities everything supports */
2110 *(DWORD*)pcaps &= caps;
2112 return hr;
2115 /*** IMediaSeeking methods ***/
2116 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2118 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2119 HRESULT hr;
2121 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2123 if (!pCapabilities)
2124 return E_POINTER;
2126 EnterCriticalSection(&This->cs);
2127 *pCapabilities = 0xffffffff;
2129 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2130 LeaveCriticalSection(&This->cs);
2132 return hr;
2135 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2137 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2138 DWORD originalcaps;
2139 HRESULT hr;
2141 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2143 if (!pCapabilities)
2144 return E_POINTER;
2146 EnterCriticalSection(&This->cs);
2147 originalcaps = *pCapabilities;
2148 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2149 LeaveCriticalSection(&This->cs);
2151 if (FAILED(hr))
2152 return hr;
2154 if (!*pCapabilities)
2155 return E_FAIL;
2156 if (*pCapabilities != originalcaps)
2157 return S_FALSE;
2158 return S_OK;
2161 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface, const GUID *pFormat)
2163 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2165 if (!pFormat)
2166 return E_POINTER;
2168 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2170 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2172 WARN("Unhandled time format %s\n", debugstr_guid(pFormat));
2173 return S_FALSE;
2176 return S_OK;
2179 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *pFormat)
2181 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2183 if (!pFormat)
2184 return E_POINTER;
2186 FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2187 memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2189 return S_OK;
2192 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface, GUID *pFormat)
2194 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2196 if (!pFormat)
2197 return E_POINTER;
2199 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2200 memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2202 return S_OK;
2205 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2207 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2209 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2210 if (!pFormat)
2211 return E_POINTER;
2213 if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2214 return S_FALSE;
2216 return S_OK;
2219 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2221 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2223 if (!pFormat)
2224 return E_POINTER;
2226 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2228 if (This->state != State_Stopped)
2229 return VFW_E_WRONG_STATE;
2231 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2233 FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2234 return E_INVALIDARG;
2237 return S_OK;
2240 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface, LONGLONG *duration)
2242 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2243 HRESULT hr = E_NOTIMPL, filter_hr;
2244 LONGLONG filter_duration;
2245 struct filter *filter;
2247 TRACE("graph %p, duration %p.\n", graph, duration);
2249 if (!duration)
2250 return E_POINTER;
2252 *duration = 0;
2254 EnterCriticalSection(&graph->cs);
2256 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2258 update_seeking(filter);
2259 if (!filter->seeking)
2260 continue;
2262 filter_hr = IMediaSeeking_GetDuration(filter->seeking, &filter_duration);
2263 if (SUCCEEDED(filter_hr))
2265 hr = S_OK;
2266 *duration = max(*duration, filter_duration);
2268 else if (filter_hr != E_NOTIMPL)
2270 LeaveCriticalSection(&graph->cs);
2271 return filter_hr;
2275 LeaveCriticalSection(&graph->cs);
2277 TRACE("Returning hr %#x, duration %s (%s seconds).\n", hr,
2278 wine_dbgstr_longlong(*duration), debugstr_time(*duration));
2279 return hr;
2282 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *stop)
2284 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2285 HRESULT hr = E_NOTIMPL, filter_hr;
2286 struct filter *filter;
2287 LONGLONG filter_stop;
2289 TRACE("graph %p, stop %p.\n", graph, stop);
2291 if (!stop)
2292 return E_POINTER;
2294 *stop = 0;
2296 EnterCriticalSection(&graph->cs);
2298 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2300 update_seeking(filter);
2301 if (!filter->seeking)
2302 continue;
2304 filter_hr = IMediaSeeking_GetStopPosition(filter->seeking, &filter_stop);
2305 if (SUCCEEDED(filter_hr))
2307 hr = S_OK;
2308 *stop = max(*stop, filter_stop);
2310 else if (filter_hr != E_NOTIMPL)
2312 LeaveCriticalSection(&graph->cs);
2313 return filter_hr;
2317 LeaveCriticalSection(&graph->cs);
2319 TRACE("Returning %s (%s seconds).\n", wine_dbgstr_longlong(*stop), debugstr_time(*stop));
2320 return hr;
2323 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *current)
2325 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2326 LONGLONG ret = graph->current_pos;
2328 TRACE("graph %p, current %p.\n", graph, current);
2330 if (!current)
2331 return E_POINTER;
2333 EnterCriticalSection(&graph->cs);
2335 if (graph->got_ec_complete)
2337 ret = graph->stream_stop;
2339 else if (graph->state == State_Running && !graph->needs_async_run && graph->refClock)
2341 REFERENCE_TIME time;
2342 IReferenceClock_GetTime(graph->refClock, &time);
2343 if (time)
2344 ret += time - graph->stream_start;
2347 LeaveCriticalSection(&graph->cs);
2349 TRACE("Returning %s (%s seconds).\n", wine_dbgstr_longlong(ret), debugstr_time(ret));
2350 *current = ret;
2352 return S_OK;
2355 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
2356 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2358 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2360 TRACE("(%p/%p)->(%p, %s, 0x%s, %s)\n", This, iface, pTarget,
2361 debugstr_guid(pTargetFormat), wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
2363 if (!pSourceFormat)
2364 pSourceFormat = &This->timeformatseek;
2366 if (!pTargetFormat)
2367 pTargetFormat = &This->timeformatseek;
2369 if (IsEqualGUID(pTargetFormat, pSourceFormat))
2370 *pTarget = Source;
2371 else
2372 FIXME("conversion %s->%s not supported\n", debugstr_guid(pSourceFormat), debugstr_guid(pTargetFormat));
2374 return S_OK;
2377 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *current_ptr,
2378 DWORD current_flags, LONGLONG *stop_ptr, DWORD stop_flags)
2380 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2381 HRESULT hr = E_NOTIMPL, filter_hr;
2382 struct filter *filter;
2383 FILTER_STATE state;
2385 TRACE("graph %p, current %s, current_flags %#x, stop %s, stop_flags %#x.\n", graph,
2386 current_ptr ? wine_dbgstr_longlong(*current_ptr) : "<null>", current_flags,
2387 stop_ptr ? wine_dbgstr_longlong(*stop_ptr): "<null>", stop_flags);
2388 if (current_ptr)
2389 TRACE("Setting current position to %s (%s seconds).\n",
2390 wine_dbgstr_longlong(*current_ptr), debugstr_time(*current_ptr));
2391 if (stop_ptr)
2392 TRACE("Setting stop position to %s (%s seconds).\n",
2393 wine_dbgstr_longlong(*stop_ptr), debugstr_time(*stop_ptr));
2395 if ((current_flags & 0x7) != AM_SEEKING_AbsolutePositioning
2396 && (current_flags & 0x7) != AM_SEEKING_NoPositioning)
2397 FIXME("Unhandled current_flags %#x.\n", current_flags & 0x7);
2399 if ((stop_flags & 0x7) != AM_SEEKING_NoPositioning
2400 && (stop_flags & 0x7) != AM_SEEKING_AbsolutePositioning)
2401 FIXME("Unhandled stop_flags %#x.\n", stop_flags & 0x7);
2403 EnterCriticalSection(&graph->cs);
2405 state = graph->state;
2406 if (state == State_Running && !graph->needs_async_run)
2407 IMediaControl_Pause(&graph->IMediaControl_iface);
2409 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2411 LONGLONG current = current_ptr ? *current_ptr : 0, stop = stop_ptr ? *stop_ptr : 0;
2413 update_seeking(filter);
2414 if (!filter->seeking)
2415 continue;
2417 filter_hr = IMediaSeeking_SetPositions(filter->seeking, &current,
2418 current_flags | AM_SEEKING_ReturnTime, &stop, stop_flags);
2419 if (SUCCEEDED(filter_hr))
2421 hr = S_OK;
2423 if (current_ptr && (current_flags & AM_SEEKING_ReturnTime))
2424 *current_ptr = current;
2425 if (stop_ptr && (stop_flags & AM_SEEKING_ReturnTime))
2426 *stop_ptr = stop;
2427 graph->current_pos = current;
2429 else if (filter_hr != E_NOTIMPL)
2431 LeaveCriticalSection(&graph->cs);
2432 return filter_hr;
2436 if ((current_flags & 0x7) != AM_SEEKING_NoPositioning && graph->refClock)
2438 IReferenceClock_GetTime(graph->refClock, &graph->stream_start);
2439 graph->stream_elapsed = 0;
2442 if (state == State_Running && !graph->needs_async_run)
2443 IMediaControl_Run(&graph->IMediaControl_iface);
2445 LeaveCriticalSection(&graph->cs);
2446 return hr;
2449 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
2450 LONGLONG *current, LONGLONG *stop)
2452 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2453 HRESULT hr = S_OK;
2455 TRACE("graph %p, current %p, stop %p.\n", graph, current, stop);
2457 if (current)
2458 hr = IMediaSeeking_GetCurrentPosition(iface, current);
2459 if (SUCCEEDED(hr) && stop)
2460 hr = IMediaSeeking_GetStopPosition(iface, stop);
2462 return hr;
2465 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, LONGLONG *pEarliest,
2466 LONGLONG *pLatest)
2468 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2470 FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2472 return S_OK;
2475 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2477 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2479 FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2481 return S_OK;
2484 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2486 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2488 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2490 if (!pdRate)
2491 return E_POINTER;
2493 *pdRate = 1.0;
2495 return S_OK;
2498 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
2500 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2502 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2504 return S_OK;
2508 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2510 MediaSeeking_QueryInterface,
2511 MediaSeeking_AddRef,
2512 MediaSeeking_Release,
2513 MediaSeeking_GetCapabilities,
2514 MediaSeeking_CheckCapabilities,
2515 MediaSeeking_IsFormatSupported,
2516 MediaSeeking_QueryPreferredFormat,
2517 MediaSeeking_GetTimeFormat,
2518 MediaSeeking_IsUsingTimeFormat,
2519 MediaSeeking_SetTimeFormat,
2520 MediaSeeking_GetDuration,
2521 MediaSeeking_GetStopPosition,
2522 MediaSeeking_GetCurrentPosition,
2523 MediaSeeking_ConvertTimeFormat,
2524 MediaSeeking_SetPositions,
2525 MediaSeeking_GetPositions,
2526 MediaSeeking_GetAvailable,
2527 MediaSeeking_SetRate,
2528 MediaSeeking_GetRate,
2529 MediaSeeking_GetPreroll
2532 static struct filter_graph *impl_from_IMediaPosition(IMediaPosition *iface)
2534 return CONTAINING_RECORD(iface, struct filter_graph, IMediaPosition_iface);
2537 /*** IUnknown methods ***/
2538 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition *iface, REFIID iid, void **out)
2540 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2541 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2544 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2546 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2547 return IUnknown_AddRef(graph->outer_unk);
2550 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2552 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2553 return IUnknown_Release(graph->outer_unk);
2556 /*** IDispatch methods ***/
2557 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo)
2559 FIXME("(%p) stub!\n", iface);
2560 return E_NOTIMPL;
2563 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2565 FIXME("(%p) stub!\n", iface);
2566 return E_NOTIMPL;
2569 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
2571 FIXME("(%p) stub!\n", iface);
2572 return E_NOTIMPL;
2575 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
2577 FIXME("(%p) stub!\n", iface);
2578 return E_NOTIMPL;
2581 static HRESULT ConvertFromREFTIME(IMediaSeeking *seek, REFTIME time_in, LONGLONG *time_out)
2583 GUID time_format;
2584 HRESULT hr;
2586 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2587 if (FAILED(hr))
2588 return hr;
2589 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2591 FIXME("Unsupported time format.\n");
2592 return E_NOTIMPL;
2595 *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2596 return S_OK;
2599 static HRESULT ConvertToREFTIME(IMediaSeeking *seek, LONGLONG time_in, REFTIME *time_out)
2601 GUID time_format;
2602 HRESULT hr;
2604 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2605 if (FAILED(hr))
2606 return hr;
2607 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2609 FIXME("Unsupported time format.\n");
2610 return E_NOTIMPL;
2613 *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2614 return S_OK;
2617 /*** IMediaPosition methods ***/
2618 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2620 LONGLONG duration;
2621 struct filter_graph *This = impl_from_IMediaPosition( iface );
2622 HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2623 if (FAILED(hr))
2624 return hr;
2625 return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2628 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2630 struct filter_graph *This = impl_from_IMediaPosition( iface );
2631 LONGLONG reftime;
2632 HRESULT hr;
2634 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2635 if (FAILED(hr))
2636 return hr;
2637 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2638 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
2641 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2643 struct filter_graph *This = impl_from_IMediaPosition( iface );
2644 LONGLONG pos;
2645 HRESULT hr;
2647 hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2648 if (FAILED(hr))
2649 return hr;
2650 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2653 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2655 struct filter_graph *This = impl_from_IMediaPosition( iface );
2656 LONGLONG pos;
2657 HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2658 if (FAILED(hr))
2659 return hr;
2660 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2663 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2665 struct filter_graph *This = impl_from_IMediaPosition( iface );
2666 LONGLONG reftime;
2667 HRESULT hr;
2669 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2670 if (FAILED(hr))
2671 return hr;
2672 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2673 &reftime, AM_SEEKING_AbsolutePositioning);
2676 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime)
2678 FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2679 return E_NOTIMPL;
2682 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime)
2684 FIXME("(%p)->(%f) stub!\n", iface, llTime);
2685 return E_NOTIMPL;
2688 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2690 struct filter_graph *This = impl_from_IMediaPosition( iface );
2691 return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2694 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2696 struct filter_graph *This = impl_from_IMediaPosition( iface );
2697 return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2700 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward)
2702 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2703 return E_NOTIMPL;
2706 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward)
2708 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2709 return E_NOTIMPL;
2713 static const IMediaPositionVtbl IMediaPosition_VTable =
2715 MediaPosition_QueryInterface,
2716 MediaPosition_AddRef,
2717 MediaPosition_Release,
2718 MediaPosition_GetTypeInfoCount,
2719 MediaPosition_GetTypeInfo,
2720 MediaPosition_GetIDsOfNames,
2721 MediaPosition_Invoke,
2722 MediaPosition_get_Duration,
2723 MediaPosition_put_CurrentPosition,
2724 MediaPosition_get_CurrentPosition,
2725 MediaPosition_get_StopTime,
2726 MediaPosition_put_StopTime,
2727 MediaPosition_get_PrerollTime,
2728 MediaPosition_put_PrerollTime,
2729 MediaPosition_put_Rate,
2730 MediaPosition_get_Rate,
2731 MediaPosition_CanSeekForward,
2732 MediaPosition_CanSeekBackward
2735 static struct filter_graph *impl_from_IObjectWithSite(IObjectWithSite *iface)
2737 return CONTAINING_RECORD(iface, struct filter_graph, IObjectWithSite_iface);
2740 /*** IUnknown methods ***/
2741 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID iid, void **out)
2743 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2744 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2747 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
2749 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2750 return IUnknown_AddRef(graph->outer_unk);
2753 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
2755 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2756 return IUnknown_Release(graph->outer_unk);
2759 /*** IObjectWithSite methods ***/
2761 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
2763 struct filter_graph *This = impl_from_IObjectWithSite( iface );
2765 TRACE("(%p/%p)->()\n", This, iface);
2766 if (This->pSite) IUnknown_Release(This->pSite);
2767 This->pSite = pUnkSite;
2768 IUnknown_AddRef(This->pSite);
2769 return S_OK;
2772 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, PVOID *ppvSite)
2774 struct filter_graph *This = impl_from_IObjectWithSite( iface );
2776 TRACE("(%p/%p)->(%s)\n", This, iface,debugstr_guid(riid));
2778 *ppvSite = NULL;
2779 if (!This->pSite)
2780 return E_FAIL;
2781 else
2782 return IUnknown_QueryInterface(This->pSite, riid, ppvSite);
2785 static const IObjectWithSiteVtbl IObjectWithSite_VTable =
2787 ObjectWithSite_QueryInterface,
2788 ObjectWithSite_AddRef,
2789 ObjectWithSite_Release,
2790 ObjectWithSite_SetSite,
2791 ObjectWithSite_GetSite,
2794 static HRESULT GetTargetInterface(struct filter_graph* pGraph, REFIID riid, LPVOID* ppvObj)
2796 struct filter *filter;
2797 HRESULT hr;
2798 int entry;
2800 /* Check if the interface type is already registered */
2801 for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2802 if (riid == pGraph->ItfCacheEntries[entry].riid)
2804 if (pGraph->ItfCacheEntries[entry].iface)
2806 /* Return the interface if available */
2807 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2808 return S_OK;
2810 break;
2813 if (entry >= MAX_ITF_CACHE_ENTRIES)
2815 FIXME("Not enough space to store interface in the cache\n");
2816 return E_OUTOFMEMORY;
2819 /* Find a filter supporting the requested interface */
2820 LIST_FOR_EACH_ENTRY(filter, &pGraph->filters, struct filter, entry)
2822 hr = IBaseFilter_QueryInterface(filter->filter, riid, ppvObj);
2823 if (hr == S_OK)
2825 pGraph->ItfCacheEntries[entry].riid = riid;
2826 pGraph->ItfCacheEntries[entry].filter = filter->filter;
2827 pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2828 if (entry >= pGraph->nItfCacheEntries)
2829 pGraph->nItfCacheEntries++;
2830 return S_OK;
2832 if (hr != E_NOINTERFACE)
2833 return hr;
2836 return IsEqualGUID(riid, &IID_IBasicAudio) ? E_NOTIMPL : E_NOINTERFACE;
2839 static struct filter_graph *impl_from_IBasicAudio(IBasicAudio *iface)
2841 return CONTAINING_RECORD(iface, struct filter_graph, IBasicAudio_iface);
2844 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID iid, void **out)
2846 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2847 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2850 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
2852 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2853 return IUnknown_AddRef(graph->outer_unk);
2856 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
2858 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2859 return IUnknown_Release(graph->outer_unk);
2862 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *count)
2864 TRACE("iface %p, count %p.\n", iface, count);
2865 *count = 1;
2866 return S_OK;
2869 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface, UINT index,
2870 LCID lcid, ITypeInfo **typeinfo)
2872 TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
2873 return strmbase_get_typeinfo(IBasicAudio_tid, typeinfo);
2876 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface, REFIID iid,
2877 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
2879 ITypeInfo *typeinfo;
2880 HRESULT hr;
2882 TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
2883 iface, debugstr_guid(iid), names, count, lcid, ids);
2885 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo)))
2887 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
2888 ITypeInfo_Release(typeinfo);
2890 return hr;
2893 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface, DISPID id, REFIID iid, LCID lcid,
2894 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
2896 ITypeInfo *typeinfo;
2897 HRESULT hr;
2899 TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
2900 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
2902 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo)))
2904 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
2905 ITypeInfo_Release(typeinfo);
2907 return hr;
2910 /*** IBasicAudio methods ***/
2911 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface, LONG lVolume)
2913 struct filter_graph *This = impl_from_IBasicAudio(iface);
2914 IBasicAudio* pBasicAudio;
2915 HRESULT hr;
2917 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
2919 EnterCriticalSection(&This->cs);
2921 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2923 if (hr == S_OK)
2924 hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2926 LeaveCriticalSection(&This->cs);
2928 return hr;
2931 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface, LONG *plVolume)
2933 struct filter_graph *This = impl_from_IBasicAudio(iface);
2934 IBasicAudio* pBasicAudio;
2935 HRESULT hr;
2937 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
2939 EnterCriticalSection(&This->cs);
2941 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2943 if (hr == S_OK)
2944 hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
2946 LeaveCriticalSection(&This->cs);
2948 return hr;
2951 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface, LONG lBalance)
2953 struct filter_graph *This = impl_from_IBasicAudio(iface);
2954 IBasicAudio* pBasicAudio;
2955 HRESULT hr;
2957 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
2959 EnterCriticalSection(&This->cs);
2961 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2963 if (hr == S_OK)
2964 hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
2966 LeaveCriticalSection(&This->cs);
2968 return hr;
2971 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface, LONG *plBalance)
2973 struct filter_graph *This = impl_from_IBasicAudio(iface);
2974 IBasicAudio* pBasicAudio;
2975 HRESULT hr;
2977 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
2979 EnterCriticalSection(&This->cs);
2981 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2983 if (hr == S_OK)
2984 hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
2986 LeaveCriticalSection(&This->cs);
2988 return hr;
2991 static const IBasicAudioVtbl IBasicAudio_VTable =
2993 BasicAudio_QueryInterface,
2994 BasicAudio_AddRef,
2995 BasicAudio_Release,
2996 BasicAudio_GetTypeInfoCount,
2997 BasicAudio_GetTypeInfo,
2998 BasicAudio_GetIDsOfNames,
2999 BasicAudio_Invoke,
3000 BasicAudio_put_Volume,
3001 BasicAudio_get_Volume,
3002 BasicAudio_put_Balance,
3003 BasicAudio_get_Balance
3006 static struct filter_graph *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3008 return CONTAINING_RECORD(iface, struct filter_graph, IBasicVideo2_iface);
3011 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface, REFIID iid, void **out)
3013 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3014 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
3017 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface)
3019 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3020 return IUnknown_AddRef(graph->outer_unk);
3023 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface)
3025 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3026 return IUnknown_Release(graph->outer_unk);
3029 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface, UINT *count)
3031 TRACE("iface %p, count %p.\n", iface, count);
3032 *count = 1;
3033 return S_OK;
3036 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface, UINT index,
3037 LCID lcid, ITypeInfo **typeinfo)
3039 TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
3040 return strmbase_get_typeinfo(IBasicVideo_tid, typeinfo);
3043 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface, REFIID iid,
3044 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
3046 ITypeInfo *typeinfo;
3047 HRESULT hr;
3049 TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
3050 iface, debugstr_guid(iid), names, count, lcid, ids);
3052 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo)))
3054 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
3055 ITypeInfo_Release(typeinfo);
3057 return hr;
3060 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface, DISPID id, REFIID iid, LCID lcid,
3061 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
3063 ITypeInfo *typeinfo;
3064 HRESULT hr;
3066 TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
3067 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
3069 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo)))
3071 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
3072 ITypeInfo_Release(typeinfo);
3074 return hr;
3077 /*** IBasicVideo methods ***/
3078 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface, REFTIME *pAvgTimePerFrame)
3080 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3081 IBasicVideo *pBasicVideo;
3082 HRESULT hr;
3084 TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3086 EnterCriticalSection(&This->cs);
3088 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3090 if (hr == S_OK)
3091 hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3093 LeaveCriticalSection(&This->cs);
3095 return hr;
3098 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface, LONG *pBitRate)
3100 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3101 IBasicVideo *pBasicVideo;
3102 HRESULT hr;
3104 TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3106 EnterCriticalSection(&This->cs);
3108 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3110 if (hr == S_OK)
3111 hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3113 LeaveCriticalSection(&This->cs);
3115 return hr;
3118 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface, LONG *pBitErrorRate)
3120 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3121 IBasicVideo *pBasicVideo;
3122 HRESULT hr;
3124 TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3126 EnterCriticalSection(&This->cs);
3128 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3130 if (hr == S_OK)
3131 hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3133 LeaveCriticalSection(&This->cs);
3135 return hr;
3138 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface, LONG *pVideoWidth)
3140 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3141 IBasicVideo *pBasicVideo;
3142 HRESULT hr;
3144 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3146 EnterCriticalSection(&This->cs);
3148 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3150 if (hr == S_OK)
3151 hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3153 LeaveCriticalSection(&This->cs);
3155 return hr;
3158 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface, LONG *pVideoHeight)
3160 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3161 IBasicVideo *pBasicVideo;
3162 HRESULT hr;
3164 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3166 EnterCriticalSection(&This->cs);
3168 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3170 if (hr == S_OK)
3171 hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3173 LeaveCriticalSection(&This->cs);
3175 return hr;
3178 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface, LONG SourceLeft)
3180 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3181 IBasicVideo *pBasicVideo;
3182 HRESULT hr;
3184 TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
3186 EnterCriticalSection(&This->cs);
3188 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3190 if (hr == S_OK)
3191 hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3193 LeaveCriticalSection(&This->cs);
3195 return hr;
3198 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface, LONG *pSourceLeft)
3200 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3201 IBasicVideo *pBasicVideo;
3202 HRESULT hr;
3204 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3206 EnterCriticalSection(&This->cs);
3208 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3210 if (hr == S_OK)
3211 hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3213 LeaveCriticalSection(&This->cs);
3215 return hr;
3218 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface, LONG SourceWidth)
3220 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3221 IBasicVideo *pBasicVideo;
3222 HRESULT hr;
3224 TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
3226 EnterCriticalSection(&This->cs);
3228 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3230 if (hr == S_OK)
3231 hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3233 LeaveCriticalSection(&This->cs);
3235 return hr;
3238 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface, LONG *pSourceWidth)
3240 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3241 IBasicVideo *pBasicVideo;
3242 HRESULT hr;
3244 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3246 EnterCriticalSection(&This->cs);
3248 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3250 if (hr == S_OK)
3251 hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3253 LeaveCriticalSection(&This->cs);
3255 return hr;
3258 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface, LONG SourceTop)
3260 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3261 IBasicVideo *pBasicVideo;
3262 HRESULT hr;
3264 TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
3266 EnterCriticalSection(&This->cs);
3268 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3270 if (hr == S_OK)
3271 hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3273 LeaveCriticalSection(&This->cs);
3275 return hr;
3278 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface, LONG *pSourceTop)
3280 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3281 IBasicVideo *pBasicVideo;
3282 HRESULT hr;
3284 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3286 EnterCriticalSection(&This->cs);
3288 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3290 if (hr == S_OK)
3291 hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3293 LeaveCriticalSection(&This->cs);
3295 return hr;
3298 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface, LONG SourceHeight)
3300 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3301 IBasicVideo *pBasicVideo;
3302 HRESULT hr;
3304 TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
3306 EnterCriticalSection(&This->cs);
3308 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3310 if (hr == S_OK)
3311 hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3313 LeaveCriticalSection(&This->cs);
3315 return hr;
3318 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface, LONG *pSourceHeight)
3320 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3321 IBasicVideo *pBasicVideo;
3322 HRESULT hr;
3324 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3326 EnterCriticalSection(&This->cs);
3328 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3330 if (hr == S_OK)
3331 hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3333 LeaveCriticalSection(&This->cs);
3335 return hr;
3338 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface, LONG DestinationLeft)
3340 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3341 IBasicVideo *pBasicVideo;
3342 HRESULT hr;
3344 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
3346 EnterCriticalSection(&This->cs);
3348 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3350 if (hr == S_OK)
3351 hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3353 LeaveCriticalSection(&This->cs);
3355 return hr;
3358 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface, LONG *pDestinationLeft)
3360 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3361 IBasicVideo *pBasicVideo;
3362 HRESULT hr;
3364 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3366 EnterCriticalSection(&This->cs);
3368 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3370 if (hr == S_OK)
3371 hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3373 LeaveCriticalSection(&This->cs);
3375 return hr;
3378 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface, LONG DestinationWidth)
3380 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3381 IBasicVideo *pBasicVideo;
3382 HRESULT hr;
3384 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
3386 EnterCriticalSection(&This->cs);
3388 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3390 if (hr == S_OK)
3391 hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3393 LeaveCriticalSection(&This->cs);
3395 return hr;
3398 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface, LONG *pDestinationWidth)
3400 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3401 IBasicVideo *pBasicVideo;
3402 HRESULT hr;
3404 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3406 EnterCriticalSection(&This->cs);
3408 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3410 if (hr == S_OK)
3411 hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3413 LeaveCriticalSection(&This->cs);
3415 return hr;
3418 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface, LONG DestinationTop)
3420 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3421 IBasicVideo *pBasicVideo;
3422 HRESULT hr;
3424 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
3426 EnterCriticalSection(&This->cs);
3428 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3430 if (hr == S_OK)
3431 hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3433 LeaveCriticalSection(&This->cs);
3435 return hr;
3438 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface, LONG *pDestinationTop)
3440 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3441 IBasicVideo *pBasicVideo;
3442 HRESULT hr;
3444 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3446 EnterCriticalSection(&This->cs);
3448 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3450 if (hr == S_OK)
3451 hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3453 LeaveCriticalSection(&This->cs);
3455 return hr;
3458 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface, LONG DestinationHeight)
3460 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3461 IBasicVideo *pBasicVideo;
3462 HRESULT hr;
3464 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
3466 EnterCriticalSection(&This->cs);
3468 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3470 if (hr == S_OK)
3471 hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3473 LeaveCriticalSection(&This->cs);
3475 return hr;
3478 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3479 LONG *pDestinationHeight)
3481 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3482 IBasicVideo *pBasicVideo;
3483 HRESULT hr;
3485 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3487 EnterCriticalSection(&This->cs);
3489 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3491 if (hr == S_OK)
3492 hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3494 LeaveCriticalSection(&This->cs);
3496 return hr;
3499 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3500 LONG Width, LONG Height)
3502 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3503 IBasicVideo *pBasicVideo;
3504 HRESULT hr;
3506 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3508 EnterCriticalSection(&This->cs);
3510 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3512 if (hr == S_OK)
3513 hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3515 LeaveCriticalSection(&This->cs);
3517 return hr;
3520 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface, LONG *pLeft, LONG *pTop,
3521 LONG *pWidth, LONG *pHeight)
3523 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3524 IBasicVideo *pBasicVideo;
3525 HRESULT hr;
3527 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3529 EnterCriticalSection(&This->cs);
3531 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3533 if (hr == S_OK)
3534 hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3536 LeaveCriticalSection(&This->cs);
3538 return hr;
3541 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface)
3543 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3544 IBasicVideo *pBasicVideo;
3545 HRESULT hr;
3547 TRACE("(%p/%p)->()\n", This, iface);
3549 EnterCriticalSection(&This->cs);
3551 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3553 if (hr == S_OK)
3554 hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3556 LeaveCriticalSection(&This->cs);
3558 return hr;
3561 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3562 LONG Width, LONG Height)
3564 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3565 IBasicVideo *pBasicVideo;
3566 HRESULT hr;
3568 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3570 EnterCriticalSection(&This->cs);
3572 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3574 if (hr == S_OK)
3575 hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3577 LeaveCriticalSection(&This->cs);
3579 return hr;
3582 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface, LONG *pLeft,
3583 LONG *pTop, LONG *pWidth, LONG *pHeight)
3585 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3586 IBasicVideo *pBasicVideo;
3587 HRESULT hr;
3589 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3591 EnterCriticalSection(&This->cs);
3593 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3595 if (hr == S_OK)
3596 hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3598 LeaveCriticalSection(&This->cs);
3600 return hr;
3603 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface)
3605 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3606 IBasicVideo *pBasicVideo;
3607 HRESULT hr;
3609 TRACE("(%p/%p)->()\n", This, iface);
3611 EnterCriticalSection(&This->cs);
3613 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3615 if (hr == S_OK)
3616 hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3618 LeaveCriticalSection(&This->cs);
3620 return hr;
3623 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface, LONG *pWidth, LONG *pHeight)
3625 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3626 IBasicVideo *pBasicVideo;
3627 HRESULT hr;
3629 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3631 EnterCriticalSection(&This->cs);
3633 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3635 if (hr == S_OK)
3636 hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3638 LeaveCriticalSection(&This->cs);
3640 return hr;
3643 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface, LONG StartIndex,
3644 LONG Entries, LONG *pRetrieved, LONG *pPalette)
3646 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3647 IBasicVideo *pBasicVideo;
3648 HRESULT hr;
3650 TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3652 EnterCriticalSection(&This->cs);
3654 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3656 if (hr == S_OK)
3657 hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3659 LeaveCriticalSection(&This->cs);
3661 return hr;
3664 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface, LONG *pBufferSize,
3665 LONG *pDIBImage)
3667 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3668 IBasicVideo *pBasicVideo;
3669 HRESULT hr;
3671 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3673 EnterCriticalSection(&This->cs);
3675 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3677 if (hr == S_OK)
3678 hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3680 LeaveCriticalSection(&This->cs);
3682 return hr;
3685 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface)
3687 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3688 IBasicVideo *pBasicVideo;
3689 HRESULT hr;
3691 TRACE("(%p/%p)->()\n", This, iface);
3693 EnterCriticalSection(&This->cs);
3695 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3697 if (hr == S_OK)
3698 hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3700 LeaveCriticalSection(&This->cs);
3702 return hr;
3705 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface)
3707 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3708 IBasicVideo *pBasicVideo;
3709 HRESULT hr;
3711 TRACE("(%p/%p)->()\n", This, iface);
3713 EnterCriticalSection(&This->cs);
3715 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3717 if (hr == S_OK)
3718 hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3720 LeaveCriticalSection(&This->cs);
3722 return hr;
3725 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX,
3726 LONG *plAspectY)
3728 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3729 IBasicVideo2 *pBasicVideo2;
3730 HRESULT hr;
3732 TRACE("(%p/%p)->()\n", This, iface);
3734 EnterCriticalSection(&This->cs);
3736 hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3738 if (hr == S_OK)
3739 hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3741 LeaveCriticalSection(&This->cs);
3743 return hr;
3746 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3748 BasicVideo_QueryInterface,
3749 BasicVideo_AddRef,
3750 BasicVideo_Release,
3751 BasicVideo_GetTypeInfoCount,
3752 BasicVideo_GetTypeInfo,
3753 BasicVideo_GetIDsOfNames,
3754 BasicVideo_Invoke,
3755 BasicVideo_get_AvgTimePerFrame,
3756 BasicVideo_get_BitRate,
3757 BasicVideo_get_BitErrorRate,
3758 BasicVideo_get_VideoWidth,
3759 BasicVideo_get_VideoHeight,
3760 BasicVideo_put_SourceLeft,
3761 BasicVideo_get_SourceLeft,
3762 BasicVideo_put_SourceWidth,
3763 BasicVideo_get_SourceWidth,
3764 BasicVideo_put_SourceTop,
3765 BasicVideo_get_SourceTop,
3766 BasicVideo_put_SourceHeight,
3767 BasicVideo_get_SourceHeight,
3768 BasicVideo_put_DestinationLeft,
3769 BasicVideo_get_DestinationLeft,
3770 BasicVideo_put_DestinationWidth,
3771 BasicVideo_get_DestinationWidth,
3772 BasicVideo_put_DestinationTop,
3773 BasicVideo_get_DestinationTop,
3774 BasicVideo_put_DestinationHeight,
3775 BasicVideo_get_DestinationHeight,
3776 BasicVideo_SetSourcePosition,
3777 BasicVideo_GetSourcePosition,
3778 BasicVideo_SetDefaultSourcePosition,
3779 BasicVideo_SetDestinationPosition,
3780 BasicVideo_GetDestinationPosition,
3781 BasicVideo_SetDefaultDestinationPosition,
3782 BasicVideo_GetVideoSize,
3783 BasicVideo_GetVideoPaletteEntries,
3784 BasicVideo_GetCurrentImage,
3785 BasicVideo_IsUsingDefaultSource,
3786 BasicVideo_IsUsingDefaultDestination,
3787 BasicVideo2_GetPreferredAspectRatio
3790 static struct filter_graph *impl_from_IVideoWindow(IVideoWindow *iface)
3792 return CONTAINING_RECORD(iface, struct filter_graph, IVideoWindow_iface);
3795 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID iid, void **out)
3797 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3798 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
3801 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
3803 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3804 return IUnknown_AddRef(graph->outer_unk);
3807 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
3809 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3810 return IUnknown_Release(graph->outer_unk);
3813 HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface, UINT *count)
3815 TRACE("iface %p, count %p.\n", iface, count);
3816 *count = 1;
3817 return S_OK;
3820 HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface, UINT index,
3821 LCID lcid, ITypeInfo **typeinfo)
3823 TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
3824 return strmbase_get_typeinfo(IVideoWindow_tid, typeinfo);
3827 HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface, REFIID iid,
3828 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
3830 ITypeInfo *typeinfo;
3831 HRESULT hr;
3833 TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
3834 iface, debugstr_guid(iid), names, count, lcid, ids);
3836 if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo)))
3838 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
3839 ITypeInfo_Release(typeinfo);
3841 return hr;
3844 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface, DISPID id, REFIID iid, LCID lcid,
3845 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
3847 ITypeInfo *typeinfo;
3848 HRESULT hr;
3850 TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
3851 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
3853 if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo)))
3855 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
3856 ITypeInfo_Release(typeinfo);
3858 return hr;
3861 /*** IVideoWindow methods ***/
3862 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface, BSTR strCaption)
3864 struct filter_graph *This = impl_from_IVideoWindow(iface);
3865 IVideoWindow *pVideoWindow;
3866 HRESULT hr;
3868 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3870 EnterCriticalSection(&This->cs);
3872 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3874 if (hr == S_OK)
3875 hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3877 LeaveCriticalSection(&This->cs);
3879 return hr;
3882 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface, BSTR *strCaption)
3884 struct filter_graph *This = impl_from_IVideoWindow(iface);
3885 IVideoWindow *pVideoWindow;
3886 HRESULT hr;
3888 TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
3890 EnterCriticalSection(&This->cs);
3892 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3894 if (hr == S_OK)
3895 hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
3897 LeaveCriticalSection(&This->cs);
3899 return hr;
3902 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle)
3904 struct filter_graph *This = impl_from_IVideoWindow(iface);
3905 IVideoWindow *pVideoWindow;
3906 HRESULT hr;
3908 TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
3910 EnterCriticalSection(&This->cs);
3912 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3914 if (hr == S_OK)
3915 hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
3917 LeaveCriticalSection(&This->cs);
3919 return hr;
3922 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface, LONG *WindowStyle)
3924 struct filter_graph *This = impl_from_IVideoWindow(iface);
3925 IVideoWindow *pVideoWindow;
3926 HRESULT hr;
3928 TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
3930 EnterCriticalSection(&This->cs);
3932 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3934 if (hr == S_OK)
3935 hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
3937 LeaveCriticalSection(&This->cs);
3939 return hr;
3942 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx)
3944 struct filter_graph *This = impl_from_IVideoWindow(iface);
3945 IVideoWindow *pVideoWindow;
3946 HRESULT hr;
3948 TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
3950 EnterCriticalSection(&This->cs);
3952 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3954 if (hr == S_OK)
3955 hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
3957 LeaveCriticalSection(&This->cs);
3959 return hr;
3962 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx)
3964 struct filter_graph *This = impl_from_IVideoWindow(iface);
3965 IVideoWindow *pVideoWindow;
3966 HRESULT hr;
3968 TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
3970 EnterCriticalSection(&This->cs);
3972 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3974 if (hr == S_OK)
3975 hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
3977 LeaveCriticalSection(&This->cs);
3979 return hr;
3982 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow)
3984 struct filter_graph *This = impl_from_IVideoWindow(iface);
3985 IVideoWindow *pVideoWindow;
3986 HRESULT hr;
3988 TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
3990 EnterCriticalSection(&This->cs);
3992 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3994 if (hr == S_OK)
3995 hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
3997 LeaveCriticalSection(&This->cs);
3999 return hr;
4002 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface, LONG *AutoShow)
4004 struct filter_graph *This = impl_from_IVideoWindow(iface);
4005 IVideoWindow *pVideoWindow;
4006 HRESULT hr;
4008 TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4010 EnterCriticalSection(&This->cs);
4012 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4014 if (hr == S_OK)
4015 hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4017 LeaveCriticalSection(&This->cs);
4019 return hr;
4022 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface, LONG WindowState)
4024 struct filter_graph *This = impl_from_IVideoWindow(iface);
4025 IVideoWindow *pVideoWindow;
4026 HRESULT hr;
4028 TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
4030 EnterCriticalSection(&This->cs);
4032 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4034 if (hr == S_OK)
4035 hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4037 LeaveCriticalSection(&This->cs);
4039 return hr;
4042 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface, LONG *WindowState)
4044 struct filter_graph *This = impl_from_IVideoWindow(iface);
4045 IVideoWindow *pVideoWindow;
4046 HRESULT hr;
4048 TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4050 EnterCriticalSection(&This->cs);
4052 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4054 if (hr == S_OK)
4055 hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4057 LeaveCriticalSection(&This->cs);
4059 return hr;
4062 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette)
4064 struct filter_graph *This = impl_from_IVideoWindow(iface);
4065 IVideoWindow *pVideoWindow;
4066 HRESULT hr;
4068 TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
4070 EnterCriticalSection(&This->cs);
4072 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4074 if (hr == S_OK)
4075 hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4077 LeaveCriticalSection(&This->cs);
4079 return hr;
4082 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4083 LONG *pBackgroundPalette)
4085 struct filter_graph *This = impl_from_IVideoWindow(iface);
4086 IVideoWindow *pVideoWindow;
4087 HRESULT hr;
4089 TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4091 EnterCriticalSection(&This->cs);
4093 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4095 if (hr == S_OK)
4096 hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4098 LeaveCriticalSection(&This->cs);
4100 return hr;
4103 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface, LONG Visible)
4105 struct filter_graph *This = impl_from_IVideoWindow(iface);
4106 IVideoWindow *pVideoWindow;
4107 HRESULT hr;
4109 TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
4111 EnterCriticalSection(&This->cs);
4113 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4115 if (hr == S_OK)
4116 hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4118 LeaveCriticalSection(&This->cs);
4120 return hr;
4123 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface, LONG *pVisible)
4125 struct filter_graph *This = impl_from_IVideoWindow(iface);
4126 IVideoWindow *pVideoWindow;
4127 HRESULT hr;
4129 TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4131 EnterCriticalSection(&This->cs);
4133 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4135 if (hr == S_OK)
4136 hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4138 LeaveCriticalSection(&This->cs);
4140 return hr;
4143 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface, LONG Left)
4145 struct filter_graph *This = impl_from_IVideoWindow(iface);
4146 IVideoWindow *pVideoWindow;
4147 HRESULT hr;
4149 TRACE("(%p/%p)->(%d)\n", This, iface, Left);
4151 EnterCriticalSection(&This->cs);
4153 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4155 if (hr == S_OK)
4156 hr = IVideoWindow_put_Left(pVideoWindow, Left);
4158 LeaveCriticalSection(&This->cs);
4160 return hr;
4163 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface, LONG *pLeft)
4165 struct filter_graph *This = impl_from_IVideoWindow(iface);
4166 IVideoWindow *pVideoWindow;
4167 HRESULT hr;
4169 TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4171 EnterCriticalSection(&This->cs);
4173 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4175 if (hr == S_OK)
4176 hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4178 LeaveCriticalSection(&This->cs);
4180 return hr;
4183 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface, LONG Width)
4185 struct filter_graph *This = impl_from_IVideoWindow(iface);
4186 IVideoWindow *pVideoWindow;
4187 HRESULT hr;
4189 TRACE("(%p/%p)->(%d)\n", This, iface, Width);
4191 EnterCriticalSection(&This->cs);
4193 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4195 if (hr == S_OK)
4196 hr = IVideoWindow_put_Width(pVideoWindow, Width);
4198 LeaveCriticalSection(&This->cs);
4200 return hr;
4203 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface, LONG *pWidth)
4205 struct filter_graph *This = impl_from_IVideoWindow(iface);
4206 IVideoWindow *pVideoWindow;
4207 HRESULT hr;
4209 TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4211 EnterCriticalSection(&This->cs);
4213 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4215 if (hr == S_OK)
4216 hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4218 LeaveCriticalSection(&This->cs);
4220 return hr;
4223 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface, LONG Top)
4225 struct filter_graph *This = impl_from_IVideoWindow(iface);
4226 IVideoWindow *pVideoWindow;
4227 HRESULT hr;
4229 TRACE("(%p/%p)->(%d)\n", This, iface, Top);
4231 EnterCriticalSection(&This->cs);
4233 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4235 if (hr == S_OK)
4236 hr = IVideoWindow_put_Top(pVideoWindow, Top);
4238 LeaveCriticalSection(&This->cs);
4240 return hr;
4243 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface, LONG *pTop)
4245 struct filter_graph *This = impl_from_IVideoWindow(iface);
4246 IVideoWindow *pVideoWindow;
4247 HRESULT hr;
4249 TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4251 EnterCriticalSection(&This->cs);
4253 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4255 if (hr == S_OK)
4256 hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4258 LeaveCriticalSection(&This->cs);
4260 return hr;
4263 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface, LONG Height)
4265 struct filter_graph *This = impl_from_IVideoWindow(iface);
4266 IVideoWindow *pVideoWindow;
4267 HRESULT hr;
4269 TRACE("(%p/%p)->(%d)\n", This, iface, Height);
4271 EnterCriticalSection(&This->cs);
4273 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4275 if (hr == S_OK)
4276 hr = IVideoWindow_put_Height(pVideoWindow, Height);
4278 LeaveCriticalSection(&This->cs);
4280 return hr;
4283 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface, LONG *pHeight)
4285 struct filter_graph *This = impl_from_IVideoWindow(iface);
4286 IVideoWindow *pVideoWindow;
4287 HRESULT hr;
4289 TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4291 EnterCriticalSection(&This->cs);
4293 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4295 if (hr == S_OK)
4296 hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4298 LeaveCriticalSection(&This->cs);
4300 return hr;
4303 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface, OAHWND Owner)
4305 struct filter_graph *This = impl_from_IVideoWindow(iface);
4306 IVideoWindow *pVideoWindow;
4307 HRESULT hr;
4309 TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
4311 EnterCriticalSection(&This->cs);
4313 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4315 if (hr == S_OK)
4316 hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4318 LeaveCriticalSection(&This->cs);
4320 return hr;
4323 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface, OAHWND *Owner)
4325 struct filter_graph *This = impl_from_IVideoWindow(iface);
4326 IVideoWindow *pVideoWindow;
4327 HRESULT hr;
4329 TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4331 EnterCriticalSection(&This->cs);
4333 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4335 if (hr == S_OK)
4336 hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4338 LeaveCriticalSection(&This->cs);
4340 return hr;
4343 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface, OAHWND Drain)
4345 struct filter_graph *This = impl_from_IVideoWindow(iface);
4346 IVideoWindow *pVideoWindow;
4347 HRESULT hr;
4349 TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
4351 EnterCriticalSection(&This->cs);
4353 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4355 if (hr == S_OK)
4356 hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4358 LeaveCriticalSection(&This->cs);
4360 return hr;
4363 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface, OAHWND *Drain)
4365 struct filter_graph *This = impl_from_IVideoWindow(iface);
4366 IVideoWindow *pVideoWindow;
4367 HRESULT hr;
4369 TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4371 EnterCriticalSection(&This->cs);
4373 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4375 if (hr == S_OK)
4376 hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4378 LeaveCriticalSection(&This->cs);
4380 return hr;
4383 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface, LONG *Color)
4385 struct filter_graph *This = impl_from_IVideoWindow(iface);
4386 IVideoWindow *pVideoWindow;
4387 HRESULT hr;
4389 TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4391 EnterCriticalSection(&This->cs);
4393 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4395 if (hr == S_OK)
4396 hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4398 LeaveCriticalSection(&This->cs);
4400 return hr;
4403 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface, LONG Color)
4405 struct filter_graph *This = impl_from_IVideoWindow(iface);
4406 IVideoWindow *pVideoWindow;
4407 HRESULT hr;
4409 TRACE("(%p/%p)->(%d)\n", This, iface, Color);
4411 EnterCriticalSection(&This->cs);
4413 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4415 if (hr == S_OK)
4416 hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4418 LeaveCriticalSection(&This->cs);
4420 return hr;
4423 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface, LONG *FullScreenMode)
4425 struct filter_graph *This = impl_from_IVideoWindow(iface);
4426 IVideoWindow *pVideoWindow;
4427 HRESULT hr;
4429 TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4431 EnterCriticalSection(&This->cs);
4433 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4435 if (hr == S_OK)
4436 hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4438 LeaveCriticalSection(&This->cs);
4440 return hr;
4443 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, LONG FullScreenMode)
4445 struct filter_graph *This = impl_from_IVideoWindow(iface);
4446 IVideoWindow *pVideoWindow;
4447 HRESULT hr;
4449 TRACE("(%p/%p)->(%d)\n", This, iface, FullScreenMode);
4451 EnterCriticalSection(&This->cs);
4453 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4455 if (hr == S_OK)
4456 hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4458 LeaveCriticalSection(&This->cs);
4460 return hr;
4463 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface, LONG Focus)
4465 struct filter_graph *This = impl_from_IVideoWindow(iface);
4466 IVideoWindow *pVideoWindow;
4467 HRESULT hr;
4469 TRACE("(%p/%p)->(%d)\n", This, iface, Focus);
4471 EnterCriticalSection(&This->cs);
4473 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4475 if (hr == S_OK)
4476 hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4478 LeaveCriticalSection(&This->cs);
4480 return hr;
4483 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface, OAHWND hwnd, LONG uMsg,
4484 LONG_PTR wParam, LONG_PTR lParam)
4486 struct filter_graph *This = impl_from_IVideoWindow(iface);
4487 IVideoWindow *pVideoWindow;
4488 HRESULT hr;
4490 TRACE("(%p/%p)->(%08lx, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam);
4492 EnterCriticalSection(&This->cs);
4494 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4496 if (hr == S_OK)
4497 hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4499 LeaveCriticalSection(&This->cs);
4501 return hr;
4504 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface, LONG Left, LONG Top,
4505 LONG Width, LONG Height)
4507 struct filter_graph *This = impl_from_IVideoWindow(iface);
4508 IVideoWindow *pVideoWindow;
4509 HRESULT hr;
4511 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
4513 EnterCriticalSection(&This->cs);
4515 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4517 if (hr == S_OK)
4518 hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4520 LeaveCriticalSection(&This->cs);
4522 return hr;
4525 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4526 LONG *pWidth, LONG *pHeight)
4528 struct filter_graph *This = impl_from_IVideoWindow(iface);
4529 IVideoWindow *pVideoWindow;
4530 HRESULT hr;
4532 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4534 EnterCriticalSection(&This->cs);
4536 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4538 if (hr == S_OK)
4539 hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4541 LeaveCriticalSection(&This->cs);
4543 return hr;
4546 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4547 LONG *pHeight)
4549 struct filter_graph *This = impl_from_IVideoWindow(iface);
4550 IVideoWindow *pVideoWindow;
4551 HRESULT hr;
4553 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4555 EnterCriticalSection(&This->cs);
4557 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4559 if (hr == S_OK)
4560 hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4562 LeaveCriticalSection(&This->cs);
4564 return hr;
4567 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4568 LONG *pHeight)
4570 struct filter_graph *This = impl_from_IVideoWindow(iface);
4571 IVideoWindow *pVideoWindow;
4572 HRESULT hr;
4574 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4576 EnterCriticalSection(&This->cs);
4578 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4580 if (hr == S_OK)
4581 hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4583 LeaveCriticalSection(&This->cs);
4585 return hr;
4588 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4589 LONG *pWidth, LONG *pHeight)
4591 struct filter_graph *This = impl_from_IVideoWindow(iface);
4592 IVideoWindow *pVideoWindow;
4593 HRESULT hr;
4595 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4597 EnterCriticalSection(&This->cs);
4599 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4601 if (hr == S_OK)
4602 hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4604 LeaveCriticalSection(&This->cs);
4606 return hr;
4609 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface, LONG HideCursor)
4611 struct filter_graph *This = impl_from_IVideoWindow(iface);
4612 IVideoWindow *pVideoWindow;
4613 HRESULT hr;
4615 TRACE("(%p/%p)->(%d)\n", This, iface, HideCursor);
4617 EnterCriticalSection(&This->cs);
4619 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4621 if (hr == S_OK)
4622 hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4624 LeaveCriticalSection(&This->cs);
4626 return hr;
4629 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden)
4631 struct filter_graph *This = impl_from_IVideoWindow(iface);
4632 IVideoWindow *pVideoWindow;
4633 HRESULT hr;
4635 TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4637 EnterCriticalSection(&This->cs);
4639 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4641 if (hr == S_OK)
4642 hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4644 LeaveCriticalSection(&This->cs);
4646 return hr;
4650 static const IVideoWindowVtbl IVideoWindow_VTable =
4652 VideoWindow_QueryInterface,
4653 VideoWindow_AddRef,
4654 VideoWindow_Release,
4655 VideoWindow_GetTypeInfoCount,
4656 VideoWindow_GetTypeInfo,
4657 VideoWindow_GetIDsOfNames,
4658 VideoWindow_Invoke,
4659 VideoWindow_put_Caption,
4660 VideoWindow_get_Caption,
4661 VideoWindow_put_WindowStyle,
4662 VideoWindow_get_WindowStyle,
4663 VideoWindow_put_WindowStyleEx,
4664 VideoWindow_get_WindowStyleEx,
4665 VideoWindow_put_AutoShow,
4666 VideoWindow_get_AutoShow,
4667 VideoWindow_put_WindowState,
4668 VideoWindow_get_WindowState,
4669 VideoWindow_put_BackgroundPalette,
4670 VideoWindow_get_BackgroundPalette,
4671 VideoWindow_put_Visible,
4672 VideoWindow_get_Visible,
4673 VideoWindow_put_Left,
4674 VideoWindow_get_Left,
4675 VideoWindow_put_Width,
4676 VideoWindow_get_Width,
4677 VideoWindow_put_Top,
4678 VideoWindow_get_Top,
4679 VideoWindow_put_Height,
4680 VideoWindow_get_Height,
4681 VideoWindow_put_Owner,
4682 VideoWindow_get_Owner,
4683 VideoWindow_put_MessageDrain,
4684 VideoWindow_get_MessageDrain,
4685 VideoWindow_get_BorderColor,
4686 VideoWindow_put_BorderColor,
4687 VideoWindow_get_FullScreenMode,
4688 VideoWindow_put_FullScreenMode,
4689 VideoWindow_SetWindowForeground,
4690 VideoWindow_NotifyOwnerMessage,
4691 VideoWindow_SetWindowPosition,
4692 VideoWindow_GetWindowPosition,
4693 VideoWindow_GetMinIdealImageSize,
4694 VideoWindow_GetMaxIdealImageSize,
4695 VideoWindow_GetRestorePosition,
4696 VideoWindow_HideCursor,
4697 VideoWindow_IsCursorHidden
4700 static struct filter_graph *impl_from_IMediaEventEx(IMediaEventEx *iface)
4702 return CONTAINING_RECORD(iface, struct filter_graph, IMediaEventEx_iface);
4705 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface, REFIID iid, void **out)
4707 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4708 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
4711 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface)
4713 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4714 return IUnknown_AddRef(graph->outer_unk);
4717 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface)
4719 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4720 return IUnknown_Release(graph->outer_unk);
4723 /*** IDispatch methods ***/
4724 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface, UINT *pctinfo)
4726 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4728 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
4730 return S_OK;
4733 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface, UINT iTInfo, LCID lcid,
4734 ITypeInfo **ppTInfo)
4736 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4738 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
4740 return S_OK;
4743 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface, REFIID riid,
4744 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
4746 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4748 TRACE("(%p/%p)->(%s, %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), rgszNames,
4749 cNames, lcid, rgDispId);
4751 return S_OK;
4754 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface, DISPID dispIdMember, REFIID riid,
4755 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
4756 UINT *puArgErr)
4758 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4760 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember,
4761 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4763 return S_OK;
4766 /*** IMediaEvent methods ***/
4767 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface, OAEVENT *hEvent)
4769 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4771 TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4773 *hEvent = (OAEVENT)This->evqueue.msg_event;
4775 return S_OK;
4778 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface, LONG *lEventCode, LONG_PTR *lParam1,
4779 LONG_PTR *lParam2, LONG msTimeout)
4781 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4782 Event evt;
4784 TRACE("(%p/%p)->(%p, %p, %p, %d)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
4786 if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
4788 *lEventCode = evt.lEventCode;
4789 *lParam1 = evt.lParam1;
4790 *lParam2 = evt.lParam2;
4791 return S_OK;
4794 *lEventCode = 0;
4795 return E_ABORT;
4798 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface, LONG msTimeout,
4799 LONG *pEvCode)
4801 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4803 TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pEvCode);
4805 if (This->state != State_Running)
4806 return VFW_E_WRONG_STATE;
4808 if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4810 *pEvCode = This->CompletionStatus;
4811 return S_OK;
4814 *pEvCode = 0;
4815 return E_ABORT;
4818 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4820 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4822 TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4824 if (lEvCode == EC_COMPLETE)
4825 This->HandleEcComplete = FALSE;
4826 else if (lEvCode == EC_REPAINT)
4827 This->HandleEcRepaint = FALSE;
4828 else if (lEvCode == EC_CLOCK_CHANGED)
4829 This->HandleEcClockChanged = FALSE;
4830 else
4831 return S_FALSE;
4833 return S_OK;
4836 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4838 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4840 TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4842 if (lEvCode == EC_COMPLETE)
4843 This->HandleEcComplete = TRUE;
4844 else if (lEvCode == EC_REPAINT)
4845 This->HandleEcRepaint = TRUE;
4846 else if (lEvCode == EC_CLOCK_CHANGED)
4847 This->HandleEcClockChanged = TRUE;
4848 else
4849 return S_FALSE;
4851 return S_OK;
4854 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface, LONG lEvCode,
4855 LONG_PTR lParam1, LONG_PTR lParam2)
4857 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4859 TRACE("(%p/%p)->(%d, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
4861 return S_OK;
4864 /*** IMediaEventEx methods ***/
4865 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface, OAHWND hwnd, LONG lMsg,
4866 LONG_PTR lInstanceData)
4868 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4870 TRACE("(%p/%p)->(%08lx, %d, %08lx)\n", This, iface, hwnd, lMsg, lInstanceData);
4872 This->notif.hWnd = (HWND)hwnd;
4873 This->notif.msg = lMsg;
4874 This->notif.instance = lInstanceData;
4876 return S_OK;
4879 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface, LONG lNoNotifyFlags)
4881 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4883 TRACE("(%p/%p)->(%d)\n", This, iface, lNoNotifyFlags);
4885 if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
4886 return E_INVALIDARG;
4888 This->notif.disabled = lNoNotifyFlags;
4890 return S_OK;
4893 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface, LONG *lplNoNotifyFlags)
4895 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4897 TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
4899 if (!lplNoNotifyFlags)
4900 return E_POINTER;
4902 *lplNoNotifyFlags = This->notif.disabled;
4904 return S_OK;
4908 static const IMediaEventExVtbl IMediaEventEx_VTable =
4910 MediaEvent_QueryInterface,
4911 MediaEvent_AddRef,
4912 MediaEvent_Release,
4913 MediaEvent_GetTypeInfoCount,
4914 MediaEvent_GetTypeInfo,
4915 MediaEvent_GetIDsOfNames,
4916 MediaEvent_Invoke,
4917 MediaEvent_GetEventHandle,
4918 MediaEvent_GetEvent,
4919 MediaEvent_WaitForCompletion,
4920 MediaEvent_CancelDefaultHandling,
4921 MediaEvent_RestoreDefaultHandling,
4922 MediaEvent_FreeEventParams,
4923 MediaEvent_SetNotifyWindow,
4924 MediaEvent_SetNotifyFlags,
4925 MediaEvent_GetNotifyFlags
4929 static struct filter_graph *impl_from_IMediaFilter(IMediaFilter *iface)
4931 return CONTAINING_RECORD(iface, struct filter_graph, IMediaFilter_iface);
4934 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID iid, void **out)
4936 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4938 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
4941 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
4943 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4945 return IUnknown_AddRef(graph->outer_unk);
4948 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
4950 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4952 return IUnknown_Release(graph->outer_unk);
4955 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
4957 FIXME("(%p): stub\n", pClassID);
4959 return E_NOTIMPL;
4962 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
4964 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4965 HRESULT hr = S_OK, filter_hr;
4966 struct filter *filter;
4967 TP_WORK *work;
4969 TRACE("graph %p.\n", graph);
4971 EnterCriticalSection(&graph->cs);
4973 if (graph->state == State_Stopped)
4975 LeaveCriticalSection(&graph->cs);
4976 return S_OK;
4979 sort_filters(graph);
4981 if (graph->state == State_Running)
4983 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
4985 filter_hr = IBaseFilter_Pause(filter->filter);
4986 if (hr == S_OK)
4987 hr = filter_hr;
4991 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
4993 filter_hr = IBaseFilter_Stop(filter->filter);
4994 if (hr == S_OK)
4995 hr = filter_hr;
4998 graph->state = State_Stopped;
4999 graph->needs_async_run = 0;
5000 work = graph->async_run_work;
5001 graph->got_ec_complete = 0;
5003 /* Update the current position, probably to synchronize multiple streams. */
5004 IMediaSeeking_SetPositions(&graph->IMediaSeeking_iface, &graph->current_pos,
5005 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
5007 LeaveCriticalSection(&graph->cs);
5009 if (work)
5010 WaitForThreadpoolWorkCallbacks(work, TRUE);
5012 return hr;
5015 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
5017 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5018 HRESULT hr = S_OK, filter_hr;
5019 struct filter *filter;
5020 TP_WORK *work;
5022 TRACE("graph %p.\n", graph);
5024 EnterCriticalSection(&graph->cs);
5026 if (graph->state == State_Paused)
5028 LeaveCriticalSection(&graph->cs);
5029 return S_OK;
5032 sort_filters(graph);
5033 update_render_count(graph);
5035 if (graph->defaultclock && !graph->refClock)
5036 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
5038 if (graph->state == State_Running && graph->refClock)
5040 REFERENCE_TIME time;
5041 IReferenceClock_GetTime(graph->refClock, &time);
5042 graph->stream_elapsed += time - graph->stream_start;
5043 graph->current_pos += graph->stream_elapsed;
5046 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5048 filter_hr = IBaseFilter_Pause(filter->filter);
5049 if (hr == S_OK)
5050 hr = filter_hr;
5053 graph->state = State_Paused;
5054 graph->needs_async_run = 0;
5055 work = graph->async_run_work;
5057 LeaveCriticalSection(&graph->cs);
5059 if (work)
5060 WaitForThreadpoolWorkCallbacks(work, TRUE);
5062 return hr;
5065 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
5067 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5068 HRESULT hr;
5070 TRACE("graph %p, start %s.\n", graph, debugstr_time(start));
5072 EnterCriticalSection(&graph->cs);
5074 if (graph->state == State_Running)
5076 LeaveCriticalSection(&graph->cs);
5077 return S_OK;
5080 sort_filters(graph);
5082 hr = graph_start(graph, start);
5084 graph->state = State_Running;
5085 graph->needs_async_run = 0;
5087 LeaveCriticalSection(&graph->cs);
5088 return hr;
5091 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, FILTER_STATE *state)
5093 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5094 DWORD end = GetTickCount() + timeout;
5095 FILTER_STATE expect_state;
5096 HRESULT hr;
5098 TRACE("graph %p, timeout %u, state %p.\n", graph, timeout, state);
5100 if (!state)
5101 return E_POINTER;
5103 /* Thread safety is a little tricky here. GetState() shouldn't block other
5104 * functions from being called on the filter graph. However, we can't just
5105 * call IBaseFilter::GetState() in one loop and drop the lock on every
5106 * iteration, since the filter list might change beneath us. So instead we
5107 * do what native does, and poll for it every 10 ms. */
5109 EnterCriticalSection(&graph->cs);
5110 *state = graph->state;
5111 expect_state = graph->needs_async_run ? State_Paused : graph->state;
5113 for (;;)
5115 IBaseFilter *async_filter = NULL;
5116 FILTER_STATE filter_state;
5117 struct filter *filter;
5119 hr = S_OK;
5121 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5123 HRESULT filter_hr = IBaseFilter_GetState(filter->filter, 0, &filter_state);
5125 TRACE("Filter %p returned hr %#x, state %u.\n", filter->filter, filter_hr, filter_state);
5127 if (filter_hr == VFW_S_STATE_INTERMEDIATE)
5128 async_filter = filter->filter;
5130 if (hr == S_OK && filter_hr == VFW_S_STATE_INTERMEDIATE)
5131 hr = VFW_S_STATE_INTERMEDIATE;
5132 else if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE)
5133 hr = filter_hr;
5135 if (hr == S_OK && filter_state == State_Paused && graph->state != State_Paused)
5137 async_filter = filter->filter;
5138 hr = VFW_S_STATE_INTERMEDIATE;
5140 else if (filter_state != graph->state && filter_state != State_Paused)
5141 hr = E_FAIL;
5143 if (filter_state != expect_state)
5144 ERR("Filter %p reported incorrect state %u (expected %u).\n",
5145 filter->filter, filter_state, expect_state);
5148 LeaveCriticalSection(&graph->cs);
5150 if (hr != VFW_S_STATE_INTERMEDIATE || (timeout != INFINITE && GetTickCount() >= end))
5151 break;
5153 IBaseFilter_GetState(async_filter, 10, &filter_state);
5155 EnterCriticalSection(&graph->cs);
5158 TRACE("Returning %#x, state %u.\n", hr, *state);
5159 return hr;
5162 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
5164 struct filter_graph *This = impl_from_IMediaFilter(iface);
5165 struct filter *filter;
5166 HRESULT hr = S_OK;
5168 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
5170 EnterCriticalSection(&This->cs);
5172 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
5174 hr = IBaseFilter_SetSyncSource(filter->filter, pClock);
5175 if (FAILED(hr))
5176 break;
5179 if (FAILED(hr))
5181 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
5182 IBaseFilter_SetSyncSource(filter->filter, This->refClock);
5184 else
5186 if (This->refClock)
5187 IReferenceClock_Release(This->refClock);
5188 This->refClock = pClock;
5189 if (This->refClock)
5190 IReferenceClock_AddRef(This->refClock);
5191 This->defaultclock = FALSE;
5193 if (This->HandleEcClockChanged)
5195 IMediaEventSink *pEventSink;
5196 HRESULT eshr;
5198 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (void **)&pEventSink);
5199 if (SUCCEEDED(eshr))
5201 IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5202 IMediaEventSink_Release(pEventSink);
5207 LeaveCriticalSection(&This->cs);
5209 return hr;
5212 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5214 struct filter_graph *This = impl_from_IMediaFilter(iface);
5216 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
5218 if (!ppClock)
5219 return E_POINTER;
5221 EnterCriticalSection(&This->cs);
5223 *ppClock = This->refClock;
5224 if (*ppClock)
5225 IReferenceClock_AddRef(*ppClock);
5227 LeaveCriticalSection(&This->cs);
5229 return S_OK;
5232 static const IMediaFilterVtbl IMediaFilter_VTable =
5234 MediaFilter_QueryInterface,
5235 MediaFilter_AddRef,
5236 MediaFilter_Release,
5237 MediaFilter_GetClassID,
5238 MediaFilter_Stop,
5239 MediaFilter_Pause,
5240 MediaFilter_Run,
5241 MediaFilter_GetState,
5242 MediaFilter_SetSyncSource,
5243 MediaFilter_GetSyncSource
5246 static struct filter_graph *impl_from_IMediaEventSink(IMediaEventSink *iface)
5248 return CONTAINING_RECORD(iface, struct filter_graph, IMediaEventSink_iface);
5251 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID iid, void **out)
5253 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5255 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5258 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5260 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5262 return IUnknown_AddRef(graph->outer_unk);
5265 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5267 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5269 return IUnknown_Release(graph->outer_unk);
5272 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCode,
5273 LONG_PTR EventParam1, LONG_PTR EventParam2)
5275 struct filter_graph *This = impl_from_IMediaEventSink(iface);
5276 Event evt;
5278 TRACE("(%p/%p)->(%d, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
5280 /* We need thread safety here, let's use the events queue's one */
5281 EnterCriticalSection(&This->evqueue.msg_crst);
5283 if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
5285 TRACE("Process EC_COMPLETE notification\n");
5286 if (++This->EcCompleteCount == This->nRenderers)
5288 evt.lEventCode = EC_COMPLETE;
5289 evt.lParam1 = S_OK;
5290 evt.lParam2 = 0;
5291 TRACE("Send EC_COMPLETE to app\n");
5292 EventsQueue_PutEvent(&This->evqueue, &evt);
5293 if (!This->notif.disabled && This->notif.hWnd)
5295 TRACE("Send Window message\n");
5296 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5298 This->CompletionStatus = EC_COMPLETE;
5299 This->got_ec_complete = 1;
5300 SetEvent(This->hEventCompletion);
5303 else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
5305 /* FIXME: Not handled yet */
5307 else
5309 evt.lEventCode = EventCode;
5310 evt.lParam1 = EventParam1;
5311 evt.lParam2 = EventParam2;
5312 EventsQueue_PutEvent(&This->evqueue, &evt);
5313 if (!This->notif.disabled && This->notif.hWnd)
5314 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5317 LeaveCriticalSection(&This->evqueue.msg_crst);
5318 return S_OK;
5321 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5323 MediaEventSink_QueryInterface,
5324 MediaEventSink_AddRef,
5325 MediaEventSink_Release,
5326 MediaEventSink_Notify
5329 static struct filter_graph *impl_from_IGraphConfig(IGraphConfig *iface)
5331 return CONTAINING_RECORD(iface, struct filter_graph, IGraphConfig_iface);
5334 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID iid, void **out)
5336 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5338 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5341 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5343 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5345 return IUnknown_AddRef(graph->outer_unk);
5348 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5350 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5352 return IUnknown_Release(graph->outer_unk);
5355 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface, IPin *pOutputPin, IPin *pInputPin,
5356 const AM_MEDIA_TYPE *pmtFirstConnection, IBaseFilter *pUsingFilter, HANDLE hAbortEvent,
5357 DWORD dwFlags)
5359 struct filter_graph *This = impl_from_IGraphConfig(iface);
5361 FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
5362 strmbase_dump_media_type(pmtFirstConnection);
5364 return E_NOTIMPL;
5367 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface, IGraphConfigCallback *pCallback,
5368 void *pvContext, DWORD dwFlags, HANDLE hAbortEvent)
5370 struct filter_graph *This = impl_from_IGraphConfig(iface);
5371 HRESULT hr;
5373 WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
5375 if (hAbortEvent)
5376 FIXME("The parameter hAbortEvent is not handled!\n");
5378 EnterCriticalSection(&This->cs);
5380 hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
5382 LeaveCriticalSection(&This->cs);
5384 return hr;
5387 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface, IBaseFilter *pFilter)
5389 struct filter_graph *This = impl_from_IGraphConfig(iface);
5391 FIXME("(%p)->(%p): stub!\n", This, pFilter);
5393 return E_NOTIMPL;
5396 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface, IEnumFilters **pEnum)
5398 struct filter_graph *This = impl_from_IGraphConfig(iface);
5400 FIXME("(%p)->(%p): stub!\n", This, pEnum);
5402 return E_NOTIMPL;
5405 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface, IBaseFilter *pFilter)
5407 struct filter_graph *This = impl_from_IGraphConfig(iface);
5409 FIXME("(%p)->(%p): stub!\n", This, pFilter);
5411 return E_NOTIMPL;
5414 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface, REFERENCE_TIME *prtStart)
5416 struct filter_graph *This = impl_from_IGraphConfig(iface);
5418 FIXME("(%p)->(%p): stub!\n", This, prtStart);
5420 return E_NOTIMPL;
5423 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface, IPin *pOutputPin,
5424 IPinConnection *pConnection, HANDLE hEventAbort)
5426 struct filter_graph *This = impl_from_IGraphConfig(iface);
5428 FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5430 return E_NOTIMPL;
5433 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5434 DWORD dwFlags)
5436 struct filter_graph *This = impl_from_IGraphConfig(iface);
5438 FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5440 return E_NOTIMPL;
5443 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5444 DWORD *dwFlags)
5446 struct filter_graph *This = impl_from_IGraphConfig(iface);
5448 FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5450 return E_NOTIMPL;
5453 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface, IBaseFilter *pFilter,
5454 DWORD dwFlags)
5456 struct filter_graph *This = impl_from_IGraphConfig(iface);
5458 FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5460 return E_NOTIMPL;
5463 static const IGraphConfigVtbl IGraphConfig_VTable =
5465 GraphConfig_QueryInterface,
5466 GraphConfig_AddRef,
5467 GraphConfig_Release,
5468 GraphConfig_Reconnect,
5469 GraphConfig_Reconfigure,
5470 GraphConfig_AddFilterToCache,
5471 GraphConfig_EnumCacheFilter,
5472 GraphConfig_RemoveFilterFromCache,
5473 GraphConfig_GetStartTime,
5474 GraphConfig_PushThroughData,
5475 GraphConfig_SetFilterFlags,
5476 GraphConfig_GetFilterFlags,
5477 GraphConfig_RemoveFilterEx
5480 static struct filter_graph *impl_from_IGraphVersion(IGraphVersion *iface)
5482 return CONTAINING_RECORD(iface, struct filter_graph, IGraphVersion_iface);
5485 static HRESULT WINAPI GraphVersion_QueryInterface(IGraphVersion *iface, REFIID iid, void **out)
5487 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5489 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5492 static ULONG WINAPI GraphVersion_AddRef(IGraphVersion *iface)
5494 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5496 return IUnknown_AddRef(graph->outer_unk);
5499 static ULONG WINAPI GraphVersion_Release(IGraphVersion *iface)
5501 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5503 return IUnknown_Release(graph->outer_unk);
5506 static HRESULT WINAPI GraphVersion_QueryVersion(IGraphVersion *iface, LONG *pVersion)
5508 struct filter_graph *This = impl_from_IGraphVersion(iface);
5510 if(!pVersion)
5511 return E_POINTER;
5513 TRACE("(%p)->(%p): current version %i\n", This, pVersion, This->version);
5515 *pVersion = This->version;
5516 return S_OK;
5519 static const IGraphVersionVtbl IGraphVersion_VTable =
5521 GraphVersion_QueryInterface,
5522 GraphVersion_AddRef,
5523 GraphVersion_Release,
5524 GraphVersion_QueryVersion,
5527 static struct filter_graph *impl_from_IVideoFrameStep(IVideoFrameStep *iface)
5529 return CONTAINING_RECORD(iface, struct filter_graph, IVideoFrameStep_iface);
5532 static HRESULT WINAPI VideoFrameStep_QueryInterface(IVideoFrameStep *iface, REFIID iid, void **out)
5534 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5535 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5538 static ULONG WINAPI VideoFrameStep_AddRef(IVideoFrameStep *iface)
5540 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5541 return IUnknown_AddRef(graph->outer_unk);
5544 static ULONG WINAPI VideoFrameStep_Release(IVideoFrameStep *iface)
5546 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5547 return IUnknown_Release(graph->outer_unk);
5550 static HRESULT WINAPI VideoFrameStep_Step(IVideoFrameStep *iface, DWORD frame_count, IUnknown *filter)
5552 FIXME("iface %p, frame_count %u, filter %p, stub!\n", iface, frame_count, filter);
5553 return E_NOTIMPL;
5556 static HRESULT WINAPI VideoFrameStep_CanStep(IVideoFrameStep *iface, LONG multiple, IUnknown *filter)
5558 FIXME("iface %p, multiple %d, filter %p, stub!\n", iface, multiple, filter);
5559 return E_NOTIMPL;
5562 static HRESULT WINAPI VideoFrameStep_CancelStep(IVideoFrameStep *iface)
5564 FIXME("iface %p, stub!\n", iface);
5565 return E_NOTIMPL;
5568 static const IVideoFrameStepVtbl VideoFrameStep_vtbl =
5570 VideoFrameStep_QueryInterface,
5571 VideoFrameStep_AddRef,
5572 VideoFrameStep_Release,
5573 VideoFrameStep_Step,
5574 VideoFrameStep_CanStep,
5575 VideoFrameStep_CancelStep
5578 static const IUnknownVtbl IInner_VTable =
5580 FilterGraphInner_QueryInterface,
5581 FilterGraphInner_AddRef,
5582 FilterGraphInner_Release
5585 static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded)
5587 struct filter_graph *object;
5588 HRESULT hr;
5590 *out = NULL;
5592 if (!(object = calloc(1, sizeof(*object))))
5593 return E_OUTOFMEMORY;
5595 object->IBasicAudio_iface.lpVtbl = &IBasicAudio_VTable;
5596 object->IBasicVideo2_iface.lpVtbl = &IBasicVideo_VTable;
5597 object->IFilterGraph2_iface.lpVtbl = &IFilterGraph2_VTable;
5598 object->IGraphConfig_iface.lpVtbl = &IGraphConfig_VTable;
5599 object->IGraphVersion_iface.lpVtbl = &IGraphVersion_VTable;
5600 object->IMediaControl_iface.lpVtbl = &IMediaControl_VTable;
5601 object->IMediaEventEx_iface.lpVtbl = &IMediaEventEx_VTable;
5602 object->IMediaEventSink_iface.lpVtbl = &IMediaEventSink_VTable;
5603 object->IMediaFilter_iface.lpVtbl = &IMediaFilter_VTable;
5604 object->IMediaPosition_iface.lpVtbl = &IMediaPosition_VTable;
5605 object->IMediaSeeking_iface.lpVtbl = &IMediaSeeking_VTable;
5606 object->IObjectWithSite_iface.lpVtbl = &IObjectWithSite_VTable;
5607 object->IUnknown_inner.lpVtbl = &IInner_VTable;
5608 object->IVideoFrameStep_iface.lpVtbl = &VideoFrameStep_vtbl;
5609 object->IVideoWindow_iface.lpVtbl = &IVideoWindow_VTable;
5610 object->ref = 1;
5611 object->outer_unk = outer ? outer : &object->IUnknown_inner;
5613 if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, object->outer_unk,
5614 CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&object->punkFilterMapper2)))
5616 ERR("Failed to create filter mapper, hr %#x.\n", hr);
5617 free(object);
5618 return hr;
5621 InitializeCriticalSection(&object->cs);
5622 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": filter_graph.cs");
5624 object->defaultclock = TRUE;
5625 EventsQueue_Init(&object->evqueue);
5626 list_init(&object->filters);
5627 object->HandleEcClockChanged = TRUE;
5628 object->HandleEcComplete = TRUE;
5629 object->HandleEcRepaint = TRUE;
5630 object->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5631 object->name_index = 1;
5632 object->timeformatseek = TIME_FORMAT_MEDIA_TIME;
5634 if (threaded)
5636 object->message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL);
5637 object->message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &object->message_thread_id);
5638 WaitForSingleObject(object->message_thread_ret, INFINITE);
5640 else
5641 object->message_thread = NULL;
5643 TRACE("Created %sthreaded filter graph %p.\n", threaded ? "" : "non-", object);
5644 *out = &object->IUnknown_inner;
5645 return S_OK;
5648 HRESULT filter_graph_create(IUnknown *outer, IUnknown **out)
5650 return filter_graph_common_create(outer, out, TRUE);
5653 HRESULT filter_graph_no_thread_create(IUnknown *outer, IUnknown **out)
5655 return filter_graph_common_create(outer, out, FALSE);