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