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