[QUARTZ]
[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 IBaseFilter ** ppFiltersInGraph;
159 LPWSTR * pFilterNames;
160 ULONG nFilters;
161 int filterCapacity;
162 LONG nameIndex;
163 IReferenceClock *refClock;
164 IBaseFilter *refClockProvider;
165 EventsQueue evqueue;
166 HANDLE hEventCompletion;
167 int CompletionStatus;
168 WndNotify notif;
169 int nRenderers;
170 int EcCompleteCount;
171 int HandleEcComplete;
172 int HandleEcRepaint;
173 int HandleEcClockChanged;
174 OAFilterState state;
175 CRITICAL_SECTION cs;
176 ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
177 int nItfCacheEntries;
178 BOOL defaultclock;
179 GUID timeformatseek;
180 REFERENCE_TIME start_time;
181 REFERENCE_TIME pause_time;
182 LONG recursioncount;
183 IUnknown *pSite;
184 LONG version;
185 } IFilterGraphImpl;
186
187 static inline IFilterGraphImpl *impl_from_IUnknown(IUnknown *iface)
188 {
189 return CONTAINING_RECORD(iface, IFilterGraphImpl, IUnknown_inner);
190 }
191
192 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown *iface, REFIID riid, void **ppvObj)
193 {
194 IFilterGraphImpl *This = impl_from_IUnknown(iface);
195 TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
196
197 if (IsEqualGUID(&IID_IUnknown, riid)) {
198 *ppvObj = &This->IUnknown_inner;
199 TRACE(" returning IUnknown interface (%p)\n", *ppvObj);
200 } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
201 IsEqualGUID(&IID_IFilterGraph2, riid) ||
202 IsEqualGUID(&IID_IGraphBuilder, riid)) {
203 *ppvObj = &This->IFilterGraph2_iface;
204 TRACE(" returning IGraphBuilder interface (%p)\n", *ppvObj);
205 } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
206 *ppvObj = &This->IMediaControl_iface;
207 TRACE(" returning IMediaControl interface (%p)\n", *ppvObj);
208 } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
209 *ppvObj = &This->IMediaSeeking_iface;
210 TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj);
211 } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
212 *ppvObj = &This->IBasicAudio_iface;
213 TRACE(" returning IBasicAudio interface (%p)\n", *ppvObj);
214 } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
215 IsEqualGUID(&IID_IBasicVideo2, riid)) {
216 *ppvObj = &This->IBasicVideo2_iface;
217 TRACE(" returning IBasicVideo2 interface (%p)\n", *ppvObj);
218 } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
219 *ppvObj = &This->IVideoWindow_iface;
220 TRACE(" returning IVideoWindow interface (%p)\n", *ppvObj);
221 } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
222 IsEqualGUID(&IID_IMediaEventEx, riid)) {
223 *ppvObj = &This->IMediaEventEx_iface;
224 TRACE(" returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
225 } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
226 IsEqualGUID(&IID_IPersist, riid)) {
227 *ppvObj = &This->IMediaFilter_iface;
228 TRACE(" returning IMediaFilter interface (%p)\n", *ppvObj);
229 } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
230 *ppvObj = &This->IMediaEventSink_iface;
231 TRACE(" returning IMediaEventSink interface (%p)\n", *ppvObj);
232 } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
233 *ppvObj = &This->IGraphConfig_iface;
234 TRACE(" returning IGraphConfig interface (%p)\n", *ppvObj);
235 } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
236 *ppvObj = &This->IMediaPosition_iface;
237 TRACE(" returning IMediaPosition interface (%p)\n", *ppvObj);
238 } else if (IsEqualGUID(&IID_IObjectWithSite, riid)) {
239 *ppvObj = &This->IObjectWithSite_iface;
240 TRACE(" returning IObjectWithSite interface (%p)\n", *ppvObj);
241 } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
242 TRACE(" requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
243 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
244 } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
245 TRACE(" returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
246 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
247 } else if (IsEqualGUID(&IID_IFilterMapper3, riid)) {
248 TRACE(" returning IFilterMapper3 interface from aggregated filtermapper (%p)\n", *ppvObj);
249 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
250 } else if (IsEqualGUID(&IID_IGraphVersion, riid)) {
251 *ppvObj = &This->IGraphConfig_iface;
252 TRACE(" returning IGraphConfig interface (%p)\n", *ppvObj);
253 } else {
254 *ppvObj = NULL;
255 FIXME("unknown interface %s\n", debugstr_guid(riid));
256 return E_NOINTERFACE;
257 }
258
259 IUnknown_AddRef((IUnknown *)*ppvObj);
260 return S_OK;
261 }
262
263 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown *iface)
264 {
265 IFilterGraphImpl *This = impl_from_IUnknown(iface);
266 ULONG ref = InterlockedIncrement(&This->ref);
267
268 TRACE("(%p)->(): new ref = %d\n", This, ref);
269
270 return ref;
271 }
272
273 static ULONG WINAPI FilterGraphInner_Release(IUnknown *iface)
274 {
275 IFilterGraphImpl *This = impl_from_IUnknown(iface);
276 ULONG ref = InterlockedDecrement(&This->ref);
277
278 TRACE("(%p)->(): new ref = %d\n", This, ref);
279
280 if (ref == 0) {
281 int i;
282
283 This->ref = 1; /* guard against reentrancy (aggregation). */
284
285 IMediaControl_Stop(&This->IMediaControl_iface);
286
287 while (This->nFilters)
288 IFilterGraph2_RemoveFilter(&This->IFilterGraph2_iface, This->ppFiltersInGraph[0]);
289
290 if (This->refClock)
291 IReferenceClock_Release(This->refClock);
292
293 for (i = 0; i < This->nItfCacheEntries; i++)
294 {
295 if (This->ItfCacheEntries[i].iface)
296 IUnknown_Release(This->ItfCacheEntries[i].iface);
297 }
298
299 IUnknown_Release(This->punkFilterMapper2);
300
301 if (This->pSite) IUnknown_Release(This->pSite);
302
303 CloseHandle(This->hEventCompletion);
304 EventsQueue_Destroy(&This->evqueue);
305 This->cs.DebugInfo->Spare[0] = 0;
306 DeleteCriticalSection(&This->cs);
307 CoTaskMemFree(This->ppFiltersInGraph);
308 CoTaskMemFree(This->pFilterNames);
309 CoTaskMemFree(This);
310 }
311 return ref;
312 }
313
314 static inline IFilterGraphImpl *impl_from_IFilterGraph2(IFilterGraph2 *iface)
315 {
316 return CONTAINING_RECORD(iface, IFilterGraphImpl, IFilterGraph2_iface);
317 }
318
319 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface, REFIID riid, void **ppvObj)
320 {
321 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
322
323 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
324
325 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
326 }
327
328 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface)
329 {
330 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
331
332 TRACE("(%p/%p)->()\n", This, iface);
333
334 return IUnknown_AddRef(This->outer_unk);
335 }
336
337 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface)
338 {
339 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
340
341 TRACE("(%p/%p)->()\n", This, iface);
342
343 return IUnknown_Release(This->outer_unk);
344 }
345
346 /*** IFilterGraph methods ***/
347 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, IBaseFilter *pFilter,
348 LPCWSTR pName)
349 {
350 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
351 HRESULT hr;
352 int i,j;
353 WCHAR* wszFilterName = NULL;
354 BOOL duplicate_name = FALSE;
355
356 TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
357
358 if (!pFilter)
359 return E_POINTER;
360
361 wszFilterName = CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
362
363 if (pName)
364 {
365 /* Check if name already exists */
366 for(i = 0; i < This->nFilters; i++)
367 if (!strcmpW(This->pFilterNames[i], pName))
368 {
369 duplicate_name = TRUE;
370 break;
371 }
372 }
373
374 /* If no name given or name already existing, generate one */
375 if (!pName || duplicate_name)
376 {
377 static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
378 static const WCHAR wszFmt2[] = {'%','0','4','d',0};
379
380 for (j = 0; j < 10000 ; j++)
381 {
382 /* Create name */
383 if (pName)
384 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
385 else
386 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
387 TRACE("Generated name %s\n", debugstr_w(wszFilterName));
388
389 /* Check if the generated name already exists */
390 for(i = 0; i < This->nFilters; i++)
391 if (!strcmpW(This->pFilterNames[i], wszFilterName))
392 break;
393
394 /* Compute next index and exit if generated name is suitable */
395 if (This->nameIndex++ == 10000)
396 This->nameIndex = 1;
397 if (i == This->nFilters)
398 break;
399 }
400 /* Unable to find a suitable name */
401 if (j == 10000)
402 {
403 CoTaskMemFree(wszFilterName);
404 return VFW_E_DUPLICATE_NAME;
405 }
406 }
407 else
408 memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
409
410 if (This->nFilters + 1 > This->filterCapacity)
411 {
412 int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
413 IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
414 LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
415 memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
416 memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
417 if (This->filterCapacity)
418 {
419 CoTaskMemFree(This->ppFiltersInGraph);
420 CoTaskMemFree(This->pFilterNames);
421 }
422 This->ppFiltersInGraph = ppNewFilters;
423 This->pFilterNames = pNewNames;
424 This->filterCapacity = newCapacity;
425 }
426
427 hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)&This->IFilterGraph2_iface, wszFilterName);
428
429 if (SUCCEEDED(hr))
430 {
431 IBaseFilter_AddRef(pFilter);
432 This->ppFiltersInGraph[This->nFilters] = pFilter;
433 This->pFilterNames[This->nFilters] = wszFilterName;
434 This->nFilters++;
435 This->version++;
436 IBaseFilter_SetSyncSource(pFilter, This->refClock);
437 }
438 else
439 CoTaskMemFree(wszFilterName);
440
441 if (SUCCEEDED(hr) && duplicate_name)
442 return VFW_S_DUPLICATE_NAME;
443
444 return hr;
445 }
446
447 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
448 {
449 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
450 int i;
451 HRESULT hr = E_FAIL;
452
453 TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
454
455 /* FIXME: check graph is stopped */
456
457 for (i = 0; i < This->nFilters; i++)
458 {
459 if (This->ppFiltersInGraph[i] == pFilter)
460 {
461 IEnumPins *penumpins = NULL;
462 FILTER_STATE state;
463
464 if (This->defaultclock && This->refClockProvider == pFilter)
465 {
466 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
467 This->defaultclock = TRUE;
468 }
469
470 TRACE("Removing filter %s\n", debugstr_w(This->pFilterNames[i]));
471 IBaseFilter_GetState(pFilter, 0, &state);
472 if (state == State_Running)
473 IBaseFilter_Pause(pFilter);
474 if (state != State_Stopped)
475 IBaseFilter_Stop(pFilter);
476
477 hr = IBaseFilter_EnumPins(pFilter, &penumpins);
478 if (SUCCEEDED(hr)) {
479 IPin *ppin;
480 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
481 {
482 IPin *victim = NULL;
483 HRESULT h;
484 IPin_ConnectedTo(ppin, &victim);
485 if (victim)
486 {
487 h = IPin_Disconnect(victim);
488 TRACE("Disconnect other side: %08x\n", h);
489 if (h == VFW_E_NOT_STOPPED)
490 {
491 PIN_INFO pinfo;
492 IPin_QueryPinInfo(victim, &pinfo);
493
494 IBaseFilter_GetState(pinfo.pFilter, 0, &state);
495 if (state == State_Running)
496 IBaseFilter_Pause(pinfo.pFilter);
497 IBaseFilter_Stop(pinfo.pFilter);
498 IBaseFilter_Release(pinfo.pFilter);
499 h = IPin_Disconnect(victim);
500 TRACE("Disconnect retry: %08x\n", h);
501 }
502 IPin_Release(victim);
503 }
504 h = IPin_Disconnect(ppin);
505 TRACE("Disconnect 2: %08x\n", h);
506
507 IPin_Release(ppin);
508 }
509 IEnumPins_Release(penumpins);
510 }
511
512 hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
513 if (SUCCEEDED(hr))
514 {
515 IBaseFilter_SetSyncSource(pFilter, NULL);
516 IBaseFilter_Release(pFilter);
517 CoTaskMemFree(This->pFilterNames[i]);
518 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
519 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
520 This->nFilters--;
521 This->version++;
522 /* Invalidate interfaces in the cache */
523 for (i = 0; i < This->nItfCacheEntries; i++)
524 if (pFilter == This->ItfCacheEntries[i].filter)
525 {
526 IUnknown_Release(This->ItfCacheEntries[i].iface);
527 This->ItfCacheEntries[i].iface = NULL;
528 This->ItfCacheEntries[i].filter = NULL;
529 }
530 return S_OK;
531 }
532 break;
533 }
534 }
535
536 return hr; /* FIXME: check this error code */
537 }
538
539 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface, IEnumFilters **ppEnum)
540 {
541 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
542
543 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
544
545 return IEnumFiltersImpl_Construct(&This->IGraphVersion_iface, &This->ppFiltersInGraph, &This->nFilters, ppEnum);
546 }
547
548 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface, LPCWSTR pName,
549 IBaseFilter **ppFilter)
550 {
551 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
552 int i;
553
554 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
555
556 if (!ppFilter)
557 return E_POINTER;
558
559 for (i = 0; i < This->nFilters; i++)
560 {
561 if (!strcmpW(pName, This->pFilterNames[i]))
562 {
563 *ppFilter = This->ppFiltersInGraph[i];
564 IBaseFilter_AddRef(*ppFilter);
565 return S_OK;
566 }
567 }
568
569 *ppFilter = NULL;
570 return VFW_E_NOT_FOUND;
571 }
572
573 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
574 * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
575 */
576 static HRESULT CheckCircularConnection(IFilterGraphImpl *This, IPin *out, IPin *in)
577 {
578 #if 1
579 HRESULT hr;
580 PIN_INFO info_out, info_in;
581
582 hr = IPin_QueryPinInfo(out, &info_out);
583 if (FAILED(hr))
584 return hr;
585 if (info_out.dir != PINDIR_OUTPUT)
586 {
587 IBaseFilter_Release(info_out.pFilter);
588 return VFW_E_CANNOT_CONNECT;
589 }
590
591 hr = IPin_QueryPinInfo(in, &info_in);
592 if (SUCCEEDED(hr))
593 IBaseFilter_Release(info_in.pFilter);
594 if (FAILED(hr))
595 goto out;
596 if (info_in.dir != PINDIR_INPUT)
597 {
598 hr = VFW_E_CANNOT_CONNECT;
599 goto out;
600 }
601
602 if (info_out.pFilter == info_in.pFilter)
603 hr = VFW_E_CIRCULAR_GRAPH;
604 else
605 {
606 IEnumPins *enumpins;
607 IPin *test;
608
609 hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
610 if (FAILED(hr))
611 goto out;
612
613 IEnumPins_Reset(enumpins);
614 while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
615 {
616 PIN_DIRECTION dir = PINDIR_OUTPUT;
617 IPin_QueryDirection(test, &dir);
618 if (dir == PINDIR_INPUT)
619 {
620 IPin *victim = NULL;
621 IPin_ConnectedTo(test, &victim);
622 if (victim)
623 {
624 hr = CheckCircularConnection(This, victim, in);
625 IPin_Release(victim);
626 if (FAILED(hr))
627 {
628 IPin_Release(test);
629 break;
630 }
631 }
632 }
633 IPin_Release(test);
634 }
635 IEnumPins_Release(enumpins);
636 }
637
638 out:
639 IBaseFilter_Release(info_out.pFilter);
640 if (FAILED(hr))
641 ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
642 return hr;
643 #else
644 /* Debugging filtergraphs not enabled */
645 return S_OK;
646 #endif
647 }
648
649
650 /* NOTE: despite the implication, it doesn't matter which
651 * way round you put in the input and output pins */
652 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppinIn, IPin *ppinOut,
653 const AM_MEDIA_TYPE *pmt)
654 {
655 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
656 PIN_DIRECTION dir;
657 HRESULT hr;
658
659 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
660
661 /* FIXME: check pins are in graph */
662
663 if (TRACE_ON(quartz))
664 {
665 PIN_INFO PinInfo;
666
667 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
668 if (FAILED(hr))
669 return hr;
670
671 TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
672 IBaseFilter_Release(PinInfo.pFilter);
673
674 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
675 if (FAILED(hr))
676 return hr;
677
678 TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
679 IBaseFilter_Release(PinInfo.pFilter);
680 }
681
682 hr = IPin_QueryDirection(ppinIn, &dir);
683 if (SUCCEEDED(hr))
684 {
685 if (dir == PINDIR_INPUT)
686 {
687 hr = CheckCircularConnection(This, ppinOut, ppinIn);
688 if (SUCCEEDED(hr))
689 hr = IPin_Connect(ppinOut, ppinIn, pmt);
690 }
691 else
692 {
693 hr = CheckCircularConnection(This, ppinIn, ppinOut);
694 if (SUCCEEDED(hr))
695 hr = IPin_Connect(ppinIn, ppinOut, pmt);
696 }
697 }
698
699 return hr;
700 }
701
702 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface, IPin *ppin)
703 {
704 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
705 IPin *pConnectedTo = NULL;
706 HRESULT hr;
707 PIN_DIRECTION pindir;
708
709 IPin_QueryDirection(ppin, &pindir);
710 hr = IPin_ConnectedTo(ppin, &pConnectedTo);
711 if (FAILED(hr)) {
712 TRACE("Querying connected to failed: %x\n", hr);
713 return hr;
714 }
715 IPin_Disconnect(ppin);
716 IPin_Disconnect(pConnectedTo);
717 if (pindir == PINDIR_INPUT)
718 hr = IPin_Connect(pConnectedTo, ppin, NULL);
719 else
720 hr = IPin_Connect(ppin, pConnectedTo, NULL);
721 IPin_Release(pConnectedTo);
722 if (FAILED(hr))
723 WARN("Reconnecting pins failed, pins are not connected now..\n");
724 TRACE("(%p->%p) -- %p %p -> %x\n", iface, This, ppin, pConnectedTo, hr);
725 return hr;
726 }
727
728 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
729 {
730 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
731
732 TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
733
734 if (!ppin)
735 return E_POINTER;
736
737 return IPin_Disconnect(ppin);
738 }
739
740 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
741 {
742 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
743 IReferenceClock *pClock = NULL;
744 HRESULT hr = S_OK;
745 int i;
746
747 TRACE("(%p/%p)->() live sources not handled properly!\n", iface, This);
748
749 EnterCriticalSection(&This->cs);
750
751 for (i = 0; i < This->nFilters; ++i)
752 {
753 DWORD miscflags;
754 IAMFilterMiscFlags *flags = NULL;
755 IBaseFilter_QueryInterface(This->ppFiltersInGraph[i], &IID_IAMFilterMiscFlags, (void**)&flags);
756 if (!flags)
757 continue;
758 miscflags = IAMFilterMiscFlags_GetMiscFlags(flags);
759 IAMFilterMiscFlags_Release(flags);
760 if (miscflags == AM_FILTER_MISC_FLAGS_IS_RENDERER)
761 IBaseFilter_QueryInterface(This->ppFiltersInGraph[i], &IID_IReferenceClock, (void**)&pClock);
762 if (pClock)
763 break;
764 }
765
766 if (!pClock)
767 {
768 hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
769 This->refClockProvider = NULL;
770 }
771 else
772 This->refClockProvider = This->ppFiltersInGraph[i];
773
774 if (SUCCEEDED(hr))
775 {
776 hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
777 This->defaultclock = TRUE;
778 IReferenceClock_Release(pClock);
779 }
780 LeaveCriticalSection(&This->cs);
781
782 return hr;
783 }
784
785 static HRESULT GetFilterInfo(IMoniker* pMoniker, VARIANT* pvar)
786 {
787 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
788 IPropertyBag * pPropBagCat = NULL;
789 HRESULT hr;
790
791 VariantInit(pvar);
792
793 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
794
795 if (SUCCEEDED(hr))
796 hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
797
798 if (SUCCEEDED(hr))
799 TRACE("Moniker = %s\n", debugstr_w(V_BSTR(pvar)));
800
801 if (pPropBagCat)
802 IPropertyBag_Release(pPropBagCat);
803
804 return hr;
805 }
806
807 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
808 {
809 HRESULT hr;
810 ULONG nb = 0;
811
812 TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
813 hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
814 if (hr == S_OK) {
815 /* Rendered input */
816 } else if (hr == S_FALSE) {
817 *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
818 hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
819 if (hr != S_OK) {
820 WARN("Error (%x)\n", hr);
821 }
822 } else if (hr == E_NOTIMPL) {
823 /* Input connected to all outputs */
824 IEnumPins* penumpins;
825 IPin* ppin;
826 int i = 0;
827 TRACE("E_NOTIMPL\n");
828 hr = IBaseFilter_EnumPins(pfilter, &penumpins);
829 if (FAILED(hr)) {
830 WARN("filter Enumpins failed (%x)\n", hr);
831 return hr;
832 }
833 i = 0;
834 /* Count output pins */
835 while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
836 PIN_DIRECTION pindir;
837 IPin_QueryDirection(ppin, &pindir);
838 if (pindir == PINDIR_OUTPUT)
839 i++;
840 IPin_Release(ppin);
841 }
842 *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
843 /* Retrieve output pins */
844 IEnumPins_Reset(penumpins);
845 i = 0;
846 while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
847 PIN_DIRECTION pindir;
848 IPin_QueryDirection(ppin, &pindir);
849 if (pindir == PINDIR_OUTPUT)
850 (*pppins)[i++] = ppin;
851 else
852 IPin_Release(ppin);
853 }
854 IEnumPins_Release(penumpins);
855 nb = i;
856 if (FAILED(hr)) {
857 WARN("Next failed (%x)\n", hr);
858 return hr;
859 }
860 } else if (FAILED(hr)) {
861 WARN("Cannot get internal connection (%x)\n", hr);
862 return hr;
863 }
864
865 *pnb = nb;
866 return S_OK;
867 }
868
869 /*** IGraphBuilder methods ***/
870 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
871 {
872 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
873 HRESULT hr;
874 AM_MEDIA_TYPE* mt = NULL;
875 IEnumMediaTypes* penummt = NULL;
876 ULONG nbmt;
877 IEnumPins* penumpins;
878 IEnumMoniker* pEnumMoniker;
879 GUID tab[2];
880 ULONG nb = 0;
881 IMoniker* pMoniker;
882 ULONG pin;
883 PIN_INFO PinInfo;
884 CLSID FilterCLSID;
885 PIN_DIRECTION dir;
886 unsigned int i = 0;
887 IFilterMapper2 *pFilterMapper2 = NULL;
888
889 TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
890
891 if(!ppinOut || !ppinIn)
892 return E_POINTER;
893
894 if (TRACE_ON(quartz))
895 {
896 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
897 if (FAILED(hr))
898 return hr;
899
900 TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
901 IBaseFilter_Release(PinInfo.pFilter);
902
903 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
904 if (FAILED(hr))
905 return hr;
906
907 TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
908 IBaseFilter_Release(PinInfo.pFilter);
909 }
910
911 EnterCriticalSection(&This->cs);
912 ++This->recursioncount;
913 if (This->recursioncount >= 5)
914 {
915 WARN("Recursion count has reached %d\n", This->recursioncount);
916 hr = VFW_E_CANNOT_CONNECT;
917 goto out;
918 }
919
920 hr = IPin_QueryDirection(ppinOut, &dir);
921 if (FAILED(hr))
922 goto out;
923
924 if (dir == PINDIR_INPUT)
925 {
926 IPin *temp;
927
928 temp = ppinIn;
929 ppinIn = ppinOut;
930 ppinOut = temp;
931 }
932
933 hr = CheckCircularConnection(This, ppinOut, ppinIn);
934 if (FAILED(hr))
935 goto out;
936
937 /* Try direct connection first */
938 hr = IPin_Connect(ppinOut, ppinIn, NULL);
939 if (SUCCEEDED(hr))
940 goto out;
941
942 TRACE("Direct connection failed, trying to render using extra filters\n");
943
944 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
945 if (FAILED(hr))
946 goto out;
947
948 hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
949 IBaseFilter_Release(PinInfo.pFilter);
950 if (FAILED(hr))
951 goto out;
952
953 /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream
954 * filter to the minor mediatype of input pin of the renderer */
955 hr = IPin_EnumMediaTypes(ppinOut, &penummt);
956 if (FAILED(hr))
957 {
958 WARN("EnumMediaTypes (%x)\n", hr);
959 goto out;
960 }
961
962 hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
963 if (FAILED(hr)) {
964 WARN("IEnumMediaTypes_Next (%x)\n", hr);
965 goto out;
966 }
967
968 if (!nbmt)
969 {
970 WARN("No media type found!\n");
971 hr = VFW_E_INVALIDMEDIATYPE;
972 goto out;
973 }
974 TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
975 TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
976
977 hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
978 if (FAILED(hr)) {
979 WARN("Unable to get IFilterMapper2 (%x)\n", hr);
980 goto out;
981 }
982
983 /* Try to find a suitable filter that can connect to the pin to render */
984 tab[0] = mt->majortype;
985 tab[1] = mt->subtype;
986 hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
987 if (FAILED(hr)) {
988 WARN("Unable to enum filters (%x)\n", hr);
989 goto out;
990 }
991
992 hr = VFW_E_CANNOT_RENDER;
993 while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
994 {
995 VARIANT var;
996 GUID clsid;
997 IPin** ppins = NULL;
998 IPin* ppinfilter = NULL;
999 IBaseFilter* pfilter = NULL;
1000 IAMGraphBuilderCallback *callback = NULL;
1001
1002 hr = GetFilterInfo(pMoniker, &var);
1003 if (FAILED(hr)) {
1004 WARN("Unable to retrieve filter info (%x)\n", hr);
1005 goto error;
1006 }
1007
1008 hr = IMoniker_BindToObject(pMoniker, NULL, NULL, &IID_IBaseFilter, (LPVOID*)&pfilter);
1009 IMoniker_Release(pMoniker);
1010 if (FAILED(hr)) {
1011 WARN("Unable to create filter (%x), trying next one\n", hr);
1012 goto error;
1013 }
1014
1015 hr = IBaseFilter_GetClassID(pfilter, &clsid);
1016 if (FAILED(hr))
1017 {
1018 IBaseFilter_Release(pfilter);
1019 goto error;
1020 }
1021
1022 if (IsEqualGUID(&clsid, &FilterCLSID)) {
1023 /* Skip filter (same as the one the output pin belongs to) */
1024 IBaseFilter_Release(pfilter);
1025 goto error;
1026 }
1027
1028 if (This->pSite)
1029 {
1030 IUnknown_QueryInterface(This->pSite, &IID_IAMGraphBuilderCallback, (LPVOID*)&callback);
1031 if (callback)
1032 {
1033 HRESULT rc;
1034 rc = IAMGraphBuilderCallback_SelectedFilter(callback, pMoniker);
1035 if (FAILED(rc))
1036 {
1037 TRACE("Filter rejected by IAMGraphBuilderCallback_SelectedFilter\n");
1038 IAMGraphBuilderCallback_Release(callback);
1039 goto error;
1040 }
1041 }
1042 }
1043
1044 if (callback)
1045 {
1046 HRESULT rc;
1047 rc = IAMGraphBuilderCallback_CreatedFilter(callback, pfilter);
1048 IAMGraphBuilderCallback_Release(callback);
1049 if (FAILED(rc))
1050 {
1051 IBaseFilter_Release(pfilter);
1052 pfilter = NULL;
1053 TRACE("Filter rejected by IAMGraphBuilderCallback_CreatedFilter\n");
1054 goto error;
1055 }
1056 }
1057
1058 hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
1059 if (FAILED(hr)) {
1060 WARN("Unable to add filter (%x)\n", hr);
1061 IBaseFilter_Release(pfilter);
1062 pfilter = NULL;
1063 goto error;
1064 }
1065
1066 VariantClear(&var);
1067
1068 hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1069 if (FAILED(hr)) {
1070 WARN("Enumpins (%x)\n", hr);
1071 goto error;
1072 }
1073
1074 hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
1075 IEnumPins_Release(penumpins);
1076
1077 if (FAILED(hr)) {
1078 WARN("Obtaining next pin: (%x)\n", hr);
1079 goto error;
1080 }
1081 if (pin == 0) {
1082 WARN("Cannot use this filter: no pins\n");
1083 goto error;
1084 }
1085
1086 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1087 if (FAILED(hr)) {
1088 TRACE("Cannot connect to filter (%x), trying next one\n", hr);
1089 goto error;
1090 }
1091 TRACE("Successfully connected to filter, follow chain...\n");
1092
1093 /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
1094 hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
1095
1096 if (SUCCEEDED(hr)) {
1097 if (nb == 0) {
1098 IPin_Disconnect(ppinfilter);
1099 IPin_Disconnect(ppinOut);
1100 goto error;
1101 }
1102 TRACE("pins to consider: %d\n", nb);
1103 for(i = 0; i < nb; i++)
1104 {
1105 LPWSTR pinname = NULL;
1106
1107 TRACE("Processing pin %u\n", i);
1108
1109 hr = IPin_QueryId(ppins[i], &pinname);
1110 if (SUCCEEDED(hr))
1111 {
1112 if (pinname[0] == '~')
1113 {
1114 TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
1115 hr = E_FAIL;
1116 }
1117 else
1118 hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
1119 CoTaskMemFree(pinname);
1120 }
1121
1122 if (FAILED(hr)) {
1123 TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
1124 }
1125 IPin_Release(ppins[i]);
1126 if (SUCCEEDED(hr)) break;
1127 }
1128 while (++i < nb) IPin_Release(ppins[i]);
1129 CoTaskMemFree(ppins);
1130 IPin_Release(ppinfilter);
1131 IBaseFilter_Release(pfilter);
1132 if (FAILED(hr))
1133 {
1134 IPin_Disconnect(ppinfilter);
1135 IPin_Disconnect(ppinOut);
1136 IFilterGraph2_RemoveFilter(iface, pfilter);
1137 continue;
1138 }
1139 break;
1140 }
1141
1142 error:
1143 VariantClear(&var);
1144 if (ppinfilter) IPin_Release(ppinfilter);
1145 if (pfilter) {
1146 IFilterGraph2_RemoveFilter(iface, pfilter);
1147 IBaseFilter_Release(pfilter);
1148 }
1149 while (++i < nb) IPin_Release(ppins[i]);
1150 CoTaskMemFree(ppins);
1151 }
1152
1153 IEnumMoniker_Release(pEnumMoniker);
1154
1155 out:
1156 if (pFilterMapper2)
1157 IFilterMapper2_Release(pFilterMapper2);
1158 if (penummt)
1159 IEnumMediaTypes_Release(penummt);
1160 if (mt)
1161 DeleteMediaType(mt);
1162 --This->recursioncount;
1163 LeaveCriticalSection(&This->cs);
1164 TRACE("--> %08x\n", hr);
1165 return SUCCEEDED(hr) ? S_OK : hr;
1166 }
1167
1168 static HRESULT FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
1169 {
1170 /* This pin has been connected now, try to call render on all pins that aren't connected */
1171 IPin *to = NULL;
1172 PIN_INFO info;
1173 IEnumPins *enumpins = NULL;
1174 BOOL renderany = FALSE;
1175 BOOL renderall = TRUE;
1176
1177 IPin_QueryPinInfo(ppinOut, &info);
1178
1179 IBaseFilter_EnumPins(info.pFilter, &enumpins);
1180 /* Don't need to hold a reference, IEnumPins does */
1181 IBaseFilter_Release(info.pFilter);
1182
1183 IEnumPins_Reset(enumpins);
1184 while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK)
1185 {
1186 PIN_DIRECTION dir = PINDIR_INPUT;
1187
1188 IPin_QueryDirection(to, &dir);
1189
1190 if (dir == PINDIR_OUTPUT)
1191 {
1192 IPin *out = NULL;
1193
1194 IPin_ConnectedTo(to, &out);
1195 if (!out)
1196 {
1197 HRESULT hr;
1198 hr = IFilterGraph2_Render(&This->IFilterGraph2_iface, to);
1199 if (SUCCEEDED(hr))
1200 renderany = TRUE;
1201 else
1202 renderall = FALSE;
1203 }
1204 else
1205 IPin_Release(out);
1206 }
1207
1208 IPin_Release(to);
1209 }
1210
1211 IEnumPins_Release(enumpins);
1212
1213 if (renderall)
1214 return S_OK;
1215
1216 if (renderany)
1217 return VFW_S_PARTIAL_RENDER;
1218
1219 return VFW_E_CANNOT_RENDER;
1220 }
1221
1222 /* Ogg hates me if I create a direct rendering method
1223 *
1224 * It can only connect to a pin properly once, so use a recursive method that does
1225 *
1226 * +----+ --- (PIN 1) (Render is called on this pin)
1227 * | |
1228 * +----+ --- (PIN 2)
1229 *
1230 * Enumerate possible renderers that EXACTLY match the requested type
1231 *
1232 * If none is available, try to add intermediate filters that can connect to the input pin
1233 * then call Render on that intermediate pin's output pins
1234 * if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
1235 * and another filter that can connect to the input pin is tried
1236 * if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
1237 * It's recursive, but fun!
1238 */
1239
1240 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *ppinOut)
1241 {
1242 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1243 IEnumMediaTypes* penummt;
1244 AM_MEDIA_TYPE* mt;
1245 ULONG nbmt;
1246 HRESULT hr;
1247
1248 IEnumMoniker* pEnumMoniker;
1249 GUID tab[4];
1250 ULONG nb;
1251 IMoniker* pMoniker;
1252 INT x;
1253 IFilterMapper2 *pFilterMapper2 = NULL;
1254
1255 TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
1256
1257 if (TRACE_ON(quartz))
1258 {
1259 PIN_INFO PinInfo;
1260
1261 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
1262 if (FAILED(hr))
1263 return hr;
1264
1265 TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
1266 IBaseFilter_Release(PinInfo.pFilter);
1267 }
1268
1269 /* Try to find out if there is a renderer for the specified subtype already, and use that
1270 */
1271 EnterCriticalSection(&This->cs);
1272 for (x = 0; x < This->nFilters; ++x)
1273 {
1274 IEnumPins *enumpins = NULL;
1275 IPin *pin = NULL;
1276
1277 hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
1278
1279 if (FAILED(hr) || !enumpins)
1280 continue;
1281
1282 IEnumPins_Reset(enumpins);
1283 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
1284 {
1285 IPin *to = NULL;
1286 PIN_DIRECTION dir = PINDIR_OUTPUT;
1287
1288 IPin_QueryDirection(pin, &dir);
1289 if (dir != PINDIR_INPUT)
1290 {
1291 IPin_Release(pin);
1292 continue;
1293 }
1294 IPin_ConnectedTo(pin, &to);
1295
1296 if (to == NULL)
1297 {
1298 hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
1299 if (SUCCEEDED(hr))
1300 {
1301 TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
1302 IPin_Release(pin);
1303
1304 hr = FilterGraph2_RenderRecurse(This, pin);
1305 if (FAILED(hr))
1306 {
1307 IPin_Disconnect(ppinOut);
1308 IPin_Disconnect(pin);
1309 continue;
1310 }
1311 IEnumPins_Release(enumpins);
1312 LeaveCriticalSection(&This->cs);
1313 return hr;
1314 }
1315 WARN("Could not connect!\n");
1316 }
1317 else
1318 IPin_Release(to);
1319
1320 IPin_Release(pin);
1321 }
1322 IEnumPins_Release(enumpins);
1323 }
1324
1325 LeaveCriticalSection(&This->cs);
1326
1327 hr = IPin_EnumMediaTypes(ppinOut, &penummt);
1328 if (FAILED(hr)) {
1329 WARN("EnumMediaTypes (%x)\n", hr);
1330 return hr;
1331 }
1332
1333 IEnumMediaTypes_Reset(penummt);
1334
1335 /* Looks like no existing renderer of the kind exists
1336 * Try adding new ones
1337 */
1338 tab[0] = tab[1] = GUID_NULL;
1339 while (SUCCEEDED(hr))
1340 {
1341 hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
1342 if (FAILED(hr)) {
1343 WARN("IEnumMediaTypes_Next (%x)\n", hr);
1344 break;
1345 }
1346 if (!nbmt)
1347 {
1348 hr = VFW_E_CANNOT_RENDER;
1349 break;
1350 }
1351 else
1352 {
1353 TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1354 TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1355
1356 /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
1357 if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
1358 {
1359 DeleteMediaType(mt);
1360 continue;
1361 }
1362
1363 if (pFilterMapper2 == NULL)
1364 {
1365 hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
1366 if (FAILED(hr))
1367 {
1368 WARN("Unable to query IFilterMapper2 (%x)\n", hr);
1369 break;
1370 }
1371 }
1372
1373 /* Try to find a suitable renderer with the same media type */
1374 tab[0] = mt->majortype;
1375 tab[1] = mt->subtype;
1376 hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1377 if (FAILED(hr))
1378 {
1379 WARN("Unable to enum filters (%x)\n", hr);
1380 break;
1381 }
1382 }
1383 hr = E_FAIL;
1384
1385 while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1386 {
1387 VARIANT var;
1388 IPin* ppinfilter;
1389 IBaseFilter* pfilter = NULL;
1390 IEnumPins* penumpins = NULL;
1391 ULONG pin;
1392
1393 hr = GetFilterInfo(pMoniker, &var);
1394 if (FAILED(hr)) {
1395 WARN("Unable to retrieve filter info (%x)\n", hr);
1396 goto error;
1397 }
1398
1399 hr = IMoniker_BindToObject(pMoniker, NULL, NULL, &IID_IBaseFilter, (LPVOID*)&pfilter);
1400 IMoniker_Release(pMoniker);
1401 if (FAILED(hr))
1402 {
1403 WARN("Unable to create filter (%x), trying next one\n", hr);
1404 goto error;
1405 }
1406
1407 hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
1408 if (FAILED(hr)) {
1409 WARN("Unable to add filter (%x)\n", hr);
1410 IBaseFilter_Release(pfilter);
1411 pfilter = NULL;
1412 goto error;
1413 }
1414
1415 hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1416 if (FAILED(hr)) {
1417 WARN("Splitter Enumpins (%x)\n", hr);
1418 goto error;
1419 }
1420
1421 while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
1422 {
1423 PIN_DIRECTION dir;
1424
1425 if (pin == 0) {
1426 WARN("No Pin\n");
1427 hr = E_FAIL;
1428 goto error;
1429 }
1430
1431 hr = IPin_QueryDirection(ppinfilter, &dir);
1432 if (FAILED(hr)) {
1433 IPin_Release(ppinfilter);
1434 WARN("QueryDirection failed (%x)\n", hr);
1435 goto error;
1436 }
1437 if (dir != PINDIR_INPUT) {
1438 IPin_Release(ppinfilter);
1439 continue; /* Wrong direction */
1440 }
1441
1442 /* Connect the pin to the "Renderer" */
1443 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1444 IPin_Release(ppinfilter);
1445
1446 if (FAILED(hr)) {
1447 WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_BSTR(&var)), hr);
1448 goto error;
1449 }
1450 TRACE("Connected, recursing %s\n", debugstr_w(V_BSTR(&var)));
1451
1452 VariantClear(&var);
1453
1454 hr = FilterGraph2_RenderRecurse(This, ppinfilter);
1455 if (FAILED(hr)) {
1456 WARN("Unable to connect recursively (%x)\n", hr);
1457 goto error;
1458 }
1459 IBaseFilter_Release(pfilter);
1460 break;
1461 }
1462 if (SUCCEEDED(hr)) {
1463 IEnumPins_Release(penumpins);
1464 break; /* out of IEnumMoniker_Next loop */
1465 }
1466
1467 /* IEnumPins_Next failed, all other failure case caught by goto error */
1468 WARN("IEnumPins_Next (%x)\n", hr);
1469 /* goto error */
1470
1471 error:
1472 VariantClear(&var);
1473 if (penumpins)
1474 IEnumPins_Release(penumpins);
1475 if (pfilter) {
1476 IFilterGraph2_RemoveFilter(iface, pfilter);
1477 IBaseFilter_Release(pfilter);
1478 }
1479 if (SUCCEEDED(hr)) DebugBreak();
1480 }
1481
1482 IEnumMoniker_Release(pEnumMoniker);
1483 if (nbmt)
1484 DeleteMediaType(mt);
1485 if (SUCCEEDED(hr))
1486 break;
1487 hr = S_OK;
1488 }
1489
1490 if (pFilterMapper2)
1491 IFilterMapper2_Release(pFilterMapper2);
1492
1493 IEnumMediaTypes_Release(penummt);
1494 return hr;
1495 }
1496
1497 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, LPCWSTR lpcwstrFile,
1498 LPCWSTR lpcwstrPlayList)
1499 {
1500 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1501 static const WCHAR string[] = {'R','e','a','d','e','r',0};
1502 IBaseFilter* preader = NULL;
1503 IPin* ppinreader = NULL;
1504 IEnumPins* penumpins = NULL;
1505 HRESULT hr;
1506 BOOL partial = FALSE;
1507 BOOL any = FALSE;
1508
1509 TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1510
1511 if (lpcwstrPlayList != NULL)
1512 return E_INVALIDARG;
1513
1514 hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
1515 if (FAILED(hr))
1516 return hr;
1517
1518 if (SUCCEEDED(hr))
1519 hr = IBaseFilter_EnumPins(preader, &penumpins);
1520 if (SUCCEEDED(hr))
1521 {
1522 while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1523 {
1524 PIN_DIRECTION dir;
1525
1526 IPin_QueryDirection(ppinreader, &dir);
1527 if (dir == PINDIR_OUTPUT)
1528 {
1529 INT i;
1530
1531 hr = IFilterGraph2_Render(iface, ppinreader);
1532 TRACE("Render %08x\n", hr);
1533
1534 for (i = 0; i < This->nFilters; ++i)
1535 TRACE("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
1536
1537 if (SUCCEEDED(hr))
1538 any = TRUE;
1539 if (hr != S_OK)
1540 partial = TRUE;
1541 }
1542 IPin_Release(ppinreader);
1543 }
1544 IEnumPins_Release(penumpins);
1545
1546 if (!any)
1547 hr = VFW_E_CANNOT_RENDER;
1548 else if (partial)
1549 hr = VFW_S_PARTIAL_RENDER;
1550 else
1551 hr = S_OK;
1552 }
1553 IBaseFilter_Release(preader);
1554
1555 TRACE("--> %08x\n", hr);
1556 return hr;
1557 }
1558
1559 static HRESULT CreateFilterInstanceAndLoadFile(GUID* clsid, LPCOLESTR pszFileName, IBaseFilter **filter)
1560 {
1561 IFileSourceFilter *source = NULL;
1562 HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1563 TRACE("CLSID: %s\n", debugstr_guid(clsid));
1564 if (FAILED(hr))
1565 return hr;
1566
1567 hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
1568 if (FAILED(hr))
1569 {
1570 IBaseFilter_Release(*filter);
1571 return hr;
1572 }
1573
1574 /* Load the file in the file source filter */
1575 hr = IFileSourceFilter_Load(source, pszFileName, NULL);
1576 IFileSourceFilter_Release(source);
1577 if (FAILED(hr)) {
1578 WARN("Load (%x)\n", hr);
1579 IBaseFilter_Release(*filter);
1580 return hr;
1581 }
1582
1583 return hr;
1584 }
1585
1586 /* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
1587 static HRESULT GetFileSourceFilter(LPCOLESTR pszFileName, IBaseFilter **filter)
1588 {
1589 HRESULT hr;
1590 GUID clsid;
1591 IAsyncReader * pReader = NULL;
1592 IFileSourceFilter* pSource = NULL;
1593 IPin * pOutputPin = NULL;
1594 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
1595
1596 /* Try to find a match without reading the file first */
1597 hr = GetClassMediaFile(NULL, pszFileName, NULL, NULL, &clsid);
1598
1599 if (!hr)
1600 return CreateFilterInstanceAndLoadFile(&clsid, pszFileName, filter);
1601
1602 /* Now create a AyncReader instance, to check for signature bytes in the file */
1603 hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1604 if (FAILED(hr))
1605 return hr;
1606
1607 hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID *)&pSource);
1608 if (FAILED(hr))
1609 {
1610 IBaseFilter_Release(*filter);
1611 return hr;
1612 }
1613
1614 hr = IFileSourceFilter_Load(pSource, pszFileName, NULL);
1615 IFileSourceFilter_Release(pSource);
1616 if (FAILED(hr))
1617 {
1618 IBaseFilter_Release(*filter);
1619 return hr;
1620 }
1621
1622 hr = IBaseFilter_FindPin(*filter, wszOutputPinName, &pOutputPin);
1623 if (FAILED(hr))
1624 {
1625 IBaseFilter_Release(*filter);
1626 return hr;
1627 }
1628
1629 hr = IPin_QueryInterface(pOutputPin, &IID_IAsyncReader, (LPVOID *)&pReader);
1630 IPin_Release(pOutputPin);
1631 if (FAILED(hr))
1632 {
1633 IBaseFilter_Release(*filter);
1634 return hr;
1635 }
1636
1637 /* Try again find a match */
1638 hr = GetClassMediaFile(pReader, pszFileName, NULL, NULL, &clsid);
1639 IAsyncReader_Release(pReader);
1640
1641 if (!hr)
1642 {
1643 /* Release the AsyncReader filter and create the matching one */
1644 IBaseFilter_Release(*filter);
1645 return CreateFilterInstanceAndLoadFile(&clsid, pszFileName, filter);
1646 }
1647
1648 /* Return the AsyncReader filter */
1649 return S_OK;
1650 }
1651
1652 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface, LPCWSTR lpcwstrFileName,
1653 LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1654 {
1655 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1656 HRESULT hr;
1657 IBaseFilter* preader;
1658 IFileSourceFilter* pfile = NULL;
1659 AM_MEDIA_TYPE mt;
1660 WCHAR* filename;
1661
1662 TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1663
1664 /* Try from file name first, then fall back to default asynchronous reader */
1665 hr = GetFileSourceFilter(lpcwstrFileName, &preader);
1666 if (FAILED(hr)) {
1667 WARN("Unable to create file source filter (%x)\n", hr);
1668 return hr;
1669 }
1670
1671 hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
1672 if (FAILED(hr)) {
1673 WARN("Unable add filter (%x)\n", hr);
1674 IBaseFilter_Release(preader);
1675 return hr;
1676 }
1677
1678 hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1679 if (FAILED(hr)) {
1680 WARN("Unable to get IFileSourceInterface (%x)\n", hr);
1681 goto error;
1682 }
1683
1684 /* The file has been already loaded */
1685 hr = IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1686 if (FAILED(hr)) {
1687 WARN("GetCurFile (%x)\n", hr);
1688 goto error;
1689 }
1690
1691 TRACE("File %s\n", debugstr_w(filename));
1692 TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1693 TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1694
1695 if (ppFilter)
1696 *ppFilter = preader;
1697 IFileSourceFilter_Release(pfile);
1698
1699 return S_OK;
1700
1701 error:
1702 if (pfile)
1703 IFileSourceFilter_Release(pfile);
1704 IFilterGraph2_RemoveFilter(iface, preader);
1705 IBaseFilter_Release(preader);
1706
1707 return hr;
1708 }
1709
1710 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface, DWORD_PTR hFile)
1711 {
1712 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1713
1714 TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1715
1716 return S_OK;
1717 }
1718
1719 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface)
1720 {
1721 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1722
1723 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1724
1725 return S_OK;
1726 }
1727
1728 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface)
1729 {
1730 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1731
1732 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1733
1734 return S_OK;
1735 }
1736
1737 /*** IFilterGraph2 methods ***/
1738 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1739 IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1740 {
1741 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1742 HRESULT hr;
1743 IBaseFilter* pfilter;
1744
1745 TRACE("(%p/%p)->(%p %p %s %p)\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1746
1747 hr = IMoniker_BindToObject(pMoniker, pCtx, NULL, &IID_IBaseFilter, (void**)&pfilter);
1748 if(FAILED(hr)) {
1749 WARN("Unable to bind moniker to filter object (%x)\n", hr);
1750 return hr;
1751 }
1752
1753 hr = IFilterGraph2_AddFilter(iface, pfilter, lpcwstrFilterName);
1754 if (FAILED(hr)) {
1755 WARN("Unable to add filter (%x)\n", hr);
1756 IBaseFilter_Release(pfilter);
1757 return hr;
1758 }
1759
1760 if(ppFilter)
1761 *ppFilter = pfilter;
1762 else IBaseFilter_Release(pfilter);
1763
1764 return S_OK;
1765 }
1766
1767 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *ppin,
1768 const AM_MEDIA_TYPE *pmt)
1769 {
1770 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1771
1772 TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
1773
1774 return S_OK;
1775 }
1776
1777 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *pPinOut, DWORD dwFlags,
1778 DWORD *pvContext)
1779 {
1780 IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1781
1782 TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
1783
1784 return S_OK;
1785 }
1786
1787
1788 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1789 {
1790 FilterGraph2_QueryInterface,
1791 FilterGraph2_AddRef,
1792 FilterGraph2_Release,
1793 FilterGraph2_AddFilter,
1794 FilterGraph2_RemoveFilter,
1795 FilterGraph2_EnumFilters,
1796 FilterGraph2_FindFilterByName,
1797 FilterGraph2_ConnectDirect,
1798 FilterGraph2_Reconnect,
1799 FilterGraph2_Disconnect,
1800 FilterGraph2_SetDefaultSyncSource,
1801 FilterGraph2_Connect,
1802 FilterGraph2_Render,
1803 FilterGraph2_RenderFile,
1804 FilterGraph2_AddSourceFilter,
1805 FilterGraph2_SetLogFile,
1806 FilterGraph2_Abort,
1807 FilterGraph2_ShouldOperationContinue,
1808 FilterGraph2_AddSourceFilterForMoniker,
1809 FilterGraph2_ReconnectEx,
1810 FilterGraph2_RenderEx
1811 };
1812
1813 static inline IFilterGraphImpl *impl_from_IMediaControl(IMediaControl *iface)
1814 {
1815 return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaControl_iface);
1816 }
1817
1818 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID riid, void **ppvObj)
1819 {
1820 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1821
1822 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1823
1824 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
1825 }
1826
1827 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1828 {
1829 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1830
1831 TRACE("(%p/%p)->()\n", This, iface);
1832
1833 return IUnknown_AddRef(This->outer_unk);
1834 }
1835
1836 static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1837 {
1838 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1839
1840 TRACE("(%p/%p)->()\n", This, iface);
1841
1842 return IUnknown_Release(This->outer_unk);
1843
1844 }
1845
1846 /*** IDispatch methods ***/
1847 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *pctinfo)
1848 {
1849 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1850
1851 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1852
1853 return S_OK;
1854 }
1855
1856 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT iTInfo, LCID lcid,
1857 ITypeInfo **ppTInfo)
1858 {
1859 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1860
1861 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1862
1863 return S_OK;
1864 }
1865
1866 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID riid,
1867 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1868 {
1869 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1870
1871 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1872
1873 return S_OK;
1874 }
1875
1876 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMember, REFIID riid,
1877 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
1878 UINT *puArgErr)
1879 {
1880 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1881
1882 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);
1883
1884 return S_OK;
1885 }
1886
1887 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *, DWORD_PTR data);
1888
1889 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
1890 {
1891 HRESULT hr;
1892 IPin* pInputPin;
1893 IPin** ppPins;
1894 ULONG nb;
1895 ULONG i;
1896 PIN_INFO PinInfo;
1897
1898 TRACE("%p %p\n", pGraph, pOutputPin);
1899 PinInfo.pFilter = NULL;
1900
1901 hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1902
1903 if (SUCCEEDED(hr))
1904 {
1905 hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1906 if (SUCCEEDED(hr))
1907 hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1908 IPin_Release(pInputPin);
1909 }
1910
1911 if (SUCCEEDED(hr))
1912 {
1913 if (nb == 0)
1914 {
1915 TRACE("Reached a renderer\n");
1916 /* Count renderers for end of stream notification */
1917 pGraph->nRenderers++;
1918 }
1919 else
1920 {
1921 for(i = 0; i < nb; i++)
1922 {
1923 /* Explore the graph downstream from this pin
1924 * FIXME: We should prevent exploring from a pin more than once. This can happens when
1925 * several input pins are connected to the same output (a MUX for instance). */
1926 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
1927 IPin_Release(ppPins[i]);
1928 }
1929
1930 CoTaskMemFree(ppPins);
1931 }
1932 TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1933
1934 FoundFilter(PinInfo.pFilter, data);
1935 }
1936
1937 if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1938 return hr;
1939 }
1940
1941 static HRESULT WINAPI SendRun(IBaseFilter *pFilter, DWORD_PTR data)
1942 {
1943 REFERENCE_TIME time = *(REFERENCE_TIME*)data;
1944 return IBaseFilter_Run(pFilter, time);
1945 }
1946
1947 static HRESULT WINAPI SendPause(IBaseFilter *pFilter, DWORD_PTR data)
1948 {
1949 return IBaseFilter_Pause(pFilter);
1950 }
1951
1952 static HRESULT WINAPI SendStop(IBaseFilter *pFilter, DWORD_PTR data)
1953 {
1954 return IBaseFilter_Stop(pFilter);
1955 }
1956
1957 static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data)
1958 {
1959 FILTER_STATE state;
1960 DWORD time_end = data;
1961 DWORD time_now = GetTickCount();
1962 LONG wait;
1963
1964 if (time_end == INFINITE)
1965 {
1966 wait = INFINITE;
1967 }
1968 else if (time_end > time_now)
1969 {
1970 wait = time_end - time_now;
1971 }
1972 else
1973 wait = 0;
1974
1975 return IBaseFilter_GetState(pFilter, wait, &state);
1976 }
1977
1978
1979 static HRESULT SendFilterMessage(IFilterGraphImpl *This, fnFoundFilter FoundFilter, DWORD_PTR data)
1980 {
1981 int i;
1982 IBaseFilter* pfilter;
1983 IEnumPins* pEnum;
1984 HRESULT hr;
1985 IPin* pPin;
1986 DWORD dummy;
1987 PIN_DIRECTION dir;
1988
1989 TRACE("(%p)->()\n", This);
1990
1991 /* Explorer the graph from source filters to renderers, determine renderers
1992 * number and run filters from renderers to source filters */
1993 This->nRenderers = 0;
1994 ResetEvent(This->hEventCompletion);
1995
1996 for(i = 0; i < This->nFilters; i++)
1997 {
1998 BOOL source = TRUE;
1999 pfilter = This->ppFiltersInGraph[i];
2000 hr = IBaseFilter_EnumPins(pfilter, &pEnum);
2001 if (hr != S_OK)
2002 {
2003 WARN("Enum pins failed %x\n", hr);
2004 continue;
2005 }
2006 /* Check if it is a source filter */
2007 while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
2008 {
2009 IPin_QueryDirection(pPin, &dir);
2010 IPin_Release(pPin);
2011 if (dir == PINDIR_INPUT)
2012 {
2013 source = FALSE;
2014 break;
2015 }
2016 }
2017 if (source)
2018 {
2019 TRACE("Found a source filter %p\n", pfilter);
2020 IEnumPins_Reset(pEnum);
2021 while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
2022 {
2023 /* Explore the graph downstream from this pin */
2024 ExploreGraph(This, pPin, FoundFilter, data);
2025 IPin_Release(pPin);
2026 }
2027 FoundFilter(pfilter, data);
2028 }
2029 IEnumPins_Release(pEnum);
2030 }
2031
2032 return S_FALSE;
2033 }
2034
2035 /*** IMediaControl methods ***/
2036 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
2037 {
2038 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2039
2040 TRACE("(%p/%p)->()\n", This, iface);
2041
2042 EnterCriticalSection(&This->cs);
2043 if (This->state == State_Running)
2044 goto out;
2045 This->EcCompleteCount = 0;
2046
2047 if (This->defaultclock && !This->refClock)
2048 IFilterGraph2_SetDefaultSyncSource(&This->IFilterGraph2_iface);
2049
2050 if (This->refClock)
2051 {
2052 REFERENCE_TIME now;
2053 IReferenceClock_GetTime(This->refClock, &now);
2054 if (This->state == State_Stopped)
2055 This->start_time = now + 500000;
2056 else if (This->pause_time >= 0)
2057 This->start_time += now - This->pause_time;
2058 else
2059 This->start_time = now;
2060 }
2061 else This->start_time = 0;
2062
2063 SendFilterMessage(This, SendRun, (DWORD_PTR)&This->start_time);
2064 This->state = State_Running;
2065 out:
2066 LeaveCriticalSection(&This->cs);
2067 return S_FALSE;
2068 }
2069
2070 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
2071 {
2072 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2073
2074 TRACE("(%p/%p)->()\n", This, iface);
2075
2076 EnterCriticalSection(&This->cs);
2077 if (This->state == State_Paused)
2078 goto out;
2079
2080 if (This->state == State_Running && This->refClock && This->start_time >= 0)
2081 IReferenceClock_GetTime(This->refClock, &This->pause_time);
2082 else
2083 This->pause_time = -1;
2084
2085 SendFilterMessage(This, SendPause, 0);
2086 This->state = State_Paused;
2087 out:
2088 LeaveCriticalSection(&This->cs);
2089 return S_FALSE;
2090 }
2091
2092 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
2093 {
2094 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2095
2096 TRACE("(%p/%p)->()\n", This, iface);
2097
2098 if (This->state == State_Stopped) return S_OK;
2099
2100 EnterCriticalSection(&This->cs);
2101 if (This->state == State_Running) SendFilterMessage(This, SendPause, 0);
2102 SendFilterMessage(This, SendStop, 0);
2103 This->state = State_Stopped;
2104 LeaveCriticalSection(&This->cs);
2105 return S_OK;
2106 }
2107
2108 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG msTimeout,
2109 OAFilterState *pfs)
2110 {
2111 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2112 DWORD end;
2113
2114 TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
2115
2116 if (!pfs)
2117 return E_POINTER;
2118
2119 EnterCriticalSection(&This->cs);
2120
2121 *pfs = This->state;
2122 if (msTimeout > 0)
2123 {
2124 end = GetTickCount() + msTimeout;
2125 }
2126 else if (msTimeout < 0)
2127 {
2128 end = INFINITE;
2129 }
2130 else
2131 {
2132 end = 0;
2133 }
2134 if (end)
2135 SendFilterMessage(This, SendGetState, end);
2136
2137 LeaveCriticalSection(&This->cs);
2138
2139 return S_OK;
2140 }
2141
2142 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
2143 {
2144 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2145
2146 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strFilename), strFilename);
2147
2148 return IFilterGraph2_RenderFile(&This->IFilterGraph2_iface, strFilename, NULL);
2149 }
2150
2151 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
2152 IDispatch **ppUnk)
2153 {
2154 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2155
2156 FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
2157
2158 return S_OK;
2159 }
2160
2161 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2162 {
2163 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2164
2165 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2166
2167 return S_OK;
2168 }
2169
2170 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2171 {
2172 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2173
2174 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2175
2176 return S_OK;
2177 }
2178
2179 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2180 {
2181 IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2182
2183 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2184
2185 return S_OK;
2186 }
2187
2188
2189 static const IMediaControlVtbl IMediaControl_VTable =
2190 {
2191 MediaControl_QueryInterface,
2192 MediaControl_AddRef,
2193 MediaControl_Release,
2194 MediaControl_GetTypeInfoCount,
2195 MediaControl_GetTypeInfo,
2196 MediaControl_GetIDsOfNames,
2197 MediaControl_Invoke,
2198 MediaControl_Run,
2199 MediaControl_Pause,
2200 MediaControl_Stop,
2201 MediaControl_GetState,
2202 MediaControl_RenderFile,
2203 MediaControl_AddSourceFilter,
2204 MediaControl_get_FilterCollection,
2205 MediaControl_get_RegFilterCollection,
2206 MediaControl_StopWhenReady
2207 };
2208
2209 static inline IFilterGraphImpl *impl_from_IMediaSeeking(IMediaSeeking *iface)
2210 {
2211 return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaSeeking_iface);
2212 }
2213
2214 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface, REFIID riid, void **ppvObj)
2215 {
2216 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2217
2218 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2219
2220 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2221 }
2222
2223 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
2224 {
2225 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2226
2227 TRACE("(%p/%p)->()\n", This, iface);
2228
2229 return IUnknown_AddRef(This->outer_unk);
2230 }
2231
2232 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
2233 {
2234 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2235
2236 TRACE("(%p/%p)->()\n", This, iface);
2237
2238 return IUnknown_Release(This->outer_unk);
2239 }
2240
2241 typedef HRESULT (WINAPI *fnFoundSeek)(IFilterGraphImpl *This, IMediaSeeking*, DWORD_PTR arg);
2242
2243 static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2244 BOOL allnotimpl = TRUE;
2245 int i;
2246 HRESULT hr, hr_return = S_OK;
2247
2248 TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2249 /* Send a message to all renderers, they are responsible for broadcasting it further */
2250
2251 for(i = 0; i < This->nFilters; i++)
2252 {
2253 IMediaSeeking *seek = NULL;
2254 IBaseFilter* pfilter = This->ppFiltersInGraph[i];
2255 IAMFilterMiscFlags *flags = NULL;
2256 ULONG filterflags;
2257 IBaseFilter_QueryInterface(pfilter, &IID_IAMFilterMiscFlags, (void**)&flags);
2258 if (!flags)
2259 continue;
2260 filterflags = IAMFilterMiscFlags_GetMiscFlags(flags);
2261 IAMFilterMiscFlags_Release(flags);
2262 if (filterflags != AM_FILTER_MISC_FLAGS_IS_RENDERER)
2263 continue;
2264
2265 IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
2266 if (!seek)
2267 continue;
2268 hr = FoundSeek(This, seek, arg);
2269 IMediaSeeking_Release(seek);
2270 if (hr_return != E_NOTIMPL)
2271 allnotimpl = FALSE;
2272 if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2273 hr_return = hr;
2274 }
2275
2276 if (allnotimpl)
2277 return E_NOTIMPL;
2278 return hr_return;
2279 }
2280
2281 static HRESULT WINAPI FoundCapabilities(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2282 {
2283 HRESULT hr;
2284 DWORD caps = 0;
2285
2286 hr = IMediaSeeking_GetCapabilities(seek, &caps);
2287 if (FAILED(hr))
2288 return hr;
2289
2290 /* Only add common capabilities everything supports */
2291 *(DWORD*)pcaps &= caps;
2292
2293 return hr;
2294 }
2295
2296 /*** IMediaSeeking methods ***/
2297 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2298 {
2299 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2300 HRESULT hr;
2301
2302 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2303
2304 if (!pCapabilities)
2305 return E_POINTER;
2306
2307 EnterCriticalSection(&This->cs);
2308 *pCapabilities = 0xffffffff;
2309
2310 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2311 LeaveCriticalSection(&This->cs);
2312
2313 return hr;
2314 }
2315
2316 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2317 {
2318 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2319 DWORD originalcaps;
2320 HRESULT hr;
2321
2322 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2323
2324 if (!pCapabilities)
2325 return E_POINTER;
2326
2327 EnterCriticalSection(&This->cs);
2328 originalcaps = *pCapabilities;
2329 hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2330 LeaveCriticalSection(&This->cs);
2331
2332 if (FAILED(hr))
2333 return hr;
2334
2335 if (!*pCapabilities)
2336 return E_FAIL;
2337 if (*pCapabilities != originalcaps)
2338 return S_FALSE;
2339 return S_OK;
2340 }
2341
2342 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface, const GUID *pFormat)
2343 {
2344 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2345
2346 if (!pFormat)
2347 return E_POINTER;
2348
2349 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2350
2351 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2352 {
2353 FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2354 return S_FALSE;
2355 }
2356
2357 return S_OK;
2358 }
2359
2360 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *pFormat)
2361 {
2362 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2363
2364 if (!pFormat)
2365 return E_POINTER;
2366
2367 FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2368 memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2369
2370 return S_OK;
2371 }
2372
2373 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface, GUID *pFormat)
2374 {
2375 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2376
2377 if (!pFormat)
2378 return E_POINTER;
2379
2380 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2381 memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2382
2383 return S_OK;
2384 }
2385
2386 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2387 {
2388 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2389
2390 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2391 if (!pFormat)
2392 return E_POINTER;
2393
2394 if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2395 return S_FALSE;
2396
2397 return S_OK;
2398 }
2399
2400 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2401 {
2402 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2403
2404 if (!pFormat)
2405 return E_POINTER;
2406
2407 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2408
2409 if (This->state != State_Stopped)
2410 return VFW_E_WRONG_STATE;
2411
2412 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2413 {
2414 FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2415 return E_INVALIDARG;
2416 }
2417
2418 return S_OK;
2419 }
2420
2421 static HRESULT WINAPI FoundDuration(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pduration)
2422 {
2423 HRESULT hr;
2424 LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2425
2426 hr = IMediaSeeking_GetDuration(seek, &duration);
2427 if (FAILED(hr))
2428 return hr;
2429
2430 if (*pdur < duration)
2431 *pdur = duration;
2432 return hr;
2433 }
2434
2435 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface, LONGLONG *pDuration)
2436 {
2437 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2438 HRESULT hr;
2439
2440 TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2441
2442 if (!pDuration)
2443 return E_POINTER;
2444
2445 EnterCriticalSection(&This->cs);
2446 *pDuration = 0;
2447 hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
2448 LeaveCriticalSection(&This->cs);
2449
2450 TRACE("--->%08x\n", hr);
2451 return hr;
2452 }
2453
2454 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
2455 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2456 {
2457 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2458
2459 TRACE("(%p/%p)->(%p, %s, 0x%s, %s)\n", This, iface, pTarget,
2460 debugstr_guid(pTargetFormat), wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
2461
2462 if (!pSourceFormat)
2463 pSourceFormat = &This->timeformatseek;
2464
2465 if (IsEqualGUID(pTargetFormat, pSourceFormat))
2466 *pTarget = Source;
2467 else
2468 FIXME("conversion %s->%s not supported\n", debugstr_guid(pSourceFormat), debugstr_guid(pTargetFormat));
2469
2470 return S_OK;
2471 }
2472
2473 struct pos_args {
2474 LONGLONG* current, *stop;
2475 DWORD curflags, stopflags;
2476 };
2477
2478 static HRESULT WINAPI found_setposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
2479 {
2480 struct pos_args *args = (void*)pargs;
2481
2482 return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
2483 }
2484
2485 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
2486 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
2487 {
2488 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2489 HRESULT hr = S_OK;
2490 FILTER_STATE state;
2491 struct pos_args args;
2492
2493 TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
2494
2495 EnterCriticalSection(&This->cs);
2496 state = This->state;
2497 TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
2498
2499 if ((dwCurrentFlags & 0x7) != AM_SEEKING_AbsolutePositioning &&
2500 (dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2501 FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
2502
2503 if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2504 IMediaControl_Pause(&This->IMediaControl_iface);
2505 args.current = pCurrent;
2506 args.stop = pStop;
2507 args.curflags = dwCurrentFlags;
2508 args.stopflags = dwStopFlags;
2509 hr = all_renderers_seek(This, found_setposition, (DWORD_PTR)&args);
2510
2511 if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2512 This->pause_time = This->start_time = -1;
2513 if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2514 IMediaControl_Run(&This->IMediaControl_iface);
2515 LeaveCriticalSection(&This->cs);
2516
2517 return hr;
2518 }
2519
2520 static HRESULT WINAPI found_getposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
2521 {
2522 struct pos_args *args = (void*)pargs;
2523
2524 return IMediaSeeking_GetPositions(seek, args->current, args->stop);
2525 }
2526
2527 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
2528 LONGLONG *pStop)
2529 {
2530 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2531 struct pos_args args;
2532 LONGLONG time = 0;
2533 HRESULT hr;
2534
2535 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
2536
2537 args.current = pCurrent;
2538 args.stop = pStop;
2539 EnterCriticalSection(&This->cs);
2540 hr = all_renderers_seek(This, found_getposition, (DWORD_PTR)&args);
2541 if (This->state == State_Running && This->refClock && This->start_time >= 0)
2542 {
2543 IReferenceClock_GetTime(This->refClock, &time);
2544 if (time)
2545 time -= This->start_time;
2546 }
2547 if (This->pause_time > 0)
2548 time += This->pause_time;
2549 *pCurrent += time;
2550 LeaveCriticalSection(&This->cs);
2551
2552 return hr;
2553 }
2554
2555 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *pCurrent)
2556 {
2557 LONGLONG time;
2558 HRESULT hr;
2559
2560 if (!pCurrent)
2561 return E_POINTER;
2562
2563 hr = MediaSeeking_GetPositions(iface, pCurrent, &time);
2564
2565 TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
2566
2567 return hr;
2568 }
2569
2570 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *pStop)
2571 {
2572 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2573 LONGLONG time;
2574 HRESULT hr;
2575
2576 TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
2577
2578 if (!pStop)
2579 return E_POINTER;
2580
2581 hr = MediaSeeking_GetPositions(iface, &time, pStop);
2582
2583 return hr;
2584 }
2585
2586 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, LONGLONG *pEarliest,
2587 LONGLONG *pLatest)
2588 {
2589 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2590
2591 FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2592
2593 return S_OK;
2594 }
2595
2596 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2597 {
2598 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2599
2600 FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2601
2602 return S_OK;
2603 }
2604
2605 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2606 {
2607 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2608
2609 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2610
2611 return S_OK;
2612 }
2613
2614 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
2615 {
2616 IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2617
2618 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2619
2620 return S_OK;
2621 }
2622
2623
2624 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2625 {
2626 MediaSeeking_QueryInterface,
2627 MediaSeeking_AddRef,
2628 MediaSeeking_Release,
2629 MediaSeeking_GetCapabilities,
2630 MediaSeeking_CheckCapabilities,
2631 MediaSeeking_IsFormatSupported,
2632 MediaSeeking_QueryPreferredFormat,
2633 MediaSeeking_GetTimeFormat,
2634 MediaSeeking_IsUsingTimeFormat,
2635 MediaSeeking_SetTimeFormat,
2636 MediaSeeking_GetDuration,
2637 MediaSeeking_GetStopPosition,
2638 MediaSeeking_GetCurrentPosition,
2639 MediaSeeking_ConvertTimeFormat,
2640 MediaSeeking_SetPositions,
2641 MediaSeeking_GetPositions,
2642 MediaSeeking_GetAvailable,
2643 MediaSeeking_SetRate,
2644 MediaSeeking_GetRate,
2645 MediaSeeking_GetPreroll
2646 };
2647
2648 static inline IFilterGraphImpl *impl_from_IMediaPosition(IMediaPosition *iface)
2649 {
2650 return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaPosition_iface);
2651 }
2652
2653 /*** IUnknown methods ***/
2654 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj)
2655 {
2656 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2657
2658 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2659
2660 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2661 }
2662
2663 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2664 {
2665 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2666
2667 TRACE("(%p/%p)->()\n", This, iface);
2668
2669 return IUnknown_AddRef(This->outer_unk);
2670 }
2671
2672 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2673 {
2674 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2675
2676 TRACE("(%p/%p)->()\n", This, iface);
2677
2678 return IUnknown_Release(This->outer_unk);
2679 }
2680
2681 /*** IDispatch methods ***/
2682 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo)
2683 {
2684 FIXME("(%p) stub!\n", iface);
2685 return E_NOTIMPL;
2686 }
2687
2688 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2689 {
2690 FIXME("(%p) stub!\n", iface);
2691 return E_NOTIMPL;
2692 }
2693
2694 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
2695 {
2696 FIXME("(%p) stub!\n", iface);
2697 return E_NOTIMPL;
2698 }
2699
2700 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
2701 {
2702 FIXME("(%p) stub!\n", iface);
2703 return E_NOTIMPL;
2704 }
2705
2706 static HRESULT ConvertFromREFTIME(IMediaSeeking *seek, REFTIME time_in, LONGLONG *time_out)
2707 {
2708 GUID time_format;
2709 HRESULT hr;
2710
2711 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2712 if (FAILED(hr))
2713 return hr;
2714 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2715 {
2716 FIXME("Unsupported time format.\n");
2717 return E_NOTIMPL;
2718 }
2719
2720 *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2721 return S_OK;
2722 }
2723
2724 static HRESULT ConvertToREFTIME(IMediaSeeking *seek, LONGLONG time_in, REFTIME *time_out)
2725 {
2726 GUID time_format;
2727 HRESULT hr;
2728
2729 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2730 if (FAILED(hr))
2731 return hr;
2732 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2733 {
2734 FIXME("Unsupported time format.\n");
2735 return E_NOTIMPL;
2736 }
2737
2738 *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2739 return S_OK;
2740 }
2741
2742 /*** IMediaPosition methods ***/
2743 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2744 {
2745 LONGLONG duration;
2746 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2747 HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2748 if (FAILED(hr))
2749 return hr;
2750 return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2751 }
2752
2753 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2754 {
2755 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2756 LONGLONG reftime;
2757 HRESULT hr;
2758
2759 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2760 if (FAILED(hr))
2761 return hr;
2762 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2763 AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
2764 }
2765
2766 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2767 {
2768 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2769 LONGLONG pos;
2770 HRESULT hr;
2771
2772 hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2773 if (FAILED(hr))
2774 return hr;
2775 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2776 }
2777
2778 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2779 {
2780 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2781 LONGLONG pos;
2782 HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2783 if (FAILED(hr))
2784 return hr;
2785 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2786 }
2787
2788 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2789 {
2790 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2791 LONGLONG reftime;
2792 HRESULT hr;
2793
2794 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2795 if (FAILED(hr))
2796 return hr;
2797 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2798 &reftime, AM_SEEKING_AbsolutePositioning);
2799 }
2800
2801 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime)
2802 {
2803 FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2804 return E_NOTIMPL;
2805 }
2806
2807 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime)
2808 {
2809 FIXME("(%p)->(%f) stub!\n", iface, llTime);
2810 return E_NOTIMPL;
2811 }
2812
2813 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2814 {
2815 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2816 return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2817 }
2818
2819 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2820 {
2821 IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2822 return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2823 }
2824
2825 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward)
2826 {
2827 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2828 return E_NOTIMPL;
2829 }
2830
2831 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward)
2832 {
2833 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2834 return E_NOTIMPL;
2835 }
2836
2837
2838 static const IMediaPositionVtbl IMediaPosition_VTable =
2839 {
2840 MediaPosition_QueryInterface,
2841 MediaPosition_AddRef,
2842 MediaPosition_Release,
2843 MediaPosition_GetTypeInfoCount,
2844 MediaPosition_GetTypeInfo,
2845 MediaPosition_GetIDsOfNames,
2846 MediaPosition_Invoke,
2847 MediaPosition_get_Duration,
2848 MediaPosition_put_CurrentPosition,
2849 MediaPosition_get_CurrentPosition,
2850 MediaPosition_get_StopTime,
2851 MediaPosition_put_StopTime,
2852 MediaPosition_get_PrerollTime,
2853 MediaPosition_put_PrerollTime,
2854 MediaPosition_put_Rate,
2855 MediaPosition_get_Rate,
2856 MediaPosition_CanSeekForward,
2857 MediaPosition_CanSeekBackward
2858 };
2859
2860 static inline IFilterGraphImpl *impl_from_IObjectWithSite(IObjectWithSite *iface)
2861 {
2862 return CONTAINING_RECORD(iface, IFilterGraphImpl, IObjectWithSite_iface);
2863 }
2864
2865 /*** IUnknown methods ***/
2866 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite* iface, REFIID riid, void** ppvObj)
2867 {
2868 IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2869
2870 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2871
2872 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2873 }
2874
2875 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
2876 {
2877 IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2878
2879 TRACE("(%p/%p)->()\n", This, iface);
2880
2881 return IUnknown_AddRef(This->outer_unk);
2882 }
2883
2884 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
2885 {
2886 IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2887
2888 TRACE("(%p/%p)->()\n", This, iface);
2889
2890 return IUnknown_Release(This->outer_unk);
2891 }
2892
2893 /*** IObjectWithSite methods ***/
2894
2895 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
2896 {
2897 IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2898
2899 TRACE("(%p/%p)->()\n", This, iface);
2900 if (This->pSite) IUnknown_Release(This->pSite);
2901 This->pSite = pUnkSite;
2902 IUnknown_AddRef(This->pSite);
2903 return S_OK;
2904 }
2905
2906 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, PVOID *ppvSite)
2907 {
2908 IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2909
2910 TRACE("(%p/%p)->(%s)\n", This, iface,debugstr_guid(riid));
2911
2912 *ppvSite = NULL;
2913 if (!This->pSite)
2914 return E_FAIL;
2915 else
2916 return IUnknown_QueryInterface(This->pSite, riid, ppvSite);
2917 }
2918
2919 static const IObjectWithSiteVtbl IObjectWithSite_VTable =
2920 {
2921 ObjectWithSite_QueryInterface,
2922 ObjectWithSite_AddRef,
2923 ObjectWithSite_Release,
2924 ObjectWithSite_SetSite,
2925 ObjectWithSite_GetSite,
2926 };
2927
2928 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
2929 {
2930 HRESULT hr = E_NOINTERFACE;
2931 int i;
2932 int entry;
2933
2934 /* Check if the interface type is already registered */
2935 for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2936 if (riid == pGraph->ItfCacheEntries[entry].riid)
2937 {
2938 if (pGraph->ItfCacheEntries[entry].iface)
2939 {
2940 /* Return the interface if available */
2941 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2942 return S_OK;
2943 }
2944 break;
2945 }
2946
2947 if (entry >= MAX_ITF_CACHE_ENTRIES)
2948 {
2949 FIXME("Not enough space to store interface in the cache\n");
2950 return E_OUTOFMEMORY;
2951 }
2952
2953 /* Find a filter supporting the requested interface */
2954 for (i = 0; i < pGraph->nFilters; i++)
2955 {
2956 hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
2957 if (hr == S_OK)
2958 {
2959 pGraph->ItfCacheEntries[entry].riid = riid;
2960 pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
2961 pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2962 if (entry >= pGraph->nItfCacheEntries)
2963 pGraph->nItfCacheEntries++;
2964 return S_OK;
2965 }
2966 if (hr != E_NOINTERFACE)
2967 return hr;
2968 }
2969
2970 return hr;
2971 }
2972
2973 static inline IFilterGraphImpl *impl_from_IBasicAudio(IBasicAudio *iface)
2974 {
2975 return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicAudio_iface);
2976 }
2977
2978 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID riid, void **ppvObj)
2979 {
2980 IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2981
2982 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2983
2984 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2985 }
2986
2987 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
2988 {
2989 IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2990
2991 TRACE("(%p/%p)->()\n", This, iface);
2992
2993 return IUnknown_AddRef(This->outer_unk);
2994 }
2995
2996 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
2997 {
2998 IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2999
3000 TRACE("(%p/%p)->()\n", This, iface);
3001
3002 return IUnknown_Release(This->outer_unk);
3003 }
3004
3005 /*** IDispatch methods ***/
3006 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *pctinfo)
3007 {
3008 IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
3009 IBasicAudio* pBasicAudio;
3010 HRESULT hr;
3011
3012 TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3013
3014 EnterCriticalSection(&This->cs);
3015
3016 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3017