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