winealsa: Unify the checks for wBitsPerSample.
[wine] / dlls / quartz / filtergraph.c
1 /*              DirectShow FilterGraph object (QUARTZ.DLL)
2  *
3  * Copyright 2002 Lionel Ulmer
4  * Copyright 2004 Christian Costa
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #define COBJMACROS
25
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/unicode.h"
40
41
42 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
43
44 typedef struct {
45     HWND     hWnd;      /* Target window */
46     UINT     msg;       /* User window message */
47     LONG_PTR instance;  /* User data */
48     int      disabled;  /* Disabled messages posting */
49 } WndNotify;
50
51 typedef struct {
52     LONG lEventCode;   /* Event code */
53     LONG_PTR lParam1;  /* Param1 */
54     LONG_PTR lParam2;  /* Param2 */
55 } Event;
56
57 /* messages ring implementation for queuing events (taken from winmm) */
58 #define EVENTS_RING_BUFFER_INCREMENT      64
59 typedef struct {
60     Event* messages;
61     int ring_buffer_size;
62     int msg_tosave;
63     int msg_toget;
64     CRITICAL_SECTION msg_crst;
65     HANDLE msg_event; /* Signaled for no empty queue */
66 } EventsQueue;
67
68 static int EventsQueue_Init(EventsQueue* omr)
69 {
70     omr->msg_toget = 0;
71     omr->msg_tosave = 0;
72     omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
73     omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
74     omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
75     ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
76
77     InitializeCriticalSection(&omr->msg_crst);
78     omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
79     return TRUE;
80 }
81
82 static int EventsQueue_Destroy(EventsQueue* omr)
83 {
84     CloseHandle(omr->msg_event);
85     CoTaskMemFree(omr->messages);
86     omr->msg_crst.DebugInfo->Spare[0] = 0;
87     DeleteCriticalSection(&omr->msg_crst);
88     return TRUE;
89 }
90
91 static int EventsQueue_PutEvent(EventsQueue* omr, const Event* evt)
92 {
93     EnterCriticalSection(&omr->msg_crst);
94     if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
95     {
96         int old_ring_buffer_size = omr->ring_buffer_size;
97         omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
98         TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
99         omr->messages = CoTaskMemRealloc(omr->messages, omr->ring_buffer_size * sizeof(Event));
100         /* Now we need to rearrange the ring buffer so that the new
101            buffers just allocated are in between omr->msg_tosave and
102            omr->msg_toget.
103         */
104         if (omr->msg_tosave < omr->msg_toget)
105         {
106             memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
107                     &(omr->messages[omr->msg_toget]),
108                     sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
109                     );
110             omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
111         }
112     }
113     omr->messages[omr->msg_tosave] = *evt;
114     SetEvent(omr->msg_event);
115     omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
116     LeaveCriticalSection(&omr->msg_crst);
117     return TRUE;
118 }
119
120 static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, LONG msTimeOut)
121 {
122     if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
123         return FALSE;
124         
125     EnterCriticalSection(&omr->msg_crst);
126
127     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
128     {
129         LeaveCriticalSection(&omr->msg_crst);
130         return FALSE;
131     }
132
133     *evt = omr->messages[omr->msg_toget];
134     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
135
136     /* Mark the buffer as empty if needed */
137     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
138         ResetEvent(omr->msg_event);
139
140     LeaveCriticalSection(&omr->msg_crst);
141     return TRUE;
142 }
143
144 #define MAX_ITF_CACHE_ENTRIES 3
145 typedef struct _ITF_CACHE_ENTRY {
146    const IID* riid;
147    IBaseFilter* filter;
148    IUnknown* iface;
149 } ITF_CACHE_ENTRY;
150
151 typedef struct _IFilterGraphImpl {
152     IFilterGraph2 IFilterGraph2_iface;
153     IMediaControl IMediaControl_iface;
154     IMediaSeeking IMediaSeeking_iface;
155     IBasicAudio IBasicAudio_iface;
156     IBasicVideo2 IBasicVideo2_iface;
157     IVideoWindow IVideoWindow_iface;
158     IMediaEventEx IMediaEventEx_iface;
159     IMediaFilter IMediaFilter_iface;
160     IMediaEventSink IMediaEventSink_iface;
161     IGraphConfig IGraphConfig_iface;
162     IMediaPosition IMediaPosition_iface;
163     const IUnknownVtbl * IInner_vtbl;
164     /* IAMGraphStreams */
165     /* IAMStats */
166     /* IFilterChain */
167     /* IFilterMapper2 */
168     /* IGraphVersion */
169     /* IQueueCommand */
170     /* IRegisterServiceProvider */
171     /* IResourceMananger */
172     /* IServiceProvider */
173     /* IVideoFrameStep */
174
175     LONG ref;
176     IUnknown *punkFilterMapper2;
177     IFilterMapper2 * pFilterMapper2;
178     IBaseFilter ** ppFiltersInGraph;
179     LPWSTR * pFilterNames;
180     int nFilters;
181     int filterCapacity;
182     LONG nameIndex;
183     IReferenceClock *refClock;
184     IBaseFilter *refClockProvider;
185     EventsQueue evqueue;
186     HANDLE hEventCompletion;
187     int CompletionStatus;
188     WndNotify notif;
189     int nRenderers;
190     int EcCompleteCount;
191     int HandleEcComplete;
192     int HandleEcRepaint;
193     int HandleEcClockChanged;
194     OAFilterState state;
195     CRITICAL_SECTION cs;
196     ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
197     int nItfCacheEntries;
198     IUnknown * pUnkOuter;
199     BOOL bUnkOuterValid;
200     BOOL bAggregatable;
201     BOOL defaultclock;
202     GUID timeformatseek;
203     REFERENCE_TIME start_time;
204     REFERENCE_TIME pause_time;
205     LONGLONG stop_position;
206     LONG recursioncount;
207 } IFilterGraphImpl;
208
209 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
210                                           REFIID riid, LPVOID * ppv);
211 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This);
212 static ULONG Filtergraph_Release(IFilterGraphImpl *This);
213
214 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown * iface,
215                                           REFIID riid,
216                                           LPVOID *ppvObj) {
217     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
218     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
219     
220     if (This->bAggregatable)
221         This->bUnkOuterValid = TRUE;
222
223     if (IsEqualGUID(&IID_IUnknown, riid)) {
224         *ppvObj = &(This->IInner_vtbl);
225         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
226     } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
227         IsEqualGUID(&IID_IFilterGraph2, riid) ||
228         IsEqualGUID(&IID_IGraphBuilder, riid)) {
229         *ppvObj = &This->IFilterGraph2_iface;
230         TRACE("   returning IGraphBuilder interface (%p)\n", *ppvObj);
231     } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
232         *ppvObj = &This->IMediaControl_iface;
233         TRACE("   returning IMediaControl interface (%p)\n", *ppvObj);
234     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
235         *ppvObj = &This->IMediaSeeking_iface;
236         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
237     } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
238         *ppvObj = &This->IBasicAudio_iface;
239         TRACE("   returning IBasicAudio interface (%p)\n", *ppvObj);
240     } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
241                IsEqualGUID(&IID_IBasicVideo2, riid)) {
242         *ppvObj = &This->IBasicVideo2_iface;
243         TRACE("   returning IBasicVideo2 interface (%p)\n", *ppvObj);
244     } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
245         *ppvObj = &This->IVideoWindow_iface;
246         TRACE("   returning IVideoWindow interface (%p)\n", *ppvObj);
247     } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
248            IsEqualGUID(&IID_IMediaEventEx, riid)) {
249         *ppvObj = &This->IMediaEventEx_iface;
250         TRACE("   returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
251     } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
252           IsEqualGUID(&IID_IPersist, riid)) {
253         *ppvObj = &This->IMediaFilter_iface;
254         TRACE("   returning IMediaFilter interface (%p)\n", *ppvObj);
255     } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
256         *ppvObj = &This->IMediaEventSink_iface;
257         TRACE("   returning IMediaEventSink interface (%p)\n", *ppvObj);
258     } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
259         *ppvObj = &This->IGraphConfig_iface;
260         TRACE("   returning IGraphConfig interface (%p)\n", *ppvObj);
261     } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
262         *ppvObj = &This->IMediaPosition_iface;
263         TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
264     } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
265         TRACE("   requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
266         return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
267     } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
268         *ppvObj = This->pFilterMapper2;
269         TRACE("   returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
270     } else if (IsEqualGUID(&IID_IFilterMapper3, riid)) {
271         *ppvObj = This->pFilterMapper2;
272         TRACE("   returning IFilterMapper3 interface from aggregated filtermapper (%p)\n", *ppvObj);
273     } else {
274         *ppvObj = NULL;
275         FIXME("unknown interface %s\n", debugstr_guid(riid));
276         return E_NOINTERFACE;
277     }
278
279     IUnknown_AddRef((IUnknown *)(*ppvObj));
280     return S_OK;
281 }
282
283 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown * iface) {
284     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
285     ULONG ref = InterlockedIncrement(&This->ref);
286
287     TRACE("(%p)->(): new ref = %d\n", This, ref);
288     
289     return ref;
290 }
291
292 static ULONG WINAPI FilterGraphInner_Release(IUnknown * iface)
293 {
294     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
295     ULONG ref = InterlockedDecrement(&This->ref);
296
297     TRACE("(%p)->(): new ref = %d\n", This, ref);
298
299     if (ref == 0) {
300         int i;
301
302         This->ref = 1; /* guard against reentrancy (aggregation). */
303
304         IMediaControl_Stop(&This->IMediaControl_iface);
305
306         while (This->nFilters)
307             IFilterGraph2_RemoveFilter((IFilterGraph2*)This, This->ppFiltersInGraph[0]);
308
309         if (This->refClock)
310             IReferenceClock_Release(This->refClock);
311
312         for (i = 0; i < This->nItfCacheEntries; i++)
313         {
314             if (This->ItfCacheEntries[i].iface)
315                 IUnknown_Release(This->ItfCacheEntries[i].iface);
316         }
317
318         /* AddRef on controlling IUnknown, to compensate for Release of cached IFilterMapper2 interface below.
319
320          * NOTE: Filtergraph_AddRef isn't suitable, because bUnkOuterValid may be FALSE but punkOuter non-NULL
321          * and already passed as punkOuter to filtermapper in FilterGraph_create - this will happen in case of
322          * CoCreateInstance of filtergraph with non-null pUnkOuter and REFIID other than IID_Unknown that is
323          * cleaning up after error. */
324         if (This->pUnkOuter) IUnknown_AddRef(This->pUnkOuter);
325         else IUnknown_AddRef((IUnknown*)&This->IInner_vtbl);
326
327         IFilterMapper2_Release(This->pFilterMapper2);
328         IUnknown_Release(This->punkFilterMapper2);
329
330         CloseHandle(This->hEventCompletion);
331         EventsQueue_Destroy(&This->evqueue);
332         This->cs.DebugInfo->Spare[0] = 0;
333         DeleteCriticalSection(&This->cs);
334         CoTaskMemFree(This->ppFiltersInGraph);
335         CoTaskMemFree(This->pFilterNames);
336         CoTaskMemFree(This);
337     }
338     return ref;
339 }
340
341 static inline IFilterGraphImpl *impl_from_IFilterGraph2(IFilterGraph2 *iface)
342 {
343     return CONTAINING_RECORD(iface, IFilterGraphImpl, IFilterGraph2_iface);
344 }
345
346 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface, REFIID riid, void **ppvObj)
347 {
348     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
349
350     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
351
352     return Filtergraph_QueryInterface(This, riid, ppvObj);
353 }
354
355 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface)
356 {
357     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
358
359     TRACE("(%p/%p)->() calling FilterGraph AddRef\n", This, iface);
360
361     return Filtergraph_AddRef(This);
362 }
363
364 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface)
365 {
366     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
367
368     TRACE("(%p/%p)->() calling FilterGraph Release\n", This, iface);
369
370     return Filtergraph_Release(This);
371 }
372
373 /*** IFilterGraph methods ***/
374 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, IBaseFilter *pFilter,
375         LPCWSTR pName)
376 {
377     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
378     HRESULT hr;
379     int i,j;
380     WCHAR* wszFilterName = NULL;
381     int duplicate_name = FALSE;
382
383     TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
384
385     if (!pFilter)
386         return E_POINTER;
387
388     wszFilterName = CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
389
390     if (pName)
391     {
392         /* Check if name already exists */
393         for(i = 0; i < This->nFilters; i++)
394             if (!strcmpW(This->pFilterNames[i], pName))
395             {
396                 duplicate_name = TRUE;
397                 break;
398             }
399     }
400
401     /* If no name given or name already existing, generate one */
402     if (!pName || duplicate_name)
403     {
404         static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
405         static const WCHAR wszFmt2[] = {'%','0','4','d',0};
406
407         for (j = 0; j < 10000 ; j++)
408         {
409             /* Create name */
410             if (pName)
411                 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
412             else
413                 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
414             TRACE("Generated name %s\n", debugstr_w(wszFilterName));
415
416             /* Check if the generated name already exists */
417             for(i = 0; i < This->nFilters; i++)
418                 if (!strcmpW(This->pFilterNames[i], wszFilterName))
419                     break;
420
421             /* Compute next index and exit if generated name is suitable */
422             if (This->nameIndex++ == 10000)
423                 This->nameIndex = 1;
424             if (i == This->nFilters)
425                 break;
426         }
427         /* Unable to find a suitable name */
428         if (j == 10000)
429         {
430             CoTaskMemFree(wszFilterName);
431             return VFW_E_DUPLICATE_NAME;
432         }
433     }
434     else
435         memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
436
437     if (This->nFilters + 1 > This->filterCapacity)
438     {
439         int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
440         IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
441         LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
442         memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
443         memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
444         if (This->filterCapacity)
445         {
446             CoTaskMemFree(This->ppFiltersInGraph);
447             CoTaskMemFree(This->pFilterNames);
448         }
449         This->ppFiltersInGraph = ppNewFilters;
450         This->pFilterNames = pNewNames;
451         This->filterCapacity = newCapacity;
452     }
453
454     hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)This, wszFilterName);
455
456     if (SUCCEEDED(hr))
457     {
458         IBaseFilter_AddRef(pFilter);
459         This->ppFiltersInGraph[This->nFilters] = pFilter;
460         This->pFilterNames[This->nFilters] = wszFilterName;
461         This->nFilters++;
462         IBaseFilter_SetSyncSource(pFilter, This->refClock);
463     }
464     else
465         CoTaskMemFree(wszFilterName);
466
467     if (SUCCEEDED(hr) && duplicate_name)
468         return VFW_S_DUPLICATE_NAME;
469         
470     return hr;
471 }
472
473 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
474 {
475     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
476     int i;
477     HRESULT hr = E_FAIL;
478
479     TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
480
481     /* FIXME: check graph is stopped */
482
483     for (i = 0; i < This->nFilters; i++)
484     {
485         if (This->ppFiltersInGraph[i] == pFilter)
486         {
487             IEnumPins *penumpins = NULL;
488             FILTER_STATE state;
489
490             if (This->defaultclock && This->refClockProvider == pFilter)
491             {
492                 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
493                 This->defaultclock = 1;
494             }
495
496             TRACE("Removing filter %s\n", debugstr_w(This->pFilterNames[i]));
497             IBaseFilter_GetState(pFilter, 0, &state);
498             if (state == State_Running)
499                 IBaseFilter_Pause(pFilter);
500             if (state != State_Stopped)
501                 IBaseFilter_Stop(pFilter);
502
503             hr = IBaseFilter_EnumPins(pFilter, &penumpins);
504             if (SUCCEEDED(hr)) {
505                 IPin *ppin;
506                 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
507                 {
508                     IPin *victim = NULL;
509                     HRESULT h;
510                     IPin_ConnectedTo(ppin, &victim);
511                     if (victim)
512                     {
513                         h = IPin_Disconnect(victim);
514                         TRACE("Disconnect other side: %08x\n", h);
515                         if (h == VFW_E_NOT_STOPPED)
516                         {
517                             PIN_INFO pinfo;
518                             IPin_QueryPinInfo(victim, &pinfo);
519
520                             IBaseFilter_GetState(pinfo.pFilter, 0, &state);
521                             if (state == State_Running)
522                                 IBaseFilter_Pause(pinfo.pFilter);
523                             IBaseFilter_Stop(pinfo.pFilter);
524                             IBaseFilter_Release(pinfo.pFilter);
525                             h = IPin_Disconnect(victim);
526                             TRACE("Disconnect retry: %08x\n", h);
527                         }
528                         IPin_Release(victim);
529                     }
530                     h = IPin_Disconnect(ppin);
531                     TRACE("Disconnect 2: %08x\n", h);
532
533                     IPin_Release(ppin);
534                 }
535                 IEnumPins_Release(penumpins);
536             }
537
538             hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
539             if (SUCCEEDED(hr))
540             {
541                 IBaseFilter_SetSyncSource(pFilter, NULL);
542                 IBaseFilter_Release(pFilter);
543                 CoTaskMemFree(This->pFilterNames[i]);
544                 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
545                 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
546                 This->nFilters--;
547                 /* Invalidate interfaces in the cache */
548                 for (i = 0; i < This->nItfCacheEntries; i++)
549                     if (pFilter == This->ItfCacheEntries[i].filter)
550                     {
551                         IUnknown_Release(This->ItfCacheEntries[i].iface);
552                         This->ItfCacheEntries[i].iface = NULL;
553                         This->ItfCacheEntries[i].filter = NULL;
554                     }
555                 return S_OK;
556             }
557             break;
558         }
559     }
560
561     return hr; /* FIXME: check this error code */
562 }
563
564 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface, IEnumFilters **ppEnum)
565 {
566     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
567
568     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
569
570     return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
571 }
572
573 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface, LPCWSTR pName,
574         IBaseFilter **ppFilter)
575 {
576     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
577     int i;
578
579     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
580
581     if (!ppFilter)
582         return E_POINTER;
583
584     for (i = 0; i < This->nFilters; i++)
585     {
586         if (!strcmpW(pName, This->pFilterNames[i]))
587         {
588             *ppFilter = This->ppFiltersInGraph[i];
589             IBaseFilter_AddRef(*ppFilter);
590             return S_OK;
591         }
592     }
593
594     *ppFilter = NULL;
595     return VFW_E_NOT_FOUND;
596 }
597
598 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
599  * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
600  */
601 static HRESULT CheckCircularConnection(IFilterGraphImpl *This, IPin *out, IPin *in)
602 {
603 #if 1
604     HRESULT hr;
605     PIN_INFO info_out, info_in;
606
607     hr = IPin_QueryPinInfo(out, &info_out);
608     if (FAILED(hr))
609         return hr;
610     if (info_out.dir != PINDIR_OUTPUT)
611     {
612         IBaseFilter_Release(info_out.pFilter);
613         return E_UNEXPECTED;
614     }
615
616     hr = IPin_QueryPinInfo(in, &info_in);
617     if (SUCCEEDED(hr))
618         IBaseFilter_Release(info_in.pFilter);
619     if (FAILED(hr))
620         goto out;
621     if (info_in.dir != PINDIR_INPUT)
622     {
623         hr = E_UNEXPECTED;
624         goto out;
625     }
626
627     if (info_out.pFilter == info_in.pFilter)
628         hr = VFW_E_CIRCULAR_GRAPH;
629     else
630     {
631         IEnumPins *enumpins;
632         IPin *test;
633
634         hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
635         if (FAILED(hr))
636             goto out;
637
638         IEnumPins_Reset(enumpins);
639         while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
640         {
641             PIN_DIRECTION dir = PINDIR_OUTPUT;
642             IPin_QueryDirection(test, &dir);
643             if (dir == PINDIR_INPUT)
644             {
645                 IPin *victim = NULL;
646                 IPin_ConnectedTo(test, &victim);
647                 if (victim)
648                 {
649                     hr = CheckCircularConnection(This, victim, in);
650                     IPin_Release(victim);
651                     if (FAILED(hr))
652                     {
653                         IPin_Release(test);
654                         break;
655                     }
656                 }
657             }
658             IPin_Release(test);
659         }
660         IEnumPins_Release(enumpins);
661     }
662
663 out:
664     IBaseFilter_Release(info_out.pFilter);
665     if (FAILED(hr))
666         ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
667     return hr;
668 #else
669     /* Debugging filtergraphs not enabled */
670     return S_OK;
671 #endif
672 }
673
674
675 /* NOTE: despite the implication, it doesn't matter which
676  * way round you put in the input and output pins */
677 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppinIn, IPin *ppinOut,
678         const AM_MEDIA_TYPE *pmt)
679 {
680     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
681     PIN_DIRECTION dir;
682     HRESULT hr;
683
684     TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
685
686     /* FIXME: check pins are in graph */
687
688     if (TRACE_ON(quartz))
689     {
690         PIN_INFO PinInfo;
691
692         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
693         if (FAILED(hr))
694             return hr;
695
696         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
697         IBaseFilter_Release(PinInfo.pFilter);
698
699         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
700         if (FAILED(hr))
701             return hr;
702
703         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
704         IBaseFilter_Release(PinInfo.pFilter);
705     }
706
707     hr = IPin_QueryDirection(ppinIn, &dir);
708     if (SUCCEEDED(hr))
709     {
710         if (dir == PINDIR_INPUT)
711         {
712             hr = CheckCircularConnection(This, ppinOut, ppinIn);
713             if (SUCCEEDED(hr))
714                 hr = IPin_Connect(ppinOut, ppinIn, pmt);
715         }
716         else
717         {
718             hr = CheckCircularConnection(This, ppinIn, ppinOut);
719             if (SUCCEEDED(hr))
720                 hr = IPin_Connect(ppinIn, ppinOut, pmt);
721         }
722     }
723
724     return hr;
725 }
726
727 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface, IPin *ppin)
728 {
729     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
730     IPin *pConnectedTo = NULL;
731     HRESULT hr;
732     PIN_DIRECTION pindir;
733
734     IPin_QueryDirection(ppin, &pindir);
735     hr = IPin_ConnectedTo(ppin, &pConnectedTo);
736     if (FAILED(hr)) {
737         TRACE("Querying connected to failed: %x\n", hr);
738         return hr; 
739     }
740     IPin_Disconnect(ppin);
741     IPin_Disconnect(pConnectedTo);
742     if (pindir == PINDIR_INPUT)
743         hr = IPin_Connect(pConnectedTo, ppin, NULL);
744     else
745         hr = IPin_Connect(ppin, pConnectedTo, NULL);
746     IPin_Release(pConnectedTo);
747     if (FAILED(hr))
748         WARN("Reconnecting pins failed, pins are not connected now..\n");
749     TRACE("(%p->%p) -- %p %p -> %x\n", iface, This, ppin, pConnectedTo, hr);
750     return hr;
751 }
752
753 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
754 {
755     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
756
757     TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
758
759     if (!ppin)
760        return E_POINTER;
761
762     return IPin_Disconnect(ppin);
763 }
764
765 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
766 {
767     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
768     IReferenceClock *pClock = NULL;
769     HRESULT hr = S_OK;
770     int i;
771
772     TRACE("(%p/%p)->() live sources not handled properly!\n", iface, This);
773
774     EnterCriticalSection(&This->cs);
775
776     for (i = 0; i < This->nFilters; ++i)
777     {
778         DWORD miscflags;
779         IAMFilterMiscFlags *flags = NULL;
780         IUnknown_QueryInterface(This->ppFiltersInGraph[i], &IID_IAMFilterMiscFlags, (void**)&flags);
781         if (!flags)
782             continue;
783         miscflags = IAMFilterMiscFlags_GetMiscFlags(flags);
784         IUnknown_Release(flags);
785         if (miscflags == AM_FILTER_MISC_FLAGS_IS_RENDERER)
786             IUnknown_QueryInterface(This->ppFiltersInGraph[i], &IID_IReferenceClock, (void**)&pClock);
787         if (pClock)
788             break;
789     }
790
791     if (!pClock)
792     {
793         hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
794         This->refClockProvider = NULL;
795     }
796     else
797         This->refClockProvider = This->ppFiltersInGraph[i];
798
799     if (SUCCEEDED(hr))
800     {
801         hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
802         This->defaultclock = TRUE;
803         IReferenceClock_Release(pClock);
804     }
805     LeaveCriticalSection(&This->cs);
806
807     return hr;
808 }
809
810 static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
811 {
812     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
813     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
814     IPropertyBag * pPropBagCat = NULL;
815     HRESULT hr;
816
817     VariantInit(pvar);
818
819     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
820
821     if (SUCCEEDED(hr))
822         hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
823
824     if (SUCCEEDED(hr))
825         hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
826
827     VariantClear(pvar);
828
829     if (SUCCEEDED(hr))
830         hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
831
832     if (SUCCEEDED(hr))
833         TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
834
835     if (pPropBagCat)
836         IPropertyBag_Release(pPropBagCat);
837
838     return hr;
839 }
840
841 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
842 {
843     HRESULT hr;
844     ULONG nb = 0;
845
846     TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
847     hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
848     if (hr == S_OK) {
849         /* Rendered input */
850     } else if (hr == S_FALSE) {
851         *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
852         hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
853         if (hr != S_OK) {
854             WARN("Error (%x)\n", hr);
855         }
856     } else if (hr == E_NOTIMPL) {
857         /* Input connected to all outputs */
858         IEnumPins* penumpins;
859         IPin* ppin;
860         int i = 0;
861         TRACE("E_NOTIMPL\n");
862         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
863         if (FAILED(hr)) {
864             WARN("filter Enumpins failed (%x)\n", hr);
865             return hr;
866         }
867         i = 0;
868         /* Count output pins */
869         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
870             PIN_DIRECTION pindir;
871             IPin_QueryDirection(ppin, &pindir);
872             if (pindir == PINDIR_OUTPUT)
873                 i++;
874             IPin_Release(ppin);
875         }
876         *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
877         /* Retrieve output pins */
878         IEnumPins_Reset(penumpins);
879         i = 0;
880         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
881             PIN_DIRECTION pindir;
882             IPin_QueryDirection(ppin, &pindir);
883             if (pindir == PINDIR_OUTPUT)
884                 (*pppins)[i++] = ppin;
885             else
886                 IPin_Release(ppin);
887         }
888         IEnumPins_Release(penumpins);
889         nb = i;
890         if (FAILED(hr)) {
891             WARN("Next failed (%x)\n", hr);
892             return hr;
893         }
894     } else if (FAILED(hr)) {
895         WARN("Cannot get internal connection (%x)\n", hr);
896         return hr;
897     }
898
899     *pnb = nb;
900     return S_OK;
901 }
902
903 /*** IGraphBuilder methods ***/
904 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
905 {
906     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
907     HRESULT hr;
908     AM_MEDIA_TYPE* mt = NULL;
909     IEnumMediaTypes* penummt = NULL;
910     ULONG nbmt;
911     IEnumPins* penumpins;
912     IEnumMoniker* pEnumMoniker;
913     GUID tab[2];
914     ULONG nb;
915     IMoniker* pMoniker;
916     ULONG pin;
917     PIN_INFO PinInfo;
918     CLSID FilterCLSID;
919     PIN_DIRECTION dir;
920
921     TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
922
923     if (TRACE_ON(quartz))
924     {
925         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
926         if (FAILED(hr))
927             return hr;
928
929         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
930         IBaseFilter_Release(PinInfo.pFilter);
931
932         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
933         if (FAILED(hr))
934             return hr;
935
936         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
937         IBaseFilter_Release(PinInfo.pFilter);
938     }
939
940     EnterCriticalSection(&This->cs);
941     ++This->recursioncount;
942     if (This->recursioncount >= 5)
943     {
944         WARN("Recursion count has reached %d\n", This->recursioncount);
945         hr = VFW_E_CANNOT_CONNECT;
946         goto out;
947     }
948
949     hr = IPin_QueryDirection(ppinOut, &dir);
950     if (FAILED(hr))
951         goto out;
952
953     if (dir == PINDIR_INPUT)
954     {
955         IPin *temp;
956
957         temp = ppinIn;
958         ppinIn = ppinOut;
959         ppinOut = temp;
960     }
961
962     hr = CheckCircularConnection(This, ppinOut, ppinIn);
963     if (FAILED(hr))
964         goto out;
965
966     /* Try direct connection first */
967     hr = IPin_Connect(ppinOut, ppinIn, NULL);
968     if (SUCCEEDED(hr))
969         goto out;
970
971     TRACE("Direct connection failed, trying to render using extra filters\n");
972
973     hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
974     if (FAILED(hr))
975         goto out;
976
977     hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
978     IBaseFilter_Release(PinInfo.pFilter);
979     if (FAILED(hr))
980         goto out;
981
982     /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream 
983      * filter to the minor mediatype of input pin of the renderer */
984     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
985     if (FAILED(hr))
986     {
987         WARN("EnumMediaTypes (%x)\n", hr);
988         goto out;
989     }
990
991     hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
992     if (FAILED(hr)) {
993         WARN("IEnumMediaTypes_Next (%x)\n", hr);
994         goto out;
995     }
996
997     if (!nbmt)
998     {
999         WARN("No media type found!\n");
1000         hr = VFW_E_INVALIDMEDIATYPE;
1001         goto out;
1002     }
1003     TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1004     TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1005
1006     /* Try to find a suitable filter that can connect to the pin to render */
1007     tab[0] = mt->majortype;
1008     tab[1] = mt->subtype;
1009     hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1010     if (FAILED(hr)) {
1011         WARN("Unable to enum filters (%x)\n", hr);
1012         goto out;
1013     }
1014
1015     hr = VFW_E_CANNOT_RENDER;
1016     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1017     {
1018         VARIANT var;
1019         GUID clsid;
1020         IPin** ppins;
1021         IPin* ppinfilter = NULL;
1022         IBaseFilter* pfilter = NULL;
1023
1024         hr = GetFilterInfo(pMoniker, &clsid, &var);
1025         IMoniker_Release(pMoniker);
1026         if (FAILED(hr)) {
1027             WARN("Unable to retrieve filter info (%x)\n", hr);
1028             goto error;
1029         }
1030
1031         if (IsEqualGUID(&clsid, &FilterCLSID)) {
1032             /* Skip filter (same as the one the output pin belongs to) */
1033             goto error;
1034         }
1035
1036         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1037         if (FAILED(hr)) {
1038             WARN("Unable to create filter (%x), trying next one\n", hr);
1039             goto error;
1040         }
1041
1042         hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1043         if (FAILED(hr)) {
1044             WARN("Unable to add filter (%x)\n", hr);
1045             IBaseFilter_Release(pfilter);
1046             pfilter = NULL;
1047             goto error;
1048         }
1049
1050         VariantClear(&var);
1051
1052         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1053         if (FAILED(hr)) {
1054             WARN("Enumpins (%x)\n", hr);
1055             goto error;
1056         }
1057
1058         hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
1059         IEnumPins_Release(penumpins);
1060
1061         if (FAILED(hr)) {
1062             WARN("Obtaining next pin: (%x)\n", hr);
1063             goto error;
1064         }
1065         if (pin == 0) {
1066             WARN("Cannot use this filter: no pins\n");
1067             goto error;
1068         }
1069
1070         hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1071         if (FAILED(hr)) {
1072             TRACE("Cannot connect to filter (%x), trying next one\n", hr);
1073             goto error;
1074         }
1075         TRACE("Successfully connected to filter, follow chain...\n");
1076
1077         /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
1078         hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
1079
1080         if (SUCCEEDED(hr)) {
1081             unsigned int i;
1082             if (nb == 0) {
1083                 IPin_Disconnect(ppinfilter);
1084                 IPin_Disconnect(ppinOut);
1085                 goto error;
1086             }
1087             TRACE("pins to consider: %d\n", nb);
1088             for(i = 0; i < nb; i++)
1089             {
1090                 LPWSTR pinname = NULL;
1091
1092                 TRACE("Processing pin %u\n", i);
1093
1094                 hr = IPin_QueryId(ppins[i], &pinname);
1095                 if (SUCCEEDED(hr))
1096                 {
1097                     if (pinname[0] == '~')
1098                     {
1099                         TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
1100                         hr = E_FAIL;
1101                     }
1102                     else
1103                         hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
1104                     CoTaskMemFree(pinname);
1105                 }
1106
1107                 if (FAILED(hr)) {
1108                    TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
1109                 }
1110                 IPin_Release(ppins[i]);
1111                 if (SUCCEEDED(hr)) break;
1112             }
1113             while (++i < nb) IPin_Release(ppins[i]);
1114             CoTaskMemFree(ppins);
1115             IPin_Release(ppinfilter);
1116             IBaseFilter_Release(pfilter);
1117             if (FAILED(hr))
1118             {
1119                 IPin_Disconnect(ppinfilter);
1120                 IPin_Disconnect(ppinOut);
1121                 IFilterGraph2_RemoveFilter(iface, pfilter);
1122                 continue;
1123             }
1124             break;
1125         }
1126
1127 error:
1128         VariantClear(&var);
1129         if (ppinfilter) IPin_Release(ppinfilter);
1130         if (pfilter) {
1131             IFilterGraph2_RemoveFilter(iface, pfilter);
1132             IBaseFilter_Release(pfilter);
1133         }
1134     }
1135
1136 out:
1137     if (penummt)
1138         IEnumMediaTypes_Release(penummt);
1139     if (mt)
1140         DeleteMediaType(mt);
1141     --This->recursioncount;
1142     LeaveCriticalSection(&This->cs);
1143     TRACE("--> %08x\n", hr);
1144     return SUCCEEDED(hr) ? S_OK : hr;
1145 }
1146
1147 static HRESULT FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
1148 {
1149     /* This pin has been connected now, try to call render on all pins that aren't connected */
1150     IPin *to = NULL;
1151     PIN_INFO info;
1152     IEnumPins *enumpins = NULL;
1153     BOOL renderany = FALSE;
1154     BOOL renderall = TRUE;
1155
1156     IPin_QueryPinInfo(ppinOut, &info);
1157
1158     IBaseFilter_EnumPins(info.pFilter, &enumpins);
1159     /* Don't need to hold a reference, IEnumPins does */
1160     IBaseFilter_Release(info.pFilter);
1161
1162     IEnumPins_Reset(enumpins);
1163     while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK)
1164     {
1165         PIN_DIRECTION dir = PINDIR_INPUT;
1166
1167         IPin_QueryDirection(to, &dir);
1168
1169         if (dir == PINDIR_OUTPUT)
1170         {
1171             IPin *out = NULL;
1172
1173             IPin_ConnectedTo(to, &out);
1174             if (!out)
1175             {
1176                 HRESULT hr;
1177                 hr = IFilterGraph2_Render(&This->IFilterGraph2_iface, to);
1178                 if (SUCCEEDED(hr))
1179                     renderany = TRUE;
1180                 else
1181                     renderall = FALSE;
1182             }
1183             else
1184                 IPin_Release(out);
1185         }
1186
1187         IPin_Release(to);
1188     }
1189
1190     IEnumPins_Release(enumpins);
1191
1192     if (renderall)
1193         return S_OK;
1194
1195     if (renderany)
1196         return VFW_S_PARTIAL_RENDER;
1197
1198     return VFW_E_CANNOT_RENDER;
1199 }
1200
1201 /* Ogg hates me if I create a direct rendering method
1202  *
1203  * It can only connect to a pin properly once, so use a recursive method that does
1204  *
1205  *  +----+ --- (PIN 1) (Render is called on this pin)
1206  *  |    |
1207  *  +----+ --- (PIN 2)
1208  *
1209  *  Enumerate possible renderers that EXACTLY match the requested type
1210  *
1211  *  If none is available, try to add intermediate filters that can connect to the input pin
1212  *  then call Render on that intermediate pin's output pins
1213  *  if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
1214  *  and another filter that can connect to the input pin is tried
1215  *  if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
1216  *  It's recursive, but fun!
1217  */
1218
1219 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *ppinOut)
1220 {
1221     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1222     IEnumMediaTypes* penummt;
1223     AM_MEDIA_TYPE* mt;
1224     ULONG nbmt;
1225     HRESULT hr;
1226
1227     IEnumMoniker* pEnumMoniker;
1228     GUID tab[4];
1229     ULONG nb;
1230     IMoniker* pMoniker;
1231     INT x;
1232
1233     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
1234
1235     if (TRACE_ON(quartz))
1236     {
1237         PIN_INFO PinInfo;
1238
1239         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
1240         if (FAILED(hr))
1241             return hr;
1242
1243         TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
1244         IBaseFilter_Release(PinInfo.pFilter);
1245     }
1246
1247     /* Try to find out if there is a renderer for the specified subtype already, and use that
1248      */
1249     EnterCriticalSection(&This->cs);
1250     for (x = 0; x < This->nFilters; ++x)
1251     {
1252         IEnumPins *enumpins = NULL;
1253         IPin *pin = NULL;
1254
1255         hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
1256
1257         if (FAILED(hr) || !enumpins)
1258             continue;
1259
1260         IEnumPins_Reset(enumpins);
1261         while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
1262         {
1263             IPin *to = NULL;
1264             PIN_DIRECTION dir = PINDIR_OUTPUT;
1265
1266             IPin_QueryDirection(pin, &dir);
1267             if (dir != PINDIR_INPUT)
1268             {
1269                 IPin_Release(pin);
1270                 continue;
1271             }
1272             IPin_ConnectedTo(pin, &to);
1273
1274             if (to == NULL)
1275             {
1276                 hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
1277                 if (SUCCEEDED(hr))
1278                 {
1279                     TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
1280                     IPin_Release(pin);
1281
1282                     hr = FilterGraph2_RenderRecurse(This, pin);
1283                     if (FAILED(hr))
1284                     {
1285                         IPin_Disconnect(ppinOut);
1286                         IPin_Disconnect(pin);
1287                         continue;
1288                     }
1289                     IEnumPins_Release(enumpins);
1290                     LeaveCriticalSection(&This->cs);
1291                     return hr;
1292                 }
1293                 WARN("Could not connect!\n");
1294             }
1295             else
1296                 IPin_Release(to);
1297
1298             IPin_Release(pin);
1299         }
1300         IEnumPins_Release(enumpins);
1301     }
1302
1303     LeaveCriticalSection(&This->cs);
1304
1305     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
1306     if (FAILED(hr)) {
1307         WARN("EnumMediaTypes (%x)\n", hr);
1308         return hr;
1309     }
1310
1311     IEnumMediaTypes_Reset(penummt);
1312
1313     /* Looks like no existing renderer of the kind exists
1314      * Try adding new ones
1315      */
1316     tab[0] = tab[1] = GUID_NULL;
1317     while (SUCCEEDED(hr))
1318     {
1319         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
1320         if (FAILED(hr)) {
1321             WARN("IEnumMediaTypes_Next (%x)\n", hr);
1322             break;
1323         }
1324         if (!nbmt)
1325         {
1326             hr = VFW_E_CANNOT_RENDER;
1327             break;
1328         }
1329         else
1330         {
1331             TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1332             TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1333
1334             /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
1335             if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
1336             {
1337                 DeleteMediaType(mt);
1338                 continue;
1339             }
1340
1341             /* Try to find a suitable renderer with the same media type */
1342             tab[0] = mt->majortype;
1343             tab[1] = mt->subtype;
1344             hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1345             if (FAILED(hr))
1346             {
1347                 WARN("Unable to enum filters (%x)\n", hr);
1348                 break;
1349             }
1350         }
1351         hr = E_FAIL;
1352
1353         while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1354         {
1355             VARIANT var;
1356             GUID clsid;
1357             IPin* ppinfilter;
1358             IBaseFilter* pfilter = NULL;
1359             IEnumPins* penumpins = NULL;
1360             ULONG pin;
1361
1362             hr = GetFilterInfo(pMoniker, &clsid, &var);
1363             IMoniker_Release(pMoniker);
1364             if (FAILED(hr)) {
1365                 WARN("Unable to retrieve filter info (%x)\n", hr);
1366                 goto error;
1367             }
1368
1369             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1370             if (FAILED(hr))
1371             {
1372                 WARN("Unable to create filter (%x), trying next one\n", hr);
1373                 goto error;
1374             }
1375
1376             hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1377             if (FAILED(hr)) {
1378                 WARN("Unable to add filter (%x)\n", hr);
1379                 IBaseFilter_Release(pfilter);
1380                 pfilter = NULL;
1381                 goto error;
1382             }
1383
1384             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1385             if (FAILED(hr)) {
1386                 WARN("Splitter Enumpins (%x)\n", hr);
1387                 goto error;
1388             }
1389
1390             while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
1391             {
1392                 PIN_DIRECTION dir;
1393
1394                 if (pin == 0) {
1395                     WARN("No Pin\n");
1396                     hr = E_FAIL;
1397                     goto error;
1398                 }
1399
1400                 hr = IPin_QueryDirection(ppinfilter, &dir);
1401                 if (FAILED(hr)) {
1402                     IPin_Release(ppinfilter);
1403                     WARN("QueryDirection failed (%x)\n", hr);
1404                     goto error;
1405                 }
1406                 if (dir != PINDIR_INPUT) {
1407                     IPin_Release(ppinfilter);
1408                     continue; /* Wrong direction */
1409                 }
1410
1411                 /* Connect the pin to the "Renderer" */
1412                 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1413                 IPin_Release(ppinfilter);
1414
1415                 if (FAILED(hr)) {
1416                     WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_UNION(&var, bstrVal)), hr);
1417                     goto error;
1418                 }
1419                 TRACE("Connected, recursing %s\n",  debugstr_w(V_UNION(&var, bstrVal)));
1420
1421                 VariantClear(&var);
1422
1423                 hr = FilterGraph2_RenderRecurse(This, ppinfilter);
1424                 if (FAILED(hr)) {
1425                     WARN("Unable to connect recursively (%x)\n", hr);
1426                     goto error;
1427                 }
1428                 IBaseFilter_Release(pfilter);
1429                 break;
1430             }
1431             if (SUCCEEDED(hr)) {
1432                 IEnumPins_Release(penumpins);
1433                 break; /* out of IEnumMoniker_Next loop */
1434             }
1435
1436             /* IEnumPins_Next failed, all other failure case caught by goto error */
1437             WARN("IEnumPins_Next (%x)\n", hr);
1438             /* goto error */
1439
1440 error:
1441             VariantClear(&var);
1442             if (penumpins)
1443                 IEnumPins_Release(penumpins);
1444             if (pfilter) {
1445                 IFilterGraph2_RemoveFilter(iface, pfilter);
1446                 IBaseFilter_Release(pfilter);
1447             }
1448             if (SUCCEEDED(hr)) DebugBreak();
1449         }
1450
1451         IEnumMoniker_Release(pEnumMoniker);
1452         if (nbmt)
1453             DeleteMediaType(mt);
1454         if (SUCCEEDED(hr))
1455             break;
1456         hr = S_OK;
1457     }
1458
1459     IEnumMediaTypes_Release(penummt);
1460     return hr;
1461 }
1462
1463 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, LPCWSTR lpcwstrFile,
1464         LPCWSTR lpcwstrPlayList)
1465 {
1466     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1467     static const WCHAR string[] = {'R','e','a','d','e','r',0};
1468     IBaseFilter* preader = NULL;
1469     IPin* ppinreader = NULL;
1470     IEnumPins* penumpins = NULL;
1471     HRESULT hr;
1472     BOOL partial = FALSE;
1473     HRESULT any = FALSE;
1474
1475     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1476
1477     if (lpcwstrPlayList != NULL)
1478         return E_INVALIDARG;
1479
1480     hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
1481     if (FAILED(hr))
1482         return hr;
1483
1484     if (SUCCEEDED(hr))
1485         hr = IBaseFilter_EnumPins(preader, &penumpins);
1486     if (SUCCEEDED(hr))
1487     {
1488         while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1489         {
1490             PIN_DIRECTION dir;
1491
1492             IPin_QueryDirection(ppinreader, &dir);
1493             if (dir == PINDIR_OUTPUT)
1494             {
1495                 INT i;
1496
1497                 hr = IFilterGraph2_Render(iface, ppinreader);
1498                 TRACE("Render %08x\n", hr);
1499
1500                 for (i = 0; i < This->nFilters; ++i)
1501                     TRACE("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
1502
1503                 if (SUCCEEDED(hr))
1504                     any = TRUE;
1505                 if (hr != S_OK)
1506                     partial = TRUE;
1507             }
1508             IPin_Release(ppinreader);
1509         }
1510         IEnumPins_Release(penumpins);
1511
1512         if (!any)
1513             hr = VFW_E_CANNOT_RENDER;
1514         else if (partial)
1515             hr = VFW_S_PARTIAL_RENDER;
1516         else
1517             hr = S_OK;
1518     }
1519     IBaseFilter_Release(preader);
1520
1521     TRACE("--> %08x\n", hr);
1522     return hr;
1523 }
1524
1525 /* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
1526 static HRESULT GetFileSourceFilter(LPCOLESTR pszFileName, IBaseFilter **filter)
1527 {
1528     static const WCHAR wszReg[] = {'M','e','d','i','a',' ','T','y','p','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1529     HRESULT hr = S_OK;
1530     HKEY extkey;
1531     LONG lRet;
1532
1533     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszReg, 0, KEY_READ, &extkey);
1534     hr = HRESULT_FROM_WIN32(lRet);
1535
1536     if (SUCCEEDED(hr))
1537     {
1538         static const WCHAR filtersource[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
1539         WCHAR *ext = PathFindExtensionW(pszFileName);
1540         WCHAR clsid_key[39];
1541         GUID clsid;
1542         DWORD size = sizeof(clsid_key);
1543         HKEY pathkey;
1544
1545         if (!ext)
1546         {
1547             CloseHandle(extkey);
1548             return E_FAIL;
1549         }
1550
1551         lRet = RegOpenKeyExW(extkey, ext, 0, KEY_READ, &pathkey);
1552         hr = HRESULT_FROM_WIN32(lRet);
1553         CloseHandle(extkey);
1554         if (FAILED(hr))
1555             return hr;
1556
1557         lRet = RegQueryValueExW(pathkey, filtersource, NULL, NULL, (LPBYTE)clsid_key, &size);
1558         hr = HRESULT_FROM_WIN32(lRet);
1559         CloseHandle(pathkey);
1560         if (FAILED(hr))
1561             return hr;
1562
1563         CLSIDFromString(clsid_key, &clsid);
1564
1565         TRACE("CLSID: %s\n", debugstr_guid(&clsid));
1566         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1567         if (SUCCEEDED(hr))
1568         {
1569             IFileSourceFilter *source = NULL;
1570             hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
1571             if (SUCCEEDED(hr))
1572                 IFileSourceFilter_Release(source);
1573             else
1574                 IBaseFilter_Release(*filter);
1575         }
1576     }
1577     if (FAILED(hr))
1578         *filter = NULL;
1579     return hr;
1580 }
1581
1582 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface, LPCWSTR lpcwstrFileName,
1583         LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1584 {
1585     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1586     HRESULT hr;
1587     IBaseFilter* preader;
1588     IFileSourceFilter* pfile = NULL;
1589     AM_MEDIA_TYPE mt;
1590     WCHAR* filename;
1591
1592     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1593
1594     /* Try from file name first, then fall back to default asynchronous reader */
1595     hr = GetFileSourceFilter(lpcwstrFileName, &preader);
1596
1597     if (FAILED(hr))
1598         hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
1599     if (FAILED(hr)) {
1600         WARN("Unable to create file source filter (%x)\n", hr);
1601         return hr;
1602     }
1603
1604     hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
1605     if (FAILED(hr)) {
1606         WARN("Unable add filter (%x)\n", hr);
1607         IBaseFilter_Release(preader);
1608         return hr;
1609     }
1610
1611     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1612     if (FAILED(hr)) {
1613         WARN("Unable to get IFileSourceInterface (%x)\n", hr);
1614         goto error;
1615     }
1616
1617     /* Load the file in the file source filter */
1618     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
1619     if (FAILED(hr)) {
1620         WARN("Load (%x)\n", hr);
1621         goto error;
1622     }
1623
1624     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1625     if (FAILED(hr)) {
1626         WARN("GetCurFile (%x)\n", hr);
1627         goto error;
1628     }
1629
1630     TRACE("File %s\n", debugstr_w(filename));
1631     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1632     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1633
1634     if (ppFilter)
1635         *ppFilter = preader;
1636     IFileSourceFilter_Release(pfile);
1637
1638     return S_OK;
1639     
1640 error:
1641     if (pfile)
1642         IFileSourceFilter_Release(pfile);
1643     IFilterGraph2_RemoveFilter(iface, preader);
1644     IBaseFilter_Release(preader);
1645        
1646     return hr;
1647 }
1648
1649 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface, DWORD_PTR hFile)
1650 {
1651     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1652
1653     TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1654
1655     return S_OK;
1656 }
1657
1658 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface)
1659 {
1660     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1661
1662     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1663
1664     return S_OK;
1665 }
1666
1667 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface)
1668 {
1669     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1670
1671     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1672
1673     return S_OK;
1674 }
1675
1676 /*** IFilterGraph2 methods ***/
1677 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1678         IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1679 {
1680     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1681
1682     TRACE("(%p/%p)->(%p %p %s %p): stub !!!\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1683
1684     return S_OK;
1685 }
1686
1687 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *ppin,
1688         const AM_MEDIA_TYPE *pmt)
1689 {
1690     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1691
1692     TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
1693
1694     return S_OK;
1695 }
1696
1697 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *pPinOut, DWORD dwFlags,
1698         DWORD *pvContext)
1699 {
1700     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1701
1702     TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
1703
1704     return S_OK;
1705 }
1706
1707
1708 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1709 {
1710     FilterGraph2_QueryInterface,
1711     FilterGraph2_AddRef,
1712     FilterGraph2_Release,
1713     FilterGraph2_AddFilter,
1714     FilterGraph2_RemoveFilter,
1715     FilterGraph2_EnumFilters,
1716     FilterGraph2_FindFilterByName,
1717     FilterGraph2_ConnectDirect,
1718     FilterGraph2_Reconnect,
1719     FilterGraph2_Disconnect,
1720     FilterGraph2_SetDefaultSyncSource,
1721     FilterGraph2_Connect,
1722     FilterGraph2_Render,
1723     FilterGraph2_RenderFile,
1724     FilterGraph2_AddSourceFilter,
1725     FilterGraph2_SetLogFile,
1726     FilterGraph2_Abort,
1727     FilterGraph2_ShouldOperationContinue,
1728     FilterGraph2_AddSourceFilterForMoniker,
1729     FilterGraph2_ReconnectEx,
1730     FilterGraph2_RenderEx
1731 };
1732
1733 static inline IFilterGraphImpl *impl_from_IMediaControl(IMediaControl *iface)
1734 {
1735     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaControl_iface);
1736 }
1737
1738 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID riid, void **ppvObj)
1739 {
1740     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1741
1742     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1743
1744     return Filtergraph_QueryInterface(This, riid, ppvObj);
1745 }
1746
1747 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1748 {
1749     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1750
1751     TRACE("(%p/%p)->()\n", This, iface);
1752
1753     return Filtergraph_AddRef(This);
1754 }
1755
1756 static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1757 {
1758     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1759
1760     TRACE("(%p/%p)->()\n", This, iface);
1761
1762     return Filtergraph_Release(This);
1763
1764 }
1765
1766 /*** IDispatch methods ***/
1767 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *pctinfo)
1768 {
1769     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1770
1771     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1772
1773     return S_OK;
1774 }
1775
1776 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT iTInfo, LCID lcid,
1777         ITypeInfo **ppTInfo)
1778 {
1779     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1780
1781     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1782
1783     return S_OK;
1784 }
1785
1786 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID riid,
1787         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1788 {
1789     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1790
1791     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1792
1793     return S_OK;
1794 }
1795
1796 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMember, REFIID riid,
1797         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
1798         UINT *puArgErr)
1799 {
1800     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1801
1802     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1803
1804     return S_OK;
1805 }
1806
1807 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *, DWORD_PTR data);
1808
1809 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
1810 {
1811     HRESULT hr;
1812     IPin* pInputPin;
1813     IPin** ppPins;
1814     ULONG nb;
1815     ULONG i;
1816     PIN_INFO PinInfo;
1817
1818     TRACE("%p %p\n", pGraph, pOutputPin);
1819     PinInfo.pFilter = NULL;
1820
1821     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1822
1823     if (SUCCEEDED(hr))
1824     {
1825         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1826         if (SUCCEEDED(hr))
1827             hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1828         IPin_Release(pInputPin);
1829     }
1830
1831     if (SUCCEEDED(hr))
1832     {
1833         if (nb == 0)
1834         {
1835             TRACE("Reached a renderer\n");
1836             /* Count renderers for end of stream notification */
1837             pGraph->nRenderers++;
1838         }
1839         else
1840         {
1841             for(i = 0; i < nb; i++)
1842             {
1843                 /* Explore the graph downstream from this pin
1844                  * FIXME: We should prevent exploring from a pin more than once. This can happens when
1845                  * several input pins are connected to the same output (a MUX for instance). */
1846                 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
1847                 IPin_Release(ppPins[i]);
1848             }
1849
1850             CoTaskMemFree(ppPins);
1851         }
1852         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1853
1854         FoundFilter(PinInfo.pFilter, data);
1855     }
1856
1857     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1858     return hr;
1859 }
1860
1861 static HRESULT WINAPI SendRun(IBaseFilter *pFilter, DWORD_PTR data)
1862 {
1863     REFERENCE_TIME time = *(REFERENCE_TIME*)data;
1864     return IBaseFilter_Run(pFilter, time);
1865 }
1866
1867 static HRESULT WINAPI SendPause(IBaseFilter *pFilter, DWORD_PTR data)
1868 {
1869     return IBaseFilter_Pause(pFilter);
1870 }
1871
1872 static HRESULT WINAPI SendStop(IBaseFilter *pFilter, DWORD_PTR data)
1873 {
1874     return IBaseFilter_Stop(pFilter);
1875 }
1876
1877 static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data)
1878 {
1879     FILTER_STATE state;
1880     DWORD time_end = data;
1881     DWORD time_now = GetTickCount();
1882     LONG wait;
1883
1884     if (time_end == INFINITE)
1885     {
1886         wait = INFINITE;
1887     }
1888     else if (time_end > time_now)
1889     {
1890         wait = time_end - time_now;
1891     }
1892     else
1893         wait = 0;
1894
1895     return IBaseFilter_GetState(pFilter, wait, &state);
1896 }
1897
1898
1899 static HRESULT SendFilterMessage(IFilterGraphImpl *This, fnFoundFilter FoundFilter, DWORD_PTR data)
1900 {
1901     int i;
1902     IBaseFilter* pfilter;
1903     IEnumPins* pEnum;
1904     HRESULT hr;
1905     IPin* pPin;
1906     DWORD dummy;
1907     PIN_DIRECTION dir;
1908
1909     TRACE("(%p)->()\n", This);
1910
1911     /* Explorer the graph from source filters to renderers, determine renderers
1912      * number and run filters from renderers to source filters */
1913     This->nRenderers = 0;
1914     ResetEvent(This->hEventCompletion);
1915
1916     for(i = 0; i < This->nFilters; i++)
1917     {
1918         BOOL source = TRUE;
1919         pfilter = This->ppFiltersInGraph[i];
1920         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
1921         if (hr != S_OK)
1922         {
1923             WARN("Enum pins failed %x\n", hr);
1924             continue;
1925         }
1926         /* Check if it is a source filter */
1927         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1928         {
1929             IPin_QueryDirection(pPin, &dir);
1930             IPin_Release(pPin);
1931             if (dir == PINDIR_INPUT)
1932             {
1933                 source = FALSE;
1934                 break;
1935             }
1936         }
1937         if (source)
1938         {
1939             TRACE("Found a source filter %p\n", pfilter);
1940             IEnumPins_Reset(pEnum);
1941             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1942             {
1943                 /* Explore the graph downstream from this pin */
1944                 ExploreGraph(This, pPin, FoundFilter, data);
1945                 IPin_Release(pPin);
1946             }
1947             FoundFilter(pfilter, data);
1948         }
1949         IEnumPins_Release(pEnum);
1950     }
1951
1952     return S_FALSE;
1953 }
1954
1955 /*** IMediaControl methods ***/
1956 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
1957 {
1958     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1959
1960     TRACE("(%p/%p)->()\n", This, iface);
1961
1962     EnterCriticalSection(&This->cs);
1963     if (This->state == State_Running)
1964         goto out;
1965     This->EcCompleteCount = 0;
1966
1967     if (This->defaultclock && !This->refClock)
1968         IFilterGraph2_SetDefaultSyncSource((IFilterGraph2*)This);
1969
1970     if (This->refClock)
1971     {
1972         REFERENCE_TIME now;
1973         IReferenceClock_GetTime(This->refClock, &now);
1974         if (This->state == State_Stopped)
1975             This->start_time = now + 500000;
1976         else if (This->pause_time >= 0)
1977             This->start_time += now - This->pause_time;
1978         else
1979             This->start_time = now;
1980     }
1981     else This->start_time = 0;
1982
1983     SendFilterMessage(This, SendRun, (DWORD_PTR)&This->start_time);
1984     This->state = State_Running;
1985 out:
1986     LeaveCriticalSection(&This->cs);
1987     return S_FALSE;
1988 }
1989
1990 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
1991 {
1992     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1993
1994     TRACE("(%p/%p)->()\n", This, iface);
1995
1996     EnterCriticalSection(&This->cs);
1997     if (This->state == State_Paused)
1998         goto out;
1999
2000     if (This->state == State_Running && This->refClock && This->start_time >= 0)
2001         IReferenceClock_GetTime(This->refClock, &This->pause_time);
2002     else
2003         This->pause_time = -1;
2004
2005     SendFilterMessage(This, SendPause, 0);
2006     This->state = State_Paused;
2007 out:
2008     LeaveCriticalSection(&This->cs);
2009     return S_FALSE;
2010 }
2011
2012 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
2013 {
2014     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2015
2016     TRACE("(%p/%p)->()\n", This, iface);
2017
2018     if (This->state == State_Stopped) return S_OK;
2019
2020     EnterCriticalSection(&This->cs);
2021     if (This->state == State_Running) SendFilterMessage(This, SendPause, 0);
2022     SendFilterMessage(This, SendStop, 0);
2023     This->state = State_Stopped;
2024     LeaveCriticalSection(&This->cs);
2025     return S_OK;
2026 }
2027
2028 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG msTimeout,
2029         OAFilterState *pfs)
2030 {
2031     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2032     DWORD end;
2033
2034     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
2035
2036     if (!pfs)
2037         return E_POINTER;
2038
2039     EnterCriticalSection(&This->cs);
2040
2041     *pfs = This->state;
2042     if (msTimeout > 0)
2043     {
2044         end = GetTickCount() + msTimeout;
2045     }
2046     else if (msTimeout < 0)
2047     {
2048         end = INFINITE;
2049     }
2050     else
2051     {
2052         end = 0;
2053     }
2054     if (end)
2055         SendFilterMessage(This, SendGetState, end);
2056
2057     LeaveCriticalSection(&This->cs);
2058
2059     return S_OK;
2060 }
2061
2062 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
2063 {
2064     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2065
2066     FIXME("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
2067
2068     return S_OK;
2069 }
2070
2071 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
2072         IDispatch **ppUnk)
2073 {
2074     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2075
2076     FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
2077
2078     return S_OK;
2079 }
2080
2081 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2082 {
2083     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2084
2085     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2086
2087     return S_OK;
2088 }
2089
2090 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2091 {
2092     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2093
2094     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2095
2096     return S_OK;
2097 }
2098
2099 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2100 {
2101     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2102
2103     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2104
2105     return S_OK;
2106 }
2107
2108
2109 static const IMediaControlVtbl IMediaControl_VTable =
2110 {
2111     MediaControl_QueryInterface,
2112     MediaControl_AddRef,
2113     MediaControl_Release,
2114     MediaControl_GetTypeInfoCount,
2115     MediaControl_GetTypeInfo,
2116     MediaControl_GetIDsOfNames,
2117     MediaControl_Invoke,
2118     MediaControl_Run,
2119     MediaControl_Pause,
2120     MediaControl_Stop,
2121     MediaControl_GetState,
2122     MediaControl_RenderFile,
2123     MediaControl_AddSourceFilter,
2124     MediaControl_get_FilterCollection,
2125     MediaControl_get_RegFilterCollection,
2126     MediaControl_StopWhenReady
2127 };
2128
2129 static inline IFilterGraphImpl *impl_from_IMediaSeeking(IMediaSeeking *iface)
2130 {
2131     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaSeeking_iface);
2132 }
2133
2134 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface, REFIID riid, void **ppvObj)
2135 {
2136     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2137
2138     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2139
2140     return Filtergraph_QueryInterface(This, riid, ppvObj);
2141 }
2142
2143 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
2144 {
2145     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2146
2147     TRACE("(%p/%p)->()\n", This, iface);
2148
2149     return Filtergraph_AddRef(This);
2150 }
2151
2152 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
2153 {
2154     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2155
2156     TRACE("(%p/%p)->()\n", This, iface);
2157
2158     return Filtergraph_Release(This);
2159 }
2160
2161 typedef HRESULT (WINAPI *fnFoundSeek)(IFilterGraphImpl *This, IMediaSeeking*, DWORD_PTR arg);
2162
2163 static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2164     BOOL allnotimpl = TRUE;
2165     int i;
2166     HRESULT hr, hr_return = S_OK;
2167
2168     TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2169     /* Send a message to all renderers, they are responsible for broadcasting it further */
2170
2171     for(i = 0; i < This->nFilters; i++)
2172     {
2173         IMediaSeeking *seek = NULL;
2174         IBaseFilter* pfilter = This->ppFiltersInGraph[i];
2175         IAMFilterMiscFlags *flags = NULL;
2176         ULONG filterflags;
2177         IUnknown_QueryInterface(pfilter, &IID_IAMFilterMiscFlags, (void**)&flags);
2178         if (!flags)
2179             continue;
2180         filterflags = IAMFilterMiscFlags_GetMiscFlags(flags);
2181         IUnknown_Release(flags);
2182         if (filterflags != AM_FILTER_MISC_FLAGS_IS_RENDERER)
2183             continue;
2184
2185         IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
2186         if (!seek)
2187             continue;
2188         hr = FoundSeek(This, seek, arg);
2189         IMediaSeeking_Release(seek);
2190         if (hr_return != E_NOTIMPL)
2191             allnotimpl = FALSE;
2192         if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2193             hr_return = hr;
2194     }
2195
2196     if (allnotimpl)
2197         return E_NOTIMPL;
2198     return hr_return;
2199 }
2200
2201 static HRESULT WINAPI FoundCapabilities(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2202 {
2203     HRESULT hr;
2204     DWORD caps = 0;
2205
2206     hr = IMediaSeeking_GetCapabilities(seek, &caps);
2207     if (FAILED(hr))
2208         return hr;
2209
2210     /* Only add common capabilities everything supports */
2211     *(DWORD*)pcaps &= caps;
2212
2213     return hr;
2214 }
2215
2216 /*** IMediaSeeking methods ***/
2217 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2218 {
2219     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2220     HRESULT hr;
2221
2222     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2223
2224     if (!pCapabilities)
2225         return E_POINTER;
2226
2227     EnterCriticalSection(&This->cs);
2228     *pCapabilities = 0xffffffff;
2229
2230     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2231     LeaveCriticalSection(&This->cs);
2232
2233     return hr;
2234 }
2235
2236 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2237 {
2238     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2239     DWORD originalcaps;
2240     HRESULT hr;
2241
2242     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2243
2244     if (!pCapabilities)
2245         return E_POINTER;
2246
2247     EnterCriticalSection(&This->cs);
2248     originalcaps = *pCapabilities;
2249     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2250     LeaveCriticalSection(&This->cs);
2251
2252     if (FAILED(hr))
2253         return hr;
2254
2255     if (!*pCapabilities)
2256         return E_FAIL;
2257     if (*pCapabilities != originalcaps)
2258         return S_FALSE;
2259     return S_OK;
2260 }
2261
2262 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface, const GUID *pFormat)
2263 {
2264     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2265
2266     if (!pFormat)
2267         return E_POINTER;
2268
2269     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2270
2271     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2272     {
2273         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2274         return S_FALSE;
2275     }
2276
2277     return S_OK;
2278 }
2279
2280 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *pFormat)
2281 {
2282     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2283
2284     if (!pFormat)
2285         return E_POINTER;
2286
2287     FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2288     memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2289
2290     return S_OK;
2291 }
2292
2293 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface, GUID *pFormat)
2294 {
2295     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2296
2297     if (!pFormat)
2298         return E_POINTER;
2299
2300     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2301     memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2302
2303     return S_OK;
2304 }
2305
2306 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2307 {
2308     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2309
2310     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2311     if (!pFormat)
2312         return E_POINTER;
2313
2314     if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2315         return S_FALSE;
2316
2317     return S_OK;
2318 }
2319
2320 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2321 {
2322     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2323
2324     if (!pFormat)
2325         return E_POINTER;
2326
2327     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2328
2329     if (This->state != State_Stopped)
2330         return VFW_E_WRONG_STATE;
2331
2332     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2333     {
2334         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2335         return E_INVALIDARG;
2336     }
2337
2338     return S_OK;
2339 }
2340
2341 static HRESULT WINAPI FoundDuration(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pduration)
2342 {
2343     HRESULT hr;
2344     LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2345
2346     hr = IMediaSeeking_GetDuration(seek, &duration);
2347     if (FAILED(hr))
2348         return hr;
2349
2350     if (*pdur < duration)
2351         *pdur = duration;
2352     return hr;
2353 }
2354
2355 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface, LONGLONG *pDuration)
2356 {
2357     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2358     HRESULT hr;
2359
2360     TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2361
2362     if (!pDuration)
2363         return E_POINTER;
2364
2365     EnterCriticalSection(&This->cs);
2366     *pDuration = 0;
2367     hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
2368     LeaveCriticalSection(&This->cs);
2369
2370     TRACE("--->%08x\n", hr);
2371     return hr;
2372 }
2373
2374 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *pStop)
2375 {
2376     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2377     HRESULT hr = S_OK;
2378
2379     TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
2380
2381     if (!pStop)
2382         return E_POINTER;
2383
2384     EnterCriticalSection(&This->cs);
2385     if (This->stop_position < 0)
2386         /* Stop position not set, use duration instead */
2387         hr = IMediaSeeking_GetDuration(iface, pStop);
2388     else
2389         *pStop = This->stop_position;
2390     LeaveCriticalSection(&This->cs);
2391
2392     return hr;
2393 }
2394
2395 static HRESULT WINAPI FoundCurrentPosition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pposition)
2396 {
2397     HRESULT hr;
2398     LONGLONG pos = 0, *ppos = (LONGLONG*)pposition;
2399
2400     hr = IMediaSeeking_GetCurrentPosition(seek, &pos);
2401     if (FAILED(hr))
2402         return hr;
2403
2404     if (*ppos < 0 || pos < *ppos)
2405         *ppos = pos;
2406     return hr;
2407 }
2408
2409 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *pCurrent)
2410 {
2411     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2412     HRESULT hr;
2413
2414     if (!pCurrent)
2415         return E_POINTER;
2416
2417     EnterCriticalSection(&This->cs);
2418     *pCurrent = -1;
2419     hr = all_renderers_seek(This, FoundCurrentPosition, (DWORD_PTR)pCurrent);
2420     if (hr == E_NOTIMPL) {
2421         *pCurrent = 0;
2422         hr = S_OK;
2423     }
2424     LeaveCriticalSection(&This->cs);
2425
2426     TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
2427
2428     return hr;
2429 }
2430
2431 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
2432         const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2433 {
2434     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2435
2436     FIXME("(%p/%p)->(%p, %p, 0x%s, %p): stub !!!\n", This, iface, pTarget,
2437         pTargetFormat, wine_dbgstr_longlong(Source), pSourceFormat);
2438
2439     return S_OK;
2440 }
2441
2442 struct pos_args {
2443     LONGLONG* current, *stop;
2444     DWORD curflags, stopflags;
2445 };
2446
2447 static HRESULT WINAPI found_setposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
2448 {
2449     struct pos_args *args = (void*)pargs;
2450
2451     return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
2452 }
2453
2454 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
2455         DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
2456 {
2457     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2458     HRESULT hr = S_OK;
2459     FILTER_STATE state;
2460     struct pos_args args;
2461
2462     TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
2463
2464     EnterCriticalSection(&This->cs);
2465     state = This->state;
2466     TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
2467
2468     if ((dwCurrentFlags & 0x7) != AM_SEEKING_AbsolutePositioning &&
2469         (dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2470         FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
2471
2472     if ((dwStopFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
2473         This->stop_position = *pStop;
2474     else if ((dwStopFlags & 0x7) != AM_SEEKING_NoPositioning)
2475         FIXME("Stop position not handled yet!\n");
2476
2477     if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2478         IMediaControl_Pause(&This->IMediaControl_iface);
2479     args.current = pCurrent;
2480     args.stop = pStop;
2481     args.curflags = dwCurrentFlags;
2482     args.stopflags = dwStopFlags;
2483     hr = all_renderers_seek(This, found_setposition, (DWORD_PTR)&args);
2484
2485     if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2486         This->pause_time = This->start_time = -1;
2487     if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2488         IMediaControl_Run(&This->IMediaControl_iface);
2489     LeaveCriticalSection(&This->cs);
2490
2491     return hr;
2492 }
2493
2494 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
2495         LONGLONG *pStop)
2496 {
2497     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2498     HRESULT hr;
2499
2500     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
2501     hr = IMediaSeeking_GetCurrentPosition(iface, pCurrent);
2502     if (SUCCEEDED(hr))
2503         hr = IMediaSeeking_GetStopPosition(iface, pStop);
2504
2505     return hr;
2506 }
2507
2508 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, LONGLONG *pEarliest,
2509         LONGLONG *pLatest)
2510 {
2511     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2512
2513     FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2514
2515     return S_OK;
2516 }
2517
2518 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2519 {
2520     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2521
2522     FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2523
2524     return S_OK;
2525 }
2526
2527 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2528 {
2529     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2530
2531     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2532
2533     return S_OK;
2534 }
2535
2536 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
2537 {
2538     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2539
2540     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2541
2542     return S_OK;
2543 }
2544
2545
2546 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2547 {
2548     MediaSeeking_QueryInterface,
2549     MediaSeeking_AddRef,
2550     MediaSeeking_Release,
2551     MediaSeeking_GetCapabilities,
2552     MediaSeeking_CheckCapabilities,
2553     MediaSeeking_IsFormatSupported,
2554     MediaSeeking_QueryPreferredFormat,
2555     MediaSeeking_GetTimeFormat,
2556     MediaSeeking_IsUsingTimeFormat,
2557     MediaSeeking_SetTimeFormat,
2558     MediaSeeking_GetDuration,
2559     MediaSeeking_GetStopPosition,
2560     MediaSeeking_GetCurrentPosition,
2561     MediaSeeking_ConvertTimeFormat,
2562     MediaSeeking_SetPositions,
2563     MediaSeeking_GetPositions,
2564     MediaSeeking_GetAvailable,
2565     MediaSeeking_SetRate,
2566     MediaSeeking_GetRate,
2567     MediaSeeking_GetPreroll
2568 };
2569
2570 static inline IFilterGraphImpl *impl_from_IMediaPosition(IMediaPosition *iface)
2571 {
2572     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaPosition_iface);
2573 }
2574
2575 /*** IUnknown methods ***/
2576 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj)
2577 {
2578     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2579
2580     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2581     return Filtergraph_QueryInterface(This, riid, ppvObj);
2582 }
2583
2584 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2585 {
2586     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2587
2588     TRACE("(%p/%p)->()\n", This, iface);
2589     return Filtergraph_AddRef(This);
2590 }
2591
2592 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2593 {
2594     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2595
2596     TRACE("(%p/%p)->()\n", This, iface);
2597     return Filtergraph_Release(This);
2598 }
2599
2600 /*** IDispatch methods ***/
2601 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo){
2602     FIXME("(%p) stub!\n", iface);
2603     return E_NOTIMPL;
2604 }
2605
2606 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo){
2607     FIXME("(%p) stub!\n", iface);
2608     return E_NOTIMPL;
2609 }
2610
2611 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId){
2612     FIXME("(%p) stub!\n", iface);
2613     return E_NOTIMPL;
2614 }
2615
2616 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr){
2617     FIXME("(%p) stub!\n", iface);
2618     return E_NOTIMPL;
2619 }
2620
2621 static HRESULT ConvertFromREFTIME(IMediaSeeking *seek, REFTIME time_in, LONGLONG *time_out)
2622 {
2623     GUID time_format;
2624     HRESULT hr;
2625
2626     hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2627     if (FAILED(hr))
2628         return hr;
2629     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2630     {
2631         FIXME("Unsupported time format.\n");
2632         return E_NOTIMPL;
2633     }
2634
2635     *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2636     return S_OK;
2637 }
2638
2639 static HRESULT ConvertToREFTIME(IMediaSeeking *seek, LONGLONG time_in, REFTIME *time_out)
2640 {
2641     GUID time_format;
2642     HRESULT hr;
2643
2644     hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2645     if (FAILED(hr))
2646         return hr;
2647     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2648     {
2649         FIXME("Unsupported time format.\n");
2650         return E_NOTIMPL;
2651     }
2652
2653     *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2654     return S_OK;
2655 }
2656
2657 /*** IMediaPosition methods ***/
2658 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2659 {
2660     LONGLONG duration;
2661     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2662     HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2663     if (FAILED(hr))
2664         return hr;
2665     return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2666 }
2667
2668 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2669 {
2670     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2671     LONGLONG reftime;
2672     HRESULT hr;
2673
2674     hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2675     if (FAILED(hr))
2676         return hr;
2677     return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2678             AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
2679 }
2680
2681 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2682 {
2683     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2684     LONGLONG pos;
2685     HRESULT hr;
2686
2687     hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2688     if (FAILED(hr))
2689         return hr;
2690     return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2691 }
2692
2693 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2694 {
2695     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2696     LONGLONG pos;
2697     HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2698     if (FAILED(hr))
2699         return hr;
2700     return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2701 }
2702
2703 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2704 {
2705     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2706     LONGLONG reftime;
2707     HRESULT hr;
2708
2709     hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2710     if (FAILED(hr))
2711         return hr;
2712     return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2713             &reftime, AM_SEEKING_AbsolutePositioning);
2714 }
2715
2716 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){
2717     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2718     return E_NOTIMPL;
2719 }
2720
2721 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime){
2722     FIXME("(%p)->(%f) stub!\n", iface, llTime);
2723     return E_NOTIMPL;
2724 }
2725
2726 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2727 {
2728     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2729     return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2730 }
2731
2732 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2733 {
2734     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2735     return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2736 }
2737
2738 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){
2739     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2740     return E_NOTIMPL;
2741 }
2742
2743 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward){
2744     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2745     return E_NOTIMPL;
2746 }
2747
2748
2749 static const IMediaPositionVtbl IMediaPosition_VTable =
2750 {
2751     MediaPosition_QueryInterface,
2752     MediaPosition_AddRef,
2753     MediaPosition_Release,
2754     MediaPosition_GetTypeInfoCount,
2755     MediaPosition_GetTypeInfo,
2756     MediaPosition_GetIDsOfNames,
2757     MediaPosition_Invoke,
2758     MediaPosition_get_Duration,
2759     MediaPosition_put_CurrentPosition,
2760     MediaPosition_get_CurrentPosition,
2761     MediaPosition_get_StopTime,
2762     MediaPosition_put_StopTime,
2763     MediaPosition_get_PrerollTime,
2764     MediaPosition_put_PrerollTime,
2765     MediaPosition_put_Rate,
2766     MediaPosition_get_Rate,
2767     MediaPosition_CanSeekForward,
2768     MediaPosition_CanSeekBackward
2769 };
2770
2771 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
2772 {
2773     HRESULT hr = E_NOINTERFACE;
2774     int i;
2775     int entry;
2776
2777     /* Check if the interface type is already registered */
2778     for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2779         if (riid == pGraph->ItfCacheEntries[entry].riid)
2780         {
2781             if (pGraph->ItfCacheEntries[entry].iface)
2782             {
2783                 /* Return the interface if available */
2784                 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2785                 return S_OK;
2786             }
2787             break;
2788         }
2789
2790     if (entry >= MAX_ITF_CACHE_ENTRIES)
2791     {
2792         FIXME("Not enough space to store interface in the cache\n");
2793         return E_OUTOFMEMORY;
2794     }
2795
2796     /* Find a filter supporting the requested interface */
2797     for (i = 0; i < pGraph->nFilters; i++)
2798     {
2799         hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
2800         if (hr == S_OK)
2801         {
2802             pGraph->ItfCacheEntries[entry].riid = riid;
2803             pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
2804             pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2805             if (entry >= pGraph->nItfCacheEntries)
2806                 pGraph->nItfCacheEntries++;
2807             return S_OK;
2808         }
2809         if (hr != E_NOINTERFACE)
2810             return hr;
2811     }
2812
2813     return hr;
2814 }
2815
2816 static inline IFilterGraphImpl *impl_from_IBasicAudio(IBasicAudio *iface)
2817 {
2818     return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicAudio_iface);
2819 }
2820
2821 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID riid, void **ppvObj)
2822 {
2823     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2824
2825     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2826
2827     return Filtergraph_QueryInterface(This, riid, ppvObj);
2828 }
2829
2830 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
2831 {
2832     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2833
2834     TRACE("(%p/%p)->()\n", This, iface);
2835
2836     return Filtergraph_AddRef(This);
2837 }
2838
2839 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
2840 {
2841     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2842
2843     TRACE("(%p/%p)->()\n", This, iface);
2844
2845     return Filtergraph_Release(This);
2846 }
2847
2848 /*** IDispatch methods ***/
2849 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *pctinfo)
2850 {
2851     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2852     IBasicAudio* pBasicAudio;
2853     HRESULT hr;
2854
2855     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
2856
2857     EnterCriticalSection(&This->cs);
2858
2859     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2860
2861     if (hr == S_OK)
2862         hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
2863
2864     LeaveCriticalSection(&This->cs);
2865
2866     return hr;
2867 }
2868
2869 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface, UINT iTInfo, LCID lcid,
2870         ITypeInfo **ppTInfo)
2871 {
2872     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2873     IBasicAudio* pBasicAudio;
2874     HRESULT hr;
2875
2876     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
2877
2878     EnterCriticalSection(&This->cs);
2879
2880     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2881
2882     if (hr == S_OK)
2883         hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
2884
2885     LeaveCriticalSection(&This->cs);
2886
2887     return hr;
2888 }
2889
2890 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface, REFIID riid, LPOLESTR *rgszNames,
2891         UINT cNames, LCID lcid, DISPID *rgDispId)
2892 {
2893     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2894     IBasicAudio* pBasicAudio;
2895     HRESULT hr;
2896
2897     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2898
2899     EnterCriticalSection(&This->cs);
2900
2901     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2902
2903     if (hr == S_OK)
2904         hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
2905
2906     LeaveCriticalSection(&This->cs);
2907
2908     return hr;
2909 }
2910
2911 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface, DISPID dispIdMember, REFIID riid,
2912         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
2913         UINT *puArgErr)
2914 {
2915     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2916     IBasicAudio* pBasicAudio;
2917     HRESULT hr;
2918
2919     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2920
2921     EnterCriticalSection(&This->cs);
2922
2923     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2924
2925     if (hr == S_OK)
2926         hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2927
2928     LeaveCriticalSection(&This->cs);
2929
2930     return hr;
2931 }
2932
2933 /*** IBasicAudio methods ***/
2934 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface, LONG lVolume)
2935 {
2936     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2937     IBasicAudio* pBasicAudio;
2938     HRESULT hr;
2939
2940     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
2941
2942     EnterCriticalSection(&This->cs);
2943
2944     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2945
2946     if (hr == S_OK)
2947         hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2948
2949     LeaveCriticalSection(&This->cs);
2950
2951     return hr;
2952 }
2953
2954 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface, LONG *plVolume)
2955 {
2956     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2957     IBasicAudio* pBasicAudio;
2958     HRESULT hr;
2959
2960     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
2961
2962     EnterCriticalSection(&This->cs);
2963
2964     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2965
2966     if (hr == S_OK)
2967         hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
2968
2969     LeaveCriticalSection(&This->cs);
2970
2971     return hr;
2972 }
2973
2974 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface, LONG lBalance)
2975 {
2976     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2977     IBasicAudio* pBasicAudio;
2978     HRESULT hr;
2979
2980     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
2981
2982     EnterCriticalSection(&This->cs);
2983
2984     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2985
2986     if (hr == S_OK)
2987         hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
2988
2989     LeaveCriticalSection(&This->cs);
2990
2991     return hr;
2992 }
2993
2994 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface, LONG *plBalance)
2995 {
2996     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2997     IBasicAudio* pBasicAudio;
2998     HRESULT hr;
2999
3000     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
3001
3002     EnterCriticalSection(&This->cs);
3003
3004     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3005
3006     if (hr == S_OK)
3007         hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
3008
3009     LeaveCriticalSection(&This->cs);
3010
3011     return hr;
3012 }
3013
3014 static const IBasicAudioVtbl IBasicAudio_VTable =
3015 {
3016     BasicAudio_QueryInterface,
3017     BasicAudio_AddRef,
3018     BasicAudio_Release,
3019     BasicAudio_GetTypeInfoCount,
3020     BasicAudio_GetTypeInfo,
3021     BasicAudio_GetIDsOfNames,
3022     BasicAudio_Invoke,
3023     BasicAudio_put_Volume,
3024     BasicAudio_get_Volume,
3025     BasicAudio_put_Balance,
3026     BasicAudio_get_Balance
3027 };
3028
3029 static inline IFilterGraphImpl *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3030 {
3031     return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicVideo2_iface);
3032 }
3033
3034 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface, REFIID riid, void **ppvObj)
3035 {
3036     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3037
3038     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3039
3040     return Filtergraph_QueryInterface(This, riid, ppvObj);
3041 }
3042
3043 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface)
3044 {
3045     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3046
3047     TRACE("(%p/%p)->()\n", This, iface);
3048
3049     return Filtergraph_AddRef(This);
3050 }
3051
3052 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface)
3053 {
3054     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3055
3056     TRACE("(%p/%p)->()\n", This, iface);
3057
3058     return Filtergraph_Release(This);
3059 }
3060
3061 /*** IDispatch methods ***/
3062 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface, UINT *pctinfo)
3063 {
3064     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3065     IBasicVideo *pBasicVideo;
3066     HRESULT hr;
3067
3068     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3069
3070     EnterCriticalSection(&This->cs);
3071
3072     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3073
3074     if (hr == S_OK)
3075         hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
3076
3077     LeaveCriticalSection(&This->cs);
3078
3079     return hr;
3080 }
3081
3082 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface, UINT iTInfo, LCID lcid,
3083         ITypeInfo **ppTInfo)
3084 {
3085     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3086     IBasicVideo *pBasicVideo;
3087     HRESULT hr;
3088
3089     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3090
3091     EnterCriticalSection(&This->cs);
3092
3093     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3094
3095     if (hr == S_OK)
3096         hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
3097
3098     LeaveCriticalSection(&This->cs);
3099
3100     return hr;
3101 }
3102
3103 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface, REFIID riid,
3104         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
3105 {
3106     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3107     IBasicVideo *pBasicVideo;
3108     HRESULT hr;
3109
3110     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3111
3112     EnterCriticalSection(&This->cs);
3113
3114     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3115
3116     if (hr == S_OK)
3117         hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
3118
3119     LeaveCriticalSection(&This->cs);
3120
3121     return hr;
3122 }
3123
3124 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface, DISPID dispIdMember, REFIID riid,
3125         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
3126         UINT *puArgErr)
3127 {
3128     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3129     IBasicVideo *pBasicVideo;
3130     HRESULT hr;
3131
3132     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3133
3134     EnterCriticalSection(&This->cs);
3135
3136     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3137
3138     if (hr == S_OK)
3139         hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3140
3141     LeaveCriticalSection(&This->cs);
3142
3143     return hr;
3144 }
3145
3146 /*** IBasicVideo methods ***/
3147 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface, REFTIME *pAvgTimePerFrame)
3148 {
3149     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3150     IBasicVideo *pBasicVideo;
3151     HRESULT hr;
3152
3153     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3154
3155     EnterCriticalSection(&This->cs);
3156
3157     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3158
3159     if (hr == S_OK)
3160         hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3161
3162     LeaveCriticalSection(&This->cs);
3163
3164     return hr;
3165 }
3166
3167 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface, LONG *pBitRate)
3168 {
3169     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3170     IBasicVideo *pBasicVideo;
3171     HRESULT hr;
3172
3173     TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3174
3175     EnterCriticalSection(&This->cs);
3176
3177     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3178
3179     if (hr == S_OK)
3180         hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3181
3182     LeaveCriticalSection(&This->cs);
3183
3184     return hr;
3185 }
3186
3187 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface, LONG *pBitErrorRate)
3188 {
3189     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3190     IBasicVideo *pBasicVideo;
3191     HRESULT hr;
3192
3193     TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3194
3195     EnterCriticalSection(&This->cs);
3196
3197     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3198
3199     if (hr == S_OK)
3200         hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3201
3202     LeaveCriticalSection(&This->cs);
3203
3204     return hr;
3205 }
3206
3207 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface, LONG *pVideoWidth)
3208 {
3209     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3210     IBasicVideo *pBasicVideo;
3211     HRESULT hr;
3212
3213     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3214
3215     EnterCriticalSection(&This->cs);
3216
3217     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3218
3219     if (hr == S_OK)
3220         hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3221
3222     LeaveCriticalSection(&This->cs);
3223
3224     return hr;
3225 }
3226
3227 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface, LONG *pVideoHeight)
3228 {
3229     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3230     IBasicVideo *pBasicVideo;
3231     HRESULT hr;
3232
3233     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3234
3235     EnterCriticalSection(&This->cs);
3236
3237     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3238
3239     if (hr == S_OK)
3240         hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3241
3242     LeaveCriticalSection(&This->cs);
3243
3244     return hr;
3245 }
3246
3247 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface, LONG SourceLeft)
3248 {
3249     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3250     IBasicVideo *pBasicVideo;
3251     HRESULT hr;
3252
3253     TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
3254
3255     EnterCriticalSection(&This->cs);
3256
3257     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3258
3259     if (hr == S_OK)
3260         hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3261
3262     LeaveCriticalSection(&This->cs);
3263
3264     return hr;
3265 }
3266
3267 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface, LONG *pSourceLeft)
3268 {
3269     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3270     IBasicVideo *pBasicVideo;
3271     HRESULT hr;
3272
3273     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3274
3275     EnterCriticalSection(&This->cs);
3276
3277     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3278
3279     if (hr == S_OK)
3280         hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3281
3282     LeaveCriticalSection(&This->cs);
3283
3284     return hr;
3285 }
3286
3287 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface, LONG SourceWidth)
3288 {
3289     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3290     IBasicVideo *pBasicVideo;
3291     HRESULT hr;
3292
3293     TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
3294
3295     EnterCriticalSection(&This->cs);
3296
3297     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3298
3299     if (hr == S_OK)
3300         hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3301
3302     LeaveCriticalSection(&This->cs);
3303
3304     return hr;
3305 }
3306
3307 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface, LONG *pSourceWidth)
3308 {
3309     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3310     IBasicVideo *pBasicVideo;
3311     HRESULT hr;
3312
3313     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3314
3315     EnterCriticalSection(&This->cs);
3316
3317     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3318
3319     if (hr == S_OK)
3320         hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3321
3322     LeaveCriticalSection(&This->cs);
3323
3324     return hr;
3325 }
3326
3327 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface, LONG SourceTop)
3328 {
3329     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3330     IBasicVideo *pBasicVideo;
3331     HRESULT hr;
3332
3333     TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
3334
3335     EnterCriticalSection(&This->cs);
3336
3337     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3338
3339     if (hr == S_OK)
3340         hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3341
3342     LeaveCriticalSection(&This->cs);
3343
3344     return hr;
3345 }
3346
3347 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface, LONG *pSourceTop)
3348 {
3349     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3350     IBasicVideo *pBasicVideo;
3351     HRESULT hr;
3352
3353     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3354
3355     EnterCriticalSection(&This->cs);
3356
3357     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3358
3359     if (hr == S_OK)
3360         hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3361
3362     LeaveCriticalSection(&This->cs);
3363
3364     return hr;
3365 }
3366
3367 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface, LONG SourceHeight)
3368 {
3369     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3370     IBasicVideo *pBasicVideo;
3371     HRESULT hr;
3372
3373     TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
3374
3375     EnterCriticalSection(&This->cs);
3376
3377     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3378
3379     if (hr == S_OK)
3380         hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3381
3382     LeaveCriticalSection(&This->cs);
3383
3384     return hr;
3385 }
3386
3387 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface, LONG *pSourceHeight)
3388 {
3389     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3390     IBasicVideo *pBasicVideo;
3391     HRESULT hr;
3392
3393     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3394
3395     EnterCriticalSection(&This->cs);
3396
3397     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3398
3399     if (hr == S_OK)
3400         hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3401
3402     LeaveCriticalSection(&This->cs);
3403
3404     return hr;
3405 }
3406
3407 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface, LONG DestinationLeft)
3408 {
3409     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3410     IBasicVideo *pBasicVideo;
3411     HRESULT hr;
3412
3413     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
3414
3415     EnterCriticalSection(&This->cs);
3416
3417     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3418
3419     if (hr == S_OK)
3420         hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3421
3422     LeaveCriticalSection(&This->cs);
3423
3424     return hr;
3425 }
3426
3427 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface, LONG *pDestinationLeft)
3428 {
3429     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3430     IBasicVideo *pBasicVideo;
3431     HRESULT hr;
3432
3433     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3434
3435     EnterCriticalSection(&This->cs);
3436
3437     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3438
3439     if (hr == S_OK)
3440         hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3441
3442     LeaveCriticalSection(&This->cs);
3443
3444     return hr;
3445 }
3446
3447 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface, LONG DestinationWidth)
3448 {
3449     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3450     IBasicVideo *pBasicVideo;
3451     HRESULT hr;
3452
3453     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
3454
3455     EnterCriticalSection(&This->cs);
3456
3457     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3458
3459     if (hr == S_OK)
3460         hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3461
3462     LeaveCriticalSection(&This->cs);
3463
3464     return hr;
3465 }
3466
3467 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface, LONG *pDestinationWidth)
3468 {
3469     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3470     IBasicVideo *pBasicVideo;
3471     HRESULT hr;
3472
3473     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3474
3475     EnterCriticalSection(&This->cs);
3476
3477     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3478
3479     if (hr == S_OK)
3480         hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3481
3482     LeaveCriticalSection(&This->cs);
3483
3484     return hr;
3485 }
3486
3487 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface, LONG DestinationTop)
3488 {
3489     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3490     IBasicVideo *pBasicVideo;
3491     HRESULT hr;
3492
3493     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
3494
3495     EnterCriticalSection(&This->cs);
3496
3497     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3498
3499     if (hr == S_OK)
3500         hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3501
3502     LeaveCriticalSection(&This->cs);
3503
3504     return hr;
3505 }
3506
3507 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface, LONG *pDestinationTop)
3508 {
3509     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3510     IBasicVideo *pBasicVideo;
3511     HRESULT hr;
3512
3513     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3514
3515     EnterCriticalSection(&This->cs);
3516
3517     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3518
3519     if (hr == S_OK)
3520         hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3521
3522     LeaveCriticalSection(&This->cs);
3523
3524     return hr;
3525 }
3526
3527 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface, LONG DestinationHeight)
3528 {
3529     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3530     IBasicVideo *pBasicVideo;
3531     HRESULT hr;
3532
3533     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
3534
3535     EnterCriticalSection(&This->cs);
3536
3537     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3538
3539     if (hr == S_OK)
3540         hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3541
3542     LeaveCriticalSection(&This->cs);
3543
3544     return hr;
3545 }
3546
3547 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3548         LONG *pDestinationHeight)
3549 {
3550     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3551     IBasicVideo *pBasicVideo;
3552     HRESULT hr;
3553
3554     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3555
3556     EnterCriticalSection(&This->cs);
3557
3558     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3559
3560     if (hr == S_OK)
3561         hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3562
3563     LeaveCriticalSection(&This->cs);
3564
3565     return hr;
3566 }
3567
3568 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3569         LONG Width, LONG Height)
3570 {
3571     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3572     IBasicVideo *pBasicVideo;
3573     HRESULT hr;
3574
3575     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3576
3577     EnterCriticalSection(&This->cs);
3578
3579     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3580
3581     if (hr == S_OK)
3582         hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3583
3584     LeaveCriticalSection(&This->cs);
3585
3586     return hr;
3587 }
3588
3589 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface, LONG *pLeft, LONG *pTop,
3590         LONG *pWidth, LONG *pHeight)
3591 {
3592     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3593     IBasicVideo *pBasicVideo;
3594     HRESULT hr;
3595
3596     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3597
3598     EnterCriticalSection(&This->cs);
3599
3600     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3601
3602     if (hr == S_OK)
3603         hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3604
3605     LeaveCriticalSection(&This->cs);
3606
3607     return hr;
3608 }
3609
3610 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface)
3611 {
3612     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3613     IBasicVideo *pBasicVideo;
3614     HRESULT hr;
3615
3616     TRACE("(%p/%p)->()\n", This, iface);
3617
3618     EnterCriticalSection(&This->cs);
3619
3620     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3621
3622     if (hr == S_OK)
3623         hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3624
3625     LeaveCriticalSection(&This->cs);
3626
3627     return hr;
3628 }
3629
3630 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3631         LONG Width, LONG Height)
3632 {
3633     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3634     IBasicVideo *pBasicVideo;
3635     HRESULT hr;
3636
3637     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3638
3639     EnterCriticalSection(&This->cs);
3640
3641     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3642
3643     if (hr == S_OK)
3644         hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3645
3646     LeaveCriticalSection(&This->cs);
3647
3648     return hr;
3649 }
3650
3651 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface, LONG *pLeft,
3652         LONG *pTop, LONG *pWidth, LONG *pHeight)
3653 {
3654     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3655     IBasicVideo *pBasicVideo;
3656     HRESULT hr;
3657
3658     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3659
3660     EnterCriticalSection(&This->cs);
3661
3662     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3663
3664     if (hr == S_OK)
3665         hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3666
3667     LeaveCriticalSection(&This->cs);
3668
3669     return hr;
3670 }
3671
3672 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface)
3673 {
3674     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3675     IBasicVideo *pBasicVideo;
3676     HRESULT hr;
3677
3678     TRACE("(%p/%p)->()\n", This, iface);
3679
3680     EnterCriticalSection(&This->cs);
3681
3682     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3683
3684     if (hr == S_OK)
3685         hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3686
3687     LeaveCriticalSection(&This->cs);
3688
3689     return hr;
3690 }
3691
3692 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface, LONG *pWidth, LONG *pHeight)
3693 {
3694     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3695     IBasicVideo *pBasicVideo;
3696     HRESULT hr;
3697
3698     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3699
3700     EnterCriticalSection(&This->cs);
3701
3702     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3703
3704     if (hr == S_OK)
3705         hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3706
3707     LeaveCriticalSection(&This->cs);
3708
3709     return hr;
3710 }
3711
3712 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface, LONG StartIndex,
3713         LONG Entries, LONG *pRetrieved, LONG *pPalette)
3714 {
3715     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3716     IBasicVideo *pBasicVideo;
3717     HRESULT hr;
3718
3719     TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3720
3721     EnterCriticalSection(&This->cs);
3722
3723     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3724
3725     if (hr == S_OK)
3726         hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3727
3728     LeaveCriticalSection(&This->cs);
3729
3730     return hr;
3731 }
3732
3733 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface, LONG *pBufferSize,
3734         LONG *pDIBImage)
3735 {
3736     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3737     IBasicVideo *pBasicVideo;
3738     HRESULT hr;
3739
3740     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3741
3742     EnterCriticalSection(&This->cs);
3743
3744     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3745
3746     if (hr == S_OK)
3747         hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3748
3749     LeaveCriticalSection(&This->cs);
3750
3751     return hr;
3752 }
3753
3754 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface)
3755 {
3756     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3757     IBasicVideo *pBasicVideo;
3758     HRESULT hr;
3759
3760     TRACE("(%p/%p)->()\n", This, iface);
3761
3762     EnterCriticalSection(&This->cs);
3763
3764     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3765
3766     if (hr == S_OK)
3767         hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3768
3769     LeaveCriticalSection(&This->cs);
3770
3771     return hr;
3772 }
3773
3774 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface)
3775 {
3776     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3777     IBasicVideo *pBasicVideo;
3778     HRESULT hr;
3779
3780     TRACE("(%p/%p)->()\n", This, iface);
3781
3782     EnterCriticalSection(&This->cs);
3783
3784     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3785
3786     if (hr == S_OK)
3787         hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3788
3789     LeaveCriticalSection(&This->cs);
3790
3791     return hr;
3792 }
3793
3794 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX,
3795         LONG *plAspectY)
3796 {
3797     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3798     IBasicVideo2 *pBasicVideo2;
3799     HRESULT hr;
3800
3801     TRACE("(%p/%p)->()\n", This, iface);
3802
3803     EnterCriticalSection(&This->cs);
3804
3805     hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3806
3807     if (hr == S_OK)
3808         hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3809
3810     LeaveCriticalSection(&This->cs);
3811
3812     return hr;
3813 }
3814
3815 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3816 {
3817     BasicVideo_QueryInterface,
3818     BasicVideo_AddRef,
3819     BasicVideo_Release,
3820     BasicVideo_GetTypeInfoCount,
3821     BasicVideo_GetTypeInfo,
3822     BasicVideo_GetIDsOfNames,
3823     BasicVideo_Invoke,
3824     BasicVideo_get_AvgTimePerFrame,
3825     BasicVideo_get_BitRate,
3826     BasicVideo_get_BitErrorRate,
3827     BasicVideo_get_VideoWidth,
3828     BasicVideo_get_VideoHeight,
3829     BasicVideo_put_SourceLeft,
3830     BasicVideo_get_SourceLeft,
3831     BasicVideo_put_SourceWidth,
3832     BasicVideo_get_SourceWidth,
3833     BasicVideo_put_SourceTop,
3834     BasicVideo_get_SourceTop,
3835     BasicVideo_put_SourceHeight,
3836     BasicVideo_get_SourceHeight,
3837     BasicVideo_put_DestinationLeft,
3838     BasicVideo_get_DestinationLeft,
3839     BasicVideo_put_DestinationWidth,
3840     BasicVideo_get_DestinationWidth,
3841     BasicVideo_put_DestinationTop,
3842     BasicVideo_get_DestinationTop,
3843     BasicVideo_put_DestinationHeight,
3844     BasicVideo_get_DestinationHeight,
3845     BasicVideo_SetSourcePosition,
3846     BasicVideo_GetSourcePosition,
3847     BasicVideo_SetDefaultSourcePosition,
3848     BasicVideo_SetDestinationPosition,
3849     BasicVideo_GetDestinationPosition,
3850     BasicVideo_SetDefaultDestinationPosition,
3851     BasicVideo_GetVideoSize,
3852     BasicVideo_GetVideoPaletteEntries,
3853     BasicVideo_GetCurrentImage,
3854     BasicVideo_IsUsingDefaultSource,
3855     BasicVideo_IsUsingDefaultDestination,
3856     BasicVideo2_GetPreferredAspectRatio
3857 };
3858
3859 static inline IFilterGraphImpl *impl_from_IVideoWindow(IVideoWindow *iface)
3860 {
3861     return CONTAINING_RECORD(iface, IFilterGraphImpl, IVideoWindow_iface);
3862 }
3863
3864 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID riid, void **ppvObj)
3865 {
3866     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3867
3868     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3869
3870     return Filtergraph_QueryInterface(This, riid, ppvObj);
3871 }
3872
3873 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
3874 {
3875     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3876
3877     TRACE("(%p/%p)->()\n", This, iface);
3878
3879     return Filtergraph_AddRef(This);
3880 }
3881
3882 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
3883 {
3884     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3885
3886     TRACE("(%p/%p)->()\n", This, iface);
3887
3888     return Filtergraph_Release(This);
3889 }
3890
3891 /*** IDispatch methods ***/
3892 static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface, UINT *pctinfo)
3893 {
3894     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3895     IVideoWindow *pVideoWindow;
3896     HRESULT hr;
3897
3898     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3899
3900     EnterCriticalSection(&This->cs);
3901
3902     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3903
3904     if (hr == S_OK)
3905         hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
3906
3907     LeaveCriticalSection(&This->cs);
3908
3909     return hr;
3910 }
3911
3912 static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface, UINT iTInfo, LCID lcid,
3913         ITypeInfo **ppTInfo)
3914 {
3915     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3916     IVideoWindow *pVideoWindow;
3917     HRESULT hr;
3918
3919     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3920
3921     EnterCriticalSection(&This->cs);
3922
3923     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3924
3925     if (hr == S_OK)
3926         hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
3927
3928     LeaveCriticalSection(&This->cs);
3929
3930     return hr;
3931 }
3932
3933 static HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface, REFIID riid,
3934         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
3935 {
3936     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3937     IVideoWindow *pVideoWindow;
3938     HRESULT hr;
3939
3940     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3941
3942     EnterCriticalSection(&This->cs);
3943
3944     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3945
3946     if (hr == S_OK)
3947         hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
3948
3949     LeaveCriticalSection(&This->cs);
3950
3951     return hr;
3952 }
3953
3954 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface, DISPID dispIdMember, REFIID riid,
3955         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
3956         UINT*puArgErr)
3957 {
3958     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3959     IVideoWindow *pVideoWindow;
3960     HRESULT hr;
3961
3962     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3963
3964     EnterCriticalSection(&This->cs);
3965
3966     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3967
3968     if (hr == S_OK)
3969         hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3970
3971     LeaveCriticalSection(&This->cs);
3972
3973     return hr;
3974 }
3975
3976
3977 /*** IVideoWindow methods ***/
3978 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface, BSTR strCaption)
3979 {
3980     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3981     IVideoWindow *pVideoWindow;
3982     HRESULT hr;
3983     
3984     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3985
3986     EnterCriticalSection(&This->cs);
3987
3988     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3989
3990     if (hr == S_OK)
3991         hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3992
3993     LeaveCriticalSection(&This->cs);
3994
3995     return hr;
3996 }
3997
3998 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface, BSTR *strCaption)
3999 {
4000     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4001     IVideoWindow *pVideoWindow;
4002     HRESULT hr;
4003
4004     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
4005
4006     EnterCriticalSection(&This->cs);
4007
4008     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4009
4010     if (hr == S_OK)
4011         hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
4012
4013     LeaveCriticalSection(&This->cs);
4014
4015     return hr;
4016 }
4017
4018 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle)
4019 {
4020     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4021     IVideoWindow *pVideoWindow;
4022     HRESULT hr;
4023
4024     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
4025
4026     EnterCriticalSection(&This->cs);
4027
4028     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4029
4030     if (hr == S_OK)
4031         hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
4032
4033     LeaveCriticalSection(&This->cs);
4034
4035     return hr;
4036 }
4037
4038 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface, LONG *WindowStyle)
4039 {
4040     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4041     IVideoWindow *pVideoWindow;
4042     HRESULT hr;
4043
4044     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
4045
4046     EnterCriticalSection(&This->cs);
4047
4048     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4049
4050     if (hr == S_OK)
4051         hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
4052
4053     LeaveCriticalSection(&This->cs);
4054
4055     return hr;
4056 }
4057
4058 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx)
4059 {
4060     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4061     IVideoWindow *pVideoWindow;
4062     HRESULT hr;
4063
4064     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
4065
4066     EnterCriticalSection(&This->cs);
4067
4068     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4069
4070     if (hr == S_OK)
4071         hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
4072
4073     LeaveCriticalSection(&This->cs);
4074
4075     return hr;
4076 }
4077
4078 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx)
4079 {
4080     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4081     IVideoWindow *pVideoWindow;
4082     HRESULT hr;
4083
4084     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
4085
4086     EnterCriticalSection(&This->cs);
4087
4088     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4089
4090     if (hr == S_OK)
4091         hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
4092
4093     LeaveCriticalSection(&This->cs);
4094
4095     return hr;
4096 }
4097
4098 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow)
4099 {
4100     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4101     IVideoWindow *pVideoWindow;
4102     HRESULT hr;
4103
4104     TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
4105
4106     EnterCriticalSection(&This->cs);
4107
4108     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4109
4110     if (hr == S_OK)
4111         hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
4112
4113     LeaveCriticalSection(&This->cs);
4114
4115     return hr;
4116 }
4117
4118 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface, LONG *AutoShow)
4119 {
4120     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4121     IVideoWindow *pVideoWindow;
4122     HRESULT hr;
4123
4124     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4125
4126     EnterCriticalSection(&This->cs);
4127
4128     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4129
4130     if (hr == S_OK)
4131         hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4132
4133     LeaveCriticalSection(&This->cs);
4134
4135     return hr;
4136 }
4137
4138 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface, LONG WindowState)
4139 {
4140     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4141     IVideoWindow *pVideoWindow;
4142     HRESULT hr;
4143
4144     TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
4145
4146     EnterCriticalSection(&This->cs);
4147
4148     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4149
4150     if (hr == S_OK)
4151         hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4152
4153     LeaveCriticalSection(&This->cs);
4154
4155     return hr;
4156 }
4157
4158 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface, LONG *WindowState)
4159 {
4160     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4161     IVideoWindow *pVideoWindow;
4162     HRESULT hr;
4163
4164     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4165
4166     EnterCriticalSection(&This->cs);
4167
4168     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4169
4170     if (hr == S_OK)
4171         hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4172
4173     LeaveCriticalSection(&This->cs);
4174
4175     return hr;
4176 }
4177
4178 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette)
4179 {
4180     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4181     IVideoWindow *pVideoWindow;
4182     HRESULT hr;
4183
4184     TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
4185
4186     EnterCriticalSection(&This->cs);
4187
4188     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4189
4190     if (hr == S_OK)
4191         hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4192
4193     LeaveCriticalSection(&This->cs);
4194
4195     return hr;
4196 }
4197
4198 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4199         LONG *pBackgroundPalette)
4200 {
4201     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4202     IVideoWindow *pVideoWindow;
4203     HRESULT hr;
4204
4205     TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4206
4207     EnterCriticalSection(&This->cs);
4208
4209     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4210
4211     if (hr == S_OK)
4212         hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4213
4214     LeaveCriticalSection(&This->cs);
4215
4216     return hr;
4217 }
4218
4219 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface, LONG Visible)
4220 {
4221     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4222     IVideoWindow *pVideoWindow;
4223     HRESULT hr;
4224
4225     TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
4226
4227     EnterCriticalSection(&This->cs);
4228
4229     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4230
4231     if (hr == S_OK)
4232         hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4233
4234     LeaveCriticalSection(&This->cs);
4235
4236     return hr;
4237 }
4238
4239 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface, LONG *pVisible)
4240 {
4241     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4242     IVideoWindow *pVideoWindow;
4243     HRESULT hr;
4244
4245     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4246
4247     EnterCriticalSection(&This->cs);
4248
4249     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4250
4251     if (hr == S_OK)
4252         hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4253
4254     LeaveCriticalSection(&This->cs);
4255
4256     return hr;
4257 }
4258
4259 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface, LONG Left)
4260 {
4261     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4262     IVideoWindow *pVideoWindow;
4263     HRESULT hr;
4264
4265     TRACE("(%p/%p)->(%d)\n", This, iface, Left);
4266
4267     EnterCriticalSection(&This->cs);
4268
4269     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4270
4271     if (hr == S_OK)
4272         hr = IVideoWindow_put_Left(pVideoWindow, Left);
4273
4274     LeaveCriticalSection(&This->cs);
4275
4276     return hr;
4277 }
4278
4279 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface, LONG *pLeft)
4280 {
4281     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4282     IVideoWindow *pVideoWindow;
4283     HRESULT hr;
4284
4285     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4286
4287     EnterCriticalSection(&This->cs);
4288
4289     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4290
4291     if (hr == S_OK)
4292         hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4293
4294     LeaveCriticalSection(&This->cs);
4295
4296     return hr;
4297 }
4298
4299 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface, LONG Width)
4300 {
4301     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4302     IVideoWindow *pVideoWindow;
4303     HRESULT hr;
4304
4305     TRACE("(%p/%p)->(%d)\n", This, iface, Width);
4306
4307     EnterCriticalSection(&This->cs);
4308
4309     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4310
4311     if (hr == S_OK)
4312         hr = IVideoWindow_put_Width(pVideoWindow, Width);
4313
4314     LeaveCriticalSection(&This->cs);
4315
4316     return hr;
4317 }
4318
4319 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface, LONG *pWidth)
4320 {
4321     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4322     IVideoWindow *pVideoWindow;
4323     HRESULT hr;
4324
4325     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4326
4327     EnterCriticalSection(&This->cs);
4328
4329     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4330
4331     if (hr == S_OK)
4332         hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4333
4334     LeaveCriticalSection(&This->cs);
4335
4336     return hr;
4337 }
4338
4339 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface, LONG Top)
4340 {
4341     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4342     IVideoWindow *pVideoWindow;
4343     HRESULT hr;
4344
4345     TRACE("(%p/%p)->(%d)\n", This, iface, Top);
4346
4347     EnterCriticalSection(&This->cs);
4348
4349     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4350
4351     if (hr == S_OK)
4352         hr = IVideoWindow_put_Top(pVideoWindow, Top);
4353
4354     LeaveCriticalSection(&This->cs);
4355
4356     return hr;
4357 }
4358
4359 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface, LONG *pTop)
4360 {
4361     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4362     IVideoWindow *pVideoWindow;
4363     HRESULT hr;
4364
4365     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4366
4367     EnterCriticalSection(&This->cs);
4368
4369     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4370
4371     if (hr == S_OK)
4372         hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4373
4374     LeaveCriticalSection(&This->cs);
4375
4376     return hr;
4377 }
4378
4379 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface, LONG Height)
4380 {
4381     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4382     IVideoWindow *pVideoWindow;
4383     HRESULT hr;
4384
4385     TRACE("(%p/%p)->(%d)\n", This, iface, Height);
4386
4387     EnterCriticalSection(&This->cs);
4388
4389     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4390
4391     if (hr == S_OK)
4392         hr = IVideoWindow_put_Height(pVideoWindow, Height);
4393
4394     LeaveCriticalSection(&This->cs);
4395
4396     return hr;
4397 }
4398
4399 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface, LONG *pHeight)
4400 {
4401     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4402     IVideoWindow *pVideoWindow;
4403     HRESULT hr;
4404
4405     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4406
4407     EnterCriticalSection(&This->cs);
4408
4409     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4410
4411     if (hr == S_OK)
4412         hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4413
4414     LeaveCriticalSection(&This->cs);
4415
4416     return hr;
4417 }
4418
4419 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface, OAHWND Owner)
4420 {
4421     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4422     IVideoWindow *pVideoWindow;
4423     HRESULT hr;
4424
4425     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
4426
4427     EnterCriticalSection(&This->cs);
4428
4429     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4430
4431     if (hr == S_OK)
4432         hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4433
4434     LeaveCriticalSection(&This->cs);
4435
4436     return hr;
4437 }
4438
4439 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface, OAHWND *Owner)
4440 {
4441     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4442     IVideoWindow *pVideoWindow;
4443     HRESULT hr;
4444
4445     TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4446
4447     EnterCriticalSection(&This->cs);
4448
4449     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4450
4451     if (hr == S_OK)
4452         hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4453
4454     LeaveCriticalSection(&This->cs);
4455
4456     return hr;
4457 }
4458
4459 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface, OAHWND Drain)
4460 {
4461     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4462     IVideoWindow *pVideoWindow;
4463     HRESULT hr;
4464
4465     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
4466
4467     EnterCriticalSection(&This->cs);
4468
4469     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4470
4471     if (hr == S_OK)
4472         hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4473
4474     LeaveCriticalSection(&This->cs);
4475
4476     return hr;
4477 }
4478
4479 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface, OAHWND *Drain)
4480 {
4481     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4482     IVideoWindow *pVideoWindow;
4483     HRESULT hr;
4484
4485     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4486
4487     EnterCriticalSection(&This->cs);
4488
4489     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4490
4491     if (hr == S_OK)
4492         hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4493
4494     LeaveCriticalSection(&This->cs);
4495
4496     return hr;
4497 }
4498
4499 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface, LONG *Color)
4500 {
4501     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4502     IVideoWindow *pVideoWindow;
4503     HRESULT hr;
4504
4505     TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4506
4507     EnterCriticalSection(&This->cs);
4508
4509     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4510
4511     if (hr == S_OK)
4512         hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4513
4514     LeaveCriticalSection(&This->cs);
4515
4516     return hr;
4517 }
4518
4519 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface, LONG Color)
4520 {
4521     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4522     IVideoWindow *pVideoWindow;
4523     HRESULT hr;
4524
4525     TRACE("(%p/%p)->(%d)\n", This, iface, Color);
4526
4527     EnterCriticalSection(&This->cs);
4528
4529     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4530
4531     if (hr == S_OK)
4532         hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4533
4534     LeaveCriticalSection(&This->cs);
4535
4536     return hr;
4537 }
4538
4539 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface, LONG *FullScreenMode)
4540 {
4541     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4542     IVideoWindow *pVideoWindow;
4543     HRESULT hr;
4544
4545     TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4546
4547     EnterCriticalSection(&This->cs);
4548
4549     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4550
4551     if (hr == S_OK)
4552         hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4553
4554     LeaveCriticalSection(&This->cs);
4555
4556     return hr;
4557 }
4558
4559 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, LONG FullScreenMode)
4560 {
4561     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4562     IVideoWindow *pVideoWindow;
4563     HRESULT hr;
4564
4565     TRACE("(%p/%p)->(%d)\n", This, iface, FullScreenMode);
4566
4567     EnterCriticalSection(&This->cs);
4568
4569     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4570
4571     if (hr == S_OK)
4572         hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4573
4574     LeaveCriticalSection(&This->cs);
4575
4576     return hr;
4577 }
4578
4579 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface, LONG Focus)
4580 {
4581     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4582     IVideoWindow *pVideoWindow;
4583     HRESULT hr;
4584
4585     TRACE("(%p/%p)->(%d)\n", This, iface, Focus);
4586
4587     EnterCriticalSection(&This->cs);
4588
4589     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4590
4591     if (hr == S_OK)
4592         hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4593
4594     LeaveCriticalSection(&This->cs);
4595
4596     return hr;
4597 }
4598
4599 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface, OAHWND hwnd, LONG uMsg,
4600         LONG_PTR wParam, LONG_PTR lParam)
4601 {
4602     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4603     IVideoWindow *pVideoWindow;
4604     HRESULT hr;
4605
4606     TRACE("(%p/%p)->(%08lx, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam);
4607
4608     EnterCriticalSection(&This->cs);
4609
4610     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4611
4612     if (hr == S_OK)
4613         hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4614
4615     LeaveCriticalSection(&This->cs);
4616
4617     return hr;
4618 }
4619
4620 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface, LONG Left, LONG Top,
4621         LONG Width, LONG Height)
4622 {
4623     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4624     IVideoWindow *pVideoWindow;
4625     HRESULT hr;
4626
4627     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
4628
4629     EnterCriticalSection(&This->cs);
4630
4631     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4632
4633     if (hr == S_OK)
4634         hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4635
4636     LeaveCriticalSection(&This->cs);
4637
4638     return hr;
4639 }
4640
4641 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4642         LONG *pWidth, LONG *pHeight)
4643 {
4644     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4645     IVideoWindow *pVideoWindow;
4646     HRESULT hr;
4647
4648     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4649
4650     EnterCriticalSection(&This->cs);
4651
4652     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4653
4654     if (hr == S_OK)
4655         hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4656
4657     LeaveCriticalSection(&This->cs);
4658
4659     return hr;
4660 }
4661
4662 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4663         LONG *pHeight)
4664 {
4665     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4666     IVideoWindow *pVideoWindow;
4667     HRESULT hr;
4668
4669     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4670
4671     EnterCriticalSection(&This->cs);
4672
4673     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4674
4675     if (hr == S_OK)
4676         hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4677
4678     LeaveCriticalSection(&This->cs);
4679
4680     return hr;
4681 }
4682
4683 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4684         LONG *pHeight)
4685 {
4686     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4687     IVideoWindow *pVideoWindow;
4688     HRESULT hr;
4689
4690     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4691
4692     EnterCriticalSection(&This->cs);
4693
4694     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4695
4696     if (hr == S_OK)
4697         hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4698
4699     LeaveCriticalSection(&This->cs);
4700
4701     return hr;
4702 }
4703
4704 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4705         LONG *pWidth, LONG *pHeight)
4706 {
4707     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4708     IVideoWindow *pVideoWindow;
4709     HRESULT hr;
4710
4711     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4712
4713     EnterCriticalSection(&This->cs);
4714
4715     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4716
4717     if (hr == S_OK)
4718         hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4719
4720     LeaveCriticalSection(&This->cs);
4721
4722     return hr;
4723 }
4724
4725 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface, LONG HideCursor)
4726 {
4727     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4728     IVideoWindow *pVideoWindow;
4729     HRESULT hr;
4730
4731     TRACE("(%p/%p)->(%d)\n", This, iface, HideCursor);
4732
4733     EnterCriticalSection(&This->cs);
4734
4735     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4736
4737     if (hr == S_OK)
4738         hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4739
4740     LeaveCriticalSection(&This->cs);
4741
4742     return hr;
4743 }
4744
4745 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden)
4746 {
4747     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4748     IVideoWindow *pVideoWindow;
4749     HRESULT hr;
4750
4751     TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4752
4753     EnterCriticalSection(&This->cs);
4754
4755     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4756
4757     if (hr == S_OK)
4758         hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4759
4760     LeaveCriticalSection(&This->cs);
4761
4762     return hr;
4763 }
4764
4765
4766 static const IVideoWindowVtbl IVideoWindow_VTable =
4767 {
4768     VideoWindow_QueryInterface,
4769     VideoWindow_AddRef,
4770     VideoWindow_Release,
4771     VideoWindow_GetTypeInfoCount,
4772     VideoWindow_GetTypeInfo,
4773     VideoWindow_GetIDsOfNames,
4774     VideoWindow_Invoke,
4775     VideoWindow_put_Caption,
4776     VideoWindow_get_Caption,
4777     VideoWindow_put_WindowStyle,
4778     VideoWindow_get_WindowStyle,
4779     VideoWindow_put_WindowStyleEx,
4780     VideoWindow_get_WindowStyleEx,
4781     VideoWindow_put_AutoShow,
4782     VideoWindow_get_AutoShow,
4783     VideoWindow_put_WindowState,
4784     VideoWindow_get_WindowState,
4785     VideoWindow_put_BackgroundPalette,
4786     VideoWindow_get_BackgroundPalette,
4787     VideoWindow_put_Visible,
4788     VideoWindow_get_Visible,
4789     VideoWindow_put_Left,
4790     VideoWindow_get_Left,
4791     VideoWindow_put_Width,
4792     VideoWindow_get_Width,
4793     VideoWindow_put_Top,
4794     VideoWindow_get_Top,
4795     VideoWindow_put_Height,
4796     VideoWindow_get_Height,
4797     VideoWindow_put_Owner,
4798     VideoWindow_get_Owner,
4799     VideoWindow_put_MessageDrain,
4800     VideoWindow_get_MessageDrain,
4801     VideoWindow_get_BorderColor,
4802     VideoWindow_put_BorderColor,
4803     VideoWindow_get_FullScreenMode,
4804     VideoWindow_put_FullScreenMode,
4805     VideoWindow_SetWindowForeground,
4806     VideoWindow_NotifyOwnerMessage,
4807     VideoWindow_SetWindowPosition,
4808     VideoWindow_GetWindowPosition,
4809     VideoWindow_GetMinIdealImageSize,
4810     VideoWindow_GetMaxIdealImageSize,
4811     VideoWindow_GetRestorePosition,
4812     VideoWindow_HideCursor,
4813     VideoWindow_IsCursorHidden
4814 };
4815
4816 static inline IFilterGraphImpl *impl_from_IMediaEventEx(IMediaEventEx *iface)
4817 {
4818     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaEventEx_iface);
4819 }
4820
4821 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface, REFIID riid, void **ppvObj)
4822 {
4823     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4824
4825     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
4826
4827     return Filtergraph_QueryInterface(This, riid, ppvObj);
4828 }
4829
4830 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface)
4831 {
4832     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4833
4834     TRACE("(%p/%p)->()\n", This, iface);
4835
4836     return Filtergraph_AddRef(This);
4837 }
4838
4839 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface)
4840 {
4841     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4842
4843     TRACE("(%p/%p)->()\n", This, iface);
4844
4845     return Filtergraph_Release(This);
4846 }
4847
4848 /*** IDispatch methods ***/
4849 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface, UINT *pctinfo)
4850 {
4851     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4852
4853     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
4854
4855     return S_OK;
4856 }
4857
4858 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface, UINT iTInfo, LCID lcid,
4859         ITypeInfo **ppTInfo)
4860 {
4861     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4862
4863     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
4864
4865     return S_OK;
4866 }
4867
4868 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface, REFIID riid,
4869         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
4870 {
4871     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4872
4873     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
4874
4875     return S_OK;
4876 }
4877
4878 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface, DISPID dispIdMember, REFIID riid,
4879         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
4880         UINT *puArgErr)
4881 {
4882     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4883
4884     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4885
4886     return S_OK;
4887 }
4888
4889 /*** IMediaEvent methods ***/
4890 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface, OAEVENT *hEvent)
4891 {
4892     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4893
4894     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4895
4896     *hEvent = (OAEVENT)This->evqueue.msg_event;
4897
4898     return S_OK;
4899 }
4900
4901 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface, LONG *lEventCode, LONG_PTR *lParam1,
4902         LONG_PTR *lParam2, LONG msTimeout)
4903 {
4904     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4905     Event evt;
4906
4907     TRACE("(%p/%p)->(%p, %p, %p, %d)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
4908
4909     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
4910     {
4911         *lEventCode = evt.lEventCode;
4912         *lParam1 = evt.lParam1;
4913         *lParam2 = evt.lParam2;
4914         return S_OK;
4915     }
4916
4917     *lEventCode = 0;
4918     return E_ABORT;
4919 }
4920
4921 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface, LONG msTimeout,
4922         LONG *pEvCode)
4923 {
4924     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4925
4926     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pEvCode);
4927
4928     if (This->state != State_Running)
4929         return VFW_E_WRONG_STATE;
4930
4931     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4932     {
4933         *pEvCode = This->CompletionStatus;
4934         return S_OK;
4935     }
4936
4937     *pEvCode = 0;
4938     return E_ABORT;
4939 }
4940
4941 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4942 {
4943     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4944
4945     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4946
4947     if (lEvCode == EC_COMPLETE)
4948         This->HandleEcComplete = FALSE;
4949     else if (lEvCode == EC_REPAINT)
4950         This->HandleEcRepaint = FALSE;
4951     else if (lEvCode == EC_CLOCK_CHANGED)
4952         This->HandleEcClockChanged = FALSE;
4953     else
4954         return S_FALSE;
4955
4956     return S_OK;
4957 }
4958
4959 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
4960 {
4961     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4962
4963     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
4964
4965     if (lEvCode == EC_COMPLETE)
4966         This->HandleEcComplete = TRUE;
4967     else if (lEvCode == EC_REPAINT)
4968         This->HandleEcRepaint = TRUE;
4969     else if (lEvCode == EC_CLOCK_CHANGED)
4970         This->HandleEcClockChanged = TRUE;
4971     else
4972         return S_FALSE;
4973
4974     return S_OK;
4975 }
4976
4977 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface, LONG lEvCode,
4978         LONG_PTR lParam1, LONG_PTR lParam2)
4979 {
4980     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4981
4982     TRACE("(%p/%p)->(%d, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
4983
4984     return S_OK;
4985 }
4986
4987 /*** IMediaEventEx methods ***/
4988 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface, OAHWND hwnd, LONG lMsg,
4989         LONG_PTR lInstanceData)
4990 {
4991     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4992
4993     TRACE("(%p/%p)->(%08lx, %d, %08lx)\n", This, iface, hwnd, lMsg, lInstanceData);
4994
4995     This->notif.hWnd = (HWND)hwnd;
4996     This->notif.msg = lMsg;
4997     This->notif.instance = lInstanceData;
4998
4999     return S_OK;
5000 }
5001
5002 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface, LONG lNoNotifyFlags)
5003 {
5004     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5005
5006     TRACE("(%p/%p)->(%d)\n", This, iface, lNoNotifyFlags);
5007
5008     if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
5009         return E_INVALIDARG;
5010
5011     This->notif.disabled = lNoNotifyFlags;
5012
5013     return S_OK;
5014 }
5015
5016 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface, LONG *lplNoNotifyFlags)
5017 {
5018     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5019
5020     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
5021
5022     if (!lplNoNotifyFlags)
5023         return E_POINTER;
5024
5025     *lplNoNotifyFlags = This->notif.disabled;
5026
5027     return S_OK;
5028 }
5029
5030
5031 static const IMediaEventExVtbl IMediaEventEx_VTable =
5032 {
5033     MediaEvent_QueryInterface,
5034     MediaEvent_AddRef,
5035     MediaEvent_Release,
5036     MediaEvent_GetTypeInfoCount,
5037     MediaEvent_GetTypeInfo,
5038     MediaEvent_GetIDsOfNames,
5039     MediaEvent_Invoke,
5040     MediaEvent_GetEventHandle,
5041     MediaEvent_GetEvent,
5042     MediaEvent_WaitForCompletion,
5043     MediaEvent_CancelDefaultHandling,
5044     MediaEvent_RestoreDefaultHandling,
5045     MediaEvent_FreeEventParams,
5046     MediaEvent_SetNotifyWindow,
5047     MediaEvent_SetNotifyFlags,
5048     MediaEvent_GetNotifyFlags
5049 };
5050
5051
5052 static inline IFilterGraphImpl *impl_from_IMediaFilter(IMediaFilter *iface)
5053 {
5054     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaFilter_iface);
5055 }
5056
5057 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, void **ppv)
5058 {
5059     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5060
5061     return Filtergraph_QueryInterface(This, riid, ppv);
5062 }
5063
5064 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
5065 {
5066     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5067
5068     return Filtergraph_AddRef(This);
5069 }
5070
5071 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
5072 {
5073     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5074
5075     return Filtergraph_Release(This);
5076 }
5077
5078 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
5079 {
5080     FIXME("(%p): stub\n", pClassID);
5081
5082     return E_NOTIMPL;
5083 }
5084
5085 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
5086 {
5087     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5088
5089     return MediaControl_Stop(&This->IMediaControl_iface);
5090 }
5091
5092 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
5093 {
5094     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5095
5096     return MediaControl_Pause(&This->IMediaControl_iface);
5097 }
5098
5099 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
5100 {
5101     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5102
5103     if (tStart)
5104         FIXME("Run called with non-null tStart: %x%08x\n",
5105               (int)(tStart>>32), (int)tStart);
5106
5107     return MediaControl_Run(&This->IMediaControl_iface);
5108 }
5109
5110 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout,
5111         FILTER_STATE *pState)
5112 {
5113     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5114
5115     return MediaControl_GetState(&This->IMediaControl_iface, dwMsTimeout, (OAFilterState*)pState);
5116 }
5117
5118 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
5119 {
5120     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5121     HRESULT hr = S_OK;
5122     int i;
5123
5124     TRACE("(%p/%p)->(%p)\n", iface, This, pClock);
5125
5126     EnterCriticalSection(&This->cs);
5127     {
5128         for (i = 0;i < This->nFilters;i++)
5129         {
5130             hr = IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], pClock);
5131             if (FAILED(hr))
5132                 break;
5133         }
5134
5135         if (FAILED(hr))
5136         {
5137             for(;i >= 0;i--)
5138                 IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], This->refClock);
5139         }
5140         else
5141         {
5142             if (This->refClock)
5143                 IReferenceClock_Release(This->refClock);
5144             This->refClock = pClock;
5145             if (This->refClock)
5146                 IReferenceClock_AddRef(This->refClock);
5147             This->defaultclock = FALSE;
5148
5149             if (This->HandleEcClockChanged)
5150             {
5151                 IMediaEventSink *pEventSink;
5152                 HRESULT eshr;
5153
5154                 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (LPVOID)&pEventSink);
5155                 if (SUCCEEDED(eshr))
5156                 {
5157                     IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5158                     IMediaEventSink_Release(pEventSink);
5159                 }
5160             }
5161         }
5162     }
5163     LeaveCriticalSection(&This->cs);
5164
5165     return hr;
5166 }
5167
5168 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5169 {
5170     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5171
5172     TRACE("(%p/%p)->(%p)\n", iface, This, ppClock);
5173
5174     if (!ppClock)
5175         return E_POINTER;
5176
5177     EnterCriticalSection(&This->cs);
5178     {
5179         *ppClock = This->refClock;
5180         if (*ppClock)
5181             IReferenceClock_AddRef(*ppClock);
5182     }
5183     LeaveCriticalSection(&This->cs);
5184
5185     return S_OK;
5186 }
5187
5188 static const IMediaFilterVtbl IMediaFilter_VTable =
5189 {
5190     MediaFilter_QueryInterface,
5191     MediaFilter_AddRef,
5192     MediaFilter_Release,
5193     MediaFilter_GetClassID,
5194     MediaFilter_Stop,
5195     MediaFilter_Pause,
5196     MediaFilter_Run,
5197     MediaFilter_GetState,
5198     MediaFilter_SetSyncSource,
5199     MediaFilter_GetSyncSource
5200 };
5201
5202 static inline IFilterGraphImpl *impl_from_IMediaEventSink(IMediaEventSink *iface)
5203 {
5204     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaEventSink_iface);
5205 }
5206
5207 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, void **ppv)
5208 {
5209     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5210
5211     return Filtergraph_QueryInterface(This, riid, ppv);
5212 }
5213
5214 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5215 {
5216     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5217
5218     return Filtergraph_AddRef(This);
5219 }
5220
5221 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5222 {
5223     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5224
5225     return Filtergraph_Release(This);
5226 }
5227
5228 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCode,
5229         LONG_PTR EventParam1, LONG_PTR EventParam2)
5230 {
5231     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5232     Event evt;
5233
5234     TRACE("(%p/%p)->(%d, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
5235
5236     /* We need thread safety here, let's use the events queue's one */
5237     EnterCriticalSection(&This->evqueue.msg_crst);
5238
5239     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
5240     {
5241         TRACE("Process EC_COMPLETE notification\n");
5242         if (++This->EcCompleteCount == This->nRenderers)
5243         {
5244             evt.lEventCode = EC_COMPLETE;
5245             evt.lParam1 = S_OK;
5246             evt.lParam2 = 0;
5247             TRACE("Send EC_COMPLETE to app\n");
5248             EventsQueue_PutEvent(&This->evqueue, &evt);
5249             if (!This->notif.disabled && This->notif.hWnd)
5250             {
5251                 TRACE("Send Window message\n");
5252                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5253             }
5254             This->CompletionStatus = EC_COMPLETE;
5255             SetEvent(This->hEventCompletion);
5256         }
5257     }
5258     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
5259     {
5260         /* FIXME: Not handled yet */
5261     }
5262     else
5263     {
5264         evt.lEventCode = EventCode;
5265         evt.lParam1 = EventParam1;
5266         evt.lParam2 = EventParam2;
5267         EventsQueue_PutEvent(&This->evqueue, &evt);
5268         if (!This->notif.disabled && This->notif.hWnd)
5269             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5270     }
5271
5272     LeaveCriticalSection(&This->evqueue.msg_crst);
5273     return S_OK;
5274 }
5275
5276 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5277 {
5278     MediaEventSink_QueryInterface,
5279     MediaEventSink_AddRef,
5280     MediaEventSink_Release,
5281     MediaEventSink_Notify
5282 };
5283
5284 static inline IFilterGraphImpl *impl_from_IGraphConfig(IGraphConfig *iface)
5285 {
5286     return CONTAINING_RECORD(iface, IFilterGraphImpl, IGraphConfig_iface);
5287 }
5288
5289 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID riid, void **ppv)
5290 {
5291     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5292
5293     return Filtergraph_QueryInterface(This, riid, ppv);
5294 }
5295
5296 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5297 {
5298     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5299
5300     return Filtergraph_AddRef(This);
5301 }
5302
5303 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5304 {
5305     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5306
5307     return Filtergraph_Release(This);
5308 }
5309
5310 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface, IPin *pOutputPin, IPin *pInputPin,
5311         const AM_MEDIA_TYPE *pmtFirstConnection, IBaseFilter *pUsingFilter, HANDLE hAbortEvent,
5312         DWORD dwFlags)
5313 {
5314     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5315
5316     FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
5317     
5318     return E_NOTIMPL;
5319 }
5320
5321 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface, IGraphConfigCallback *pCallback,
5322         void *pvContext, DWORD dwFlags, HANDLE hAbortEvent)
5323 {
5324     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5325     HRESULT hr;
5326
5327     WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
5328
5329     if (hAbortEvent)
5330         FIXME("The parameter hAbortEvent is not handled!\n");
5331
5332     EnterCriticalSection(&This->cs);
5333
5334     hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
5335
5336     LeaveCriticalSection(&This->cs);
5337
5338     return hr;
5339 }
5340
5341 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface, IBaseFilter *pFilter)
5342 {
5343     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5344
5345     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5346
5347     return E_NOTIMPL;
5348 }
5349
5350 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface, IEnumFilters **pEnum)
5351 {
5352     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5353
5354     FIXME("(%p)->(%p): stub!\n", This, pEnum);
5355
5356     return E_NOTIMPL;
5357 }
5358
5359 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface, IBaseFilter *pFilter)
5360 {
5361     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5362
5363     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5364
5365     return E_NOTIMPL;
5366 }
5367
5368 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface, REFERENCE_TIME *prtStart)
5369 {
5370     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5371
5372     FIXME("(%p)->(%p): stub!\n", This, prtStart);
5373
5374     return E_NOTIMPL;
5375 }
5376
5377 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface, IPin *pOutputPin,
5378         IPinConnection *pConnection, HANDLE hEventAbort)
5379 {
5380     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5381
5382     FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5383
5384     return E_NOTIMPL;
5385 }
5386
5387 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5388         DWORD dwFlags)
5389 {
5390     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5391
5392     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5393
5394     return E_NOTIMPL;
5395 }
5396
5397 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5398         DWORD *dwFlags)
5399 {
5400     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5401
5402     FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5403
5404     return E_NOTIMPL;
5405 }
5406
5407 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface, IBaseFilter *pFilter,
5408         DWORD dwFlags)
5409 {
5410     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5411
5412     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5413
5414     return E_NOTIMPL;
5415 }
5416
5417 static const IGraphConfigVtbl IGraphConfig_VTable =
5418 {
5419     GraphConfig_QueryInterface,
5420     GraphConfig_AddRef,
5421     GraphConfig_Release,
5422     GraphConfig_Reconnect,
5423     GraphConfig_Reconfigure,
5424     GraphConfig_AddFilterToCache,
5425     GraphConfig_EnumCacheFilter,
5426     GraphConfig_RemoveFilterFromCache,
5427     GraphConfig_GetStartTime,
5428     GraphConfig_PushThroughData,
5429     GraphConfig_SetFilterFlags,
5430     GraphConfig_GetFilterFlags,
5431     GraphConfig_RemoveFilterEx
5432 };
5433
5434 static const IUnknownVtbl IInner_VTable =
5435 {
5436     FilterGraphInner_QueryInterface,
5437     FilterGraphInner_AddRef,
5438     FilterGraphInner_Release
5439 };
5440
5441 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
5442                                           REFIID riid,
5443                                           LPVOID * ppv) {
5444     if (This->bAggregatable)
5445         This->bUnkOuterValid = TRUE;
5446
5447     if (This->pUnkOuter)
5448     {
5449         if (This->bAggregatable)
5450             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
5451
5452         if (IsEqualIID(riid, &IID_IUnknown))
5453         {
5454             HRESULT hr;
5455
5456             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5457             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5458             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5459             This->bAggregatable = TRUE;
5460             return hr;
5461         }
5462
5463         *ppv = NULL;
5464         return E_NOINTERFACE;
5465     }
5466
5467     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5468 }
5469
5470 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This) {
5471     if (This->pUnkOuter && This->bUnkOuterValid)
5472         return IUnknown_AddRef(This->pUnkOuter);
5473     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5474 }
5475
5476 static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
5477     if (This->pUnkOuter && This->bUnkOuterValid)
5478         return IUnknown_Release(This->pUnkOuter);
5479     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5480 }
5481
5482 /* This is the only function that actually creates a FilterGraph class... */
5483 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5484 {
5485     IFilterGraphImpl *fimpl;
5486     HRESULT hr;
5487
5488     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
5489
5490     *ppObj = NULL;
5491
5492     fimpl = CoTaskMemAlloc(sizeof(*fimpl));
5493     fimpl->pUnkOuter = pUnkOuter;
5494     fimpl->bUnkOuterValid = FALSE;
5495     fimpl->bAggregatable = FALSE;
5496     fimpl->defaultclock = TRUE;
5497     fimpl->IInner_vtbl = &IInner_VTable;
5498     fimpl->IFilterGraph2_iface.lpVtbl = &IFilterGraph2_VTable;
5499     fimpl->IMediaControl_iface.lpVtbl = &IMediaControl_VTable;
5500     fimpl->IMediaSeeking_iface.lpVtbl = &IMediaSeeking_VTable;
5501     fimpl->IBasicAudio_iface.lpVtbl = &IBasicAudio_VTable;
5502     fimpl->IBasicVideo2_iface.lpVtbl = &IBasicVideo_VTable;
5503     fimpl->IVideoWindow_iface.lpVtbl = &IVideoWindow_VTable;
5504     fimpl->IMediaEventEx_iface.lpVtbl = &IMediaEventEx_VTable;
5505     fimpl->IMediaFilter_iface.lpVtbl = &IMediaFilter_VTable;
5506     fimpl->IMediaEventSink_iface.lpVtbl = &IMediaEventSink_VTable;
5507     fimpl->IGraphConfig_iface.lpVtbl = &IGraphConfig_VTable;
5508     fimpl->IMediaPosition_iface.lpVtbl = &IMediaPosition_VTable;
5509     fimpl->ref = 1;
5510     fimpl->ppFiltersInGraph = NULL;
5511     fimpl->pFilterNames = NULL;
5512     fimpl->nFilters = 0;
5513     fimpl->filterCapacity = 0;
5514     fimpl->nameIndex = 1;
5515     fimpl->refClock = NULL;
5516     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5517     fimpl->HandleEcComplete = TRUE;
5518     fimpl->HandleEcRepaint = TRUE;
5519     fimpl->HandleEcClockChanged = TRUE;
5520     fimpl->notif.hWnd = 0;
5521     fimpl->notif.disabled = FALSE;
5522     fimpl->nRenderers = 0;
5523     fimpl->EcCompleteCount = 0;
5524     fimpl->refClockProvider = NULL;
5525     fimpl->state = State_Stopped;
5526     EventsQueue_Init(&fimpl->evqueue);
5527     InitializeCriticalSection(&fimpl->cs);
5528     fimpl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IFilterGraphImpl.cs");
5529     fimpl->nItfCacheEntries = 0;
5530     memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
5531     fimpl->start_time = fimpl->pause_time = 0;
5532     fimpl->stop_position = -1;
5533     fimpl->punkFilterMapper2 = NULL;
5534     fimpl->recursioncount = 0;
5535
5536     /* create Filtermapper aggregated. */
5537     hr = CoCreateInstance(&CLSID_FilterMapper2, pUnkOuter ? pUnkOuter : (IUnknown*)&fimpl->IInner_vtbl, CLSCTX_INPROC_SERVER,
5538         &IID_IUnknown, (LPVOID*)&fimpl->punkFilterMapper2);
5539
5540     if (SUCCEEDED(hr)) {
5541         hr = IUnknown_QueryInterface(fimpl->punkFilterMapper2, &IID_IFilterMapper2,  (LPVOID*)&fimpl->pFilterMapper2);
5542     }
5543
5544     if (SUCCEEDED(hr)) {
5545         /* Release controlling IUnknown - compensate refcount increase from caching IFilterMapper2 interface. */
5546         if (pUnkOuter) IUnknown_Release(pUnkOuter);
5547         else IUnknown_Release((IUnknown*)&fimpl->IInner_vtbl);
5548     }
5549
5550     if (FAILED(hr)) {
5551         ERR("Unable to create filter mapper (%x)\n", hr);
5552         if (fimpl->punkFilterMapper2) IUnknown_Release(fimpl->punkFilterMapper2);
5553         CloseHandle(fimpl->hEventCompletion);
5554         EventsQueue_Destroy(&fimpl->evqueue);
5555         fimpl->cs.DebugInfo->Spare[0] = 0;
5556         DeleteCriticalSection(&fimpl->cs);
5557         CoTaskMemFree(fimpl);
5558         return hr;
5559     }
5560
5561     *ppObj = fimpl;
5562     return S_OK;
5563 }
5564
5565 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5566 {
5567     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
5568     return FilterGraph_create(pUnkOuter, ppObj);
5569 }