quartz: Return the paused timestamp from IMediaSeeking::GetCurrentPosition() if the...
[wine.git] / dlls / quartz / filtergraph.c
blobe5ae12d9452b1733de66e67173a844d7dba047eb
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 if (!filter->seeking)
590 /* The Legend of Heroes: Trails of Cold Steel II destroys its filter when
591 * its IMediaSeeking interface is released, so cache the interface instead
592 * of querying for it every time.
593 * Some filters (e.g. MediaStreamFilter) can become seekable when they are
594 * already in the graph, so always try to query IMediaSeeking if it's not
595 * cached yet. */
596 if (FAILED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaSeeking, (void **)&filter->seeking)))
597 filter->seeking = NULL;
601 static BOOL is_renderer(struct filter *filter)
603 IAMFilterMiscFlags *flags;
604 BOOL ret = FALSE;
606 if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IAMFilterMiscFlags, (void **)&flags)))
608 if (IAMFilterMiscFlags_GetMiscFlags(flags) & AM_FILTER_MISC_FLAGS_IS_RENDERER)
609 ret = TRUE;
610 IAMFilterMiscFlags_Release(flags);
612 else
614 update_seeking(filter);
615 if (filter->seeking && !has_output_pins(filter->filter))
616 ret = TRUE;
618 return ret;
621 /*** IFilterGraph methods ***/
622 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
623 IBaseFilter *filter, const WCHAR *name)
625 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
626 BOOL duplicate_name = FALSE;
627 struct filter *entry;
628 unsigned int i;
629 HRESULT hr;
631 TRACE("graph %p, filter %p, name %s.\n", graph, filter, debugstr_w(name));
633 if (!filter)
634 return E_POINTER;
636 if (!(entry = heap_alloc(sizeof(*entry))))
637 return E_OUTOFMEMORY;
639 if (!(entry->name = CoTaskMemAlloc((name ? wcslen(name) + 6 : 5) * sizeof(WCHAR))))
641 heap_free(entry);
642 return E_OUTOFMEMORY;
645 if (name && find_filter_by_name(graph, name))
646 duplicate_name = TRUE;
648 if (!name || duplicate_name)
650 for (i = 0; i < 10000 ; ++i)
652 if (name)
653 swprintf(entry->name, name ? wcslen(name) + 6 : 5, L"%s %04u", name, graph->name_index);
654 else
655 swprintf(entry->name, name ? wcslen(name) + 6 : 5, L"%04u", graph->name_index);
657 graph->name_index = (graph->name_index + 1) % 10000;
659 if (!find_filter_by_name(graph, entry->name))
660 break;
663 if (i == 10000)
665 CoTaskMemFree(entry->name);
666 heap_free(entry);
667 return VFW_E_DUPLICATE_NAME;
670 else
671 wcscpy(entry->name, name);
673 if (FAILED(hr = IBaseFilter_JoinFilterGraph(filter,
674 (IFilterGraph *)&graph->IFilterGraph2_iface, entry->name)))
676 CoTaskMemFree(entry->name);
677 heap_free(entry);
678 return hr;
681 IBaseFilter_AddRef(entry->filter = filter);
683 list_add_head(&graph->filters, &entry->entry);
684 entry->sorting = FALSE;
685 entry->seeking = NULL;
686 ++graph->version;
688 return duplicate_name ? VFW_S_DUPLICATE_NAME : hr;
691 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
693 struct filter_graph *This = impl_from_IFilterGraph2(iface);
694 struct filter *entry;
695 int i;
696 HRESULT hr = E_FAIL;
698 TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
700 /* FIXME: check graph is stopped */
702 LIST_FOR_EACH_ENTRY(entry, &This->filters, struct filter, entry)
704 if (entry->filter == pFilter)
706 IEnumPins *penumpins = NULL;
707 FILTER_STATE state;
709 if (This->defaultclock && This->refClockProvider == pFilter)
711 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
712 This->defaultclock = TRUE;
715 TRACE("Removing filter %s.\n", debugstr_w(entry->name));
716 IBaseFilter_GetState(pFilter, 0, &state);
717 if (state == State_Running)
718 IBaseFilter_Pause(pFilter);
719 if (state != State_Stopped)
720 IBaseFilter_Stop(pFilter);
722 hr = IBaseFilter_EnumPins(pFilter, &penumpins);
723 if (SUCCEEDED(hr)) {
724 IPin *ppin;
725 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
727 IPin *victim = NULL;
728 HRESULT h;
729 IPin_ConnectedTo(ppin, &victim);
730 if (victim)
732 h = IPin_Disconnect(victim);
733 TRACE("Disconnect other side: %08x\n", h);
734 if (h == VFW_E_NOT_STOPPED)
736 PIN_INFO pinfo;
737 IPin_QueryPinInfo(victim, &pinfo);
739 IBaseFilter_GetState(pinfo.pFilter, 0, &state);
740 if (state == State_Running)
741 IBaseFilter_Pause(pinfo.pFilter);
742 IBaseFilter_Stop(pinfo.pFilter);
743 IBaseFilter_Release(pinfo.pFilter);
744 h = IPin_Disconnect(victim);
745 TRACE("Disconnect retry: %08x\n", h);
747 IPin_Release(victim);
749 h = IPin_Disconnect(ppin);
750 TRACE("Disconnect 2: %08x\n", h);
752 IPin_Release(ppin);
754 IEnumPins_Release(penumpins);
757 hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, NULL);
758 if (SUCCEEDED(hr))
760 IBaseFilter_SetSyncSource(pFilter, NULL);
761 IBaseFilter_Release(pFilter);
762 if (entry->seeking)
763 IMediaSeeking_Release(entry->seeking);
764 list_remove(&entry->entry);
765 CoTaskMemFree(entry->name);
766 heap_free(entry);
767 This->version++;
768 /* Invalidate interfaces in the cache */
769 for (i = 0; i < This->nItfCacheEntries; i++)
770 if (pFilter == This->ItfCacheEntries[i].filter)
772 IUnknown_Release(This->ItfCacheEntries[i].iface);
773 This->ItfCacheEntries[i].iface = NULL;
774 This->ItfCacheEntries[i].filter = NULL;
776 return S_OK;
778 break;
782 return hr; /* FIXME: check this error code */
785 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface, IEnumFilters **out)
787 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
789 TRACE("graph %p, out %p.\n", graph, out);
791 return create_enum_filters(graph, list_head(&graph->filters), out);
794 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface,
795 const WCHAR *name, IBaseFilter **filter)
797 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
799 TRACE("graph %p, name %s, filter %p.\n", graph, debugstr_w(name), filter);
801 if (!filter)
802 return E_POINTER;
804 if ((*filter = find_filter_by_name(graph, name)))
806 IBaseFilter_AddRef(*filter);
807 return S_OK;
810 return VFW_E_NOT_FOUND;
813 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
814 * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
816 static HRESULT CheckCircularConnection(struct filter_graph *This, IPin *out, IPin *in)
818 #if 1
819 HRESULT hr;
820 PIN_INFO info_out, info_in;
822 hr = IPin_QueryPinInfo(out, &info_out);
823 if (FAILED(hr))
824 return hr;
825 if (info_out.dir != PINDIR_OUTPUT)
827 IBaseFilter_Release(info_out.pFilter);
828 return VFW_E_CANNOT_CONNECT;
831 hr = IPin_QueryPinInfo(in, &info_in);
832 if (SUCCEEDED(hr))
833 IBaseFilter_Release(info_in.pFilter);
834 if (FAILED(hr))
835 goto out;
836 if (info_in.dir != PINDIR_INPUT)
838 hr = VFW_E_CANNOT_CONNECT;
839 goto out;
842 if (info_out.pFilter == info_in.pFilter)
843 hr = VFW_E_CIRCULAR_GRAPH;
844 else
846 IEnumPins *enumpins;
847 IPin *test;
849 hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
850 if (FAILED(hr))
851 goto out;
853 IEnumPins_Reset(enumpins);
854 while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
856 PIN_DIRECTION dir = PINDIR_OUTPUT;
857 IPin_QueryDirection(test, &dir);
858 if (dir == PINDIR_INPUT)
860 IPin *victim = NULL;
861 IPin_ConnectedTo(test, &victim);
862 if (victim)
864 hr = CheckCircularConnection(This, victim, in);
865 IPin_Release(victim);
866 if (FAILED(hr))
868 IPin_Release(test);
869 break;
873 IPin_Release(test);
875 IEnumPins_Release(enumpins);
878 out:
879 IBaseFilter_Release(info_out.pFilter);
880 if (FAILED(hr))
881 ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
882 return hr;
883 #else
884 /* Debugging filtergraphs not enabled */
885 return S_OK;
886 #endif
889 static struct filter *find_sorted_filter(struct filter_graph *graph, IBaseFilter *iface)
891 struct filter *filter;
893 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
895 if (filter->filter == iface)
896 return filter;
899 return NULL;
902 static void sort_filter_recurse(struct filter_graph *graph, struct filter *filter, struct list *sorted)
904 struct filter *peer_filter;
905 IEnumPins *enumpins;
906 PIN_DIRECTION dir;
907 IPin *pin, *peer;
908 PIN_INFO info;
910 TRACE("Sorting filter %p.\n", filter->filter);
912 /* Cyclic connections should be caught by CheckCircularConnection(). */
913 assert(!filter->sorting);
915 filter->sorting = TRUE;
917 IBaseFilter_EnumPins(filter->filter, &enumpins);
918 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
920 IPin_QueryDirection(pin, &dir);
922 if (dir == PINDIR_INPUT && IPin_ConnectedTo(pin, &peer) == S_OK)
924 IPin_QueryPinInfo(peer, &info);
925 /* Note that the filter may have already been sorted. */
926 if ((peer_filter = find_sorted_filter(graph, info.pFilter)))
927 sort_filter_recurse(graph, peer_filter, sorted);
928 IBaseFilter_Release(info.pFilter);
929 IPin_Release(peer);
931 IPin_Release(pin);
933 IEnumPins_Release(enumpins);
935 filter->sorting = FALSE;
937 list_remove(&filter->entry);
938 list_add_head(sorted, &filter->entry);
941 static void sort_filters(struct filter_graph *graph)
943 struct list sorted = LIST_INIT(sorted), *cursor;
945 while ((cursor = list_head(&graph->filters)))
947 struct filter *filter = LIST_ENTRY(cursor, struct filter, entry);
948 sort_filter_recurse(graph, filter, &sorted);
951 list_move_tail(&graph->filters, &sorted);
954 /* NOTE: despite the implication, it doesn't matter which
955 * way round you put in the input and output pins */
956 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppinIn, IPin *ppinOut,
957 const AM_MEDIA_TYPE *pmt)
959 struct filter_graph *This = impl_from_IFilterGraph2(iface);
960 PIN_DIRECTION dir;
961 HRESULT hr;
963 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
964 strmbase_dump_media_type(pmt);
966 /* FIXME: check pins are in graph */
968 if (TRACE_ON(quartz))
970 PIN_INFO PinInfo;
972 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
973 if (FAILED(hr))
974 return hr;
976 TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
977 IBaseFilter_Release(PinInfo.pFilter);
979 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
980 if (FAILED(hr))
981 return hr;
983 TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
984 IBaseFilter_Release(PinInfo.pFilter);
987 hr = IPin_QueryDirection(ppinIn, &dir);
988 if (SUCCEEDED(hr))
990 if (dir == PINDIR_INPUT)
992 hr = CheckCircularConnection(This, ppinOut, ppinIn);
993 if (SUCCEEDED(hr))
994 hr = IPin_Connect(ppinOut, ppinIn, pmt);
996 else
998 hr = CheckCircularConnection(This, ppinIn, ppinOut);
999 if (SUCCEEDED(hr))
1000 hr = IPin_Connect(ppinIn, ppinOut, pmt);
1004 return hr;
1007 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface, IPin *pin)
1009 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1011 TRACE("graph %p, pin %p.\n", graph, pin);
1013 return IFilterGraph2_ReconnectEx(iface, pin, NULL);
1016 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
1018 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1020 TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
1022 if (!ppin)
1023 return E_POINTER;
1025 return IPin_Disconnect(ppin);
1028 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
1030 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1031 IReferenceClock *pClock = NULL;
1032 struct filter *filter;
1033 HRESULT hr = S_OK;
1035 TRACE("(%p/%p)->() live sources not handled properly!\n", This, iface);
1037 EnterCriticalSection(&This->cs);
1039 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
1041 if (IBaseFilter_QueryInterface(filter->filter, &IID_IReferenceClock, (void **)&pClock) == S_OK)
1042 break;
1045 if (!pClock)
1047 hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
1048 This->refClockProvider = NULL;
1050 else
1052 filter = LIST_ENTRY(list_tail(&This->filters), struct filter, entry);
1053 This->refClockProvider = filter->filter;
1056 if (SUCCEEDED(hr))
1058 hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
1059 This->defaultclock = TRUE;
1060 IReferenceClock_Release(pClock);
1062 LeaveCriticalSection(&This->cs);
1064 return hr;
1067 struct filter_create_params
1069 HRESULT hr;
1070 IMoniker *moniker;
1071 IBaseFilter *filter;
1074 static DWORD WINAPI message_thread_run(void *ctx)
1076 struct filter_graph *graph = ctx;
1077 MSG msg;
1079 /* Make sure we have a message queue. */
1080 PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
1081 SetEvent(graph->message_thread_ret);
1083 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1085 for (;;)
1087 GetMessageW(&msg, NULL, 0, 0);
1089 if (!msg.hwnd && msg.message == WM_USER)
1091 struct filter_create_params *params = (struct filter_create_params *)msg.wParam;
1093 params->hr = IMoniker_BindToObject(params->moniker, NULL, NULL,
1094 &IID_IBaseFilter, (void **)&params->filter);
1095 SetEvent(graph->message_thread_ret);
1097 else if (!msg.hwnd && msg.message == WM_USER + 1)
1099 break;
1101 else
1103 TranslateMessage(&msg);
1104 DispatchMessageW(&msg);
1108 CoUninitialize();
1109 return 0;
1112 static HRESULT create_filter(struct filter_graph *graph, IMoniker *moniker, IBaseFilter **filter)
1114 if (graph->message_thread)
1116 struct filter_create_params params;
1118 params.moniker = moniker;
1119 PostThreadMessageW(graph->message_thread_id, WM_USER, (WPARAM)&params, 0);
1120 WaitForSingleObject(graph->message_thread_ret, INFINITE);
1121 *filter = params.filter;
1122 return params.hr;
1124 else
1125 return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter);
1128 static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
1129 BOOL render_to_existing, unsigned int recursion_depth);
1131 static HRESULT autoplug_through_sink(struct filter_graph *graph, IPin *source,
1132 IBaseFilter *filter, IPin *middle_sink, IPin *sink,
1133 BOOL render_to_existing, unsigned int recursion_depth)
1135 BOOL any = FALSE, all = TRUE;
1136 IPin *middle_source, *peer;
1137 IEnumPins *source_enum;
1138 PIN_DIRECTION dir;
1139 PIN_INFO info;
1140 HRESULT hr;
1142 TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, middle_sink);
1144 IPin_QueryDirection(middle_sink, &dir);
1145 if (dir != PINDIR_INPUT)
1146 return E_FAIL;
1148 if (IPin_ConnectedTo(middle_sink, &peer) == S_OK)
1150 IPin_Release(peer);
1151 return E_FAIL;
1154 if (FAILED(hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, middle_sink, NULL)))
1155 return E_FAIL;
1157 if (FAILED(hr = IBaseFilter_EnumPins(filter, &source_enum)))
1158 goto err;
1160 while (IEnumPins_Next(source_enum, 1, &middle_source, NULL) == S_OK)
1162 IPin_QueryPinInfo(middle_source, &info);
1163 IBaseFilter_Release(info.pFilter);
1164 if (info.dir != PINDIR_OUTPUT)
1166 IPin_Release(middle_source);
1167 continue;
1169 if (info.achName[0] == '~')
1171 TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
1172 IPin_Release(middle_source);
1173 continue;
1175 if (IPin_ConnectedTo(middle_source, &peer) == S_OK)
1177 IPin_Release(peer);
1178 IPin_Release(middle_source);
1179 continue;
1182 hr = autoplug(graph, middle_source, sink, render_to_existing, recursion_depth + 1);
1183 IPin_Release(middle_source);
1184 if (SUCCEEDED(hr) && sink)
1186 IEnumPins_Release(source_enum);
1187 return hr;
1189 if (SUCCEEDED(hr))
1190 any = TRUE;
1191 if (hr != S_OK)
1192 all = FALSE;
1194 IEnumPins_Release(source_enum);
1196 if (!sink)
1198 if (all)
1199 return S_OK;
1200 if (any)
1201 return VFW_S_PARTIAL_RENDER;
1204 err:
1205 IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, source);
1206 IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, middle_sink);
1207 return E_FAIL;
1210 static HRESULT autoplug_through_filter(struct filter_graph *graph, IPin *source,
1211 IBaseFilter *filter, IPin *sink, BOOL render_to_existing,
1212 unsigned int recursion_depth)
1214 IEnumPins *sink_enum;
1215 IPin *filter_sink;
1216 HRESULT hr;
1218 TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, filter);
1220 if (FAILED(hr = IBaseFilter_EnumPins(filter, &sink_enum)))
1221 return hr;
1223 while (IEnumPins_Next(sink_enum, 1, &filter_sink, NULL) == S_OK)
1225 hr = autoplug_through_sink(graph, source, filter, filter_sink, sink,
1226 render_to_existing, recursion_depth);
1227 IPin_Release(filter_sink);
1228 if (SUCCEEDED(hr))
1230 IEnumPins_Release(sink_enum);
1231 return hr;
1234 IEnumPins_Release(sink_enum);
1235 return VFW_E_CANNOT_CONNECT;
1238 /* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which
1239 * share most of the same code. Render() calls this with a NULL sink. */
1240 static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
1241 BOOL render_to_existing, unsigned int recursion_depth)
1243 IAMGraphBuilderCallback *callback = NULL;
1244 IEnumMediaTypes *enummt;
1245 IFilterMapper2 *mapper;
1246 struct filter *filter;
1247 AM_MEDIA_TYPE *mt;
1248 HRESULT hr;
1250 TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
1252 if (recursion_depth >= 5)
1254 WARN("Recursion depth has reached 5; aborting.\n");
1255 return VFW_E_CANNOT_CONNECT;
1258 if (sink)
1260 /* Try to connect directly to this sink. */
1261 hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, sink, NULL);
1263 /* If direct connection succeeded, we should propagate that return value.
1264 * If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
1265 * even bother trying intermediate filters, since they won't succeed. */
1266 if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
1267 return hr;
1270 /* Always prefer filters in the graph. */
1271 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1273 if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter,
1274 sink, render_to_existing, recursion_depth)))
1275 return hr;
1278 IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
1280 if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
1282 IFilterMapper2_Release(mapper);
1283 return hr;
1286 if (graph->pSite)
1287 IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
1289 while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
1291 GUID types[2] = {mt->majortype, mt->subtype};
1292 IEnumMoniker *enummoniker;
1293 IBaseFilter *filter;
1294 IMoniker *moniker;
1296 DeleteMediaType(mt);
1298 if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker,
1299 0, FALSE, MERIT_UNLIKELY, TRUE, 1, types, NULL, NULL, FALSE,
1300 render_to_existing, 0, NULL, NULL, NULL)))
1301 goto out;
1303 while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
1305 IPropertyBag *bag;
1306 VARIANT var;
1308 VariantInit(&var);
1309 IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&bag);
1310 hr = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
1311 IPropertyBag_Release(bag);
1312 if (FAILED(hr))
1314 IMoniker_Release(moniker);
1315 continue;
1318 if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
1320 TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#x.\n", hr);
1321 IMoniker_Release(moniker);
1322 continue;
1325 hr = create_filter(graph, moniker, &filter);
1326 IMoniker_Release(moniker);
1327 if (FAILED(hr))
1329 ERR("Failed to create filter for %s, hr %#x.\n", debugstr_w(V_BSTR(&var)), hr);
1330 VariantClear(&var);
1331 continue;
1334 if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
1336 TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#x.\n", hr);
1337 IBaseFilter_Release(filter);
1338 continue;
1341 hr = IFilterGraph2_AddFilter(&graph->IFilterGraph2_iface, filter, V_BSTR(&var));
1342 VariantClear(&var);
1343 if (FAILED(hr))
1345 ERR("Failed to add filter, hr %#x.\n", hr);
1346 IBaseFilter_Release(filter);
1347 continue;
1350 hr = autoplug_through_filter(graph, source, filter, sink, render_to_existing, recursion_depth);
1351 if (SUCCEEDED(hr))
1353 IBaseFilter_Release(filter);
1354 goto out;
1357 IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
1358 IBaseFilter_Release(filter);
1360 IEnumMoniker_Release(enummoniker);
1363 hr = VFW_E_CANNOT_CONNECT;
1365 out:
1366 if (callback) IAMGraphBuilderCallback_Release(callback);
1367 IEnumMediaTypes_Release(enummt);
1368 IFilterMapper2_Release(mapper);
1369 return hr;
1372 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *source, IPin *sink)
1374 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1375 PIN_DIRECTION dir;
1376 HRESULT hr;
1378 TRACE("graph %p, source %p, sink %p.\n", graph, source, sink);
1380 if (!source || !sink)
1381 return E_POINTER;
1383 if (FAILED(hr = IPin_QueryDirection(source, &dir)))
1384 return hr;
1386 if (dir == PINDIR_INPUT)
1388 IPin *temp;
1390 TRACE("Directions seem backwards, swapping pins\n");
1392 temp = sink;
1393 sink = source;
1394 source = temp;
1397 EnterCriticalSection(&graph->cs);
1399 hr = autoplug(graph, source, sink, FALSE, 0);
1401 LeaveCriticalSection(&graph->cs);
1403 TRACE("Returning %#x.\n", hr);
1404 return hr;
1407 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *source)
1409 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1410 HRESULT hr;
1412 TRACE("graph %p, source %p.\n", graph, source);
1414 EnterCriticalSection(&graph->cs);
1415 hr = autoplug(graph, source, NULL, FALSE, 0);
1416 LeaveCriticalSection(&graph->cs);
1417 if (hr == VFW_E_CANNOT_CONNECT)
1418 hr = VFW_E_CANNOT_RENDER;
1420 TRACE("Returning %#x.\n", hr);
1421 return hr;
1424 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, LPCWSTR lpcwstrFile,
1425 LPCWSTR lpcwstrPlayList)
1427 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1428 IBaseFilter* preader = NULL;
1429 IPin* ppinreader = NULL;
1430 IEnumPins* penumpins = NULL;
1431 struct filter *filter;
1432 HRESULT hr;
1433 BOOL partial = FALSE;
1434 BOOL any = FALSE;
1436 TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1438 if (lpcwstrPlayList != NULL)
1439 return E_INVALIDARG;
1441 hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, L"Reader", &preader);
1442 if (FAILED(hr))
1443 return hr;
1445 hr = IBaseFilter_EnumPins(preader, &penumpins);
1446 if (SUCCEEDED(hr))
1448 while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1450 PIN_DIRECTION dir;
1452 IPin_QueryDirection(ppinreader, &dir);
1453 if (dir == PINDIR_OUTPUT)
1455 hr = IFilterGraph2_Render(iface, ppinreader);
1457 TRACE("Filters in chain:\n");
1458 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
1459 TRACE("- %s.\n", debugstr_w(filter->name));
1461 if (SUCCEEDED(hr))
1462 any = TRUE;
1463 if (hr != S_OK)
1464 partial = TRUE;
1466 IPin_Release(ppinreader);
1468 IEnumPins_Release(penumpins);
1470 if (!any)
1471 hr = VFW_E_CANNOT_RENDER;
1472 else if (partial)
1473 hr = VFW_S_PARTIAL_RENDER;
1474 else
1475 hr = S_OK;
1477 IBaseFilter_Release(preader);
1479 TRACE("--> %08x\n", hr);
1480 return hr;
1483 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface,
1484 const WCHAR *filename, const WCHAR *filter_name, IBaseFilter **ret_filter)
1486 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1487 IFileSourceFilter *filesource;
1488 IBaseFilter *filter;
1489 HRESULT hr;
1490 GUID clsid;
1492 TRACE("graph %p, filename %s, filter_name %s, ret_filter %p.\n",
1493 graph, debugstr_w(filename), debugstr_w(filter_name), ret_filter);
1495 if (!get_media_type(filename, NULL, NULL, &clsid))
1496 clsid = CLSID_AsyncReader;
1497 TRACE("Using source filter %s.\n", debugstr_guid(&clsid));
1499 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
1500 &IID_IBaseFilter, (void **)&filter)))
1502 WARN("Failed to create filter, hr %#x.\n", hr);
1503 return hr;
1506 if (FAILED(hr = IBaseFilter_QueryInterface(filter, &IID_IFileSourceFilter, (void **)&filesource)))
1508 WARN("Failed to get IFileSourceFilter, hr %#x.\n", hr);
1509 IBaseFilter_Release(filter);
1510 return hr;
1513 hr = IFileSourceFilter_Load(filesource, filename, NULL);
1514 IFileSourceFilter_Release(filesource);
1515 if (FAILED(hr))
1517 WARN("Failed to load file, hr %#x.\n", hr);
1518 return hr;
1521 if (FAILED(hr = IFilterGraph2_AddFilter(iface, filter, filter_name)))
1523 IBaseFilter_Release(filter);
1524 return hr;
1527 if (ret_filter)
1528 *ret_filter = filter;
1529 return S_OK;
1532 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface, DWORD_PTR hFile)
1534 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1536 TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1538 return S_OK;
1541 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface)
1543 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1545 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1547 return S_OK;
1550 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface)
1552 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1554 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1556 return S_OK;
1559 /*** IFilterGraph2 methods ***/
1560 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1561 IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1563 struct filter_graph *This = impl_from_IFilterGraph2(iface);
1564 HRESULT hr;
1565 IBaseFilter* pfilter;
1567 TRACE("(%p/%p)->(%p %p %s %p)\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1569 hr = IMoniker_BindToObject(pMoniker, pCtx, NULL, &IID_IBaseFilter, (void**)&pfilter);
1570 if(FAILED(hr)) {
1571 WARN("Unable to bind moniker to filter object (%x)\n", hr);
1572 return hr;
1575 hr = IFilterGraph2_AddFilter(iface, pfilter, lpcwstrFilterName);
1576 if (FAILED(hr)) {
1577 WARN("Unable to add filter (%x)\n", hr);
1578 IBaseFilter_Release(pfilter);
1579 return hr;
1582 if(ppFilter)
1583 *ppFilter = pfilter;
1584 else IBaseFilter_Release(pfilter);
1586 return S_OK;
1589 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *pin, const AM_MEDIA_TYPE *mt)
1591 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1592 PIN_DIRECTION dir;
1593 HRESULT hr;
1594 IPin *peer;
1596 TRACE("graph %p, pin %p, mt %p.\n", graph, pin, mt);
1598 if (FAILED(hr = IPin_ConnectedTo(pin, &peer)))
1599 return hr;
1601 IPin_QueryDirection(pin, &dir);
1602 IFilterGraph2_Disconnect(iface, peer);
1603 IFilterGraph2_Disconnect(iface, pin);
1605 if (dir == PINDIR_INPUT)
1606 hr = IFilterGraph2_ConnectDirect(iface, peer, pin, mt);
1607 else
1608 hr = IFilterGraph2_ConnectDirect(iface, pin, peer, mt);
1610 IPin_Release(peer);
1611 return hr;
1614 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *source, DWORD flags, DWORD *context)
1616 struct filter_graph *graph = impl_from_IFilterGraph2(iface);
1617 HRESULT hr;
1619 TRACE("graph %p, source %p, flags %#x, context %p.\n", graph, source, flags, context);
1621 if (flags & ~AM_RENDEREX_RENDERTOEXISTINGRENDERERS)
1622 FIXME("Unknown flags %#x.\n", flags);
1624 EnterCriticalSection(&graph->cs);
1625 hr = autoplug(graph, source, NULL, !!(flags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS), 0);
1626 LeaveCriticalSection(&graph->cs);
1627 if (hr == VFW_E_CANNOT_CONNECT)
1628 hr = VFW_E_CANNOT_RENDER;
1630 TRACE("Returning %#x.\n", hr);
1631 return hr;
1635 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1637 FilterGraph2_QueryInterface,
1638 FilterGraph2_AddRef,
1639 FilterGraph2_Release,
1640 FilterGraph2_AddFilter,
1641 FilterGraph2_RemoveFilter,
1642 FilterGraph2_EnumFilters,
1643 FilterGraph2_FindFilterByName,
1644 FilterGraph2_ConnectDirect,
1645 FilterGraph2_Reconnect,
1646 FilterGraph2_Disconnect,
1647 FilterGraph2_SetDefaultSyncSource,
1648 FilterGraph2_Connect,
1649 FilterGraph2_Render,
1650 FilterGraph2_RenderFile,
1651 FilterGraph2_AddSourceFilter,
1652 FilterGraph2_SetLogFile,
1653 FilterGraph2_Abort,
1654 FilterGraph2_ShouldOperationContinue,
1655 FilterGraph2_AddSourceFilterForMoniker,
1656 FilterGraph2_ReconnectEx,
1657 FilterGraph2_RenderEx
1660 static struct filter_graph *impl_from_IMediaControl(IMediaControl *iface)
1662 return CONTAINING_RECORD(iface, struct filter_graph, IMediaControl_iface);
1665 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID iid, void **out)
1667 struct filter_graph *graph = impl_from_IMediaControl(iface);
1668 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
1671 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1673 struct filter_graph *graph = impl_from_IMediaControl(iface);
1674 return IUnknown_AddRef(graph->outer_unk);
1677 static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1679 struct filter_graph *graph = impl_from_IMediaControl(iface);
1680 return IUnknown_Release(graph->outer_unk);
1684 /*** IDispatch methods ***/
1685 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *pctinfo)
1687 struct filter_graph *This = impl_from_IMediaControl(iface);
1689 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1691 return S_OK;
1694 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT iTInfo, LCID lcid,
1695 ITypeInfo **ppTInfo)
1697 struct filter_graph *This = impl_from_IMediaControl(iface);
1699 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1701 return S_OK;
1704 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID riid,
1705 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1707 struct filter_graph *This = impl_from_IMediaControl(iface);
1709 TRACE("(%p/%p)->(%s, %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), rgszNames,
1710 cNames, lcid, rgDispId);
1712 return S_OK;
1715 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMember, REFIID riid,
1716 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
1717 UINT *puArgErr)
1719 struct filter_graph *This = impl_from_IMediaControl(iface);
1721 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember,
1722 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1724 return S_OK;
1727 static void update_render_count(struct filter_graph *graph)
1729 /* Some filters (e.g. MediaStreamFilter) can become renderers when they are
1730 * already in the graph. */
1731 struct filter *filter;
1732 graph->nRenderers = 0;
1733 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1735 if (is_renderer(filter))
1736 ++graph->nRenderers;
1740 /* Perform the paused -> running transition. The caller must hold graph->cs. */
1741 static HRESULT graph_start(struct filter_graph *graph, REFERENCE_TIME stream_start)
1743 REFERENCE_TIME stream_stop;
1744 struct filter *filter;
1745 HRESULT hr = S_OK;
1747 graph->EcCompleteCount = 0;
1748 update_render_count(graph);
1750 if (graph->defaultclock && !graph->refClock)
1751 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
1753 if (!stream_start && graph->refClock)
1755 IReferenceClock_GetTime(graph->refClock, &graph->stream_start);
1756 stream_start = graph->stream_start - graph->stream_elapsed;
1757 /* Delay presentation time by 200 ms, to give filters time to
1758 * initialize. */
1759 stream_start += 200 * 10000;
1762 if (SUCCEEDED(IMediaSeeking_GetStopPosition(&graph->IMediaSeeking_iface, &stream_stop)))
1763 graph->stream_stop = stream_stop;
1765 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1767 HRESULT filter_hr = IBaseFilter_Run(filter->filter, stream_start);
1768 if (hr == S_OK)
1769 hr = filter_hr;
1770 TRACE("Filter %p returned %#x.\n", filter->filter, filter_hr);
1773 if (FAILED(hr))
1774 WARN("Failed to start stream, hr %#x.\n", hr);
1776 return hr;
1779 static void CALLBACK async_run_cb(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work)
1781 struct filter_graph *graph = context;
1782 struct filter *filter;
1783 FILTER_STATE state;
1784 HRESULT hr;
1786 TRACE("Performing asynchronous state change.\n");
1788 /* We can't just call GetState(), since that will return State_Running and
1789 * VFW_S_STATE_INTERMEDIATE regardless of whether we're done pausing yet.
1790 * Instead replicate it here. */
1792 for (;;)
1794 IBaseFilter *async_filter = NULL;
1796 hr = S_OK;
1798 EnterCriticalSection(&graph->cs);
1800 if (!graph->needs_async_run)
1801 break;
1803 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1805 hr = IBaseFilter_GetState(filter->filter, 0, &state);
1807 if (hr == VFW_S_STATE_INTERMEDIATE)
1808 async_filter = filter->filter;
1810 if (SUCCEEDED(hr) && state != State_Paused)
1811 ERR("Filter %p reported incorrect state %u.\n", filter->filter, state);
1813 if (hr != S_OK)
1814 break;
1817 if (hr != VFW_S_STATE_INTERMEDIATE)
1818 break;
1820 LeaveCriticalSection(&graph->cs);
1822 IBaseFilter_GetState(async_filter, 10, &state);
1825 if (hr == S_OK && graph->needs_async_run)
1827 sort_filters(graph);
1828 graph_start(graph, 0);
1829 graph->needs_async_run = 0;
1832 LeaveCriticalSection(&graph->cs);
1833 IUnknown_Release(graph->outer_unk);
1836 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
1838 struct filter_graph *graph = impl_from_IMediaControl(iface);
1839 BOOL need_async_run = TRUE;
1840 struct filter *filter;
1841 FILTER_STATE state;
1842 HRESULT hr = S_OK;
1844 TRACE("graph %p.\n", graph);
1846 EnterCriticalSection(&graph->cs);
1848 if (graph->state == State_Running)
1850 LeaveCriticalSection(&graph->cs);
1851 return S_OK;
1854 sort_filters(graph);
1855 update_render_count(graph);
1857 if (graph->state == State_Stopped)
1859 if (graph->defaultclock && !graph->refClock)
1860 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
1862 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
1864 HRESULT filter_hr = IBaseFilter_Pause(filter->filter);
1865 if (hr == S_OK)
1866 hr = filter_hr;
1867 TRACE("Filter %p returned %#x.\n", filter->filter, filter_hr);
1869 /* If a filter returns VFW_S_CANT_CUE, we shouldn't wait for a
1870 * paused state. */
1871 filter_hr = IBaseFilter_GetState(filter->filter, 0, &state);
1872 if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE)
1873 need_async_run = FALSE;
1876 if (FAILED(hr))
1878 LeaveCriticalSection(&graph->cs);
1879 WARN("Failed to pause, hr %#x.\n", hr);
1880 return hr;
1884 graph->state = State_Running;
1886 if (SUCCEEDED(hr))
1888 if (hr != S_OK && need_async_run)
1890 if (!graph->async_run_work)
1891 graph->async_run_work = CreateThreadpoolWork(async_run_cb, graph, NULL);
1892 graph->needs_async_run = 1;
1893 IUnknown_AddRef(graph->outer_unk);
1894 SubmitThreadpoolWork(graph->async_run_work);
1896 else
1898 graph_start(graph, 0);
1902 LeaveCriticalSection(&graph->cs);
1903 return hr;
1906 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
1908 struct filter_graph *graph = impl_from_IMediaControl(iface);
1910 TRACE("graph %p.\n", graph);
1912 return IMediaFilter_Pause(&graph->IMediaFilter_iface);
1915 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
1917 struct filter_graph *graph = impl_from_IMediaControl(iface);
1919 TRACE("graph %p.\n", graph);
1921 return IMediaFilter_Stop(&graph->IMediaFilter_iface);
1924 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG timeout, OAFilterState *state)
1926 struct filter_graph *graph = impl_from_IMediaControl(iface);
1928 TRACE("graph %p, timeout %u, state %p.\n", graph, timeout, state);
1930 if (timeout < 0) timeout = INFINITE;
1932 return IMediaFilter_GetState(&graph->IMediaFilter_iface, timeout, (FILTER_STATE *)state);
1935 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
1937 struct filter_graph *This = impl_from_IMediaControl(iface);
1939 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strFilename), strFilename);
1941 return IFilterGraph2_RenderFile(&This->IFilterGraph2_iface, strFilename, NULL);
1944 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
1945 IDispatch **ppUnk)
1947 struct filter_graph *This = impl_from_IMediaControl(iface);
1949 FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
1951 return S_OK;
1954 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
1956 struct filter_graph *This = impl_from_IMediaControl(iface);
1958 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1960 return S_OK;
1963 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
1965 struct filter_graph *This = impl_from_IMediaControl(iface);
1967 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1969 return S_OK;
1972 static void CALLBACK wait_pause_cb(TP_CALLBACK_INSTANCE *instance, void *context)
1974 IMediaControl *control = context;
1975 OAFilterState state;
1976 HRESULT hr;
1978 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
1979 ERR("Failed to get paused state, hr %#x.\n", hr);
1981 if (FAILED(hr = IMediaControl_Stop(control)))
1982 ERR("Failed to stop, hr %#x.\n", hr);
1984 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
1985 ERR("Failed to get paused state, hr %#x.\n", hr);
1987 IMediaControl_Release(control);
1990 static void CALLBACK wait_stop_cb(TP_CALLBACK_INSTANCE *instance, void *context)
1992 IMediaControl *control = context;
1993 OAFilterState state;
1994 HRESULT hr;
1996 if ((hr = IMediaControl_GetState(control, INFINITE, &state)) != S_OK)
1997 ERR("Failed to get state, hr %#x.\n", hr);
1999 IMediaControl_Release(control);
2002 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2004 struct filter_graph *graph = impl_from_IMediaControl(iface);
2005 HRESULT hr;
2007 TRACE("graph %p.\n", graph);
2009 /* Even if we are already stopped, we still pause. */
2010 hr = IMediaControl_Pause(iface);
2011 if (FAILED(hr))
2012 return hr;
2013 else if (hr == S_FALSE)
2015 IMediaControl_AddRef(iface);
2016 TrySubmitThreadpoolCallback(wait_pause_cb, iface, NULL);
2017 return S_FALSE;
2020 hr = IMediaControl_Stop(iface);
2021 if (FAILED(hr))
2022 return hr;
2023 else if (hr == S_FALSE)
2025 IMediaControl_AddRef(iface);
2026 TrySubmitThreadpoolCallback(wait_stop_cb, iface, NULL);
2027 return S_FALSE;
2030 return S_OK;
2034 static const IMediaControlVtbl IMediaControl_VTable =
2036 MediaControl_QueryInterface,
2037 MediaControl_AddRef,
2038 MediaControl_Release,
2039 MediaControl_GetTypeInfoCount,
2040 MediaControl_GetTypeInfo,
2041 MediaControl_GetIDsOfNames,
2042 MediaControl_Invoke,
2043 MediaControl_Run,
2044 MediaControl_Pause,
2045 MediaControl_Stop,
2046 MediaControl_GetState,
2047 MediaControl_RenderFile,
2048 MediaControl_AddSourceFilter,
2049 MediaControl_get_FilterCollection,
2050 MediaControl_get_RegFilterCollection,
2051 MediaControl_StopWhenReady
2054 static struct filter_graph *impl_from_IMediaSeeking(IMediaSeeking *iface)
2056 return CONTAINING_RECORD(iface, struct filter_graph, IMediaSeeking_iface);
2059 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface, REFIID iid, void **out)
2061 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2062 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2065 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
2067 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2068 return IUnknown_AddRef(graph->outer_unk);
2071 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
2073 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2074 return IUnknown_Release(graph->outer_unk);
2077 typedef HRESULT (WINAPI *fnFoundSeek)(struct filter_graph *This, IMediaSeeking*, DWORD_PTR arg);
2079 static HRESULT all_renderers_seek(struct filter_graph *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2080 BOOL allnotimpl = TRUE;
2081 HRESULT hr, hr_return = S_OK;
2082 struct filter *filter;
2084 TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2085 /* Send a message to all renderers, they are responsible for broadcasting it further */
2087 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
2089 update_seeking(filter);
2090 if (!filter->seeking)
2091 continue;
2092 hr = FoundSeek(This, filter->seeking, arg);
2093 if (hr_return != E_NOTIMPL)
2094 allnotimpl = FALSE;
2095 if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2096 hr_return = hr;
2099 if (allnotimpl)
2100 return E_NOTIMPL;
2101 return hr_return;
2104 static HRESULT WINAPI FoundCapabilities(struct filter_graph *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2106 HRESULT hr;
2107 DWORD caps = 0;
2109 hr = IMediaSeeking_GetCapabilities(seek, &caps);
2110 if (FAILED(hr))
2111 return hr;
2113 /* Only add common capabilities everything supports */
2114 *(DWORD*)pcaps &= caps;
2116 return hr;
2119 /*** IMediaSeeking methods ***/
2120 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2122 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2123 HRESULT hr;
2125 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2127 if (!pCapabilities)
2128 return E_POINTER;
2130 EnterCriticalSection(&This->cs);
2131 *pCapabilities = 0xffffffff;
2133 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2134 LeaveCriticalSection(&This->cs);
2136 return hr;
2139 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2141 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2142 DWORD originalcaps;
2143 HRESULT hr;
2145 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2147 if (!pCapabilities)
2148 return E_POINTER;
2150 EnterCriticalSection(&This->cs);
2151 originalcaps = *pCapabilities;
2152 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2153 LeaveCriticalSection(&This->cs);
2155 if (FAILED(hr))
2156 return hr;
2158 if (!*pCapabilities)
2159 return E_FAIL;
2160 if (*pCapabilities != originalcaps)
2161 return S_FALSE;
2162 return S_OK;
2165 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface, const GUID *pFormat)
2167 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2169 if (!pFormat)
2170 return E_POINTER;
2172 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2174 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2176 WARN("Unhandled time format %s\n", debugstr_guid(pFormat));
2177 return S_FALSE;
2180 return S_OK;
2183 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *pFormat)
2185 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2187 if (!pFormat)
2188 return E_POINTER;
2190 FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2191 memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2193 return S_OK;
2196 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface, GUID *pFormat)
2198 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2200 if (!pFormat)
2201 return E_POINTER;
2203 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2204 memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2206 return S_OK;
2209 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2211 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2213 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2214 if (!pFormat)
2215 return E_POINTER;
2217 if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2218 return S_FALSE;
2220 return S_OK;
2223 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2225 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2227 if (!pFormat)
2228 return E_POINTER;
2230 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2232 if (This->state != State_Stopped)
2233 return VFW_E_WRONG_STATE;
2235 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2237 FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2238 return E_INVALIDARG;
2241 return S_OK;
2244 static HRESULT WINAPI FoundDuration(struct filter_graph *This, IMediaSeeking *seek, DWORD_PTR pduration)
2246 HRESULT hr;
2247 LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2249 hr = IMediaSeeking_GetDuration(seek, &duration);
2250 if (FAILED(hr))
2251 return hr;
2253 if (*pdur < duration)
2254 *pdur = duration;
2255 return hr;
2258 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface, LONGLONG *pDuration)
2260 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2261 HRESULT hr;
2263 TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2265 if (!pDuration)
2266 return E_POINTER;
2268 EnterCriticalSection(&This->cs);
2269 *pDuration = 0;
2270 hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
2271 LeaveCriticalSection(&This->cs);
2273 TRACE("--->%08x\n", hr);
2274 return hr;
2277 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *stop)
2279 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2280 HRESULT hr = E_NOTIMPL, filter_hr;
2281 struct filter *filter;
2282 LONGLONG filter_stop;
2284 TRACE("graph %p, stop %p.\n", graph, stop);
2286 if (!stop)
2287 return E_POINTER;
2289 *stop = 0;
2291 EnterCriticalSection(&graph->cs);
2293 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2295 update_seeking(filter);
2296 if (!filter->seeking)
2297 continue;
2299 filter_hr = IMediaSeeking_GetStopPosition(filter->seeking, &filter_stop);
2300 if (SUCCEEDED(filter_hr))
2302 hr = S_OK;
2303 *stop = max(*stop, filter_stop);
2305 else if (filter_hr != E_NOTIMPL)
2307 LeaveCriticalSection(&graph->cs);
2308 return filter_hr;
2312 LeaveCriticalSection(&graph->cs);
2314 TRACE("Returning %s (%s seconds).\n", wine_dbgstr_longlong(*stop), debugstr_time(*stop));
2315 return hr;
2318 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *current)
2320 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2321 LONGLONG ret = graph->current_pos;
2323 TRACE("graph %p, current %p.\n", graph, current);
2325 if (!current)
2326 return E_POINTER;
2328 EnterCriticalSection(&graph->cs);
2330 if (graph->got_ec_complete)
2332 ret = graph->stream_stop;
2334 else if (graph->state == State_Running && !graph->needs_async_run && graph->refClock)
2336 REFERENCE_TIME time;
2337 IReferenceClock_GetTime(graph->refClock, &time);
2338 if (time)
2339 ret += time - graph->stream_start;
2342 LeaveCriticalSection(&graph->cs);
2344 TRACE("Returning %s (%s seconds).\n", wine_dbgstr_longlong(ret), debugstr_time(ret));
2345 *current = ret;
2347 return S_OK;
2350 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
2351 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2353 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2355 TRACE("(%p/%p)->(%p, %s, 0x%s, %s)\n", This, iface, pTarget,
2356 debugstr_guid(pTargetFormat), wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
2358 if (!pSourceFormat)
2359 pSourceFormat = &This->timeformatseek;
2361 if (!pTargetFormat)
2362 pTargetFormat = &This->timeformatseek;
2364 if (IsEqualGUID(pTargetFormat, pSourceFormat))
2365 *pTarget = Source;
2366 else
2367 FIXME("conversion %s->%s not supported\n", debugstr_guid(pSourceFormat), debugstr_guid(pTargetFormat));
2369 return S_OK;
2372 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *current_ptr,
2373 DWORD current_flags, LONGLONG *stop_ptr, DWORD stop_flags)
2375 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2376 HRESULT hr = E_NOTIMPL, filter_hr;
2377 struct filter *filter;
2378 FILTER_STATE state;
2380 TRACE("graph %p, current %s, current_flags %#x, stop %s, stop_flags %#x.\n", graph,
2381 current_ptr ? wine_dbgstr_longlong(*current_ptr) : "<null>", current_flags,
2382 stop_ptr ? wine_dbgstr_longlong(*stop_ptr): "<null>", stop_flags);
2383 if (current_ptr)
2384 TRACE("Setting current position to %s (%s seconds).\n",
2385 wine_dbgstr_longlong(*current_ptr), debugstr_time(*current_ptr));
2386 if (stop_ptr)
2387 TRACE("Setting stop position to %s (%s seconds).\n",
2388 wine_dbgstr_longlong(*stop_ptr), debugstr_time(*stop_ptr));
2390 if ((current_flags & 0x7) != AM_SEEKING_AbsolutePositioning
2391 && (current_flags & 0x7) != AM_SEEKING_NoPositioning)
2392 FIXME("Unhandled current_flags %#x.\n", current_flags & 0x7);
2394 if ((stop_flags & 0x7) != AM_SEEKING_NoPositioning
2395 && (stop_flags & 0x7) != AM_SEEKING_AbsolutePositioning)
2396 FIXME("Unhandled stop_flags %#x.\n", stop_flags & 0x7);
2398 EnterCriticalSection(&graph->cs);
2400 state = graph->state;
2401 if (state == State_Running && !graph->needs_async_run)
2402 IMediaControl_Pause(&graph->IMediaControl_iface);
2404 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
2406 LONGLONG current = current_ptr ? *current_ptr : 0, stop = stop_ptr ? *stop_ptr : 0;
2408 update_seeking(filter);
2409 if (!filter->seeking)
2410 continue;
2412 filter_hr = IMediaSeeking_SetPositions(filter->seeking, &current,
2413 current_flags | AM_SEEKING_ReturnTime, &stop, stop_flags);
2414 if (SUCCEEDED(filter_hr))
2416 hr = S_OK;
2418 if (current_ptr && (current_flags & AM_SEEKING_ReturnTime))
2419 *current_ptr = current;
2420 if (stop_ptr && (stop_flags & AM_SEEKING_ReturnTime))
2421 *stop_ptr = stop;
2422 graph->current_pos = current;
2424 else if (filter_hr != E_NOTIMPL)
2426 LeaveCriticalSection(&graph->cs);
2427 return filter_hr;
2431 if ((current_flags & 0x7) != AM_SEEKING_NoPositioning && graph->refClock)
2433 IReferenceClock_GetTime(graph->refClock, &graph->stream_start);
2434 graph->stream_elapsed = 0;
2437 if (state == State_Running && !graph->needs_async_run)
2438 IMediaControl_Run(&graph->IMediaControl_iface);
2440 LeaveCriticalSection(&graph->cs);
2441 return hr;
2444 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
2445 LONGLONG *current, LONGLONG *stop)
2447 struct filter_graph *graph = impl_from_IMediaSeeking(iface);
2448 HRESULT hr = S_OK;
2450 TRACE("graph %p, current %p, stop %p.\n", graph, current, stop);
2452 if (current)
2453 hr = IMediaSeeking_GetCurrentPosition(iface, current);
2454 if (SUCCEEDED(hr) && stop)
2455 hr = IMediaSeeking_GetStopPosition(iface, stop);
2457 return hr;
2460 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, LONGLONG *pEarliest,
2461 LONGLONG *pLatest)
2463 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2465 FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2467 return S_OK;
2470 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2472 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2474 FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2476 return S_OK;
2479 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2481 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2483 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2485 if (!pdRate)
2486 return E_POINTER;
2488 *pdRate = 1.0;
2490 return S_OK;
2493 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
2495 struct filter_graph *This = impl_from_IMediaSeeking(iface);
2497 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2499 return S_OK;
2503 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2505 MediaSeeking_QueryInterface,
2506 MediaSeeking_AddRef,
2507 MediaSeeking_Release,
2508 MediaSeeking_GetCapabilities,
2509 MediaSeeking_CheckCapabilities,
2510 MediaSeeking_IsFormatSupported,
2511 MediaSeeking_QueryPreferredFormat,
2512 MediaSeeking_GetTimeFormat,
2513 MediaSeeking_IsUsingTimeFormat,
2514 MediaSeeking_SetTimeFormat,
2515 MediaSeeking_GetDuration,
2516 MediaSeeking_GetStopPosition,
2517 MediaSeeking_GetCurrentPosition,
2518 MediaSeeking_ConvertTimeFormat,
2519 MediaSeeking_SetPositions,
2520 MediaSeeking_GetPositions,
2521 MediaSeeking_GetAvailable,
2522 MediaSeeking_SetRate,
2523 MediaSeeking_GetRate,
2524 MediaSeeking_GetPreroll
2527 static struct filter_graph *impl_from_IMediaPosition(IMediaPosition *iface)
2529 return CONTAINING_RECORD(iface, struct filter_graph, IMediaPosition_iface);
2532 /*** IUnknown methods ***/
2533 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition *iface, REFIID iid, void **out)
2535 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2536 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2539 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2541 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2542 return IUnknown_AddRef(graph->outer_unk);
2545 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2547 struct filter_graph *graph = impl_from_IMediaPosition(iface);
2548 return IUnknown_Release(graph->outer_unk);
2551 /*** IDispatch methods ***/
2552 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo)
2554 FIXME("(%p) stub!\n", iface);
2555 return E_NOTIMPL;
2558 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2560 FIXME("(%p) stub!\n", iface);
2561 return E_NOTIMPL;
2564 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
2566 FIXME("(%p) stub!\n", iface);
2567 return E_NOTIMPL;
2570 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
2572 FIXME("(%p) stub!\n", iface);
2573 return E_NOTIMPL;
2576 static HRESULT ConvertFromREFTIME(IMediaSeeking *seek, REFTIME time_in, LONGLONG *time_out)
2578 GUID time_format;
2579 HRESULT hr;
2581 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2582 if (FAILED(hr))
2583 return hr;
2584 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2586 FIXME("Unsupported time format.\n");
2587 return E_NOTIMPL;
2590 *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2591 return S_OK;
2594 static HRESULT ConvertToREFTIME(IMediaSeeking *seek, LONGLONG time_in, REFTIME *time_out)
2596 GUID time_format;
2597 HRESULT hr;
2599 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2600 if (FAILED(hr))
2601 return hr;
2602 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2604 FIXME("Unsupported time format.\n");
2605 return E_NOTIMPL;
2608 *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2609 return S_OK;
2612 /*** IMediaPosition methods ***/
2613 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2615 LONGLONG duration;
2616 struct filter_graph *This = impl_from_IMediaPosition( iface );
2617 HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2618 if (FAILED(hr))
2619 return hr;
2620 return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2623 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2625 struct filter_graph *This = impl_from_IMediaPosition( iface );
2626 LONGLONG reftime;
2627 HRESULT hr;
2629 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2630 if (FAILED(hr))
2631 return hr;
2632 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2633 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
2636 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2638 struct filter_graph *This = impl_from_IMediaPosition( iface );
2639 LONGLONG pos;
2640 HRESULT hr;
2642 hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2643 if (FAILED(hr))
2644 return hr;
2645 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2648 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2650 struct filter_graph *This = impl_from_IMediaPosition( iface );
2651 LONGLONG pos;
2652 HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2653 if (FAILED(hr))
2654 return hr;
2655 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2658 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2660 struct filter_graph *This = impl_from_IMediaPosition( iface );
2661 LONGLONG reftime;
2662 HRESULT hr;
2664 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2665 if (FAILED(hr))
2666 return hr;
2667 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2668 &reftime, AM_SEEKING_AbsolutePositioning);
2671 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime)
2673 FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2674 return E_NOTIMPL;
2677 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime)
2679 FIXME("(%p)->(%f) stub!\n", iface, llTime);
2680 return E_NOTIMPL;
2683 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2685 struct filter_graph *This = impl_from_IMediaPosition( iface );
2686 return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2689 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2691 struct filter_graph *This = impl_from_IMediaPosition( iface );
2692 return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2695 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward)
2697 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2698 return E_NOTIMPL;
2701 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward)
2703 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2704 return E_NOTIMPL;
2708 static const IMediaPositionVtbl IMediaPosition_VTable =
2710 MediaPosition_QueryInterface,
2711 MediaPosition_AddRef,
2712 MediaPosition_Release,
2713 MediaPosition_GetTypeInfoCount,
2714 MediaPosition_GetTypeInfo,
2715 MediaPosition_GetIDsOfNames,
2716 MediaPosition_Invoke,
2717 MediaPosition_get_Duration,
2718 MediaPosition_put_CurrentPosition,
2719 MediaPosition_get_CurrentPosition,
2720 MediaPosition_get_StopTime,
2721 MediaPosition_put_StopTime,
2722 MediaPosition_get_PrerollTime,
2723 MediaPosition_put_PrerollTime,
2724 MediaPosition_put_Rate,
2725 MediaPosition_get_Rate,
2726 MediaPosition_CanSeekForward,
2727 MediaPosition_CanSeekBackward
2730 static struct filter_graph *impl_from_IObjectWithSite(IObjectWithSite *iface)
2732 return CONTAINING_RECORD(iface, struct filter_graph, IObjectWithSite_iface);
2735 /*** IUnknown methods ***/
2736 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID iid, void **out)
2738 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2739 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2742 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
2744 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2745 return IUnknown_AddRef(graph->outer_unk);
2748 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
2750 struct filter_graph *graph = impl_from_IObjectWithSite(iface);
2751 return IUnknown_Release(graph->outer_unk);
2754 /*** IObjectWithSite methods ***/
2756 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
2758 struct filter_graph *This = impl_from_IObjectWithSite( iface );
2760 TRACE("(%p/%p)->()\n", This, iface);
2761 if (This->pSite) IUnknown_Release(This->pSite);
2762 This->pSite = pUnkSite;
2763 IUnknown_AddRef(This->pSite);
2764 return S_OK;
2767 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, PVOID *ppvSite)
2769 struct filter_graph *This = impl_from_IObjectWithSite( iface );
2771 TRACE("(%p/%p)->(%s)\n", This, iface,debugstr_guid(riid));
2773 *ppvSite = NULL;
2774 if (!This->pSite)
2775 return E_FAIL;
2776 else
2777 return IUnknown_QueryInterface(This->pSite, riid, ppvSite);
2780 static const IObjectWithSiteVtbl IObjectWithSite_VTable =
2782 ObjectWithSite_QueryInterface,
2783 ObjectWithSite_AddRef,
2784 ObjectWithSite_Release,
2785 ObjectWithSite_SetSite,
2786 ObjectWithSite_GetSite,
2789 static HRESULT GetTargetInterface(struct filter_graph* pGraph, REFIID riid, LPVOID* ppvObj)
2791 struct filter *filter;
2792 HRESULT hr;
2793 int entry;
2795 /* Check if the interface type is already registered */
2796 for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2797 if (riid == pGraph->ItfCacheEntries[entry].riid)
2799 if (pGraph->ItfCacheEntries[entry].iface)
2801 /* Return the interface if available */
2802 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2803 return S_OK;
2805 break;
2808 if (entry >= MAX_ITF_CACHE_ENTRIES)
2810 FIXME("Not enough space to store interface in the cache\n");
2811 return E_OUTOFMEMORY;
2814 /* Find a filter supporting the requested interface */
2815 LIST_FOR_EACH_ENTRY(filter, &pGraph->filters, struct filter, entry)
2817 hr = IBaseFilter_QueryInterface(filter->filter, riid, ppvObj);
2818 if (hr == S_OK)
2820 pGraph->ItfCacheEntries[entry].riid = riid;
2821 pGraph->ItfCacheEntries[entry].filter = filter->filter;
2822 pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2823 if (entry >= pGraph->nItfCacheEntries)
2824 pGraph->nItfCacheEntries++;
2825 return S_OK;
2827 if (hr != E_NOINTERFACE)
2828 return hr;
2831 return IsEqualGUID(riid, &IID_IBasicAudio) ? E_NOTIMPL : E_NOINTERFACE;
2834 static struct filter_graph *impl_from_IBasicAudio(IBasicAudio *iface)
2836 return CONTAINING_RECORD(iface, struct filter_graph, IBasicAudio_iface);
2839 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID iid, void **out)
2841 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2842 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
2845 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
2847 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2848 return IUnknown_AddRef(graph->outer_unk);
2851 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
2853 struct filter_graph *graph = impl_from_IBasicAudio(iface);
2854 return IUnknown_Release(graph->outer_unk);
2857 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *count)
2859 TRACE("iface %p, count %p.\n", iface, count);
2860 *count = 1;
2861 return S_OK;
2864 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface, UINT index,
2865 LCID lcid, ITypeInfo **typeinfo)
2867 TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
2868 return strmbase_get_typeinfo(IBasicAudio_tid, typeinfo);
2871 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface, REFIID iid,
2872 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
2874 ITypeInfo *typeinfo;
2875 HRESULT hr;
2877 TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
2878 iface, debugstr_guid(iid), names, count, lcid, ids);
2880 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo)))
2882 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
2883 ITypeInfo_Release(typeinfo);
2885 return hr;
2888 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface, DISPID id, REFIID iid, LCID lcid,
2889 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
2891 ITypeInfo *typeinfo;
2892 HRESULT hr;
2894 TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
2895 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
2897 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo)))
2899 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
2900 ITypeInfo_Release(typeinfo);
2902 return hr;
2905 /*** IBasicAudio methods ***/
2906 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface, LONG lVolume)
2908 struct filter_graph *This = impl_from_IBasicAudio(iface);
2909 IBasicAudio* pBasicAudio;
2910 HRESULT hr;
2912 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
2914 EnterCriticalSection(&This->cs);
2916 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2918 if (hr == S_OK)
2919 hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2921 LeaveCriticalSection(&This->cs);
2923 return hr;
2926 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface, LONG *plVolume)
2928 struct filter_graph *This = impl_from_IBasicAudio(iface);
2929 IBasicAudio* pBasicAudio;
2930 HRESULT hr;
2932 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
2934 EnterCriticalSection(&This->cs);
2936 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2938 if (hr == S_OK)
2939 hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
2941 LeaveCriticalSection(&This->cs);
2943 return hr;
2946 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface, LONG lBalance)
2948 struct filter_graph *This = impl_from_IBasicAudio(iface);
2949 IBasicAudio* pBasicAudio;
2950 HRESULT hr;
2952 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
2954 EnterCriticalSection(&This->cs);
2956 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2958 if (hr == S_OK)
2959 hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
2961 LeaveCriticalSection(&This->cs);
2963 return hr;
2966 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface, LONG *plBalance)
2968 struct filter_graph *This = impl_from_IBasicAudio(iface);
2969 IBasicAudio* pBasicAudio;
2970 HRESULT hr;
2972 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
2974 EnterCriticalSection(&This->cs);
2976 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2978 if (hr == S_OK)
2979 hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
2981 LeaveCriticalSection(&This->cs);
2983 return hr;
2986 static const IBasicAudioVtbl IBasicAudio_VTable =
2988 BasicAudio_QueryInterface,
2989 BasicAudio_AddRef,
2990 BasicAudio_Release,
2991 BasicAudio_GetTypeInfoCount,
2992 BasicAudio_GetTypeInfo,
2993 BasicAudio_GetIDsOfNames,
2994 BasicAudio_Invoke,
2995 BasicAudio_put_Volume,
2996 BasicAudio_get_Volume,
2997 BasicAudio_put_Balance,
2998 BasicAudio_get_Balance
3001 static struct filter_graph *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3003 return CONTAINING_RECORD(iface, struct filter_graph, IBasicVideo2_iface);
3006 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface, REFIID iid, void **out)
3008 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3009 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
3012 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface)
3014 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3015 return IUnknown_AddRef(graph->outer_unk);
3018 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface)
3020 struct filter_graph *graph = impl_from_IBasicVideo2(iface);
3021 return IUnknown_Release(graph->outer_unk);
3024 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface, UINT *count)
3026 TRACE("iface %p, count %p.\n", iface, count);
3027 *count = 1;
3028 return S_OK;
3031 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface, UINT index,
3032 LCID lcid, ITypeInfo **typeinfo)
3034 TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
3035 return strmbase_get_typeinfo(IBasicVideo_tid, typeinfo);
3038 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface, REFIID iid,
3039 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
3041 ITypeInfo *typeinfo;
3042 HRESULT hr;
3044 TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
3045 iface, debugstr_guid(iid), names, count, lcid, ids);
3047 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo)))
3049 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
3050 ITypeInfo_Release(typeinfo);
3052 return hr;
3055 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface, DISPID id, REFIID iid, LCID lcid,
3056 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
3058 ITypeInfo *typeinfo;
3059 HRESULT hr;
3061 TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
3062 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
3064 if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicVideo_tid, &typeinfo)))
3066 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
3067 ITypeInfo_Release(typeinfo);
3069 return hr;
3072 /*** IBasicVideo methods ***/
3073 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface, REFTIME *pAvgTimePerFrame)
3075 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3076 IBasicVideo *pBasicVideo;
3077 HRESULT hr;
3079 TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3081 EnterCriticalSection(&This->cs);
3083 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3085 if (hr == S_OK)
3086 hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3088 LeaveCriticalSection(&This->cs);
3090 return hr;
3093 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface, LONG *pBitRate)
3095 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3096 IBasicVideo *pBasicVideo;
3097 HRESULT hr;
3099 TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3101 EnterCriticalSection(&This->cs);
3103 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3105 if (hr == S_OK)
3106 hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3108 LeaveCriticalSection(&This->cs);
3110 return hr;
3113 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface, LONG *pBitErrorRate)
3115 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3116 IBasicVideo *pBasicVideo;
3117 HRESULT hr;
3119 TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3121 EnterCriticalSection(&This->cs);
3123 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3125 if (hr == S_OK)
3126 hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3128 LeaveCriticalSection(&This->cs);
3130 return hr;
3133 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface, LONG *pVideoWidth)
3135 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3136 IBasicVideo *pBasicVideo;
3137 HRESULT hr;
3139 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3141 EnterCriticalSection(&This->cs);
3143 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3145 if (hr == S_OK)
3146 hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3148 LeaveCriticalSection(&This->cs);
3150 return hr;
3153 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface, LONG *pVideoHeight)
3155 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3156 IBasicVideo *pBasicVideo;
3157 HRESULT hr;
3159 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3161 EnterCriticalSection(&This->cs);
3163 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3165 if (hr == S_OK)
3166 hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3168 LeaveCriticalSection(&This->cs);
3170 return hr;
3173 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface, LONG SourceLeft)
3175 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3176 IBasicVideo *pBasicVideo;
3177 HRESULT hr;
3179 TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
3181 EnterCriticalSection(&This->cs);
3183 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3185 if (hr == S_OK)
3186 hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3188 LeaveCriticalSection(&This->cs);
3190 return hr;
3193 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface, LONG *pSourceLeft)
3195 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3196 IBasicVideo *pBasicVideo;
3197 HRESULT hr;
3199 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3201 EnterCriticalSection(&This->cs);
3203 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3205 if (hr == S_OK)
3206 hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3208 LeaveCriticalSection(&This->cs);
3210 return hr;
3213 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface, LONG SourceWidth)
3215 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3216 IBasicVideo *pBasicVideo;
3217 HRESULT hr;
3219 TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
3221 EnterCriticalSection(&This->cs);
3223 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3225 if (hr == S_OK)
3226 hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3228 LeaveCriticalSection(&This->cs);
3230 return hr;
3233 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface, LONG *pSourceWidth)
3235 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3236 IBasicVideo *pBasicVideo;
3237 HRESULT hr;
3239 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3241 EnterCriticalSection(&This->cs);
3243 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3245 if (hr == S_OK)
3246 hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3248 LeaveCriticalSection(&This->cs);
3250 return hr;
3253 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface, LONG SourceTop)
3255 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3256 IBasicVideo *pBasicVideo;
3257 HRESULT hr;
3259 TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
3261 EnterCriticalSection(&This->cs);
3263 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3265 if (hr == S_OK)
3266 hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3268 LeaveCriticalSection(&This->cs);
3270 return hr;
3273 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface, LONG *pSourceTop)
3275 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3276 IBasicVideo *pBasicVideo;
3277 HRESULT hr;
3279 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3281 EnterCriticalSection(&This->cs);
3283 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3285 if (hr == S_OK)
3286 hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3288 LeaveCriticalSection(&This->cs);
3290 return hr;
3293 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface, LONG SourceHeight)
3295 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3296 IBasicVideo *pBasicVideo;
3297 HRESULT hr;
3299 TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
3301 EnterCriticalSection(&This->cs);
3303 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3305 if (hr == S_OK)
3306 hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3308 LeaveCriticalSection(&This->cs);
3310 return hr;
3313 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface, LONG *pSourceHeight)
3315 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3316 IBasicVideo *pBasicVideo;
3317 HRESULT hr;
3319 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3321 EnterCriticalSection(&This->cs);
3323 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3325 if (hr == S_OK)
3326 hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3328 LeaveCriticalSection(&This->cs);
3330 return hr;
3333 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface, LONG DestinationLeft)
3335 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3336 IBasicVideo *pBasicVideo;
3337 HRESULT hr;
3339 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
3341 EnterCriticalSection(&This->cs);
3343 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3345 if (hr == S_OK)
3346 hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3348 LeaveCriticalSection(&This->cs);
3350 return hr;
3353 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface, LONG *pDestinationLeft)
3355 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3356 IBasicVideo *pBasicVideo;
3357 HRESULT hr;
3359 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3361 EnterCriticalSection(&This->cs);
3363 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3365 if (hr == S_OK)
3366 hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3368 LeaveCriticalSection(&This->cs);
3370 return hr;
3373 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface, LONG DestinationWidth)
3375 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3376 IBasicVideo *pBasicVideo;
3377 HRESULT hr;
3379 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
3381 EnterCriticalSection(&This->cs);
3383 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3385 if (hr == S_OK)
3386 hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3388 LeaveCriticalSection(&This->cs);
3390 return hr;
3393 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface, LONG *pDestinationWidth)
3395 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3396 IBasicVideo *pBasicVideo;
3397 HRESULT hr;
3399 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3401 EnterCriticalSection(&This->cs);
3403 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3405 if (hr == S_OK)
3406 hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3408 LeaveCriticalSection(&This->cs);
3410 return hr;
3413 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface, LONG DestinationTop)
3415 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3416 IBasicVideo *pBasicVideo;
3417 HRESULT hr;
3419 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
3421 EnterCriticalSection(&This->cs);
3423 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3425 if (hr == S_OK)
3426 hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3428 LeaveCriticalSection(&This->cs);
3430 return hr;
3433 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface, LONG *pDestinationTop)
3435 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3436 IBasicVideo *pBasicVideo;
3437 HRESULT hr;
3439 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3441 EnterCriticalSection(&This->cs);
3443 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3445 if (hr == S_OK)
3446 hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3448 LeaveCriticalSection(&This->cs);
3450 return hr;
3453 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface, LONG DestinationHeight)
3455 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3456 IBasicVideo *pBasicVideo;
3457 HRESULT hr;
3459 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
3461 EnterCriticalSection(&This->cs);
3463 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3465 if (hr == S_OK)
3466 hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3468 LeaveCriticalSection(&This->cs);
3470 return hr;
3473 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3474 LONG *pDestinationHeight)
3476 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3477 IBasicVideo *pBasicVideo;
3478 HRESULT hr;
3480 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3482 EnterCriticalSection(&This->cs);
3484 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3486 if (hr == S_OK)
3487 hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3489 LeaveCriticalSection(&This->cs);
3491 return hr;
3494 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3495 LONG Width, LONG Height)
3497 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3498 IBasicVideo *pBasicVideo;
3499 HRESULT hr;
3501 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3503 EnterCriticalSection(&This->cs);
3505 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3507 if (hr == S_OK)
3508 hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3510 LeaveCriticalSection(&This->cs);
3512 return hr;
3515 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface, LONG *pLeft, LONG *pTop,
3516 LONG *pWidth, LONG *pHeight)
3518 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3519 IBasicVideo *pBasicVideo;
3520 HRESULT hr;
3522 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3524 EnterCriticalSection(&This->cs);
3526 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3528 if (hr == S_OK)
3529 hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3531 LeaveCriticalSection(&This->cs);
3533 return hr;
3536 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface)
3538 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3539 IBasicVideo *pBasicVideo;
3540 HRESULT hr;
3542 TRACE("(%p/%p)->()\n", This, iface);
3544 EnterCriticalSection(&This->cs);
3546 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3548 if (hr == S_OK)
3549 hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3551 LeaveCriticalSection(&This->cs);
3553 return hr;
3556 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3557 LONG Width, LONG Height)
3559 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3560 IBasicVideo *pBasicVideo;
3561 HRESULT hr;
3563 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3565 EnterCriticalSection(&This->cs);
3567 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3569 if (hr == S_OK)
3570 hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3572 LeaveCriticalSection(&This->cs);
3574 return hr;
3577 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface, LONG *pLeft,
3578 LONG *pTop, LONG *pWidth, LONG *pHeight)
3580 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3581 IBasicVideo *pBasicVideo;
3582 HRESULT hr;
3584 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3586 EnterCriticalSection(&This->cs);
3588 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3590 if (hr == S_OK)
3591 hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3593 LeaveCriticalSection(&This->cs);
3595 return hr;
3598 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface)
3600 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3601 IBasicVideo *pBasicVideo;
3602 HRESULT hr;
3604 TRACE("(%p/%p)->()\n", This, iface);
3606 EnterCriticalSection(&This->cs);
3608 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3610 if (hr == S_OK)
3611 hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3613 LeaveCriticalSection(&This->cs);
3615 return hr;
3618 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface, LONG *pWidth, LONG *pHeight)
3620 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3621 IBasicVideo *pBasicVideo;
3622 HRESULT hr;
3624 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3626 EnterCriticalSection(&This->cs);
3628 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3630 if (hr == S_OK)
3631 hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3633 LeaveCriticalSection(&This->cs);
3635 return hr;
3638 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface, LONG StartIndex,
3639 LONG Entries, LONG *pRetrieved, LONG *pPalette)
3641 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3642 IBasicVideo *pBasicVideo;
3643 HRESULT hr;
3645 TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3647 EnterCriticalSection(&This->cs);
3649 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3651 if (hr == S_OK)
3652 hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3654 LeaveCriticalSection(&This->cs);
3656 return hr;
3659 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface, LONG *pBufferSize,
3660 LONG *pDIBImage)
3662 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3663 IBasicVideo *pBasicVideo;
3664 HRESULT hr;
3666 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3668 EnterCriticalSection(&This->cs);
3670 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3672 if (hr == S_OK)
3673 hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3675 LeaveCriticalSection(&This->cs);
3677 return hr;
3680 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface)
3682 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3683 IBasicVideo *pBasicVideo;
3684 HRESULT hr;
3686 TRACE("(%p/%p)->()\n", This, iface);
3688 EnterCriticalSection(&This->cs);
3690 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3692 if (hr == S_OK)
3693 hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3695 LeaveCriticalSection(&This->cs);
3697 return hr;
3700 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface)
3702 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3703 IBasicVideo *pBasicVideo;
3704 HRESULT hr;
3706 TRACE("(%p/%p)->()\n", This, iface);
3708 EnterCriticalSection(&This->cs);
3710 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3712 if (hr == S_OK)
3713 hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3715 LeaveCriticalSection(&This->cs);
3717 return hr;
3720 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX,
3721 LONG *plAspectY)
3723 struct filter_graph *This = impl_from_IBasicVideo2(iface);
3724 IBasicVideo2 *pBasicVideo2;
3725 HRESULT hr;
3727 TRACE("(%p/%p)->()\n", This, iface);
3729 EnterCriticalSection(&This->cs);
3731 hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3733 if (hr == S_OK)
3734 hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3736 LeaveCriticalSection(&This->cs);
3738 return hr;
3741 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3743 BasicVideo_QueryInterface,
3744 BasicVideo_AddRef,
3745 BasicVideo_Release,
3746 BasicVideo_GetTypeInfoCount,
3747 BasicVideo_GetTypeInfo,
3748 BasicVideo_GetIDsOfNames,
3749 BasicVideo_Invoke,
3750 BasicVideo_get_AvgTimePerFrame,
3751 BasicVideo_get_BitRate,
3752 BasicVideo_get_BitErrorRate,
3753 BasicVideo_get_VideoWidth,
3754 BasicVideo_get_VideoHeight,
3755 BasicVideo_put_SourceLeft,
3756 BasicVideo_get_SourceLeft,
3757 BasicVideo_put_SourceWidth,
3758 BasicVideo_get_SourceWidth,
3759 BasicVideo_put_SourceTop,
3760 BasicVideo_get_SourceTop,
3761 BasicVideo_put_SourceHeight,
3762 BasicVideo_get_SourceHeight,
3763 BasicVideo_put_DestinationLeft,
3764 BasicVideo_get_DestinationLeft,
3765 BasicVideo_put_DestinationWidth,
3766 BasicVideo_get_DestinationWidth,
3767 BasicVideo_put_DestinationTop,
3768 BasicVideo_get_DestinationTop,
3769 BasicVideo_put_DestinationHeight,
3770 BasicVideo_get_DestinationHeight,
3771 BasicVideo_SetSourcePosition,
3772 BasicVideo_GetSourcePosition,
3773 BasicVideo_SetDefaultSourcePosition,
3774 BasicVideo_SetDestinationPosition,
3775 BasicVideo_GetDestinationPosition,
3776 BasicVideo_SetDefaultDestinationPosition,
3777 BasicVideo_GetVideoSize,
3778 BasicVideo_GetVideoPaletteEntries,
3779 BasicVideo_GetCurrentImage,
3780 BasicVideo_IsUsingDefaultSource,
3781 BasicVideo_IsUsingDefaultDestination,
3782 BasicVideo2_GetPreferredAspectRatio
3785 static struct filter_graph *impl_from_IVideoWindow(IVideoWindow *iface)
3787 return CONTAINING_RECORD(iface, struct filter_graph, IVideoWindow_iface);
3790 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID iid, void **out)
3792 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3793 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
3796 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
3798 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3799 return IUnknown_AddRef(graph->outer_unk);
3802 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
3804 struct filter_graph *graph = impl_from_IVideoWindow(iface);
3805 return IUnknown_Release(graph->outer_unk);
3808 HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface, UINT *count)
3810 TRACE("iface %p, count %p.\n", iface, count);
3811 *count = 1;
3812 return S_OK;
3815 HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface, UINT index,
3816 LCID lcid, ITypeInfo **typeinfo)
3818 TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
3819 return strmbase_get_typeinfo(IVideoWindow_tid, typeinfo);
3822 HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface, REFIID iid,
3823 LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
3825 ITypeInfo *typeinfo;
3826 HRESULT hr;
3828 TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
3829 iface, debugstr_guid(iid), names, count, lcid, ids);
3831 if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo)))
3833 hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
3834 ITypeInfo_Release(typeinfo);
3836 return hr;
3839 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface, DISPID id, REFIID iid, LCID lcid,
3840 WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
3842 ITypeInfo *typeinfo;
3843 HRESULT hr;
3845 TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
3846 iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);
3848 if (SUCCEEDED(hr = strmbase_get_typeinfo(IVideoWindow_tid, &typeinfo)))
3850 hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
3851 ITypeInfo_Release(typeinfo);
3853 return hr;
3856 /*** IVideoWindow methods ***/
3857 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface, BSTR strCaption)
3859 struct filter_graph *This = impl_from_IVideoWindow(iface);
3860 IVideoWindow *pVideoWindow;
3861 HRESULT hr;
3863 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3865 EnterCriticalSection(&This->cs);
3867 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3869 if (hr == S_OK)
3870 hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3872 LeaveCriticalSection(&This->cs);
3874 return hr;
3877 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface, BSTR *strCaption)
3879 struct filter_graph *This = impl_from_IVideoWindow(iface);
3880 IVideoWindow *pVideoWindow;
3881 HRESULT hr;
3883 TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
3885 EnterCriticalSection(&This->cs);
3887 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3889 if (hr == S_OK)
3890 hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
3892 LeaveCriticalSection(&This->cs);
3894 return hr;
3897 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle)
3899 struct filter_graph *This = impl_from_IVideoWindow(iface);
3900 IVideoWindow *pVideoWindow;
3901 HRESULT hr;
3903 TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
3905 EnterCriticalSection(&This->cs);
3907 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3909 if (hr == S_OK)
3910 hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
3912 LeaveCriticalSection(&This->cs);
3914 return hr;
3917 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface, LONG *WindowStyle)
3919 struct filter_graph *This = impl_from_IVideoWindow(iface);
3920 IVideoWindow *pVideoWindow;
3921 HRESULT hr;
3923 TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
3925 EnterCriticalSection(&This->cs);
3927 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3929 if (hr == S_OK)
3930 hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
3932 LeaveCriticalSection(&This->cs);
3934 return hr;
3937 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx)
3939 struct filter_graph *This = impl_from_IVideoWindow(iface);
3940 IVideoWindow *pVideoWindow;
3941 HRESULT hr;
3943 TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
3945 EnterCriticalSection(&This->cs);
3947 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3949 if (hr == S_OK)
3950 hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
3952 LeaveCriticalSection(&This->cs);
3954 return hr;
3957 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx)
3959 struct filter_graph *This = impl_from_IVideoWindow(iface);
3960 IVideoWindow *pVideoWindow;
3961 HRESULT hr;
3963 TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
3965 EnterCriticalSection(&This->cs);
3967 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3969 if (hr == S_OK)
3970 hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
3972 LeaveCriticalSection(&This->cs);
3974 return hr;
3977 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow)
3979 struct filter_graph *This = impl_from_IVideoWindow(iface);
3980 IVideoWindow *pVideoWindow;
3981 HRESULT hr;
3983 TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
3985 EnterCriticalSection(&This->cs);
3987 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3989 if (hr == S_OK)
3990 hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
3992 LeaveCriticalSection(&This->cs);
3994 return hr;
3997 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface, LONG *AutoShow)
3999 struct filter_graph *This = impl_from_IVideoWindow(iface);
4000 IVideoWindow *pVideoWindow;
4001 HRESULT hr;
4003 TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4005 EnterCriticalSection(&This->cs);
4007 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4009 if (hr == S_OK)
4010 hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4012 LeaveCriticalSection(&This->cs);
4014 return hr;
4017 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface, LONG WindowState)
4019 struct filter_graph *This = impl_from_IVideoWindow(iface);
4020 IVideoWindow *pVideoWindow;
4021 HRESULT hr;
4023 TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
4025 EnterCriticalSection(&This->cs);
4027 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4029 if (hr == S_OK)
4030 hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4032 LeaveCriticalSection(&This->cs);
4034 return hr;
4037 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface, LONG *WindowState)
4039 struct filter_graph *This = impl_from_IVideoWindow(iface);
4040 IVideoWindow *pVideoWindow;
4041 HRESULT hr;
4043 TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4045 EnterCriticalSection(&This->cs);
4047 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4049 if (hr == S_OK)
4050 hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4052 LeaveCriticalSection(&This->cs);
4054 return hr;
4057 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette)
4059 struct filter_graph *This = impl_from_IVideoWindow(iface);
4060 IVideoWindow *pVideoWindow;
4061 HRESULT hr;
4063 TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
4065 EnterCriticalSection(&This->cs);
4067 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4069 if (hr == S_OK)
4070 hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4072 LeaveCriticalSection(&This->cs);
4074 return hr;
4077 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4078 LONG *pBackgroundPalette)
4080 struct filter_graph *This = impl_from_IVideoWindow(iface);
4081 IVideoWindow *pVideoWindow;
4082 HRESULT hr;
4084 TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4086 EnterCriticalSection(&This->cs);
4088 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4090 if (hr == S_OK)
4091 hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4093 LeaveCriticalSection(&This->cs);
4095 return hr;
4098 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface, LONG Visible)
4100 struct filter_graph *This = impl_from_IVideoWindow(iface);
4101 IVideoWindow *pVideoWindow;
4102 HRESULT hr;
4104 TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
4106 EnterCriticalSection(&This->cs);
4108 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4110 if (hr == S_OK)
4111 hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4113 LeaveCriticalSection(&This->cs);
4115 return hr;
4118 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface, LONG *pVisible)
4120 struct filter_graph *This = impl_from_IVideoWindow(iface);
4121 IVideoWindow *pVideoWindow;
4122 HRESULT hr;
4124 TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4126 EnterCriticalSection(&This->cs);
4128 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4130 if (hr == S_OK)
4131 hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4133 LeaveCriticalSection(&This->cs);
4135 return hr;
4138 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface, LONG Left)
4140 struct filter_graph *This = impl_from_IVideoWindow(iface);
4141 IVideoWindow *pVideoWindow;
4142 HRESULT hr;
4144 TRACE("(%p/%p)->(%d)\n", This, iface, Left);
4146 EnterCriticalSection(&This->cs);
4148 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4150 if (hr == S_OK)
4151 hr = IVideoWindow_put_Left(pVideoWindow, Left);
4153 LeaveCriticalSection(&This->cs);
4155 return hr;
4158 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface, LONG *pLeft)
4160 struct filter_graph *This = impl_from_IVideoWindow(iface);
4161 IVideoWindow *pVideoWindow;
4162 HRESULT hr;
4164 TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4166 EnterCriticalSection(&This->cs);
4168 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4170 if (hr == S_OK)
4171 hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4173 LeaveCriticalSection(&This->cs);
4175 return hr;
4178 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface, LONG Width)
4180 struct filter_graph *This = impl_from_IVideoWindow(iface);
4181 IVideoWindow *pVideoWindow;
4182 HRESULT hr;
4184 TRACE("(%p/%p)->(%d)\n", This, iface, Width);
4186 EnterCriticalSection(&This->cs);
4188 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4190 if (hr == S_OK)
4191 hr = IVideoWindow_put_Width(pVideoWindow, Width);
4193 LeaveCriticalSection(&This->cs);
4195 return hr;
4198 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface, LONG *pWidth)
4200 struct filter_graph *This = impl_from_IVideoWindow(iface);
4201 IVideoWindow *pVideoWindow;
4202 HRESULT hr;
4204 TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4206 EnterCriticalSection(&This->cs);
4208 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4210 if (hr == S_OK)
4211 hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4213 LeaveCriticalSection(&This->cs);
4215 return hr;
4218 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface, LONG Top)
4220 struct filter_graph *This = impl_from_IVideoWindow(iface);
4221 IVideoWindow *pVideoWindow;
4222 HRESULT hr;
4224 TRACE("(%p/%p)->(%d)\n", This, iface, Top);
4226 EnterCriticalSection(&This->cs);
4228 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4230 if (hr == S_OK)
4231 hr = IVideoWindow_put_Top(pVideoWindow, Top);
4233 LeaveCriticalSection(&This->cs);
4235 return hr;
4238 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface, LONG *pTop)
4240 struct filter_graph *This = impl_from_IVideoWindow(iface);
4241 IVideoWindow *pVideoWindow;
4242 HRESULT hr;
4244 TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4246 EnterCriticalSection(&This->cs);
4248 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4250 if (hr == S_OK)
4251 hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4253 LeaveCriticalSection(&This->cs);
4255 return hr;
4258 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface, LONG Height)
4260 struct filter_graph *This = impl_from_IVideoWindow(iface);
4261 IVideoWindow *pVideoWindow;
4262 HRESULT hr;
4264 TRACE("(%p/%p)->(%d)\n", This, iface, Height);
4266 EnterCriticalSection(&This->cs);
4268 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4270 if (hr == S_OK)
4271 hr = IVideoWindow_put_Height(pVideoWindow, Height);
4273 LeaveCriticalSection(&This->cs);
4275 return hr;
4278 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface, LONG *pHeight)
4280 struct filter_graph *This = impl_from_IVideoWindow(iface);
4281 IVideoWindow *pVideoWindow;
4282 HRESULT hr;
4284 TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4286 EnterCriticalSection(&This->cs);
4288 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4290 if (hr == S_OK)
4291 hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4293 LeaveCriticalSection(&This->cs);
4295 return hr;
4298 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface, OAHWND Owner)
4300 struct filter_graph *This = impl_from_IVideoWindow(iface);
4301 IVideoWindow *pVideoWindow;
4302 HRESULT hr;
4304 TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
4306 EnterCriticalSection(&This->cs);
4308 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4310 if (hr == S_OK)
4311 hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4313 LeaveCriticalSection(&This->cs);
4315 return hr;
4318 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface, OAHWND *Owner)
4320 struct filter_graph *This = impl_from_IVideoWindow(iface);
4321 IVideoWindow *pVideoWindow;
4322 HRESULT hr;
4324 TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4326 EnterCriticalSection(&This->cs);
4328 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4330 if (hr == S_OK)
4331 hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4333 LeaveCriticalSection(&This->cs);
4335 return hr;
4338 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface, OAHWND Drain)
4340 struct filter_graph *This = impl_from_IVideoWindow(iface);
4341 IVideoWindow *pVideoWindow;
4342 HRESULT hr;
4344 TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
4346 EnterCriticalSection(&This->cs);
4348 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4350 if (hr == S_OK)
4351 hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4353 LeaveCriticalSection(&This->cs);
4355 return hr;
4358 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface, OAHWND *Drain)
4360 struct filter_graph *This = impl_from_IVideoWindow(iface);
4361 IVideoWindow *pVideoWindow;
4362 HRESULT hr;
4364 TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4366 EnterCriticalSection(&This->cs);
4368 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4370 if (hr == S_OK)
4371 hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4373 LeaveCriticalSection(&This->cs);
4375 return hr;
4378 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface, LONG *Color)
4380 struct filter_graph *This = impl_from_IVideoWindow(iface);
4381 IVideoWindow *pVideoWindow;
4382 HRESULT hr;
4384 TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4386 EnterCriticalSection(&This->cs);
4388 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4390 if (hr == S_OK)
4391 hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4393 LeaveCriticalSection(&This->cs);
4395 return hr;
4398 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface, LONG Color)
4400 struct filter_graph *This = impl_from_IVideoWindow(iface);
4401 IVideoWindow *pVideoWindow;
4402 HRESULT hr;
4404 TRACE("(%p/%p)->(%d)\n", This, iface, Color);
4406 EnterCriticalSection(&This->cs);
4408 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4410 if (hr == S_OK)
4411 hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4413 LeaveCriticalSection(&This->cs);
4415 return hr;
4418 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface, LONG *FullScreenMode)
4420 struct filter_graph *This = impl_from_IVideoWindow(iface);
4421 IVideoWindow *pVideoWindow;
4422 HRESULT hr;
4424 TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4426 EnterCriticalSection(&This->cs);
4428 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4430 if (hr == S_OK)
4431 hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4433 LeaveCriticalSection(&This->cs);
4435 return hr;
4438 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, LONG FullScreenMode)
4440 struct filter_graph *This = impl_from_IVideoWindow(iface);
4441 IVideoWindow *pVideoWindow;
4442 HRESULT hr;
4444 TRACE("(%p/%p)->(%d)\n", This, iface, FullScreenMode);
4446 EnterCriticalSection(&This->cs);
4448 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4450 if (hr == S_OK)
4451 hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4453 LeaveCriticalSection(&This->cs);
4455 return hr;
4458 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface, LONG Focus)
4460 struct filter_graph *This = impl_from_IVideoWindow(iface);
4461 IVideoWindow *pVideoWindow;
4462 HRESULT hr;
4464 TRACE("(%p/%p)->(%d)\n", This, iface, Focus);
4466 EnterCriticalSection(&This->cs);
4468 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4470 if (hr == S_OK)
4471 hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4473 LeaveCriticalSection(&This->cs);
4475 return hr;
4478 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface, OAHWND hwnd, LONG uMsg,
4479 LONG_PTR wParam, LONG_PTR lParam)
4481 struct filter_graph *This = impl_from_IVideoWindow(iface);
4482 IVideoWindow *pVideoWindow;
4483 HRESULT hr;
4485 TRACE("(%p/%p)->(%08lx, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam);
4487 EnterCriticalSection(&This->cs);
4489 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4491 if (hr == S_OK)
4492 hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4494 LeaveCriticalSection(&This->cs);
4496 return hr;
4499 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface, LONG Left, LONG Top,
4500 LONG Width, LONG Height)
4502 struct filter_graph *This = impl_from_IVideoWindow(iface);
4503 IVideoWindow *pVideoWindow;
4504 HRESULT hr;
4506 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
4508 EnterCriticalSection(&This->cs);
4510 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4512 if (hr == S_OK)
4513 hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4515 LeaveCriticalSection(&This->cs);
4517 return hr;
4520 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4521 LONG *pWidth, LONG *pHeight)
4523 struct filter_graph *This = impl_from_IVideoWindow(iface);
4524 IVideoWindow *pVideoWindow;
4525 HRESULT hr;
4527 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4529 EnterCriticalSection(&This->cs);
4531 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4533 if (hr == S_OK)
4534 hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4536 LeaveCriticalSection(&This->cs);
4538 return hr;
4541 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4542 LONG *pHeight)
4544 struct filter_graph *This = impl_from_IVideoWindow(iface);
4545 IVideoWindow *pVideoWindow;
4546 HRESULT hr;
4548 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4550 EnterCriticalSection(&This->cs);
4552 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4554 if (hr == S_OK)
4555 hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4557 LeaveCriticalSection(&This->cs);
4559 return hr;
4562 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4563 LONG *pHeight)
4565 struct filter_graph *This = impl_from_IVideoWindow(iface);
4566 IVideoWindow *pVideoWindow;
4567 HRESULT hr;
4569 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4571 EnterCriticalSection(&This->cs);
4573 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4575 if (hr == S_OK)
4576 hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4578 LeaveCriticalSection(&This->cs);
4580 return hr;
4583 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4584 LONG *pWidth, LONG *pHeight)
4586 struct filter_graph *This = impl_from_IVideoWindow(iface);
4587 IVideoWindow *pVideoWindow;
4588 HRESULT hr;
4590 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4592 EnterCriticalSection(&This->cs);
4594 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4596 if (hr == S_OK)
4597 hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4599 LeaveCriticalSection(&This->cs);
4601 return hr;
4604 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface, LONG HideCursor)
4606 struct filter_graph *This = impl_from_IVideoWindow(iface);
4607 IVideoWindow *pVideoWindow;
4608 HRESULT hr;
4610 TRACE("(%p/%p)->(%d)\n", This, iface, HideCursor);
4612 EnterCriticalSection(&This->cs);
4614 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4616 if (hr == S_OK)
4617 hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4619 LeaveCriticalSection(&This->cs);
4621 return hr;
4624 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden)
4626 struct filter_graph *This = impl_from_IVideoWindow(iface);
4627 IVideoWindow *pVideoWindow;
4628 HRESULT hr;
4630 TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4632 EnterCriticalSection(&This->cs);
4634 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4636 if (hr == S_OK)
4637 hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4639 LeaveCriticalSection(&This->cs);
4641 return hr;
4645 static const IVideoWindowVtbl IVideoWindow_VTable =
4647 VideoWindow_QueryInterface,
4648 VideoWindow_AddRef,
4649 VideoWindow_Release,
4650 VideoWindow_GetTypeInfoCount,
4651 VideoWindow_GetTypeInfo,
4652 VideoWindow_GetIDsOfNames,
4653 VideoWindow_Invoke,
4654 VideoWindow_put_Caption,
4655 VideoWindow_get_Caption,
4656 VideoWindow_put_WindowStyle,
4657 VideoWindow_get_WindowStyle,
4658 VideoWindow_put_WindowStyleEx,
4659 VideoWindow_get_WindowStyleEx,
4660 VideoWindow_put_AutoShow,
4661 VideoWindow_get_AutoShow,
4662 VideoWindow_put_WindowState,
4663 VideoWindow_get_WindowState,
4664 VideoWindow_put_BackgroundPalette,
4665 VideoWindow_get_BackgroundPalette,
4666 VideoWindow_put_Visible,
4667 VideoWindow_get_Visible,
4668 VideoWindow_put_Left,
4669 VideoWindow_get_Left,
4670 VideoWindow_put_Width,
4671 VideoWindow_get_Width,
4672 VideoWindow_put_Top,
4673 VideoWindow_get_Top,
4674 VideoWindow_put_Height,
4675 VideoWindow_get_Height,
4676 VideoWindow_put_Owner,
4677 VideoWindow_get_Owner,
4678 VideoWindow_put_MessageDrain,
4679 VideoWindow_get_MessageDrain,
4680 VideoWindow_get_BorderColor,
4681 VideoWindow_put_BorderColor,
4682 VideoWindow_get_FullScreenMode,
4683 VideoWindow_put_FullScreenMode,
4684 VideoWindow_SetWindowForeground,
4685 VideoWindow_NotifyOwnerMessage,
4686 VideoWindow_SetWindowPosition,
4687 VideoWindow_GetWindowPosition,
4688 VideoWindow_GetMinIdealImageSize,
4689 VideoWindow_GetMaxIdealImageSize,
4690 VideoWindow_GetRestorePosition,
4691 VideoWindow_HideCursor,
4692 VideoWindow_IsCursorHidden
4695 static struct filter_graph *impl_from_IMediaEventEx(IMediaEventEx *iface)
4697 return CONTAINING_RECORD(iface, struct filter_graph, IMediaEventEx_iface);
4700 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface, REFIID iid, void **out)
4702 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4703 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
4706 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface)
4708 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4709 return IUnknown_AddRef(graph->outer_unk);
4712 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface)
4714 struct filter_graph *graph = impl_from_IMediaEventEx(iface);
4715 return IUnknown_Release(graph->outer_unk);
4718 /*** IDispatch methods ***/
4719 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface, UINT *pctinfo)
4721 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4723 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
4725 return S_OK;
4728 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface, UINT iTInfo, LCID lcid,
4729 ITypeInfo **ppTInfo)
4731 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4733 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
4735 return S_OK;
4738 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface, REFIID riid,
4739 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
4741 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4743 TRACE("(%p/%p)->(%s, %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), rgszNames,
4744 cNames, lcid, rgDispId);
4746 return S_OK;
4749 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface, DISPID dispIdMember, REFIID riid,
4750 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
4751 UINT *puArgErr)
4753 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4755 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember,
4756 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4758 return S_OK;
4761 /*** IMediaEvent methods ***/
4762 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface, OAEVENT *hEvent)
4764 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4766 TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4768 *hEvent = (OAEVENT)This->evqueue.msg_event;
4770 return S_OK;
4773 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface, LONG *lEventCode, LONG_PTR *lParam1,
4774 LONG_PTR *lParam2, LONG msTimeout)
4776 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4777 Event evt;
4779 TRACE("(%p/%p)->(%p, %p, %p, %d)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
4781 if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
4783 *lEventCode = evt.lEventCode;
4784 *lParam1 = evt.lParam1;
4785 *lParam2 = evt.lParam2;
4786 return S_OK;
4789 *lEventCode = 0;
4790 return E_ABORT;
4793 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface, LONG msTimeout,
4794 LONG *pEvCode)
4796 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4798 TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pEvCode);
4800 if (This->state != State_Running)
4801 return VFW_E_WRONG_STATE;
4803 if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4805 *pEvCode = This->CompletionStatus;
4806 return S_OK;
4809 *pEvCode = 0;
4810 return E_ABORT;
4813 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4815 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4817 TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4819 if (lEvCode == EC_COMPLETE)
4820 This->HandleEcComplete = FALSE;
4821 else if (lEvCode == EC_REPAINT)
4822 This->HandleEcRepaint = FALSE;
4823 else if (lEvCode == EC_CLOCK_CHANGED)
4824 This->HandleEcClockChanged = FALSE;
4825 else
4826 return S_FALSE;
4828 return S_OK;
4831 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4833 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4835 TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4837 if (lEvCode == EC_COMPLETE)
4838 This->HandleEcComplete = TRUE;
4839 else if (lEvCode == EC_REPAINT)
4840 This->HandleEcRepaint = TRUE;
4841 else if (lEvCode == EC_CLOCK_CHANGED)
4842 This->HandleEcClockChanged = TRUE;
4843 else
4844 return S_FALSE;
4846 return S_OK;
4849 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface, LONG lEvCode,
4850 LONG_PTR lParam1, LONG_PTR lParam2)
4852 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4854 TRACE("(%p/%p)->(%d, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
4856 return S_OK;
4859 /*** IMediaEventEx methods ***/
4860 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface, OAHWND hwnd, LONG lMsg,
4861 LONG_PTR lInstanceData)
4863 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4865 TRACE("(%p/%p)->(%08lx, %d, %08lx)\n", This, iface, hwnd, lMsg, lInstanceData);
4867 This->notif.hWnd = (HWND)hwnd;
4868 This->notif.msg = lMsg;
4869 This->notif.instance = lInstanceData;
4871 return S_OK;
4874 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface, LONG lNoNotifyFlags)
4876 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4878 TRACE("(%p/%p)->(%d)\n", This, iface, lNoNotifyFlags);
4880 if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
4881 return E_INVALIDARG;
4883 This->notif.disabled = lNoNotifyFlags;
4885 return S_OK;
4888 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface, LONG *lplNoNotifyFlags)
4890 struct filter_graph *This = impl_from_IMediaEventEx(iface);
4892 TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
4894 if (!lplNoNotifyFlags)
4895 return E_POINTER;
4897 *lplNoNotifyFlags = This->notif.disabled;
4899 return S_OK;
4903 static const IMediaEventExVtbl IMediaEventEx_VTable =
4905 MediaEvent_QueryInterface,
4906 MediaEvent_AddRef,
4907 MediaEvent_Release,
4908 MediaEvent_GetTypeInfoCount,
4909 MediaEvent_GetTypeInfo,
4910 MediaEvent_GetIDsOfNames,
4911 MediaEvent_Invoke,
4912 MediaEvent_GetEventHandle,
4913 MediaEvent_GetEvent,
4914 MediaEvent_WaitForCompletion,
4915 MediaEvent_CancelDefaultHandling,
4916 MediaEvent_RestoreDefaultHandling,
4917 MediaEvent_FreeEventParams,
4918 MediaEvent_SetNotifyWindow,
4919 MediaEvent_SetNotifyFlags,
4920 MediaEvent_GetNotifyFlags
4924 static struct filter_graph *impl_from_IMediaFilter(IMediaFilter *iface)
4926 return CONTAINING_RECORD(iface, struct filter_graph, IMediaFilter_iface);
4929 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID iid, void **out)
4931 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4933 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
4936 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
4938 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4940 return IUnknown_AddRef(graph->outer_unk);
4943 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
4945 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4947 return IUnknown_Release(graph->outer_unk);
4950 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
4952 FIXME("(%p): stub\n", pClassID);
4954 return E_NOTIMPL;
4957 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
4959 struct filter_graph *graph = impl_from_IMediaFilter(iface);
4960 HRESULT hr = S_OK, filter_hr;
4961 struct filter *filter;
4962 TP_WORK *work;
4964 TRACE("graph %p.\n", graph);
4966 EnterCriticalSection(&graph->cs);
4968 if (graph->state == State_Stopped)
4970 LeaveCriticalSection(&graph->cs);
4971 return S_OK;
4974 sort_filters(graph);
4976 if (graph->state == State_Running)
4978 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
4980 filter_hr = IBaseFilter_Pause(filter->filter);
4981 if (hr == S_OK)
4982 hr = filter_hr;
4986 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
4988 filter_hr = IBaseFilter_Stop(filter->filter);
4989 if (hr == S_OK)
4990 hr = filter_hr;
4993 graph->state = State_Stopped;
4994 graph->needs_async_run = 0;
4995 work = graph->async_run_work;
4996 graph->got_ec_complete = 0;
4998 /* Update the current position, probably to synchronize multiple streams. */
4999 IMediaSeeking_SetPositions(&graph->IMediaSeeking_iface, &graph->current_pos,
5000 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
5002 LeaveCriticalSection(&graph->cs);
5004 /* Don't cancel the callback; it's holding a reference to the graph. */
5005 if (work)
5006 WaitForThreadpoolWorkCallbacks(work, FALSE);
5008 return hr;
5011 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
5013 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5014 HRESULT hr = S_OK, filter_hr;
5015 struct filter *filter;
5016 TP_WORK *work;
5018 TRACE("graph %p.\n", graph);
5020 EnterCriticalSection(&graph->cs);
5022 if (graph->state == State_Paused)
5024 LeaveCriticalSection(&graph->cs);
5025 return S_OK;
5028 sort_filters(graph);
5029 update_render_count(graph);
5031 if (graph->defaultclock && !graph->refClock)
5032 IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
5034 if (graph->state == State_Running && graph->refClock)
5036 REFERENCE_TIME time;
5037 IReferenceClock_GetTime(graph->refClock, &time);
5038 graph->stream_elapsed += time - graph->stream_start;
5039 graph->current_pos += graph->stream_elapsed;
5042 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5044 filter_hr = IBaseFilter_Pause(filter->filter);
5045 if (hr == S_OK)
5046 hr = filter_hr;
5049 graph->state = State_Paused;
5050 graph->needs_async_run = 0;
5051 work = graph->async_run_work;
5053 LeaveCriticalSection(&graph->cs);
5055 /* Don't cancel the callback; it's holding a reference to the graph. */
5056 if (work)
5057 WaitForThreadpoolWorkCallbacks(work, FALSE);
5059 return hr;
5062 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
5064 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5065 HRESULT hr;
5067 TRACE("graph %p, start %s.\n", graph, debugstr_time(start));
5069 EnterCriticalSection(&graph->cs);
5071 if (graph->state == State_Running)
5073 LeaveCriticalSection(&graph->cs);
5074 return S_OK;
5077 sort_filters(graph);
5079 hr = graph_start(graph, start);
5081 graph->state = State_Running;
5082 graph->needs_async_run = 0;
5084 LeaveCriticalSection(&graph->cs);
5085 return hr;
5088 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, FILTER_STATE *state)
5090 struct filter_graph *graph = impl_from_IMediaFilter(iface);
5091 DWORD end = GetTickCount() + timeout;
5092 FILTER_STATE expect_state;
5093 HRESULT hr;
5095 TRACE("graph %p, timeout %u, state %p.\n", graph, timeout, state);
5097 if (!state)
5098 return E_POINTER;
5100 /* Thread safety is a little tricky here. GetState() shouldn't block other
5101 * functions from being called on the filter graph. However, we can't just
5102 * call IBaseFilter::GetState() in one loop and drop the lock on every
5103 * iteration, since the filter list might change beneath us. So instead we
5104 * do what native does, and poll for it every 10 ms. */
5106 EnterCriticalSection(&graph->cs);
5107 *state = graph->state;
5108 expect_state = graph->needs_async_run ? State_Paused : graph->state;
5110 for (;;)
5112 IBaseFilter *async_filter = NULL;
5113 FILTER_STATE filter_state;
5114 struct filter *filter;
5116 hr = S_OK;
5118 LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
5120 HRESULT filter_hr = IBaseFilter_GetState(filter->filter, 0, &filter_state);
5122 TRACE("Filter %p returned hr %#x, state %u.\n", filter->filter, filter_hr, filter_state);
5124 if (filter_hr == VFW_S_STATE_INTERMEDIATE)
5125 async_filter = filter->filter;
5127 if (hr == S_OK && filter_hr == VFW_S_STATE_INTERMEDIATE)
5128 hr = VFW_S_STATE_INTERMEDIATE;
5129 else if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE)
5130 hr = filter_hr;
5132 if (hr == S_OK && filter_state == State_Paused && graph->state != State_Paused)
5134 async_filter = filter->filter;
5135 hr = VFW_S_STATE_INTERMEDIATE;
5137 else if (filter_state != graph->state && filter_state != State_Paused)
5138 hr = E_FAIL;
5140 if (filter_state != expect_state)
5141 ERR("Filter %p reported incorrect state %u (expected %u).\n",
5142 filter->filter, filter_state, expect_state);
5145 LeaveCriticalSection(&graph->cs);
5147 if (hr != VFW_S_STATE_INTERMEDIATE || (timeout != INFINITE && GetTickCount() >= end))
5148 break;
5150 IBaseFilter_GetState(async_filter, 10, &filter_state);
5152 EnterCriticalSection(&graph->cs);
5155 TRACE("Returning %#x, state %u.\n", hr, *state);
5156 return hr;
5159 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
5161 struct filter_graph *This = impl_from_IMediaFilter(iface);
5162 struct filter *filter;
5163 HRESULT hr = S_OK;
5165 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
5167 EnterCriticalSection(&This->cs);
5169 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
5171 hr = IBaseFilter_SetSyncSource(filter->filter, pClock);
5172 if (FAILED(hr))
5173 break;
5176 if (FAILED(hr))
5178 LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
5179 IBaseFilter_SetSyncSource(filter->filter, This->refClock);
5181 else
5183 if (This->refClock)
5184 IReferenceClock_Release(This->refClock);
5185 This->refClock = pClock;
5186 if (This->refClock)
5187 IReferenceClock_AddRef(This->refClock);
5188 This->defaultclock = FALSE;
5190 if (This->HandleEcClockChanged)
5192 IMediaEventSink *pEventSink;
5193 HRESULT eshr;
5195 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (void **)&pEventSink);
5196 if (SUCCEEDED(eshr))
5198 IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5199 IMediaEventSink_Release(pEventSink);
5204 LeaveCriticalSection(&This->cs);
5206 return hr;
5209 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5211 struct filter_graph *This = impl_from_IMediaFilter(iface);
5213 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
5215 if (!ppClock)
5216 return E_POINTER;
5218 EnterCriticalSection(&This->cs);
5220 *ppClock = This->refClock;
5221 if (*ppClock)
5222 IReferenceClock_AddRef(*ppClock);
5224 LeaveCriticalSection(&This->cs);
5226 return S_OK;
5229 static const IMediaFilterVtbl IMediaFilter_VTable =
5231 MediaFilter_QueryInterface,
5232 MediaFilter_AddRef,
5233 MediaFilter_Release,
5234 MediaFilter_GetClassID,
5235 MediaFilter_Stop,
5236 MediaFilter_Pause,
5237 MediaFilter_Run,
5238 MediaFilter_GetState,
5239 MediaFilter_SetSyncSource,
5240 MediaFilter_GetSyncSource
5243 static struct filter_graph *impl_from_IMediaEventSink(IMediaEventSink *iface)
5245 return CONTAINING_RECORD(iface, struct filter_graph, IMediaEventSink_iface);
5248 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID iid, void **out)
5250 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5252 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5255 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5257 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5259 return IUnknown_AddRef(graph->outer_unk);
5262 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5264 struct filter_graph *graph = impl_from_IMediaEventSink(iface);
5266 return IUnknown_Release(graph->outer_unk);
5269 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCode,
5270 LONG_PTR EventParam1, LONG_PTR EventParam2)
5272 struct filter_graph *This = impl_from_IMediaEventSink(iface);
5273 Event evt;
5275 TRACE("(%p/%p)->(%d, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
5277 /* We need thread safety here, let's use the events queue's one */
5278 EnterCriticalSection(&This->evqueue.msg_crst);
5280 if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
5282 TRACE("Process EC_COMPLETE notification\n");
5283 if (++This->EcCompleteCount == This->nRenderers)
5285 evt.lEventCode = EC_COMPLETE;
5286 evt.lParam1 = S_OK;
5287 evt.lParam2 = 0;
5288 TRACE("Send EC_COMPLETE to app\n");
5289 EventsQueue_PutEvent(&This->evqueue, &evt);
5290 if (!This->notif.disabled && This->notif.hWnd)
5292 TRACE("Send Window message\n");
5293 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5295 This->CompletionStatus = EC_COMPLETE;
5296 This->got_ec_complete = 1;
5297 SetEvent(This->hEventCompletion);
5300 else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
5302 /* FIXME: Not handled yet */
5304 else
5306 evt.lEventCode = EventCode;
5307 evt.lParam1 = EventParam1;
5308 evt.lParam2 = EventParam2;
5309 EventsQueue_PutEvent(&This->evqueue, &evt);
5310 if (!This->notif.disabled && This->notif.hWnd)
5311 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5314 LeaveCriticalSection(&This->evqueue.msg_crst);
5315 return S_OK;
5318 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5320 MediaEventSink_QueryInterface,
5321 MediaEventSink_AddRef,
5322 MediaEventSink_Release,
5323 MediaEventSink_Notify
5326 static struct filter_graph *impl_from_IGraphConfig(IGraphConfig *iface)
5328 return CONTAINING_RECORD(iface, struct filter_graph, IGraphConfig_iface);
5331 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID iid, void **out)
5333 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5335 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5338 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5340 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5342 return IUnknown_AddRef(graph->outer_unk);
5345 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5347 struct filter_graph *graph = impl_from_IGraphConfig(iface);
5349 return IUnknown_Release(graph->outer_unk);
5352 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface, IPin *pOutputPin, IPin *pInputPin,
5353 const AM_MEDIA_TYPE *pmtFirstConnection, IBaseFilter *pUsingFilter, HANDLE hAbortEvent,
5354 DWORD dwFlags)
5356 struct filter_graph *This = impl_from_IGraphConfig(iface);
5358 FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
5359 strmbase_dump_media_type(pmtFirstConnection);
5361 return E_NOTIMPL;
5364 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface, IGraphConfigCallback *pCallback,
5365 void *pvContext, DWORD dwFlags, HANDLE hAbortEvent)
5367 struct filter_graph *This = impl_from_IGraphConfig(iface);
5368 HRESULT hr;
5370 WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
5372 if (hAbortEvent)
5373 FIXME("The parameter hAbortEvent is not handled!\n");
5375 EnterCriticalSection(&This->cs);
5377 hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
5379 LeaveCriticalSection(&This->cs);
5381 return hr;
5384 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface, IBaseFilter *pFilter)
5386 struct filter_graph *This = impl_from_IGraphConfig(iface);
5388 FIXME("(%p)->(%p): stub!\n", This, pFilter);
5390 return E_NOTIMPL;
5393 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface, IEnumFilters **pEnum)
5395 struct filter_graph *This = impl_from_IGraphConfig(iface);
5397 FIXME("(%p)->(%p): stub!\n", This, pEnum);
5399 return E_NOTIMPL;
5402 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface, IBaseFilter *pFilter)
5404 struct filter_graph *This = impl_from_IGraphConfig(iface);
5406 FIXME("(%p)->(%p): stub!\n", This, pFilter);
5408 return E_NOTIMPL;
5411 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface, REFERENCE_TIME *prtStart)
5413 struct filter_graph *This = impl_from_IGraphConfig(iface);
5415 FIXME("(%p)->(%p): stub!\n", This, prtStart);
5417 return E_NOTIMPL;
5420 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface, IPin *pOutputPin,
5421 IPinConnection *pConnection, HANDLE hEventAbort)
5423 struct filter_graph *This = impl_from_IGraphConfig(iface);
5425 FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5427 return E_NOTIMPL;
5430 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5431 DWORD dwFlags)
5433 struct filter_graph *This = impl_from_IGraphConfig(iface);
5435 FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5437 return E_NOTIMPL;
5440 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5441 DWORD *dwFlags)
5443 struct filter_graph *This = impl_from_IGraphConfig(iface);
5445 FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5447 return E_NOTIMPL;
5450 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface, IBaseFilter *pFilter,
5451 DWORD dwFlags)
5453 struct filter_graph *This = impl_from_IGraphConfig(iface);
5455 FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5457 return E_NOTIMPL;
5460 static const IGraphConfigVtbl IGraphConfig_VTable =
5462 GraphConfig_QueryInterface,
5463 GraphConfig_AddRef,
5464 GraphConfig_Release,
5465 GraphConfig_Reconnect,
5466 GraphConfig_Reconfigure,
5467 GraphConfig_AddFilterToCache,
5468 GraphConfig_EnumCacheFilter,
5469 GraphConfig_RemoveFilterFromCache,
5470 GraphConfig_GetStartTime,
5471 GraphConfig_PushThroughData,
5472 GraphConfig_SetFilterFlags,
5473 GraphConfig_GetFilterFlags,
5474 GraphConfig_RemoveFilterEx
5477 static struct filter_graph *impl_from_IGraphVersion(IGraphVersion *iface)
5479 return CONTAINING_RECORD(iface, struct filter_graph, IGraphVersion_iface);
5482 static HRESULT WINAPI GraphVersion_QueryInterface(IGraphVersion *iface, REFIID iid, void **out)
5484 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5486 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5489 static ULONG WINAPI GraphVersion_AddRef(IGraphVersion *iface)
5491 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5493 return IUnknown_AddRef(graph->outer_unk);
5496 static ULONG WINAPI GraphVersion_Release(IGraphVersion *iface)
5498 struct filter_graph *graph = impl_from_IGraphVersion(iface);
5500 return IUnknown_Release(graph->outer_unk);
5503 static HRESULT WINAPI GraphVersion_QueryVersion(IGraphVersion *iface, LONG *pVersion)
5505 struct filter_graph *This = impl_from_IGraphVersion(iface);
5507 if(!pVersion)
5508 return E_POINTER;
5510 TRACE("(%p)->(%p): current version %i\n", This, pVersion, This->version);
5512 *pVersion = This->version;
5513 return S_OK;
5516 static const IGraphVersionVtbl IGraphVersion_VTable =
5518 GraphVersion_QueryInterface,
5519 GraphVersion_AddRef,
5520 GraphVersion_Release,
5521 GraphVersion_QueryVersion,
5524 static struct filter_graph *impl_from_IVideoFrameStep(IVideoFrameStep *iface)
5526 return CONTAINING_RECORD(iface, struct filter_graph, IVideoFrameStep_iface);
5529 static HRESULT WINAPI VideoFrameStep_QueryInterface(IVideoFrameStep *iface, REFIID iid, void **out)
5531 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5532 return IUnknown_QueryInterface(graph->outer_unk, iid, out);
5535 static ULONG WINAPI VideoFrameStep_AddRef(IVideoFrameStep *iface)
5537 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5538 return IUnknown_AddRef(graph->outer_unk);
5541 static ULONG WINAPI VideoFrameStep_Release(IVideoFrameStep *iface)
5543 struct filter_graph *graph = impl_from_IVideoFrameStep(iface);
5544 return IUnknown_Release(graph->outer_unk);
5547 static HRESULT WINAPI VideoFrameStep_Step(IVideoFrameStep *iface, DWORD frame_count, IUnknown *filter)
5549 FIXME("iface %p, frame_count %u, filter %p, stub!\n", iface, frame_count, filter);
5550 return E_NOTIMPL;
5553 static HRESULT WINAPI VideoFrameStep_CanStep(IVideoFrameStep *iface, LONG multiple, IUnknown *filter)
5555 FIXME("iface %p, multiple %d, filter %p, stub!\n", iface, multiple, filter);
5556 return E_NOTIMPL;
5559 static HRESULT WINAPI VideoFrameStep_CancelStep(IVideoFrameStep *iface)
5561 FIXME("iface %p, stub!\n", iface);
5562 return E_NOTIMPL;
5565 static const IVideoFrameStepVtbl VideoFrameStep_vtbl =
5567 VideoFrameStep_QueryInterface,
5568 VideoFrameStep_AddRef,
5569 VideoFrameStep_Release,
5570 VideoFrameStep_Step,
5571 VideoFrameStep_CanStep,
5572 VideoFrameStep_CancelStep
5575 static const IUnknownVtbl IInner_VTable =
5577 FilterGraphInner_QueryInterface,
5578 FilterGraphInner_AddRef,
5579 FilterGraphInner_Release
5582 static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded)
5584 struct filter_graph *object;
5585 HRESULT hr;
5587 *out = NULL;
5589 if (!(object = calloc(1, sizeof(*object))))
5590 return E_OUTOFMEMORY;
5592 object->IBasicAudio_iface.lpVtbl = &IBasicAudio_VTable;
5593 object->IBasicVideo2_iface.lpVtbl = &IBasicVideo_VTable;
5594 object->IFilterGraph2_iface.lpVtbl = &IFilterGraph2_VTable;
5595 object->IGraphConfig_iface.lpVtbl = &IGraphConfig_VTable;
5596 object->IGraphVersion_iface.lpVtbl = &IGraphVersion_VTable;
5597 object->IMediaControl_iface.lpVtbl = &IMediaControl_VTable;
5598 object->IMediaEventEx_iface.lpVtbl = &IMediaEventEx_VTable;
5599 object->IMediaEventSink_iface.lpVtbl = &IMediaEventSink_VTable;
5600 object->IMediaFilter_iface.lpVtbl = &IMediaFilter_VTable;
5601 object->IMediaPosition_iface.lpVtbl = &IMediaPosition_VTable;
5602 object->IMediaSeeking_iface.lpVtbl = &IMediaSeeking_VTable;
5603 object->IObjectWithSite_iface.lpVtbl = &IObjectWithSite_VTable;
5604 object->IUnknown_inner.lpVtbl = &IInner_VTable;
5605 object->IVideoFrameStep_iface.lpVtbl = &VideoFrameStep_vtbl;
5606 object->IVideoWindow_iface.lpVtbl = &IVideoWindow_VTable;
5607 object->ref = 1;
5608 object->outer_unk = outer ? outer : &object->IUnknown_inner;
5610 if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, object->outer_unk,
5611 CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&object->punkFilterMapper2)))
5613 ERR("Failed to create filter mapper, hr %#x.\n", hr);
5614 free(object);
5615 return hr;
5618 InitializeCriticalSection(&object->cs);
5619 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": filter_graph.cs");
5621 object->defaultclock = TRUE;
5622 EventsQueue_Init(&object->evqueue);
5623 list_init(&object->filters);
5624 object->HandleEcClockChanged = TRUE;
5625 object->HandleEcComplete = TRUE;
5626 object->HandleEcRepaint = TRUE;
5627 object->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5628 object->name_index = 1;
5629 object->timeformatseek = TIME_FORMAT_MEDIA_TIME;
5631 if (threaded)
5633 object->message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL);
5634 object->message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &object->message_thread_id);
5635 WaitForSingleObject(object->message_thread_ret, INFINITE);
5637 else
5638 object->message_thread = NULL;
5640 TRACE("Created %sthreaded filter graph %p.\n", threaded ? "" : "non-", object);
5641 *out = &object->IUnknown_inner;
5642 return S_OK;
5645 HRESULT filter_graph_create(IUnknown *outer, IUnknown **out)
5647 return filter_graph_common_create(outer, out, TRUE);
5650 HRESULT filter_graph_no_thread_create(IUnknown *outer, IUnknown **out)
5652 return filter_graph_common_create(outer, out, FALSE);