quartz: Fix return value for video renderer.
[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         ERR("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             ERR("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             ERR("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             ERR("Next failed (%x)\n", hr);
826             return hr;
827         }
828     } else if (FAILED(hr)) {
829         ERR("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     BOOL final = FALSE;
1150
1151     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
1152
1153     if (TRACE_ON(quartz))
1154     {
1155         PIN_INFO PinInfo;
1156
1157         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
1158         if (FAILED(hr))
1159             return hr;
1160
1161         TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
1162         IBaseFilter_Release(PinInfo.pFilter);
1163     }
1164
1165     /* Try to find out if there is a renderer for the specified subtype already, and use that
1166      */
1167     EnterCriticalSection(&This->cs);
1168     for (x = 0; x < This->nFilters; ++x)
1169     {
1170         IEnumPins *enumpins = NULL;
1171         IPin *pin = NULL;
1172
1173         hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
1174
1175         if (FAILED(hr) || !enumpins)
1176             continue;
1177
1178         IEnumPins_Reset(enumpins);
1179         while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
1180         {
1181             IPin *to = NULL;
1182             PIN_DIRECTION dir = PINDIR_OUTPUT;
1183
1184             IPin_QueryDirection(pin, &dir);
1185             if (dir != PINDIR_INPUT)
1186             {
1187                 IPin_Release(pin);
1188                 continue;
1189             }
1190             IPin_ConnectedTo(pin, &to);
1191
1192             if (to == NULL)
1193             {
1194                 hr = IPin_Connect(ppinOut, pin, NULL);
1195                 if (SUCCEEDED(hr))
1196                 {
1197                     TRACE("Connected succesfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
1198                     IPin_Release(pin);
1199
1200                     hr = FilterGraph2_RenderRecurse(This, pin);
1201                     if (FAILED(hr))
1202                     {
1203                         IPin_Disconnect(ppinOut);
1204                         IPin_Disconnect(pin);
1205                         continue;
1206                     }
1207                     IEnumPins_Release(enumpins);
1208                     LeaveCriticalSection(&This->cs);
1209                     return hr;
1210                 }
1211                 WARN("Could not connect!\n");
1212             }
1213             else
1214                 IPin_Release(to);
1215
1216             IPin_Release(pin);
1217         }
1218         IEnumPins_Release(enumpins);
1219     }
1220
1221     LeaveCriticalSection(&This->cs);
1222
1223     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
1224     if (FAILED(hr)) {
1225         WARN("EnumMediaTypes (%x)\n", hr);
1226         return hr;
1227     }
1228
1229     IEnumMediaTypes_Reset(penummt);
1230
1231     /* Looks like no existing renderer of the kind exists
1232      * Try adding new ones
1233      */
1234     tab[0] = tab[1] = GUID_NULL;
1235     while (SUCCEEDED(hr))
1236     {
1237         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
1238         if (FAILED(hr)) {
1239             WARN("IEnumMediaTypes_Next (%x)\n", hr);
1240             break;
1241         }
1242         if (!nbmt && !final)
1243         {
1244             final = TRUE;
1245             tab[0] = tab[1] = GUID_NULL;
1246             IEnumMediaTypes_Reset(penummt);
1247             continue;
1248         }
1249         else if (!nbmt)
1250         {
1251             hr = VFW_E_CANNOT_RENDER;
1252             break;
1253         }
1254         else
1255         {
1256             TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1257             TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1258
1259             /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
1260             if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[0], &mt->majortype))
1261             {
1262                 DeleteMediaType(mt);
1263                 continue;
1264             }
1265
1266             /* Try to find a suitable renderer with the same media type */
1267             tab[0] = mt->majortype;
1268             tab[1] = mt->subtype;
1269             hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, !final, FALSE, 0, NULL, NULL, NULL);
1270             if (FAILED(hr))
1271             {
1272                 WARN("Unable to enum filters (%x)\n", hr);
1273                 break;
1274             }
1275         }
1276         hr = E_FAIL;
1277
1278         while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1279         {
1280             VARIANT var;
1281             GUID clsid;
1282             IPin* ppinfilter;
1283             IBaseFilter* pfilter = NULL;
1284             IEnumPins* penumpins;
1285             ULONG pin;
1286
1287             hr = GetFilterInfo(pMoniker, &clsid, &var);
1288             IMoniker_Release(pMoniker);
1289             if (FAILED(hr)) {
1290                 WARN("Unable to retrieve filter info (%x)\n", hr);
1291                 goto error;
1292             }
1293
1294             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1295             if (FAILED(hr))
1296             {
1297                 WARN("Unable to create filter (%x), trying next one\n", hr);
1298                 goto error;
1299             }
1300
1301             hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1302             if (FAILED(hr)) {
1303                 WARN("Unable to add filter (%x)\n", hr);
1304                 IBaseFilter_Release(pfilter);
1305                 pfilter = NULL;
1306                 goto error;
1307             }
1308
1309             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1310             if (FAILED(hr)) {
1311                 WARN("Splitter Enumpins (%x)\n", hr);
1312                 goto error;
1313             }
1314             hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
1315             IEnumPins_Release(penumpins);
1316             if (FAILED(hr)) {
1317                 WARN("Next (%x)\n", hr);
1318                 goto error;
1319             }
1320             if (pin == 0) {
1321                 WARN("No Pin\n");
1322                 hr = E_FAIL;
1323                 goto error;
1324             }
1325
1326             /* Connect the pin to the "Renderer" */
1327             hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1328             IPin_Release(ppinfilter);
1329
1330             if (FAILED(hr)) {
1331                 WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_UNION(&var, bstrVal)), hr);
1332                 goto error;
1333             }
1334             TRACE("Connected, recursing %s\n",  debugstr_w(V_UNION(&var, bstrVal)));
1335             hr = FilterGraph2_RenderRecurse(This, ppinfilter);
1336             if (FAILED(hr)) {
1337                 WARN("Unable to connect recursively (%x)\n", hr);
1338                 goto error;
1339             }
1340             IBaseFilter_Release(pfilter);
1341             break;
1342
1343 error:
1344             if (pfilter) {
1345                 IFilterGraph2_RemoveFilter(iface, pfilter);
1346                 IBaseFilter_Release(pfilter);
1347             }
1348             if (!FAILED(hr)) DebugBreak();
1349         }
1350
1351         if (nbmt)
1352             DeleteMediaType(mt);
1353         if (SUCCEEDED(hr))
1354             break;
1355         hr = S_OK;
1356     }
1357
1358     IEnumMediaTypes_Release(penummt);
1359     return hr;
1360 }
1361
1362 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface,
1363                                               LPCWSTR lpcwstrFile,
1364                                               LPCWSTR lpcwstrPlayList)
1365 {
1366     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1367     static const WCHAR string[] = {'R','e','a','d','e','r',0};
1368     IBaseFilter* preader = NULL;
1369     IPin* ppinreader = NULL;
1370     IEnumPins* penumpins = NULL;
1371     HRESULT hr;
1372     BOOL partial = FALSE;
1373     HRESULT any = FALSE;
1374
1375     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1376
1377     if (lpcwstrPlayList != NULL)
1378         return E_INVALIDARG;
1379
1380     hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
1381     if (FAILED(hr))
1382         return hr;
1383
1384     if (SUCCEEDED(hr))
1385         hr = IBaseFilter_EnumPins(preader, &penumpins);
1386     if (SUCCEEDED(hr))
1387     {
1388         while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1389         {
1390             PIN_DIRECTION dir;
1391
1392             IPin_QueryDirection(ppinreader, &dir);
1393             if (dir == PINDIR_OUTPUT)
1394             {
1395                 INT i;
1396
1397                 hr = IFilterGraph2_Render(iface, ppinreader);
1398                 ERR("Render %08x\n", hr);
1399
1400                 for (i = 0; i < This->nFilters; ++i)
1401                     FIXME("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
1402
1403                 if (SUCCEEDED(hr))
1404                     any = TRUE;
1405                 if (hr != S_OK)
1406                     partial = TRUE;
1407             }
1408             IPin_Release(ppinreader);
1409         }
1410         IEnumPins_Release(penumpins);
1411
1412         if (!any)
1413             hr = VFW_E_CANNOT_RENDER;
1414         else if (partial)
1415             hr = VFW_S_PARTIAL_RENDER;
1416         else
1417             hr = S_OK;
1418     }
1419     IBaseFilter_Release(preader);
1420
1421     TRACE("--> %08x\n", hr);
1422     return hr;
1423 }
1424
1425 /* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
1426 static HRESULT GetFileSourceFilter(LPCOLESTR pszFileName, IBaseFilter **filter)
1427 {
1428     static const WCHAR wszReg[] = {'M','e','d','i','a',' ','T','y','p','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1429     HRESULT hr = S_OK;
1430     HKEY extkey;
1431     LONG lRet;
1432
1433     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszReg, 0, KEY_READ, &extkey);
1434     hr = HRESULT_FROM_WIN32(lRet);
1435
1436     if (SUCCEEDED(hr))
1437     {
1438         static const WCHAR filtersource[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
1439         WCHAR *ext = PathFindExtensionW(pszFileName);
1440         WCHAR clsid_key[39];
1441         GUID clsid;
1442         DWORD size = sizeof(clsid_key);
1443         HKEY pathkey;
1444
1445         if (!ext)
1446         {
1447             CloseHandle(extkey);
1448             return E_FAIL;
1449         }
1450
1451         lRet = RegOpenKeyExW(extkey, ext, 0, KEY_READ, &pathkey);
1452         hr = HRESULT_FROM_WIN32(lRet);
1453         CloseHandle(extkey);
1454         if (FAILED(hr))
1455             return hr;
1456
1457         lRet = RegQueryValueExW(pathkey, filtersource, NULL, NULL, (LPBYTE)clsid_key, &size);
1458         hr = HRESULT_FROM_WIN32(lRet);
1459         CloseHandle(pathkey);
1460         if (FAILED(hr))
1461             return hr;
1462
1463         CLSIDFromString(clsid_key, &clsid);
1464
1465         TRACE("CLSID: %s\n", debugstr_guid(&clsid));
1466         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1467         if (SUCCEEDED(hr))
1468         {
1469             IFileSourceFilter *source = NULL;
1470             hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
1471             if (SUCCEEDED(hr))
1472                 IFileSourceFilter_Release(source);
1473             else
1474                 IBaseFilter_Release(*filter);
1475         }
1476     }
1477     if (FAILED(hr))
1478         *filter = NULL;
1479     return hr;
1480 }
1481
1482 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface,
1483                                                    LPCWSTR lpcwstrFileName,
1484                                                    LPCWSTR lpcwstrFilterName,
1485                                                    IBaseFilter **ppFilter) {
1486     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1487     HRESULT hr;
1488     IBaseFilter* preader;
1489     IFileSourceFilter* pfile = NULL;
1490     AM_MEDIA_TYPE mt;
1491     WCHAR* filename;
1492
1493     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1494
1495     /* Try from file name first, then fall back to default asynchronous reader */
1496     hr = GetFileSourceFilter(lpcwstrFileName, &preader);
1497
1498     if (FAILED(hr))
1499         hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
1500     if (FAILED(hr)) {
1501         ERR("Unable to create file source filter (%x)\n", hr);
1502         return hr;
1503     }
1504
1505     hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
1506     if (FAILED(hr)) {
1507         ERR("Unable add filter (%x)\n", hr);
1508         IBaseFilter_Release(preader);
1509         return hr;
1510     }
1511
1512     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1513     if (FAILED(hr)) {
1514         ERR("Unable to get IFileSourceInterface (%x)\n", hr);
1515         goto error;
1516     }
1517
1518     /* Load the file in the file source filter */
1519     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
1520     if (FAILED(hr)) {
1521         ERR("Load (%x)\n", hr);
1522         goto error;
1523     }
1524
1525     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1526     if (FAILED(hr)) {
1527         ERR("GetCurFile (%x)\n", hr);
1528         goto error;
1529     }
1530
1531     TRACE("File %s\n", debugstr_w(filename));
1532     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1533     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1534
1535     if (ppFilter)
1536         *ppFilter = preader;
1537     IFileSourceFilter_Release(pfile);
1538
1539     return S_OK;
1540     
1541 error:
1542     if (pfile)
1543         IFileSourceFilter_Release(pfile);
1544     IFilterGraph2_RemoveFilter(iface, preader);
1545     IBaseFilter_Release(preader);
1546        
1547     return hr;
1548 }
1549
1550 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface,
1551                                               DWORD_PTR hFile) {
1552     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1553
1554     TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1555
1556     return S_OK;
1557 }
1558
1559 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface) {
1560     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1561
1562     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1563
1564     return S_OK;
1565 }
1566
1567 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface) {
1568     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1569
1570     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1571
1572     return S_OK;
1573 }
1574
1575 /*** IFilterGraph2 methods ***/
1576 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1577                                                              IMoniker *pMoniker,
1578                                                              IBindCtx *pCtx,
1579                                                              LPCWSTR lpcwstrFilterName,
1580                                                              IBaseFilter **ppFilter) {
1581     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1582
1583     TRACE("(%p/%p)->(%p %p %s %p): stub !!!\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1584
1585     return S_OK;
1586 }
1587
1588 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface,
1589                                                IPin *ppin,
1590                                                const AM_MEDIA_TYPE *pmt) {
1591     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1592
1593     TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
1594
1595     return S_OK;
1596 }
1597
1598 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface,
1599                                             IPin *pPinOut,
1600                                             DWORD dwFlags,
1601                                             DWORD *pvContext) {
1602     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
1603
1604     TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
1605
1606     return S_OK;
1607 }
1608
1609
1610 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1611 {
1612     FilterGraph2_QueryInterface,
1613     FilterGraph2_AddRef,
1614     FilterGraph2_Release,
1615     FilterGraph2_AddFilter,
1616     FilterGraph2_RemoveFilter,
1617     FilterGraph2_EnumFilters,
1618     FilterGraph2_FindFilterByName,
1619     FilterGraph2_ConnectDirect,
1620     FilterGraph2_Reconnect,
1621     FilterGraph2_Disconnect,
1622     FilterGraph2_SetDefaultSyncSource,
1623     FilterGraph2_Connect,
1624     FilterGraph2_Render,
1625     FilterGraph2_RenderFile,
1626     FilterGraph2_AddSourceFilter,
1627     FilterGraph2_SetLogFile,
1628     FilterGraph2_Abort,
1629     FilterGraph2_ShouldOperationContinue,
1630     FilterGraph2_AddSourceFilterForMoniker,
1631     FilterGraph2_ReconnectEx,
1632     FilterGraph2_RenderEx
1633 };
1634
1635 /*** IUnknown methods ***/
1636 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface,
1637                                                   REFIID riid,
1638                                                   LPVOID*ppvObj) {
1639     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1640
1641     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1642
1643     return Filtergraph_QueryInterface(This, riid, ppvObj);
1644 }
1645
1646 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface) {
1647     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1648
1649     TRACE("(%p/%p)->()\n", This, iface);
1650
1651     return Filtergraph_AddRef(This);
1652 }
1653
1654 static ULONG WINAPI MediaControl_Release(IMediaControl *iface) {
1655     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1656
1657     TRACE("(%p/%p)->()\n", This, iface);
1658
1659     return Filtergraph_Release(This);
1660
1661 }
1662
1663 /*** IDispatch methods ***/
1664 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface,
1665                                                     UINT*pctinfo) {
1666     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1667
1668     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1669
1670     return S_OK;
1671 }
1672
1673 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface,
1674                                                UINT iTInfo,
1675                                                LCID lcid,
1676                                                ITypeInfo**ppTInfo) {
1677     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1678
1679     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1680
1681     return S_OK;
1682 }
1683
1684 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface,
1685                                                  REFIID riid,
1686                                                  LPOLESTR*rgszNames,
1687                                                  UINT cNames,
1688                                                  LCID lcid,
1689                                                  DISPID*rgDispId) {
1690     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1691
1692     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1693
1694     return S_OK;
1695 }
1696
1697 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface,
1698                                           DISPID dispIdMember,
1699                                           REFIID riid,
1700                                           LCID lcid,
1701                                           WORD wFlags,
1702                                           DISPPARAMS*pDispParams,
1703                                           VARIANT*pVarResult,
1704                                           EXCEPINFO*pExepInfo,
1705                                           UINT*puArgErr) {
1706     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1707
1708     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);
1709
1710     return S_OK;
1711 }
1712
1713 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *, DWORD_PTR data);
1714
1715 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
1716 {
1717     HRESULT hr;
1718     IPin* pInputPin;
1719     IPin** ppPins;
1720     ULONG nb;
1721     ULONG i;
1722     PIN_INFO PinInfo;
1723
1724     TRACE("%p %p\n", pGraph, pOutputPin);
1725     PinInfo.pFilter = NULL;
1726
1727     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1728
1729     if (SUCCEEDED(hr))
1730     {
1731         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1732         if (SUCCEEDED(hr))
1733             hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1734         IPin_Release(pInputPin);
1735     }
1736
1737     if (SUCCEEDED(hr))
1738     {
1739         if (nb == 0)
1740         {
1741             TRACE("Reached a renderer\n");
1742             /* Count renderers for end of stream notification */
1743             pGraph->nRenderers++;
1744         }
1745         else
1746         {
1747             for(i = 0; i < nb; i++)
1748             {
1749                 /* Explore the graph downstream from this pin
1750                  * FIXME: We should prevent exploring from a pin more than once. This can happens when
1751                  * several input pins are connected to the same output (a MUX for instance). */
1752                 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
1753                 IPin_Release(ppPins[i]);
1754             }
1755
1756             CoTaskMemFree(ppPins);
1757         }
1758         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1759
1760         FoundFilter(PinInfo.pFilter, data);
1761     }
1762
1763     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1764     return hr;
1765 }
1766
1767 static HRESULT WINAPI SendRun(IBaseFilter *pFilter, DWORD_PTR data)
1768 {
1769     LONGLONG time = 0;
1770     IReferenceClock *clock = NULL;
1771
1772     IBaseFilter_GetSyncSource(pFilter, &clock);
1773     if (clock)
1774     {
1775         IReferenceClock_GetTime(clock, &time);
1776         if (time)
1777             /* Add 50 ms */
1778             time += 500000;
1779         if (time < 0)
1780             time = 0;
1781         IReferenceClock_Release(clock);
1782     }
1783
1784     return IBaseFilter_Run(pFilter, time);
1785 }
1786
1787 static HRESULT WINAPI SendPause(IBaseFilter *pFilter, DWORD_PTR data)
1788 {
1789     return IBaseFilter_Pause(pFilter);
1790 }
1791
1792 static HRESULT WINAPI SendStop(IBaseFilter *pFilter, DWORD_PTR data)
1793 {
1794     return IBaseFilter_Stop(pFilter);
1795 }
1796
1797 static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data)
1798 {
1799     FILTER_STATE state;
1800     DWORD time_end = data;
1801     DWORD time_now = GetTickCount();
1802     LONG wait;
1803
1804     if (time_end == INFINITE)
1805     {
1806         wait = INFINITE;
1807     }
1808     else if (time_end > time_now)
1809     {
1810         wait = time_end - time_now;
1811     }
1812     else
1813         wait = 0;
1814
1815     return IBaseFilter_GetState(pFilter, wait, &state);
1816 }
1817
1818
1819 static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter, DWORD_PTR data)
1820 {
1821     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1822     int i;
1823     IBaseFilter* pfilter;
1824     IEnumPins* pEnum;
1825     HRESULT hr;
1826     IPin* pPin;
1827     DWORD dummy;
1828     PIN_DIRECTION dir;
1829     TRACE("(%p/%p)->()\n", This, iface);
1830
1831     /* Explorer the graph from source filters to renderers, determine renderers
1832      * number and run filters from renderers to source filters */
1833     This->nRenderers = 0;
1834     ResetEvent(This->hEventCompletion);
1835
1836     for(i = 0; i < This->nFilters; i++)
1837     {
1838         BOOL source = TRUE;
1839         pfilter = This->ppFiltersInGraph[i];
1840         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
1841         if (hr != S_OK)
1842         {
1843             ERR("Enum pins failed %x\n", hr);
1844             continue;
1845         }
1846         /* Check if it is a source filter */
1847         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1848         {
1849             IPin_QueryDirection(pPin, &dir);
1850             IPin_Release(pPin);
1851             if (dir == PINDIR_INPUT)
1852             {
1853                 source = FALSE;
1854                 break;
1855             }
1856         }
1857         if (source)
1858         {
1859             TRACE("Found a source filter %p\n", pfilter);
1860             IEnumPins_Reset(pEnum);
1861             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1862             {
1863                 /* Explore the graph downstream from this pin */
1864                 ExploreGraph(This, pPin, FoundFilter, data);
1865                 IPin_Release(pPin);
1866             }
1867             FoundFilter(pfilter, data);
1868         }
1869         IEnumPins_Release(pEnum);
1870     }
1871
1872     return S_FALSE;
1873 }
1874
1875 /*** IMediaControl methods ***/
1876 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface) {
1877     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1878     TRACE("(%p/%p)->()\n", This, iface);
1879
1880     if (This->state == State_Running) return S_OK;
1881
1882     EnterCriticalSection(&This->cs);
1883     if (This->state == State_Stopped)
1884         This->EcCompleteCount = 0;
1885
1886     if (This->refClock)
1887     {
1888         IReferenceClock_GetTime(This->refClock, &This->start_time);
1889         This->start_time += 500000;
1890     }
1891     else This->position = This->start_time = 0;
1892
1893     SendFilterMessage(iface, SendRun, 0);
1894     This->state = State_Running;
1895     LeaveCriticalSection(&This->cs);
1896     return S_FALSE;
1897 }
1898
1899 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface) {
1900     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1901     TRACE("(%p/%p)->()\n", This, iface);
1902
1903     if (This->state == State_Paused) return S_OK;
1904
1905     EnterCriticalSection(&This->cs);
1906     if (This->state == State_Stopped)
1907         This->EcCompleteCount = 0;
1908
1909     if (This->state == State_Running && This->refClock)
1910     {
1911         LONGLONG time = This->start_time;
1912         IReferenceClock_GetTime(This->refClock, &time);
1913         This->position += time - This->start_time;
1914     }
1915
1916     SendFilterMessage(iface, SendPause, 0);
1917     This->state = State_Paused;
1918     LeaveCriticalSection(&This->cs);
1919     return S_FALSE;
1920 }
1921
1922 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface) {
1923     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1924     TRACE("(%p/%p)->()\n", This, iface);
1925
1926     if (This->state == State_Stopped) return S_OK;
1927
1928     EnterCriticalSection(&This->cs);
1929     if (This->state == State_Running && This->refClock)
1930     {
1931         LONGLONG time = This->start_time;
1932         IReferenceClock_GetTime(This->refClock, &time);
1933         This->position += time - This->start_time;
1934     }
1935
1936     if (This->state == State_Running) SendFilterMessage(iface, SendPause, 0);
1937     SendFilterMessage(iface, SendStop, 0);
1938     This->state = State_Stopped;
1939     LeaveCriticalSection(&This->cs);
1940     return S_OK;
1941 }
1942
1943 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface,
1944                                             LONG msTimeout,
1945                                             OAFilterState *pfs) {
1946     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1947     DWORD end;
1948
1949     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
1950
1951     if (!pfs)
1952         return E_POINTER;
1953
1954     EnterCriticalSection(&This->cs);
1955
1956     *pfs = This->state;
1957     if (msTimeout > 0)
1958     {
1959         end = GetTickCount() + msTimeout;
1960     }
1961     else if (msTimeout < 0)
1962     {
1963         end = INFINITE;
1964     }
1965     else
1966     {
1967         end = 0;
1968     }
1969     if (end)
1970         SendFilterMessage(iface, SendGetState, end);
1971
1972     LeaveCriticalSection(&This->cs);
1973
1974     return S_OK;
1975 }
1976
1977 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface,
1978                                               BSTR strFilename) {
1979     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1980
1981     FIXME("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
1982
1983     return S_OK;
1984 }
1985
1986 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface,
1987                                                    BSTR strFilename,
1988                                                    IDispatch **ppUnk) {
1989     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1990
1991     FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
1992
1993     return S_OK;
1994 }
1995
1996 static HRESULT WINAPI MediaControl_get_FilterCollection(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_get_RegFilterCollection(IMediaControl *iface,
2006                                                            IDispatch **ppUnk) {
2007     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2008
2009     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2010
2011     return S_OK;
2012 }
2013
2014 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface) {
2015     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
2016
2017     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2018
2019     return S_OK;
2020 }
2021
2022
2023 static const IMediaControlVtbl IMediaControl_VTable =
2024 {
2025     MediaControl_QueryInterface,
2026     MediaControl_AddRef,
2027     MediaControl_Release,
2028     MediaControl_GetTypeInfoCount,
2029     MediaControl_GetTypeInfo,
2030     MediaControl_GetIDsOfNames,
2031     MediaControl_Invoke,
2032     MediaControl_Run,
2033     MediaControl_Pause,
2034     MediaControl_Stop,
2035     MediaControl_GetState,
2036     MediaControl_RenderFile,
2037     MediaControl_AddSourceFilter,
2038     MediaControl_get_FilterCollection,
2039     MediaControl_get_RegFilterCollection,
2040     MediaControl_StopWhenReady
2041 };
2042
2043
2044 /*** IUnknown methods ***/
2045 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface,
2046                                                   REFIID riid,
2047                                                   LPVOID*ppvObj) {
2048     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2049
2050     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2051
2052     return Filtergraph_QueryInterface(This, riid, ppvObj);
2053 }
2054
2055 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface) {
2056     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2057
2058     TRACE("(%p/%p)->()\n", This, iface);
2059
2060     return Filtergraph_AddRef(This);
2061 }
2062
2063 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface) {
2064     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2065
2066     TRACE("(%p/%p)->()\n", This, iface);
2067
2068     return Filtergraph_Release(This);
2069 }
2070
2071 typedef HRESULT WINAPI (*fnFoundSeek)(IFilterGraphImpl *This, IMediaSeeking*, DWORD_PTR arg);
2072
2073 static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2074     BOOL allnotimpl = TRUE;
2075     int i;
2076     IBaseFilter* pfilter;
2077     IEnumPins* pEnum;
2078     HRESULT hr, hr_return = S_OK;
2079     IPin* pPin;
2080     DWORD dummy;
2081     PIN_DIRECTION dir;
2082
2083     TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2084     /* Send a message to all renderers, they are responsible for broadcasting it further */
2085
2086     for(i = 0; i < This->nFilters; i++)
2087     {
2088         BOOL renderer = TRUE;
2089         pfilter = This->ppFiltersInGraph[i];
2090         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
2091         if (hr != S_OK)
2092         {
2093             ERR("Enum pins failed %x\n", hr);
2094             continue;
2095         }
2096         /* Check if it is a source filter */
2097         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
2098         {
2099             IPin_QueryDirection(pPin, &dir);
2100             IPin_Release(pPin);
2101             if (dir != PINDIR_INPUT)
2102             {
2103                 renderer = FALSE;
2104                 break;
2105             }
2106         }
2107         IEnumPins_Release(pEnum);
2108         if (renderer)
2109         {
2110             IMediaSeeking *seek = NULL;
2111             IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
2112             if (!seek)
2113                 continue;
2114
2115             hr = FoundSeek(This, seek, arg);
2116
2117             IMediaSeeking_Release(seek);
2118             if (hr_return != E_NOTIMPL)
2119                 allnotimpl = FALSE;
2120             if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && !FAILED(hr_return)))
2121                 hr_return = hr;
2122         }
2123     }
2124
2125     if (allnotimpl)
2126         return E_NOTIMPL;
2127     return hr_return;
2128 }
2129
2130 static HRESULT WINAPI FoundCapabilities(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2131 {
2132     HRESULT hr;
2133     DWORD caps = 0;
2134
2135     hr = IMediaSeeking_GetCapabilities(seek, &caps);
2136     if (FAILED(hr))
2137         return hr;
2138
2139     /* Only add common capabilities everything supports */
2140     *(DWORD*)pcaps &= caps;
2141
2142     return hr;
2143 }
2144
2145 /*** IMediaSeeking methods ***/
2146 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface,
2147                                                    DWORD *pCapabilities) {
2148     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2149     HRESULT hr;
2150     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2151
2152     if (!pCapabilities)
2153         return E_POINTER;
2154
2155     EnterCriticalSection(&This->cs);
2156     *pCapabilities = 0xffffffff;
2157
2158     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2159     LeaveCriticalSection(&This->cs);
2160
2161     return hr;
2162 }
2163
2164 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface,
2165                                                      DWORD *pCapabilities) {
2166     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2167     DWORD originalcaps;
2168     HRESULT hr;
2169     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2170
2171     if (!pCapabilities)
2172         return E_POINTER;
2173
2174     EnterCriticalSection(&This->cs);
2175     originalcaps = *pCapabilities;
2176     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2177     LeaveCriticalSection(&This->cs);
2178
2179     if (FAILED(hr))
2180         return hr;
2181
2182     if (!*pCapabilities)
2183         return E_FAIL;
2184     if (*pCapabilities != originalcaps)
2185         return S_FALSE;
2186     return S_OK;
2187 }
2188
2189 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface,
2190                                                      const GUID *pFormat) {
2191     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2192
2193     if (!pFormat)
2194         return E_POINTER;
2195
2196     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2197
2198     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2199     {
2200         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2201         return S_FALSE;
2202     }
2203
2204     return S_OK;
2205 }
2206
2207 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface,
2208                                                         GUID *pFormat) {
2209     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2210
2211     if (!pFormat)
2212         return E_POINTER;
2213
2214     FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2215     memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2216
2217     return S_OK;
2218 }
2219
2220 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface,
2221                                                  GUID *pFormat) {
2222     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2223
2224     if (!pFormat)
2225         return E_POINTER;
2226
2227     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2228     memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2229
2230     return S_OK;
2231 }
2232
2233 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface,
2234                                                      const GUID *pFormat) {
2235     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2236
2237     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2238     if (!pFormat)
2239         return E_POINTER;
2240
2241     if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2242         return S_FALSE;
2243
2244     return S_OK;
2245 }
2246
2247 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface,
2248                                                  const GUID *pFormat) {
2249     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2250
2251     if (!pFormat)
2252         return E_POINTER;
2253
2254     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2255
2256     if (This->state != State_Stopped)
2257         return VFW_E_WRONG_STATE;
2258
2259     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2260     {
2261         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2262         return E_INVALIDARG;
2263     }
2264
2265     return S_OK;
2266 }
2267
2268 static HRESULT WINAPI FoundDuration(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pduration)
2269 {
2270     HRESULT hr;
2271     LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2272
2273     hr = IMediaSeeking_GetDuration(seek, &duration);
2274     if (FAILED(hr))
2275         return hr;
2276
2277     /* FIXME: Minimum or maximum duration? Assuming minimum */
2278     if (duration > 0 && *pdur < duration)
2279         *pdur = duration;
2280
2281     return hr;
2282 }
2283
2284 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface,
2285                                                LONGLONG *pDuration) {
2286     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2287     HRESULT hr;
2288
2289     TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2290
2291     if (!pDuration)
2292         return E_POINTER;
2293
2294     EnterCriticalSection(&This->cs);
2295     *pDuration = -1;
2296     hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
2297     LeaveCriticalSection(&This->cs);
2298
2299     TRACE("--->%08x\n", hr);
2300     return hr;
2301 }
2302
2303 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface,
2304                                                    LONGLONG *pStop) {
2305     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2306     HRESULT hr = S_OK;
2307
2308     TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
2309
2310     if (!pStop)
2311         return E_POINTER;
2312
2313     EnterCriticalSection(&This->cs);
2314     if (This->stop_position < 0)
2315         /* Stop position not set, use duration instead */
2316         hr = IMediaSeeking_GetDuration(iface, pStop);
2317     else
2318         *pStop = This->stop_position;
2319
2320     LeaveCriticalSection(&This->cs);
2321
2322     return hr;
2323 }
2324
2325 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface,
2326                                                       LONGLONG *pCurrent) {
2327     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2328     LONGLONG time = 0;
2329
2330     if (!pCurrent)
2331         return E_POINTER;
2332
2333     EnterCriticalSection(&This->cs);
2334     if (This->state == State_Running && This->refClock)
2335     {
2336         IReferenceClock_GetTime(This->refClock, &time);
2337         if (time)
2338             time += This->position - This->start_time;
2339         if (time < This->position)
2340             time = This->position;
2341         *pCurrent = time;
2342     }
2343     else
2344         *pCurrent = This->position;
2345     LeaveCriticalSection(&This->cs);
2346
2347     TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
2348
2349     return S_OK;
2350 }
2351
2352 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface,
2353                                                      LONGLONG *pTarget,
2354                                                      const GUID *pTargetFormat,
2355                                                      LONGLONG Source,
2356                                                      const GUID *pSourceFormat) {
2357     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2358
2359     FIXME("(%p/%p)->(%p, %p, 0x%s, %p): stub !!!\n", This, iface, pTarget,
2360         pTargetFormat, wine_dbgstr_longlong(Source), pSourceFormat);
2361
2362     return S_OK;
2363 }
2364
2365 struct pos_args {
2366     LONGLONG* current, *stop;
2367     DWORD curflags, stopflags;
2368 };
2369
2370 static HRESULT WINAPI found_setposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
2371 {
2372     struct pos_args *args = (void*)pargs;
2373
2374     return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
2375 }
2376
2377 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface,
2378                                                 LONGLONG *pCurrent,
2379                                                 DWORD dwCurrentFlags,
2380                                                 LONGLONG *pStop,
2381                                                 DWORD dwStopFlags) {
2382     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2383     HRESULT hr = S_OK;
2384     FILTER_STATE state;
2385     struct pos_args args;
2386
2387     TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
2388
2389     EnterCriticalSection(&This->cs);
2390     state = This->state;
2391     TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
2392
2393     if ((dwCurrentFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
2394     {
2395         This->position = *pCurrent;
2396     }
2397     else if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2398         FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
2399
2400     if ((dwStopFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
2401         This->stop_position = *pStop;
2402     else if ((dwStopFlags & 0x7) != AM_SEEKING_NoPositioning)
2403         FIXME("Stop position not handled yet!\n");
2404
2405     args.current = pCurrent;
2406     args.stop = pStop;
2407     args.curflags = dwCurrentFlags;
2408     args.stopflags = dwStopFlags;
2409     hr = all_renderers_seek(This, found_setposition, (DWORD_PTR)&args);
2410
2411     if (This->refClock && ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning))
2412     {
2413         /* Update start time, prevents weird jumps */
2414         IReferenceClock_GetTime(This->refClock, &This->start_time);
2415     }
2416     LeaveCriticalSection(&This->cs);
2417
2418     return hr;
2419 }
2420
2421 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
2422                                                 LONGLONG *pCurrent,
2423                                                 LONGLONG *pStop) {
2424     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2425     HRESULT hr;
2426
2427     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
2428     hr = IMediaSeeking_GetCurrentPosition(iface, pCurrent);
2429     if (SUCCEEDED(hr))
2430         hr = IMediaSeeking_GetStopPosition(iface, pStop);
2431
2432     return hr;
2433 }
2434
2435 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
2436                                                 LONGLONG *pEarliest,
2437                                                 LONGLONG *pLatest) {
2438     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2439
2440     FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2441
2442     return S_OK;
2443 }
2444
2445 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface,
2446                                            double dRate) {
2447     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2448
2449     FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2450
2451     return S_OK;
2452 }
2453
2454 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface,
2455                                            double *pdRate) {
2456     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2457
2458     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2459
2460     return S_OK;
2461 }
2462
2463 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface,
2464                                               LONGLONG *pllPreroll) {
2465     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
2466
2467     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2468
2469     return S_OK;
2470 }
2471
2472
2473 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2474 {
2475     MediaSeeking_QueryInterface,
2476     MediaSeeking_AddRef,
2477     MediaSeeking_Release,
2478     MediaSeeking_GetCapabilities,
2479     MediaSeeking_CheckCapabilities,
2480     MediaSeeking_IsFormatSupported,
2481     MediaSeeking_QueryPreferredFormat,
2482     MediaSeeking_GetTimeFormat,
2483     MediaSeeking_IsUsingTimeFormat,
2484     MediaSeeking_SetTimeFormat,
2485     MediaSeeking_GetDuration,
2486     MediaSeeking_GetStopPosition,
2487     MediaSeeking_GetCurrentPosition,
2488     MediaSeeking_ConvertTimeFormat,
2489     MediaSeeking_SetPositions,
2490     MediaSeeking_GetPositions,
2491     MediaSeeking_GetAvailable,
2492     MediaSeeking_SetRate,
2493     MediaSeeking_GetRate,
2494     MediaSeeking_GetPreroll
2495 };
2496
2497 /*** IUnknown methods ***/
2498 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj){
2499     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface);
2500
2501     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2502
2503     return Filtergraph_QueryInterface(This, riid, ppvObj);
2504 }
2505
2506 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface){
2507     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface);
2508
2509     TRACE("(%p/%p)->()\n", This, iface);
2510
2511     return Filtergraph_AddRef(This);
2512 }
2513
2514 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface){
2515     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface);
2516
2517     TRACE("(%p/%p)->()\n", This, iface);
2518
2519     return Filtergraph_Release(This);
2520 }
2521
2522 /*** IDispatch methods ***/
2523 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo){
2524     FIXME("(%p) stub!\n", iface);
2525     return E_NOTIMPL;
2526 }
2527
2528 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo){
2529     FIXME("(%p) stub!\n", iface);
2530     return E_NOTIMPL;
2531 }
2532
2533 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId){
2534     FIXME("(%p) stub!\n", iface);
2535     return E_NOTIMPL;
2536 }
2537
2538 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr){
2539     FIXME("(%p) stub!\n", iface);
2540     return E_NOTIMPL;
2541 }
2542
2543 /*** IMediaPosition methods ***/
2544 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength){
2545     FIXME("(%p)->(%p) stub!\n", iface, plength);
2546     return E_NOTIMPL;
2547 }
2548
2549 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime){
2550     FIXME("(%p)->(%f) stub!\n", iface, llTime);
2551     return E_NOTIMPL;
2552 }
2553
2554 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime){
2555     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2556     return E_NOTIMPL;
2557 }
2558
2559 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime){
2560     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2561     return E_NOTIMPL;
2562 }
2563
2564 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime){
2565     FIXME("(%p)->(%f) stub!\n", iface, llTime);
2566     return E_NOTIMPL;
2567 }
2568
2569 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){
2570     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2571     return E_NOTIMPL;
2572 }
2573
2574 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime){
2575     FIXME("(%p)->(%f) stub!\n", iface, llTime);
2576     return E_NOTIMPL;
2577 }
2578
2579 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate){
2580     FIXME("(%p)->(%f) stub!\n", iface, dRate);
2581     return E_NOTIMPL;
2582 }
2583
2584 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate){
2585     FIXME("(%p)->(%p) stub!\n", iface, pdRate);
2586     return E_NOTIMPL;
2587 }
2588
2589 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){
2590     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2591     return E_NOTIMPL;
2592 }
2593
2594 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward){
2595     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2596     return E_NOTIMPL;
2597 }
2598
2599
2600 static const IMediaPositionVtbl IMediaPosition_VTable =
2601 {
2602     MediaPosition_QueryInterface,
2603     MediaPosition_AddRef,
2604     MediaPosition_Release,
2605     MediaPosition_GetTypeInfoCount,
2606     MediaPosition_GetTypeInfo,
2607     MediaPosition_GetIDsOfNames,
2608     MediaPosition_Invoke,
2609     MediaPosition_get_Duration,
2610     MediaPosition_put_CurrentPosition,
2611     MediaPosition_get_CurrentPosition,
2612     MediaPosition_get_StopTime,
2613     MediaPosition_put_StopTime,
2614     MediaPosition_get_PrerollTime,
2615     MediaPosition_put_PrerollTime,
2616     MediaPosition_put_Rate,
2617     MediaPosition_get_Rate,
2618     MediaPosition_CanSeekForward,
2619     MediaPosition_CanSeekBackward
2620 };
2621
2622 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
2623 {
2624     HRESULT hr = E_NOINTERFACE;
2625     int i;
2626     int entry;
2627
2628     /* Check if the interface type is already registered */
2629     for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2630         if (riid == pGraph->ItfCacheEntries[entry].riid)
2631         {
2632             if (pGraph->ItfCacheEntries[entry].iface)
2633             {
2634                 /* Return the interface if available */
2635                 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2636                 return S_OK;
2637             }
2638             break;
2639         }
2640
2641     if (entry >= MAX_ITF_CACHE_ENTRIES)
2642     {
2643         FIXME("Not enough space to store interface in the cache\n");
2644         return E_OUTOFMEMORY;
2645     }
2646
2647     /* Find a filter supporting the requested interface */
2648     for (i = 0; i < pGraph->nFilters; i++)
2649     {
2650         hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
2651         if (hr == S_OK)
2652         {
2653             pGraph->ItfCacheEntries[entry].riid = riid;
2654             pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
2655             pGraph->ItfCacheEntries[entry].iface = (IUnknown*)*ppvObj;
2656             if (entry >= pGraph->nItfCacheEntries)
2657                 pGraph->nItfCacheEntries++;
2658             return S_OK;
2659         }
2660         if (hr != E_NOINTERFACE)
2661             return hr;
2662     }
2663
2664     return hr;
2665 }
2666
2667 /*** IUnknown methods ***/
2668 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface,
2669                                                 REFIID riid,
2670                                                 LPVOID*ppvObj) {
2671     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2672
2673     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2674
2675     return Filtergraph_QueryInterface(This, riid, ppvObj);
2676 }
2677
2678 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface) {
2679     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2680
2681     TRACE("(%p/%p)->()\n", This, iface);
2682
2683     return Filtergraph_AddRef(This);
2684 }
2685
2686 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface) {
2687     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2688
2689     TRACE("(%p/%p)->()\n", This, iface);
2690
2691     return Filtergraph_Release(This);
2692 }
2693
2694 /*** IDispatch methods ***/
2695 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface,
2696                                                   UINT*pctinfo) {
2697     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2698     IBasicAudio* pBasicAudio;
2699     HRESULT hr;
2700
2701     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
2702
2703     EnterCriticalSection(&This->cs);
2704
2705     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2706
2707     if (hr == S_OK)
2708         hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
2709
2710     LeaveCriticalSection(&This->cs);
2711
2712     return hr;
2713 }
2714
2715 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface,
2716                                              UINT iTInfo,
2717                                              LCID lcid,
2718                                              ITypeInfo**ppTInfo) {
2719     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2720     IBasicAudio* pBasicAudio;
2721     HRESULT hr;
2722
2723     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
2724
2725     EnterCriticalSection(&This->cs);
2726
2727     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2728
2729     if (hr == S_OK)
2730         hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
2731
2732     LeaveCriticalSection(&This->cs);
2733
2734     return hr;
2735 }
2736
2737 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface,
2738                                                REFIID riid,
2739                                                LPOLESTR*rgszNames,
2740                                                UINT cNames,
2741                                                LCID lcid,
2742                                                DISPID*rgDispId) {
2743     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2744     IBasicAudio* pBasicAudio;
2745     HRESULT hr;
2746
2747     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2748
2749     EnterCriticalSection(&This->cs);
2750
2751     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2752
2753     if (hr == S_OK)
2754         hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
2755
2756     LeaveCriticalSection(&This->cs);
2757
2758     return hr;
2759 }
2760
2761 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface,
2762                                         DISPID dispIdMember,
2763                                         REFIID riid,
2764                                         LCID lcid,
2765                                         WORD wFlags,
2766                                         DISPPARAMS*pDispParams,
2767                                         VARIANT*pVarResult,
2768                                         EXCEPINFO*pExepInfo,
2769                                         UINT*puArgErr) {
2770     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2771     IBasicAudio* pBasicAudio;
2772     HRESULT hr;
2773
2774     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);
2775
2776     EnterCriticalSection(&This->cs);
2777
2778     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2779
2780     if (hr == S_OK)
2781         hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2782
2783     LeaveCriticalSection(&This->cs);
2784
2785     return hr;
2786 }
2787
2788 /*** IBasicAudio methods ***/
2789 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface,
2790                                             long lVolume) {
2791     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2792     IBasicAudio* pBasicAudio;
2793     HRESULT hr;
2794
2795     TRACE("(%p/%p)->(%ld)\n", This, iface, lVolume);
2796
2797     EnterCriticalSection(&This->cs);
2798
2799     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2800
2801     if (hr == S_OK)
2802         hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
2803
2804     LeaveCriticalSection(&This->cs);
2805
2806     return hr;
2807 }
2808
2809 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface,
2810                                             long *plVolume) {
2811     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2812     IBasicAudio* pBasicAudio;
2813     HRESULT hr;
2814
2815     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
2816
2817     EnterCriticalSection(&This->cs);
2818
2819     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2820
2821     if (hr == S_OK)
2822         hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
2823
2824     LeaveCriticalSection(&This->cs);
2825
2826     return hr;
2827 }
2828
2829 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface,
2830                                              long lBalance) {
2831     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2832     IBasicAudio* pBasicAudio;
2833     HRESULT hr;
2834
2835     TRACE("(%p/%p)->(%ld)\n", This, iface, lBalance);
2836
2837     EnterCriticalSection(&This->cs);
2838
2839     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2840
2841     if (hr == S_OK)
2842         hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
2843
2844     LeaveCriticalSection(&This->cs);
2845
2846     return hr;
2847 }
2848
2849 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface,
2850                                              long *plBalance) {
2851     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
2852     IBasicAudio* pBasicAudio;
2853     HRESULT hr;
2854
2855     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
2856
2857     EnterCriticalSection(&This->cs);
2858
2859     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2860
2861     if (hr == S_OK)
2862         hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
2863
2864     LeaveCriticalSection(&This->cs);
2865
2866     return hr;
2867 }
2868
2869 static const IBasicAudioVtbl IBasicAudio_VTable =
2870 {
2871     BasicAudio_QueryInterface,
2872     BasicAudio_AddRef,
2873     BasicAudio_Release,
2874     BasicAudio_GetTypeInfoCount,
2875     BasicAudio_GetTypeInfo,
2876     BasicAudio_GetIDsOfNames,
2877     BasicAudio_Invoke,
2878     BasicAudio_put_Volume,
2879     BasicAudio_get_Volume,
2880     BasicAudio_put_Balance,
2881     BasicAudio_get_Balance
2882 };
2883
2884 /*** IUnknown methods ***/
2885 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface,
2886                                                 REFIID riid,
2887                                                 LPVOID*ppvObj) {
2888     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2889
2890     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2891
2892     return Filtergraph_QueryInterface(This, riid, ppvObj);
2893 }
2894
2895 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface) {
2896     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2897
2898     TRACE("(%p/%p)->()\n", This, iface);
2899
2900     return Filtergraph_AddRef(This);
2901 }
2902
2903 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface) {
2904     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2905
2906     TRACE("(%p/%p)->()\n", This, iface);
2907
2908     return Filtergraph_Release(This);
2909 }
2910
2911 /*** IDispatch methods ***/
2912 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface,
2913                                                   UINT*pctinfo) {
2914     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2915     IBasicVideo* pBasicVideo;
2916     HRESULT hr;
2917
2918     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
2919
2920     EnterCriticalSection(&This->cs);
2921
2922     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2923
2924     if (hr == S_OK)
2925         hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
2926
2927     LeaveCriticalSection(&This->cs);
2928
2929     return hr;
2930 }
2931
2932 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface,
2933                                              UINT iTInfo,
2934                                              LCID lcid,
2935                                              ITypeInfo**ppTInfo) {
2936     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2937     IBasicVideo* pBasicVideo;
2938     HRESULT hr;
2939
2940     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
2941
2942     EnterCriticalSection(&This->cs);
2943
2944     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2945
2946     if (hr == S_OK)
2947         hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
2948
2949     LeaveCriticalSection(&This->cs);
2950
2951     return hr;
2952 }
2953
2954 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface,
2955                                                REFIID riid,
2956                                                LPOLESTR*rgszNames,
2957                                                UINT cNames,
2958                                                LCID lcid,
2959                                                DISPID*rgDispId) {
2960     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2961     IBasicVideo* pBasicVideo;
2962     HRESULT hr;
2963
2964     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2965
2966     EnterCriticalSection(&This->cs);
2967
2968     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2969
2970     if (hr == S_OK)
2971         hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
2972
2973     LeaveCriticalSection(&This->cs);
2974
2975     return hr;
2976 }
2977
2978 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface,
2979                                         DISPID dispIdMember,
2980                                         REFIID riid,
2981                                         LCID lcid,
2982                                         WORD wFlags,
2983                                         DISPPARAMS*pDispParams,
2984                                         VARIANT*pVarResult,
2985                                         EXCEPINFO*pExepInfo,
2986                                         UINT*puArgErr) {
2987     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2988     IBasicVideo* pBasicVideo;
2989     HRESULT hr;
2990
2991     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);
2992
2993     EnterCriticalSection(&This->cs);
2994
2995     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
2996
2997     if (hr == S_OK)
2998         hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2999
3000     LeaveCriticalSection(&This->cs);
3001
3002     return hr;
3003 }
3004
3005 /*** IBasicVideo methods ***/
3006 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface,
3007                                                      REFTIME *pAvgTimePerFrame) {
3008     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3009     IBasicVideo* pBasicVideo;
3010     HRESULT hr;
3011
3012     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3013
3014     EnterCriticalSection(&This->cs);
3015
3016     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3017
3018     if (hr == S_OK)
3019         hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3020
3021     LeaveCriticalSection(&This->cs);
3022
3023     return hr;
3024 }
3025
3026 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface,
3027                                              long *pBitRate) {
3028     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3029     IBasicVideo* pBasicVideo;
3030     HRESULT hr;
3031
3032     TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3033
3034     EnterCriticalSection(&This->cs);
3035
3036     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3037
3038     if (hr == S_OK)
3039         hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3040
3041     LeaveCriticalSection(&This->cs);
3042
3043     return hr;
3044 }
3045
3046 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface,
3047                                                   long *pBitErrorRate) {
3048     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3049     IBasicVideo* pBasicVideo;
3050     HRESULT hr;
3051
3052     TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3053
3054     EnterCriticalSection(&This->cs);
3055
3056     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3057
3058     if (hr == S_OK)
3059         hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3060
3061     LeaveCriticalSection(&This->cs);
3062
3063     return hr;
3064 }
3065
3066 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface,
3067                                                 long *pVideoWidth) {
3068     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3069     IBasicVideo* pBasicVideo;
3070     HRESULT hr;
3071
3072     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3073
3074     EnterCriticalSection(&This->cs);
3075
3076     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3077
3078     if (hr == S_OK)
3079         hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3080
3081     LeaveCriticalSection(&This->cs);
3082
3083     return hr;
3084 }
3085
3086 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface,
3087                                                  long *pVideoHeight) {
3088     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3089     IBasicVideo* pBasicVideo;
3090     HRESULT hr;
3091
3092     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3093
3094     EnterCriticalSection(&This->cs);
3095
3096     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3097
3098     if (hr == S_OK)
3099         hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3100
3101     LeaveCriticalSection(&This->cs);
3102
3103     return hr;
3104 }
3105
3106 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface,
3107                                                 long SourceLeft) {
3108     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3109     IBasicVideo* pBasicVideo;
3110     HRESULT hr;
3111
3112     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceLeft);
3113
3114     EnterCriticalSection(&This->cs);
3115
3116     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3117
3118     if (hr == S_OK)
3119         hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3120
3121     LeaveCriticalSection(&This->cs);
3122
3123     return hr;
3124 }
3125
3126 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface,
3127                                                 long *pSourceLeft) {
3128     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3129     IBasicVideo* pBasicVideo;
3130     HRESULT hr;
3131
3132     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3133
3134     EnterCriticalSection(&This->cs);
3135
3136     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3137
3138     if (hr == S_OK)
3139         hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3140
3141     LeaveCriticalSection(&This->cs);
3142
3143     return hr;
3144 }
3145
3146 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface,
3147                                                  long SourceWidth) {
3148     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3149     IBasicVideo* pBasicVideo;
3150     HRESULT hr;
3151
3152     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceWidth);
3153
3154     EnterCriticalSection(&This->cs);
3155
3156     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3157
3158     if (hr == S_OK)
3159         hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3160
3161     LeaveCriticalSection(&This->cs);
3162
3163     return hr;
3164 }
3165
3166 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface,
3167                                                  long *pSourceWidth) {
3168     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3169     IBasicVideo* pBasicVideo;
3170     HRESULT hr;
3171
3172     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3173
3174     EnterCriticalSection(&This->cs);
3175
3176     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3177
3178     if (hr == S_OK)
3179         hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3180
3181     LeaveCriticalSection(&This->cs);
3182
3183     return hr;
3184 }
3185
3186 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface,
3187                                                long SourceTop) {
3188     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3189     IBasicVideo* pBasicVideo;
3190     HRESULT hr;
3191
3192     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceTop);
3193
3194     EnterCriticalSection(&This->cs);
3195
3196     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3197
3198     if (hr == S_OK)
3199         hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3200
3201     LeaveCriticalSection(&This->cs);
3202
3203     return hr;
3204 }
3205
3206 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface,
3207                                                long *pSourceTop) {
3208     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3209     IBasicVideo* pBasicVideo;
3210     HRESULT hr;
3211
3212     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3213
3214     EnterCriticalSection(&This->cs);
3215
3216     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3217
3218     if (hr == S_OK)
3219         hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3220
3221     LeaveCriticalSection(&This->cs);
3222
3223     return hr;
3224 }
3225
3226 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface,
3227                                                   long SourceHeight) {
3228     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3229     IBasicVideo* pBasicVideo;
3230     HRESULT hr;
3231
3232     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceHeight);
3233
3234     EnterCriticalSection(&This->cs);
3235
3236     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3237
3238     if (hr == S_OK)
3239         hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3240
3241     LeaveCriticalSection(&This->cs);
3242
3243     return hr;
3244 }
3245
3246 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface,
3247                                                   long *pSourceHeight) {
3248     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3249     IBasicVideo* pBasicVideo;
3250     HRESULT hr;
3251
3252     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3253
3254     EnterCriticalSection(&This->cs);
3255
3256     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3257
3258     if (hr == S_OK)
3259         hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3260
3261     LeaveCriticalSection(&This->cs);
3262
3263     return hr;
3264 }
3265
3266 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface,
3267                                                      long DestinationLeft) {
3268     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3269     IBasicVideo* pBasicVideo;
3270     HRESULT hr;
3271
3272     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationLeft);
3273
3274     EnterCriticalSection(&This->cs);
3275
3276     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3277
3278     if (hr == S_OK)
3279         hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3280
3281     LeaveCriticalSection(&This->cs);
3282
3283     return hr;
3284 }
3285
3286 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface,
3287                                                      long *pDestinationLeft) {
3288     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3289     IBasicVideo* pBasicVideo;
3290     HRESULT hr;
3291
3292     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3293
3294     EnterCriticalSection(&This->cs);
3295
3296     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3297
3298     if (hr == S_OK)
3299         hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3300
3301     LeaveCriticalSection(&This->cs);
3302
3303     return hr;
3304 }
3305
3306 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface,
3307                                                       long DestinationWidth) {
3308     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3309     IBasicVideo* pBasicVideo;
3310     HRESULT hr;
3311
3312     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationWidth);
3313
3314     EnterCriticalSection(&This->cs);
3315
3316     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3317
3318     if (hr == S_OK)
3319         hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3320
3321     LeaveCriticalSection(&This->cs);
3322
3323     return hr;
3324 }
3325
3326 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface,
3327                                                       long *pDestinationWidth) {
3328     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3329     IBasicVideo* pBasicVideo;
3330     HRESULT hr;
3331
3332     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3333
3334     EnterCriticalSection(&This->cs);
3335
3336     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3337
3338     if (hr == S_OK)
3339         hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3340
3341     LeaveCriticalSection(&This->cs);
3342
3343     return hr;
3344 }
3345
3346 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface,
3347                                                     long DestinationTop) {
3348     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3349     IBasicVideo* pBasicVideo;
3350     HRESULT hr;
3351
3352     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationTop);
3353
3354     EnterCriticalSection(&This->cs);
3355
3356     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3357
3358     if (hr == S_OK)
3359         hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3360
3361     LeaveCriticalSection(&This->cs);
3362
3363     return hr;
3364 }
3365
3366 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface,
3367                                                     long *pDestinationTop) {
3368     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3369     IBasicVideo* pBasicVideo;
3370     HRESULT hr;
3371
3372     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3373
3374     EnterCriticalSection(&This->cs);
3375
3376     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3377
3378     if (hr == S_OK)
3379         hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3380
3381     LeaveCriticalSection(&This->cs);
3382
3383     return hr;
3384 }
3385
3386 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface,
3387                                                        long DestinationHeight) {
3388     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3389     IBasicVideo* pBasicVideo;
3390     HRESULT hr;
3391
3392     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationHeight);
3393
3394     EnterCriticalSection(&This->cs);
3395
3396     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3397
3398     if (hr == S_OK)
3399         hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3400
3401     LeaveCriticalSection(&This->cs);
3402
3403     return hr;
3404 }
3405
3406 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3407                                                        long *pDestinationHeight) {
3408     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3409     IBasicVideo* pBasicVideo;
3410     HRESULT hr;
3411
3412     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3413
3414     EnterCriticalSection(&This->cs);
3415
3416     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3417
3418     if (hr == S_OK)
3419         hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3420
3421     LeaveCriticalSection(&This->cs);
3422
3423     return hr;
3424 }
3425
3426 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface,
3427                                                    long Left,
3428                                                    long Top,
3429                                                    long Width,
3430                                                    long Height) {
3431     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3432     IBasicVideo* pBasicVideo;
3433     HRESULT hr;
3434
3435     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
3436
3437     EnterCriticalSection(&This->cs);
3438
3439     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3440
3441     if (hr == S_OK)
3442         hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3443
3444     LeaveCriticalSection(&This->cs);
3445
3446     return hr;
3447 }
3448
3449 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface,
3450                                                    long *pLeft,
3451                                                    long *pTop,
3452                                                    long *pWidth,
3453                                                    long *pHeight) {
3454     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3455     IBasicVideo* pBasicVideo;
3456     HRESULT hr;
3457
3458     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3459
3460     EnterCriticalSection(&This->cs);
3461
3462     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3463
3464     if (hr == S_OK)
3465         hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3466
3467     LeaveCriticalSection(&This->cs);
3468
3469     return hr;
3470 }
3471
3472 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface) {
3473     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3474     IBasicVideo* pBasicVideo;
3475     HRESULT hr;
3476
3477     TRACE("(%p/%p)->()\n", This, iface);
3478
3479     EnterCriticalSection(&This->cs);
3480
3481     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3482
3483     if (hr == S_OK)
3484         hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3485
3486     LeaveCriticalSection(&This->cs);
3487
3488     return hr;
3489 }
3490
3491 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface,
3492                                                         long Left,
3493                                                         long Top,
3494                                                         long Width,
3495                                                         long Height) {
3496     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3497     IBasicVideo* pBasicVideo;
3498     HRESULT hr;
3499
3500     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
3501
3502     EnterCriticalSection(&This->cs);
3503
3504     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3505
3506     if (hr == S_OK)
3507         hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3508
3509     LeaveCriticalSection(&This->cs);
3510
3511     return hr;
3512 }
3513
3514 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface,
3515                                                         long *pLeft,
3516                                                         long *pTop,
3517                                                         long *pWidth,
3518                                                         long *pHeight) {
3519     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3520     IBasicVideo* pBasicVideo;
3521     HRESULT hr;
3522
3523     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3524
3525     EnterCriticalSection(&This->cs);
3526
3527     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3528
3529     if (hr == S_OK)
3530         hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3531
3532     LeaveCriticalSection(&This->cs);
3533
3534     return hr;
3535 }
3536
3537 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface) {
3538     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3539     IBasicVideo* pBasicVideo;
3540     HRESULT hr;
3541
3542     TRACE("(%p/%p)->()\n", This, iface);
3543
3544     EnterCriticalSection(&This->cs);
3545
3546     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3547
3548     if (hr == S_OK)
3549         hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3550
3551     LeaveCriticalSection(&This->cs);
3552
3553     return hr;
3554 }
3555
3556 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface,
3557                                               long *pWidth,
3558                                               long *pHeight) {
3559     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3560     IBasicVideo* pBasicVideo;
3561     HRESULT hr;
3562
3563     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3564
3565     EnterCriticalSection(&This->cs);
3566
3567     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3568
3569     if (hr == S_OK)
3570         hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3571
3572     LeaveCriticalSection(&This->cs);
3573
3574     return hr;
3575 }
3576
3577 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface,
3578                                                         long StartIndex,
3579                                                         long Entries,
3580                                                         long *pRetrieved,
3581                                                         long *pPalette) {
3582     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3583     IBasicVideo* pBasicVideo;
3584     HRESULT hr;
3585
3586     TRACE("(%p/%p)->(%ld, %ld, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3587
3588     EnterCriticalSection(&This->cs);
3589
3590     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3591
3592     if (hr == S_OK)
3593         hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3594
3595     LeaveCriticalSection(&This->cs);
3596
3597     return hr;
3598 }
3599
3600 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface,
3601                                                  long *pBufferSize,
3602                                                  long *pDIBImage) {
3603     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3604     IBasicVideo* pBasicVideo;
3605     HRESULT hr;
3606
3607     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3608
3609     EnterCriticalSection(&This->cs);
3610
3611     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3612
3613     if (hr == S_OK)
3614         hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3615
3616     LeaveCriticalSection(&This->cs);
3617
3618     return hr;
3619 }
3620
3621 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface) {
3622     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3623     IBasicVideo* pBasicVideo;
3624     HRESULT hr;
3625
3626     TRACE("(%p/%p)->()\n", This, iface);
3627
3628     EnterCriticalSection(&This->cs);
3629
3630     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3631
3632     if (hr == S_OK)
3633         hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3634
3635     LeaveCriticalSection(&This->cs);
3636
3637     return hr;
3638 }
3639
3640 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface) {
3641     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3642     IBasicVideo* pBasicVideo;
3643     HRESULT hr;
3644
3645     TRACE("(%p/%p)->()\n", This, iface);
3646
3647     EnterCriticalSection(&This->cs);
3648
3649     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3650
3651     if (hr == S_OK)
3652         hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3653
3654     LeaveCriticalSection(&This->cs);
3655
3656     return hr;
3657 }
3658
3659 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX, LONG *plAspectY) {
3660     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
3661     IBasicVideo2 *pBasicVideo2;
3662     HRESULT hr;
3663
3664     TRACE("(%p/%p)->()\n", This, iface);
3665
3666     EnterCriticalSection(&This->cs);
3667
3668     hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3669
3670     if (hr == S_OK)
3671         hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3672
3673     LeaveCriticalSection(&This->cs);
3674
3675     return hr;
3676 }
3677
3678 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3679 {
3680     BasicVideo_QueryInterface,
3681     BasicVideo_AddRef,
3682     BasicVideo_Release,
3683     BasicVideo_GetTypeInfoCount,
3684     BasicVideo_GetTypeInfo,
3685     BasicVideo_GetIDsOfNames,
3686     BasicVideo_Invoke,
3687     BasicVideo_get_AvgTimePerFrame,
3688     BasicVideo_get_BitRate,
3689     BasicVideo_get_BitErrorRate,
3690     BasicVideo_get_VideoWidth,
3691     BasicVideo_get_VideoHeight,
3692     BasicVideo_put_SourceLeft,
3693     BasicVideo_get_SourceLeft,
3694     BasicVideo_put_SourceWidth,
3695     BasicVideo_get_SourceWidth,
3696     BasicVideo_put_SourceTop,
3697     BasicVideo_get_SourceTop,
3698     BasicVideo_put_SourceHeight,
3699     BasicVideo_get_SourceHeight,
3700     BasicVideo_put_DestinationLeft,
3701     BasicVideo_get_DestinationLeft,
3702     BasicVideo_put_DestinationWidth,
3703     BasicVideo_get_DestinationWidth,
3704     BasicVideo_put_DestinationTop,
3705     BasicVideo_get_DestinationTop,
3706     BasicVideo_put_DestinationHeight,
3707     BasicVideo_get_DestinationHeight,
3708     BasicVideo_SetSourcePosition,
3709     BasicVideo_GetSourcePosition,
3710     BasicVideo_SetDefaultSourcePosition,
3711     BasicVideo_SetDestinationPosition,
3712     BasicVideo_GetDestinationPosition,
3713     BasicVideo_SetDefaultDestinationPosition,
3714     BasicVideo_GetVideoSize,
3715     BasicVideo_GetVideoPaletteEntries,
3716     BasicVideo_GetCurrentImage,
3717     BasicVideo_IsUsingDefaultSource,
3718     BasicVideo_IsUsingDefaultDestination,
3719     BasicVideo2_GetPreferredAspectRatio
3720 };
3721
3722
3723 /*** IUnknown methods ***/
3724 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface,
3725                                                  REFIID riid,
3726                                                  LPVOID*ppvObj) {
3727     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3728
3729     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3730
3731     return Filtergraph_QueryInterface(This, riid, ppvObj);
3732 }
3733
3734 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface) {
3735     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3736
3737     TRACE("(%p/%p)->()\n", This, iface);
3738
3739     return Filtergraph_AddRef(This);
3740 }
3741
3742 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface) {
3743     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3744
3745     TRACE("(%p/%p)->()\n", This, iface);
3746
3747     return Filtergraph_Release(This);
3748 }
3749
3750 /*** IDispatch methods ***/
3751 static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface,
3752                                                    UINT*pctinfo) {
3753     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3754     IVideoWindow* pVideoWindow;
3755     HRESULT hr;
3756
3757     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3758
3759     EnterCriticalSection(&This->cs);
3760
3761     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3762
3763     if (hr == S_OK)
3764         hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
3765
3766     LeaveCriticalSection(&This->cs);
3767
3768     return hr;
3769 }
3770
3771 static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface,
3772                                               UINT iTInfo,
3773                                               LCID lcid,
3774                                               ITypeInfo**ppTInfo) {
3775     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3776     IVideoWindow* pVideoWindow;
3777     HRESULT hr;
3778
3779     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3780
3781     EnterCriticalSection(&This->cs);
3782
3783     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3784
3785     if (hr == S_OK)
3786         hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
3787
3788     LeaveCriticalSection(&This->cs);
3789
3790     return hr;
3791 }
3792
3793 static HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface,
3794                                                 REFIID riid,
3795                                                 LPOLESTR*rgszNames,
3796                                                 UINT cNames,
3797                                                 LCID lcid,
3798                                                 DISPID*rgDispId) {
3799     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3800     IVideoWindow* pVideoWindow;
3801     HRESULT hr;
3802
3803     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3804
3805     EnterCriticalSection(&This->cs);
3806
3807     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3808
3809     if (hr == S_OK)
3810         hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
3811
3812     LeaveCriticalSection(&This->cs);
3813
3814     return hr;
3815 }
3816
3817 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface,
3818                                          DISPID dispIdMember,
3819                                          REFIID riid,
3820                                          LCID lcid,
3821                                          WORD wFlags,
3822                                          DISPPARAMS*pDispParams,
3823                                          VARIANT*pVarResult,
3824                                          EXCEPINFO*pExepInfo,
3825                                          UINT*puArgErr) {
3826     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3827     IVideoWindow* pVideoWindow;
3828     HRESULT hr;
3829
3830     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);
3831
3832     EnterCriticalSection(&This->cs);
3833
3834     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3835
3836     if (hr == S_OK)
3837         hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3838
3839     LeaveCriticalSection(&This->cs);
3840
3841     return hr;
3842 }
3843
3844
3845 /*** IVideoWindow methods ***/
3846 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface,
3847                                               BSTR strCaption) {
3848     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3849     IVideoWindow* pVideoWindow;
3850     HRESULT hr;
3851     
3852     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
3853
3854     EnterCriticalSection(&This->cs);
3855
3856     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3857
3858     if (hr == S_OK)
3859         hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
3860
3861     LeaveCriticalSection(&This->cs);
3862
3863     return hr;
3864 }
3865
3866 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface,
3867                                               BSTR *strCaption) {
3868     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3869     IVideoWindow* pVideoWindow;
3870     HRESULT hr;
3871
3872     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
3873
3874     EnterCriticalSection(&This->cs);
3875
3876     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3877
3878     if (hr == S_OK)
3879         hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
3880
3881     LeaveCriticalSection(&This->cs);
3882
3883     return hr;
3884 }
3885
3886 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface,
3887                                                   long WindowStyle) {
3888     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3889     IVideoWindow* pVideoWindow;
3890     HRESULT hr;
3891
3892     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowStyle);
3893
3894     EnterCriticalSection(&This->cs);
3895
3896     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3897
3898     if (hr == S_OK)
3899         hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
3900
3901     LeaveCriticalSection(&This->cs);
3902
3903     return hr;
3904 }
3905
3906 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface,
3907                                                   long *WindowStyle) {
3908     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3909     IVideoWindow* pVideoWindow;
3910     HRESULT hr;
3911
3912     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
3913
3914     EnterCriticalSection(&This->cs);
3915
3916     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3917
3918     if (hr == S_OK)
3919         hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
3920
3921     LeaveCriticalSection(&This->cs);
3922
3923     return hr;
3924 }
3925
3926 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface,
3927                                                     long WindowStyleEx) {
3928     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3929     IVideoWindow* pVideoWindow;
3930     HRESULT hr;
3931
3932     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowStyleEx);
3933
3934     EnterCriticalSection(&This->cs);
3935
3936     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3937
3938     if (hr == S_OK)
3939         hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
3940
3941     LeaveCriticalSection(&This->cs);
3942
3943     return hr;
3944 }
3945
3946 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface,
3947                                                     long *WindowStyleEx) {
3948     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3949     IVideoWindow* pVideoWindow;
3950     HRESULT hr;
3951
3952     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
3953
3954     EnterCriticalSection(&This->cs);
3955
3956     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3957
3958     if (hr == S_OK)
3959         hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
3960
3961     LeaveCriticalSection(&This->cs);
3962
3963     return hr;
3964 }
3965
3966 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface,
3967                                                long AutoShow) {
3968     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3969     IVideoWindow* pVideoWindow;
3970     HRESULT hr;
3971
3972     TRACE("(%p/%p)->(%ld)\n", This, iface, AutoShow);
3973
3974     EnterCriticalSection(&This->cs);
3975
3976     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3977
3978     if (hr == S_OK)
3979         hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
3980
3981     LeaveCriticalSection(&This->cs);
3982
3983     return hr;
3984 }
3985
3986 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface,
3987                                                long *AutoShow) {
3988     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
3989     IVideoWindow* pVideoWindow;
3990     HRESULT hr;
3991
3992     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
3993
3994     EnterCriticalSection(&This->cs);
3995
3996     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
3997
3998     if (hr == S_OK)
3999         hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4000
4001     LeaveCriticalSection(&This->cs);
4002
4003     return hr;
4004 }
4005
4006 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface,
4007                                                   long WindowState) {
4008     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4009     IVideoWindow* pVideoWindow;
4010     HRESULT hr;
4011
4012     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowState);
4013
4014     EnterCriticalSection(&This->cs);
4015
4016     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4017
4018     if (hr == S_OK)
4019         hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4020
4021     LeaveCriticalSection(&This->cs);
4022
4023     return hr;
4024 }
4025
4026 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface,
4027                                                   long *WindowState) {
4028     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4029     IVideoWindow* pVideoWindow;
4030     HRESULT hr;
4031
4032     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4033
4034     EnterCriticalSection(&This->cs);
4035
4036     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4037
4038     if (hr == S_OK)
4039         hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4040
4041     LeaveCriticalSection(&This->cs);
4042
4043     return hr;
4044 }
4045
4046 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface,
4047                                                         long BackgroundPalette) {
4048     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4049     IVideoWindow* pVideoWindow;
4050     HRESULT hr;
4051
4052     TRACE("(%p/%p)->(%ld)\n", This, iface, BackgroundPalette);
4053
4054     EnterCriticalSection(&This->cs);
4055
4056     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4057
4058     if (hr == S_OK)
4059         hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4060
4061     LeaveCriticalSection(&This->cs);
4062
4063     return hr;
4064 }
4065
4066 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4067                                                         long *pBackgroundPalette) {
4068     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4069     IVideoWindow* pVideoWindow;
4070     HRESULT hr;
4071
4072     TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4073
4074     EnterCriticalSection(&This->cs);
4075
4076     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4077
4078     if (hr == S_OK)
4079         hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4080
4081     LeaveCriticalSection(&This->cs);
4082
4083     return hr;
4084 }
4085
4086 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface,
4087                                               long Visible) {
4088     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4089     IVideoWindow* pVideoWindow;
4090     HRESULT hr;
4091
4092     TRACE("(%p/%p)->(%ld)\n", This, iface, Visible);
4093
4094     EnterCriticalSection(&This->cs);
4095
4096     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4097
4098     if (hr == S_OK)
4099         hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4100
4101     LeaveCriticalSection(&This->cs);
4102
4103     return hr;
4104 }
4105
4106 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface,
4107                                               long *pVisible) {
4108     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4109     IVideoWindow* pVideoWindow;
4110     HRESULT hr;
4111
4112     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4113
4114     EnterCriticalSection(&This->cs);
4115
4116     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4117
4118     if (hr == S_OK)
4119         hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4120
4121     LeaveCriticalSection(&This->cs);
4122
4123     return hr;
4124 }
4125
4126 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface,
4127                                            long Left) {
4128     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4129     IVideoWindow* pVideoWindow;
4130     HRESULT hr;
4131
4132     TRACE("(%p/%p)->(%ld)\n", This, iface, Left);
4133
4134     EnterCriticalSection(&This->cs);
4135
4136     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4137
4138     if (hr == S_OK)
4139         hr = IVideoWindow_put_Left(pVideoWindow, Left);
4140
4141     LeaveCriticalSection(&This->cs);
4142
4143     return hr;
4144 }
4145
4146 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface,
4147                                            long *pLeft) {
4148     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4149     IVideoWindow* pVideoWindow;
4150     HRESULT hr;
4151
4152     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4153
4154     EnterCriticalSection(&This->cs);
4155
4156     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4157
4158     if (hr == S_OK)
4159         hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4160
4161     LeaveCriticalSection(&This->cs);
4162
4163     return hr;
4164 }
4165
4166 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface,
4167                                             long Width) {
4168     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4169     IVideoWindow* pVideoWindow;
4170     HRESULT hr;
4171
4172     TRACE("(%p/%p)->(%ld)\n", This, iface, Width);
4173
4174     EnterCriticalSection(&This->cs);
4175
4176     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4177
4178     if (hr == S_OK)
4179         hr = IVideoWindow_put_Width(pVideoWindow, Width);
4180
4181     LeaveCriticalSection(&This->cs);
4182
4183     return hr;
4184 }
4185
4186 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface,
4187                                             long *pWidth) {
4188     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4189     IVideoWindow* pVideoWindow;
4190     HRESULT hr;
4191
4192     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4193
4194     EnterCriticalSection(&This->cs);
4195
4196     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4197
4198     if (hr == S_OK)
4199         hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4200
4201     LeaveCriticalSection(&This->cs);
4202
4203     return hr;
4204 }
4205
4206 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface,
4207                                           long Top) {
4208     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4209     IVideoWindow* pVideoWindow;
4210     HRESULT hr;
4211
4212     TRACE("(%p/%p)->(%ld)\n", This, iface, Top);
4213
4214     EnterCriticalSection(&This->cs);
4215
4216     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4217
4218     if (hr == S_OK)
4219         hr = IVideoWindow_put_Top(pVideoWindow, Top);
4220
4221     LeaveCriticalSection(&This->cs);
4222
4223     return hr;
4224 }
4225
4226 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface,
4227                                           long *pTop) {
4228     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4229     IVideoWindow* pVideoWindow;
4230     HRESULT hr;
4231
4232     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4233
4234     EnterCriticalSection(&This->cs);
4235
4236     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4237
4238     if (hr == S_OK)
4239         hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4240
4241     LeaveCriticalSection(&This->cs);
4242
4243     return hr;
4244 }
4245
4246 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface,
4247                                              long Height) {
4248     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4249     IVideoWindow* pVideoWindow;
4250     HRESULT hr;
4251
4252     TRACE("(%p/%p)->(%ld)\n", This, iface, Height);
4253
4254     EnterCriticalSection(&This->cs);
4255
4256     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4257
4258     if (hr == S_OK)
4259         hr = IVideoWindow_put_Height(pVideoWindow, Height);
4260
4261     LeaveCriticalSection(&This->cs);
4262
4263     return hr;
4264 }
4265
4266 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface,
4267                                              long *pHeight) {
4268     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4269     IVideoWindow* pVideoWindow;
4270     HRESULT hr;
4271
4272     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4273
4274     EnterCriticalSection(&This->cs);
4275
4276     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4277
4278     if (hr == S_OK)
4279         hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4280
4281     LeaveCriticalSection(&This->cs);
4282
4283     return hr;
4284 }
4285
4286 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface,
4287                                             OAHWND Owner) {
4288     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4289     IVideoWindow* pVideoWindow;
4290     HRESULT hr;
4291
4292     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
4293
4294     EnterCriticalSection(&This->cs);
4295
4296     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4297
4298     if (hr == S_OK)
4299         hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4300
4301     LeaveCriticalSection(&This->cs);
4302
4303     return hr;
4304 }
4305
4306 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface,
4307                                             OAHWND *Owner) {
4308     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4309     IVideoWindow* pVideoWindow;
4310     HRESULT hr;
4311
4312     TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4313
4314     EnterCriticalSection(&This->cs);
4315
4316     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4317
4318     if (hr == S_OK)
4319         hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4320
4321     LeaveCriticalSection(&This->cs);
4322
4323     return hr;
4324 }
4325
4326 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface,
4327                                                    OAHWND Drain) {
4328     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4329     IVideoWindow* pVideoWindow;
4330     HRESULT hr;
4331
4332     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
4333
4334     EnterCriticalSection(&This->cs);
4335
4336     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4337
4338     if (hr == S_OK)
4339         hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4340
4341     LeaveCriticalSection(&This->cs);
4342
4343     return hr;
4344 }
4345
4346 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface,
4347                                                    OAHWND *Drain) {
4348     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4349     IVideoWindow* pVideoWindow;
4350     HRESULT hr;
4351
4352     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4353
4354     EnterCriticalSection(&This->cs);
4355
4356     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4357
4358     if (hr == S_OK)
4359         hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4360
4361     LeaveCriticalSection(&This->cs);
4362
4363     return hr;
4364 }
4365
4366 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface,
4367                                                   long *Color) {
4368     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4369     IVideoWindow* pVideoWindow;
4370     HRESULT hr;
4371
4372     TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4373
4374     EnterCriticalSection(&This->cs);
4375
4376     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4377
4378     if (hr == S_OK)
4379         hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4380
4381     LeaveCriticalSection(&This->cs);
4382
4383     return hr;
4384 }
4385
4386 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface,
4387                                                   long Color) {
4388     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4389     IVideoWindow* pVideoWindow;
4390     HRESULT hr;
4391
4392     TRACE("(%p/%p)->(%ld)\n", This, iface, Color);
4393
4394     EnterCriticalSection(&This->cs);
4395
4396     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4397
4398     if (hr == S_OK)
4399         hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4400
4401     LeaveCriticalSection(&This->cs);
4402
4403     return hr;
4404 }
4405
4406 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
4407                                                      long *FullScreenMode) {
4408     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4409     IVideoWindow* pVideoWindow;
4410     HRESULT hr;
4411
4412     TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4413
4414     EnterCriticalSection(&This->cs);
4415
4416     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4417
4418     if (hr == S_OK)
4419         hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4420
4421     LeaveCriticalSection(&This->cs);
4422
4423     return hr;
4424 }
4425
4426 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface,
4427                                                      long FullScreenMode) {
4428     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4429     IVideoWindow* pVideoWindow;
4430     HRESULT hr;
4431
4432     TRACE("(%p/%p)->(%ld)\n", This, iface, FullScreenMode);
4433
4434     EnterCriticalSection(&This->cs);
4435
4436     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4437
4438     if (hr == S_OK)
4439         hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4440
4441     LeaveCriticalSection(&This->cs);
4442
4443     return hr;
4444 }
4445
4446 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface,
4447                                                       long Focus) {
4448     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4449     IVideoWindow* pVideoWindow;
4450     HRESULT hr;
4451
4452     TRACE("(%p/%p)->(%ld)\n", This, iface, Focus);
4453
4454     EnterCriticalSection(&This->cs);
4455
4456     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4457
4458     if (hr == S_OK)
4459         hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4460
4461     LeaveCriticalSection(&This->cs);
4462
4463     return hr;
4464 }
4465
4466 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface,
4467                                                      OAHWND hwnd,
4468                                                      long uMsg,
4469                                                      LONG_PTR wParam,
4470                                                      LONG_PTR lParam) {
4471     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4472     IVideoWindow* pVideoWindow;
4473     HRESULT hr;
4474
4475     TRACE("(%p/%p)->(%08x, %ld, %08lx, %08lx)\n", This, iface, (DWORD) hwnd, uMsg, wParam, lParam);
4476
4477     EnterCriticalSection(&This->cs);
4478
4479     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4480
4481     if (hr == S_OK)
4482         hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4483
4484     LeaveCriticalSection(&This->cs);
4485
4486     return hr;
4487 }
4488
4489 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface,
4490                                                     long Left,
4491                                                     long Top,
4492                                                     long Width,
4493                                                     long Height) {
4494     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4495     IVideoWindow* pVideoWindow;
4496     HRESULT hr;
4497     
4498     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
4499
4500     EnterCriticalSection(&This->cs);
4501
4502     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4503
4504     if (hr == S_OK)
4505         hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4506
4507     LeaveCriticalSection(&This->cs);
4508
4509     return hr;
4510 }
4511
4512 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface,
4513                                                     long *pLeft,
4514                                                     long *pTop,
4515                                                     long *pWidth,
4516                                                     long *pHeight) {
4517     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4518     IVideoWindow* pVideoWindow;
4519     HRESULT hr;
4520
4521     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4522
4523     EnterCriticalSection(&This->cs);
4524
4525     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4526
4527     if (hr == S_OK)
4528         hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4529
4530     LeaveCriticalSection(&This->cs);
4531
4532     return hr;
4533 }
4534
4535 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface,
4536                                                        long *pWidth,
4537                                                        long *pHeight) {
4538     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4539     IVideoWindow* pVideoWindow;
4540     HRESULT hr;
4541
4542     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4543
4544     EnterCriticalSection(&This->cs);
4545
4546     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4547
4548     if (hr == S_OK)
4549         hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4550
4551     LeaveCriticalSection(&This->cs);
4552
4553     return hr;
4554 }
4555
4556 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface,
4557                                                        long *pWidth,
4558                                                        long *pHeight) {
4559     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4560     IVideoWindow* pVideoWindow;
4561     HRESULT hr;
4562
4563     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4564
4565     EnterCriticalSection(&This->cs);
4566
4567     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4568
4569     if (hr == S_OK)
4570         hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4571
4572     LeaveCriticalSection(&This->cs);
4573
4574     return hr;
4575 }
4576
4577 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface,
4578                                                      long *pLeft,
4579                                                      long *pTop,
4580                                                      long *pWidth,
4581                                                      long *pHeight) {
4582     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4583     IVideoWindow* pVideoWindow;
4584     HRESULT hr;
4585
4586     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4587
4588     EnterCriticalSection(&This->cs);
4589
4590     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4591
4592     if (hr == S_OK)
4593         hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4594
4595     LeaveCriticalSection(&This->cs);
4596
4597     return hr;
4598 }
4599
4600 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface,
4601                                              long HideCursor) {
4602     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4603     IVideoWindow* pVideoWindow;
4604     HRESULT hr;
4605
4606     TRACE("(%p/%p)->(%ld)\n", This, iface, HideCursor);
4607
4608     EnterCriticalSection(&This->cs);
4609
4610     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4611
4612     if (hr == S_OK)
4613         hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4614
4615     LeaveCriticalSection(&This->cs);
4616
4617     return hr;
4618 }
4619
4620 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface,
4621                                                  long *CursorHidden) {
4622     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
4623     IVideoWindow* pVideoWindow;
4624     HRESULT hr;
4625
4626     TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4627
4628     EnterCriticalSection(&This->cs);
4629
4630     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4631
4632     if (hr == S_OK)
4633         hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4634
4635     LeaveCriticalSection(&This->cs);
4636
4637     return hr;
4638 }
4639
4640
4641 static const IVideoWindowVtbl IVideoWindow_VTable =
4642 {
4643     VideoWindow_QueryInterface,
4644     VideoWindow_AddRef,
4645     VideoWindow_Release,
4646     VideoWindow_GetTypeInfoCount,
4647     VideoWindow_GetTypeInfo,
4648     VideoWindow_GetIDsOfNames,
4649     VideoWindow_Invoke,
4650     VideoWindow_put_Caption,
4651     VideoWindow_get_Caption,
4652     VideoWindow_put_WindowStyle,
4653     VideoWindow_get_WindowStyle,
4654     VideoWindow_put_WindowStyleEx,
4655     VideoWindow_get_WindowStyleEx,
4656     VideoWindow_put_AutoShow,
4657     VideoWindow_get_AutoShow,
4658     VideoWindow_put_WindowState,
4659     VideoWindow_get_WindowState,
4660     VideoWindow_put_BackgroundPalette,
4661     VideoWindow_get_BackgroundPalette,
4662     VideoWindow_put_Visible,
4663     VideoWindow_get_Visible,
4664     VideoWindow_put_Left,
4665     VideoWindow_get_Left,
4666     VideoWindow_put_Width,
4667     VideoWindow_get_Width,
4668     VideoWindow_put_Top,
4669     VideoWindow_get_Top,
4670     VideoWindow_put_Height,
4671     VideoWindow_get_Height,
4672     VideoWindow_put_Owner,
4673     VideoWindow_get_Owner,
4674     VideoWindow_put_MessageDrain,
4675     VideoWindow_get_MessageDrain,
4676     VideoWindow_get_BorderColor,
4677     VideoWindow_put_BorderColor,
4678     VideoWindow_get_FullScreenMode,
4679     VideoWindow_put_FullScreenMode,
4680     VideoWindow_SetWindowForeground,
4681     VideoWindow_NotifyOwnerMessage,
4682     VideoWindow_SetWindowPosition,
4683     VideoWindow_GetWindowPosition,
4684     VideoWindow_GetMinIdealImageSize,
4685     VideoWindow_GetMaxIdealImageSize,
4686     VideoWindow_GetRestorePosition,
4687     VideoWindow_HideCursor,
4688     VideoWindow_IsCursorHidden
4689 };
4690
4691
4692 /*** IUnknown methods ***/
4693 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface,
4694                                                 REFIID riid,
4695                                                 LPVOID*ppvObj) {
4696     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4697
4698     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
4699
4700     return Filtergraph_QueryInterface(This, riid, ppvObj);
4701 }
4702
4703 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface) {
4704     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4705
4706     TRACE("(%p/%p)->()\n", This, iface);
4707
4708     return Filtergraph_AddRef(This);
4709 }
4710
4711 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface) {
4712     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4713
4714     TRACE("(%p/%p)->()\n", This, iface);
4715
4716     return Filtergraph_Release(This);
4717 }
4718
4719 /*** IDispatch methods ***/
4720 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface,
4721                                                   UINT*pctinfo) {
4722     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4723
4724     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
4725
4726     return S_OK;
4727 }
4728
4729 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface,
4730                                              UINT iTInfo,
4731                                              LCID lcid,
4732                                              ITypeInfo**ppTInfo) {
4733     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4734
4735     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
4736
4737     return S_OK;
4738 }
4739
4740 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface,
4741                                                REFIID riid,
4742                                                LPOLESTR*rgszNames,
4743                                                UINT cNames,
4744                                                LCID lcid,
4745                                                DISPID*rgDispId) {
4746     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4747
4748     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
4749
4750     return S_OK;
4751 }
4752
4753 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface,
4754                                         DISPID dispIdMember,
4755                                         REFIID riid,
4756                                         LCID lcid,
4757                                         WORD wFlags,
4758                                         DISPPARAMS*pDispParams,
4759                                         VARIANT*pVarResult,
4760                                         EXCEPINFO*pExepInfo,
4761                                         UINT*puArgErr) {
4762     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4763
4764     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);
4765
4766     return S_OK;
4767 }
4768
4769 /*** IMediaEvent methods ***/
4770 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface,
4771                                                 OAEVENT *hEvent) {
4772     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4773
4774     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4775
4776     *hEvent = (OAEVENT)This->evqueue.msg_event;
4777
4778     return S_OK;
4779 }
4780
4781 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface,
4782                                           long *lEventCode,
4783                                           LONG_PTR *lParam1,
4784                                           LONG_PTR *lParam2,
4785                                           long msTimeout) {
4786     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4787     Event evt;
4788
4789     TRACE("(%p/%p)->(%p, %p, %p, %ld)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
4790
4791     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
4792     {
4793         *lEventCode = evt.lEventCode;
4794         *lParam1 = evt.lParam1;
4795         *lParam2 = evt.lParam2;
4796         return S_OK;
4797     }
4798
4799     *lEventCode = 0;
4800     return E_ABORT;
4801 }
4802
4803 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface,
4804                                                    long msTimeout,
4805                                                    long *pEvCode) {
4806     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4807
4808     TRACE("(%p/%p)->(%ld, %p)\n", This, iface, msTimeout, pEvCode);
4809
4810     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
4811     {
4812         *pEvCode = This->CompletionStatus;
4813         return S_OK;
4814     }
4815
4816     *pEvCode = 0;
4817     return E_ABORT;
4818 }
4819
4820 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface,
4821                                                        long lEvCode) {
4822     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4823
4824     TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
4825
4826     if (lEvCode == EC_COMPLETE)
4827         This->HandleEcComplete = FALSE;
4828     else if (lEvCode == EC_REPAINT)
4829         This->HandleEcRepaint = FALSE;
4830     else if (lEvCode == EC_CLOCK_CHANGED)
4831         This->HandleEcClockChanged = FALSE;
4832     else
4833         return S_FALSE;
4834
4835     return S_OK;
4836 }
4837
4838 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface,
4839                                                         long lEvCode) {
4840     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4841
4842     TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
4843
4844     if (lEvCode == EC_COMPLETE)
4845         This->HandleEcComplete = TRUE;
4846     else if (lEvCode == EC_REPAINT)
4847         This->HandleEcRepaint = TRUE;
4848     else if (lEvCode == EC_CLOCK_CHANGED)
4849         This->HandleEcClockChanged = TRUE;
4850     else
4851         return S_FALSE;
4852
4853     return S_OK;
4854 }
4855
4856 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface,
4857                                                  long lEvCode,
4858                                                  LONG_PTR lParam1,
4859                                                  LONG_PTR lParam2) {
4860     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4861
4862     TRACE("(%p/%p)->(%ld, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
4863
4864     return S_OK;
4865 }
4866
4867 /*** IMediaEventEx methods ***/
4868 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface,
4869                                                  OAHWND hwnd,
4870                                                  long lMsg,
4871                                                  LONG_PTR lInstanceData) {
4872     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4873
4874     TRACE("(%p/%p)->(%08x, %ld, %08lx)\n", This, iface, (DWORD) hwnd, lMsg, lInstanceData);
4875
4876     This->notif.hWnd = (HWND)hwnd;
4877     This->notif.msg = lMsg;
4878     This->notif.instance = (long) lInstanceData;
4879
4880     return S_OK;
4881 }
4882
4883 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface,
4884                                                 long lNoNotifyFlags) {
4885     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4886
4887     TRACE("(%p/%p)->(%ld)\n", This, iface, lNoNotifyFlags);
4888
4889     if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
4890         return E_INVALIDARG;
4891
4892     This->notif.disabled = lNoNotifyFlags;
4893
4894     return S_OK;
4895 }
4896
4897 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface,
4898                                                 long *lplNoNotifyFlags) {
4899     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
4900
4901     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
4902
4903     if (!lplNoNotifyFlags)
4904         return E_POINTER;
4905
4906     *lplNoNotifyFlags = This->notif.disabled;
4907
4908     return S_OK;
4909 }
4910
4911
4912 static const IMediaEventExVtbl IMediaEventEx_VTable =
4913 {
4914     MediaEvent_QueryInterface,
4915     MediaEvent_AddRef,
4916     MediaEvent_Release,
4917     MediaEvent_GetTypeInfoCount,
4918     MediaEvent_GetTypeInfo,
4919     MediaEvent_GetIDsOfNames,
4920     MediaEvent_Invoke,
4921     MediaEvent_GetEventHandle,
4922     MediaEvent_GetEvent,
4923     MediaEvent_WaitForCompletion,
4924     MediaEvent_CancelDefaultHandling,
4925     MediaEvent_RestoreDefaultHandling,
4926     MediaEvent_FreeEventParams,
4927     MediaEvent_SetNotifyWindow,
4928     MediaEvent_SetNotifyFlags,
4929     MediaEvent_GetNotifyFlags
4930 };
4931
4932
4933 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, LPVOID *ppv)
4934 {
4935     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4936
4937     return Filtergraph_QueryInterface(This, riid, ppv);
4938 }
4939
4940 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
4941 {
4942     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4943
4944     return Filtergraph_AddRef(This);
4945 }
4946
4947 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
4948 {
4949     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4950
4951     return Filtergraph_Release(This);
4952 }
4953
4954 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
4955 {
4956     FIXME("(%p): stub\n", pClassID);
4957
4958     return E_NOTIMPL;
4959 }
4960
4961 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
4962 {
4963     FIXME("(): stub\n");
4964
4965     return E_NOTIMPL;
4966 }
4967
4968 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
4969 {
4970     FIXME("(): stub\n");
4971
4972     return E_NOTIMPL;
4973 }
4974
4975 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
4976 {
4977     FIXME("(0x%s): stub\n", wine_dbgstr_longlong(tStart));
4978
4979     return E_NOTIMPL;
4980 }
4981
4982 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout, FILTER_STATE * pState)
4983 {
4984     FIXME("(%d, %p): stub\n", dwMsTimeout, pState);
4985
4986     return E_NOTIMPL;
4987 }
4988
4989 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
4990 {
4991     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
4992     HRESULT hr = S_OK;
4993     int i;
4994
4995     TRACE("(%p/%p)->(%p)\n", iface, This, pClock);
4996
4997     EnterCriticalSection(&This->cs);
4998     {
4999         for (i = 0;i < This->nFilters;i++)
5000         {
5001             hr = IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], pClock);
5002             if (FAILED(hr))
5003                 break;
5004         }
5005
5006         if (FAILED(hr))
5007         {
5008             for(;i >= 0;i--)
5009                 IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], This->refClock);
5010         }
5011         else
5012         {
5013             if (This->refClock)
5014                 IReferenceClock_Release(This->refClock);
5015             This->refClock = pClock;
5016             if (This->refClock)
5017                 IReferenceClock_AddRef(This->refClock);
5018
5019             if (This->HandleEcClockChanged)
5020             {
5021                 IMediaEventSink *pEventSink;
5022                 HRESULT eshr;
5023
5024                 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (LPVOID)&pEventSink);
5025                 if (SUCCEEDED(eshr))
5026                 {
5027                     IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5028                     IMediaEventSink_Release(pEventSink);
5029                 }
5030             }
5031         }
5032     }
5033     LeaveCriticalSection(&This->cs);
5034
5035     return hr;
5036 }
5037
5038 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5039 {
5040     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
5041
5042     TRACE("(%p/%p)->(%p)\n", iface, This, ppClock);
5043
5044     if (!ppClock)
5045         return E_POINTER;
5046
5047     EnterCriticalSection(&This->cs);
5048     {
5049         *ppClock = This->refClock;
5050         if (*ppClock)
5051             IReferenceClock_AddRef(*ppClock);
5052     }
5053     LeaveCriticalSection(&This->cs);
5054
5055     return S_OK;
5056 }
5057
5058 static const IMediaFilterVtbl IMediaFilter_VTable =
5059 {
5060     MediaFilter_QueryInterface,
5061     MediaFilter_AddRef,
5062     MediaFilter_Release,
5063     MediaFilter_GetClassID,
5064     MediaFilter_Stop,
5065     MediaFilter_Pause,
5066     MediaFilter_Run,
5067     MediaFilter_GetState,
5068     MediaFilter_SetSyncSource,
5069     MediaFilter_GetSyncSource
5070 };
5071
5072 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, LPVOID *ppv)
5073 {
5074     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5075
5076     return Filtergraph_QueryInterface(This, riid, ppv);
5077 }
5078
5079 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5080 {
5081     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5082
5083     return Filtergraph_AddRef(This);
5084 }
5085
5086 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5087 {
5088     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5089
5090     return Filtergraph_Release(This);
5091 }
5092
5093 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
5094 {
5095     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
5096     Event evt;
5097
5098     TRACE("(%p/%p)->(%ld, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
5099
5100     /* We need thread safety here, let's use the events queue's one */
5101     EnterCriticalSection(&This->evqueue.msg_crst);
5102
5103     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
5104     {
5105         TRACE("Process EC_COMPLETE notification\n");
5106         if (++This->EcCompleteCount == This->nRenderers)
5107         {
5108             evt.lEventCode = EC_COMPLETE;
5109             evt.lParam1 = S_OK;
5110             evt.lParam2 = 0;
5111             TRACE("Send EC_COMPLETE to app\n");
5112             EventsQueue_PutEvent(&This->evqueue, &evt);
5113             if (!This->notif.disabled && This->notif.hWnd)
5114             {
5115                 TRACE("Send Window message\n");
5116                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5117             }
5118             This->CompletionStatus = EC_COMPLETE;
5119             SetEvent(This->hEventCompletion);
5120         }
5121     }
5122     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
5123     {
5124         /* FIXME: Not handled yet */
5125     }
5126     else
5127     {
5128         evt.lEventCode = EventCode;
5129         evt.lParam1 = EventParam1;
5130         evt.lParam2 = EventParam2;
5131         EventsQueue_PutEvent(&This->evqueue, &evt);
5132         if (!This->notif.disabled && This->notif.hWnd)
5133             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5134     }
5135
5136     LeaveCriticalSection(&This->evqueue.msg_crst);
5137     return S_OK;
5138 }
5139
5140 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5141 {
5142     MediaEventSink_QueryInterface,
5143     MediaEventSink_AddRef,
5144     MediaEventSink_Release,
5145     MediaEventSink_Notify
5146 };
5147
5148 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID riid, LPVOID *ppv)
5149 {
5150     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5151
5152     return Filtergraph_QueryInterface(This, riid, ppv);
5153 }
5154
5155 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5156 {
5157     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5158
5159     return Filtergraph_AddRef(This);
5160 }
5161
5162 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5163 {
5164     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5165
5166     return Filtergraph_Release(This);
5167 }
5168
5169 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface,
5170                                             IPin* pOutputPin,
5171                                             IPin* pInputPin,
5172                                             const AM_MEDIA_TYPE* pmtFirstConnection,
5173                                             IBaseFilter* pUsingFilter,
5174                                             HANDLE hAbortEvent,
5175                                             DWORD dwFlags)
5176 {
5177     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5178
5179     FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
5180     
5181     return E_NOTIMPL;
5182 }
5183
5184 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface,
5185                                               IGraphConfigCallback* pCallback,
5186                                               PVOID pvContext,
5187                                               DWORD dwFlags,
5188                                               HANDLE hAbortEvent)
5189 {
5190     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5191     HRESULT hr;
5192
5193     WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
5194
5195     if (hAbortEvent)
5196         FIXME("The parameter hAbortEvent is not handled!\n");
5197
5198     EnterCriticalSection(&This->cs);
5199
5200     hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
5201
5202     LeaveCriticalSection(&This->cs);
5203
5204     return hr;
5205 }
5206
5207 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface,
5208                                                    IBaseFilter* pFilter)
5209 {
5210     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5211
5212     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5213     
5214     return E_NOTIMPL;
5215 }
5216
5217 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface,
5218                                                   IEnumFilters** pEnum)
5219 {
5220     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5221
5222     FIXME("(%p)->(%p): stub!\n", This, pEnum);
5223     
5224     return E_NOTIMPL;
5225 }
5226
5227 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface,
5228                                                         IBaseFilter* pFilter)
5229 {
5230     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5231
5232     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5233     
5234     return E_NOTIMPL;
5235 }
5236
5237 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface,
5238                                                REFERENCE_TIME* prtStart)
5239 {
5240     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5241
5242     FIXME("(%p)->(%p): stub!\n", This, prtStart);
5243     
5244     return E_NOTIMPL;
5245 }
5246
5247 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface,
5248                                                   IPin* pOutputPin,
5249                                                   IPinConnection* pConnection,
5250                                                   HANDLE hEventAbort)
5251 {
5252     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5253
5254     FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5255     
5256     return E_NOTIMPL;
5257 }
5258
5259 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface,
5260                                                  IBaseFilter* pFilter,
5261                                                  DWORD dwFlags)
5262 {
5263     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5264
5265     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5266     
5267     return E_NOTIMPL;
5268 }
5269
5270 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface,
5271                                                  IBaseFilter* pFilter,
5272                                                  DWORD* dwFlags)
5273 {
5274     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5275
5276     FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5277     
5278     return E_NOTIMPL;
5279 }
5280
5281 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface,
5282                                                  IBaseFilter* pFilter,
5283                                                  DWORD dwFlags)
5284 {
5285     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
5286
5287     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5288     
5289     return E_NOTIMPL;
5290 }
5291
5292 static const IGraphConfigVtbl IGraphConfig_VTable =
5293 {
5294     GraphConfig_QueryInterface,
5295     GraphConfig_AddRef,
5296     GraphConfig_Release,
5297     GraphConfig_Reconnect,
5298     GraphConfig_Reconfigure,
5299     GraphConfig_AddFilterToCache,
5300     GraphConfig_EnumCacheFilter,
5301     GraphConfig_RemoveFilterFromCache,
5302     GraphConfig_GetStartTime,
5303     GraphConfig_PushThroughData,
5304     GraphConfig_SetFilterFlags,
5305     GraphConfig_GetFilterFlags,
5306     GraphConfig_RemoveFilterEx
5307 };
5308
5309 static const IUnknownVtbl IInner_VTable =
5310 {
5311     FilterGraphInner_QueryInterface,
5312     FilterGraphInner_AddRef,
5313     FilterGraphInner_Release
5314 };
5315
5316 static HRESULT WINAPI Filtergraph_QueryInterface(IFilterGraphImpl *This,
5317                                                  REFIID riid,
5318                                                  LPVOID * ppv) {
5319     if (This->bAggregatable)
5320         This->bUnkOuterValid = TRUE;
5321
5322     if (This->pUnkOuter)
5323     {
5324         if (This->bAggregatable)
5325             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
5326
5327         if (IsEqualIID(riid, &IID_IUnknown))
5328         {
5329             HRESULT hr;
5330
5331             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5332             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5333             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5334             This->bAggregatable = TRUE;
5335             return hr;
5336         }
5337
5338         *ppv = NULL;
5339         return E_NOINTERFACE;
5340     }
5341
5342     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5343 }
5344
5345 static ULONG WINAPI Filtergraph_AddRef(IFilterGraphImpl *This) {
5346     if (This->pUnkOuter && This->bUnkOuterValid)
5347         return IUnknown_AddRef(This->pUnkOuter);
5348     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5349 }
5350
5351 static ULONG WINAPI Filtergraph_Release(IFilterGraphImpl *This) {
5352     if (This->pUnkOuter && This->bUnkOuterValid)
5353         return IUnknown_Release(This->pUnkOuter);
5354     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5355 }
5356
5357 /* This is the only function that actually creates a FilterGraph class... */
5358 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5359 {
5360     IFilterGraphImpl *fimpl;
5361     HRESULT hr;
5362
5363     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
5364
5365     *ppObj = NULL;
5366
5367     fimpl = CoTaskMemAlloc(sizeof(*fimpl));
5368     fimpl->pUnkOuter = pUnkOuter;
5369     fimpl->bUnkOuterValid = FALSE;
5370     fimpl->bAggregatable = FALSE;
5371     fimpl->IInner_vtbl = &IInner_VTable;
5372     fimpl->IFilterGraph2_vtbl = &IFilterGraph2_VTable;
5373     fimpl->IMediaControl_vtbl = &IMediaControl_VTable;
5374     fimpl->IMediaSeeking_vtbl = &IMediaSeeking_VTable;
5375     fimpl->IBasicAudio_vtbl = &IBasicAudio_VTable;
5376     fimpl->IBasicVideo_vtbl = &IBasicVideo_VTable;
5377     fimpl->IVideoWindow_vtbl = &IVideoWindow_VTable;
5378     fimpl->IMediaEventEx_vtbl = &IMediaEventEx_VTable;
5379     fimpl->IMediaFilter_vtbl = &IMediaFilter_VTable;
5380     fimpl->IMediaEventSink_vtbl = &IMediaEventSink_VTable;
5381     fimpl->IGraphConfig_vtbl = &IGraphConfig_VTable;
5382     fimpl->IMediaPosition_vtbl = &IMediaPosition_VTable;
5383     fimpl->ref = 1;
5384     fimpl->ppFiltersInGraph = NULL;
5385     fimpl->pFilterNames = NULL;
5386     fimpl->nFilters = 0;
5387     fimpl->filterCapacity = 0;
5388     fimpl->nameIndex = 1;
5389     fimpl->refClock = NULL;
5390     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5391     fimpl->HandleEcComplete = TRUE;
5392     fimpl->HandleEcRepaint = TRUE;
5393     fimpl->HandleEcClockChanged = TRUE;
5394     fimpl->notif.hWnd = 0;
5395     fimpl->notif.disabled = FALSE;
5396     fimpl->nRenderers = 0;
5397     fimpl->EcCompleteCount = 0;
5398     fimpl->state = State_Stopped;
5399     EventsQueue_Init(&fimpl->evqueue);
5400     InitializeCriticalSection(&fimpl->cs);
5401     fimpl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IFilterGraphImpl.cs");
5402     fimpl->nItfCacheEntries = 0;
5403     memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
5404     fimpl->start_time = fimpl->position = 0;
5405     fimpl->stop_position = -1;
5406
5407     hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2);
5408     if (FAILED(hr)) {
5409         ERR("Unable to create filter mapper (%x)\n", hr);
5410         return hr;
5411     }
5412     IFilterGraph2_SetDefaultSyncSource((IFilterGraph2*)fimpl);
5413
5414     *ppObj = fimpl;
5415     return S_OK;
5416 }
5417
5418 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5419 {
5420     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
5421     return FilterGraph_create(pUnkOuter, ppObj);
5422 }