include: Assorted spelling fixes.
[wine] / dlls / strmbase / pospass.c
1 /*
2  * Filter Seeking and Control Interfaces
3  *
4  * Copyright 2003 Robert Shearman
5  * Copyright 2012 Aric Stewart, CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 /* FIXME: critical sections */
22
23 #define COBJMACROS
24
25 #include "dshow.h"
26 #include "uuids.h"
27
28 #include "wine/debug.h"
29 #include "wine/strmbase.h"
30
31 #include <assert.h>
32
33 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
34
35 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl;
36 static const IMediaPositionVtbl IMediaPositionPassThru_Vtbl;
37
38 typedef struct PassThruImpl {
39     IUnknown  IUnknown_inner;
40     ISeekingPassThru ISeekingPassThru_iface;
41     IMediaSeeking IMediaSeeking_iface;
42     IMediaPosition IMediaPosition_iface;
43     BaseDispatch baseDispatch;
44
45     LONG ref;
46     IUnknown * outer_unk;
47     IPin * pin;
48     BOOL bUnkOuterValid;
49     BOOL bAggregatable;
50     BOOL renderer;
51     CRITICAL_SECTION time_cs;
52     BOOL timevalid;
53     REFERENCE_TIME time_earliest;
54 } PassThruImpl;
55
56 static inline PassThruImpl *impl_from_IUnknown_inner(IUnknown *iface)
57 {
58     return CONTAINING_RECORD(iface, PassThruImpl, IUnknown_inner);
59 }
60
61 static inline PassThruImpl *impl_from_ISeekingPassThru(ISeekingPassThru *iface)
62 {
63     return CONTAINING_RECORD(iface, PassThruImpl, ISeekingPassThru_iface);
64 }
65
66 static inline PassThruImpl *impl_from_IMediaSeeking(IMediaSeeking *iface)
67 {
68     return CONTAINING_RECORD(iface, PassThruImpl, IMediaSeeking_iface);
69 }
70
71 static inline PassThruImpl *impl_from_IMediaPosition(IMediaPosition *iface)
72 {
73     return CONTAINING_RECORD(iface, PassThruImpl, IMediaPosition_iface);
74 }
75
76 static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface,
77                                           REFIID riid,
78                                           LPVOID *ppvObj) {
79     PassThruImpl *This = impl_from_IUnknown_inner(iface);
80     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
81
82     if (This->bAggregatable)
83         This->bUnkOuterValid = TRUE;
84
85     if (IsEqualGUID(&IID_IUnknown, riid))
86     {
87         *ppvObj = &(This->IUnknown_inner);
88         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
89     } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) {
90         *ppvObj = &(This->ISeekingPassThru_iface);
91         TRACE("   returning ISeekingPassThru interface (%p)\n", *ppvObj);
92     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
93         *ppvObj = &(This->IMediaSeeking_iface);
94         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
95     } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
96         *ppvObj = &(This->IMediaPosition_iface);
97         TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
98     } else {
99         *ppvObj = NULL;
100         FIXME("unknown interface %s\n", debugstr_guid(riid));
101         return E_NOINTERFACE;
102     }
103
104     IUnknown_AddRef((IUnknown *)(*ppvObj));
105     return S_OK;
106 }
107
108 static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) {
109     PassThruImpl *This = impl_from_IUnknown_inner(iface);
110     ULONG ref = InterlockedIncrement(&This->ref);
111
112     TRACE("(%p)->(): new ref = %d\n", This, ref);
113
114     return ref;
115 }
116
117 static ULONG WINAPI SeekInner_Release(IUnknown * iface) {
118     PassThruImpl *This = impl_from_IUnknown_inner(iface);
119     ULONG ref = InterlockedDecrement(&This->ref);
120
121     TRACE("(%p)->(): new ref = %d\n", This, ref);
122
123     if (ref == 0)
124     {
125         BaseDispatch_Destroy(&This->baseDispatch);
126         This->time_cs.DebugInfo->Spare[0] = 0;
127         DeleteCriticalSection(&This->time_cs);
128         CoTaskMemFree(This);
129     }
130     return ref;
131 }
132
133 static const IUnknownVtbl IInner_VTable =
134 {
135     SeekInner_QueryInterface,
136     SeekInner_AddRef,
137     SeekInner_Release
138 };
139
140 /* Generic functions for aggregation */
141 static HRESULT SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv)
142 {
143     if (This->bAggregatable)
144         This->bUnkOuterValid = TRUE;
145
146     if (This->outer_unk)
147     {
148         if (This->bAggregatable)
149             return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
150
151         if (IsEqualIID(riid, &IID_IUnknown))
152         {
153             HRESULT hr;
154
155             IUnknown_AddRef((IUnknown *)&(This->IUnknown_inner));
156             hr = IUnknown_QueryInterface((IUnknown *)&(This->IUnknown_inner), riid, ppv);
157             IUnknown_Release((IUnknown *)&(This->IUnknown_inner));
158             This->bAggregatable = TRUE;
159             return hr;
160         }
161
162         *ppv = NULL;
163         return E_NOINTERFACE;
164     }
165
166     return IUnknown_QueryInterface((IUnknown *)&(This->IUnknown_inner), riid, ppv);
167 }
168
169 static ULONG SeekOuter_AddRef(PassThruImpl *This)
170 {
171     if (This->outer_unk && This->bUnkOuterValid)
172         return IUnknown_AddRef(This->outer_unk);
173     return IUnknown_AddRef((IUnknown *)&(This->IUnknown_inner));
174 }
175
176 static ULONG SeekOuter_Release(PassThruImpl *This)
177 {
178     if (This->outer_unk && This->bUnkOuterValid)
179         return IUnknown_Release(This->outer_unk);
180     return IUnknown_Release((IUnknown *)&(This->IUnknown_inner));
181 }
182
183 static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj)
184 {
185     PassThruImpl *This = impl_from_ISeekingPassThru(iface);
186
187     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
188
189     return SeekOuter_QueryInterface(This, riid, ppvObj);
190 }
191
192 static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface)
193 {
194     PassThruImpl *This = impl_from_ISeekingPassThru(iface);
195
196     TRACE("(%p/%p)->()\n", This, iface);
197
198     return SeekOuter_AddRef(This);
199 }
200
201 static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface)
202 {
203     PassThruImpl *This = impl_from_ISeekingPassThru(iface);
204
205     TRACE("(%p/%p)->()\n", This, iface);
206
207     return SeekOuter_Release(This);
208 }
209
210 static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin)
211 {
212     PassThruImpl *This = impl_from_ISeekingPassThru(iface);
213
214     TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin);
215
216     if (This->pin)
217         FIXME("Re-initializing?\n");
218
219     This->renderer = renderer;
220     This->pin = pin;
221
222     return S_OK;
223 }
224
225 static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl =
226 {
227     SeekingPassThru_QueryInterface,
228     SeekingPassThru_AddRef,
229     SeekingPassThru_Release,
230     SeekingPassThru_Init
231 };
232
233 HRESULT WINAPI CreatePosPassThru(IUnknown* pUnkOuter, BOOL bRenderer, IPin *pPin, IUnknown **ppPassThru)
234 {
235     HRESULT hr;
236     ISeekingPassThru *passthru;
237
238     hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)ppPassThru);
239
240     IUnknown_QueryInterface(*ppPassThru, &IID_ISeekingPassThru, (void**)&passthru);
241     hr = ISeekingPassThru_Init(passthru, bRenderer, pPin);
242     ISeekingPassThru_Release(passthru);
243
244     return hr;
245 }
246
247 HRESULT WINAPI PosPassThru_Construct(IUnknown *pUnkOuter, LPVOID *ppPassThru)
248 {
249     PassThruImpl *fimpl;
250
251     TRACE("(%p,%p)\n", pUnkOuter, ppPassThru);
252
253     *ppPassThru = fimpl = CoTaskMemAlloc(sizeof(*fimpl));
254     if (!fimpl)
255         return E_OUTOFMEMORY;
256
257     fimpl->outer_unk = pUnkOuter;
258     fimpl->bUnkOuterValid = FALSE;
259     fimpl->bAggregatable = FALSE;
260     fimpl->IUnknown_inner.lpVtbl = &IInner_VTable;
261     fimpl->ISeekingPassThru_iface.lpVtbl = &ISeekingPassThru_Vtbl;
262     fimpl->IMediaSeeking_iface.lpVtbl = &IMediaSeekingPassThru_Vtbl;
263     fimpl->IMediaPosition_iface.lpVtbl = &IMediaPositionPassThru_Vtbl;
264     fimpl->ref = 1;
265     fimpl->pin = NULL;
266     fimpl->timevalid = 0;
267     InitializeCriticalSection(&fimpl->time_cs);
268     fimpl->time_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PassThruImpl.time_cs");
269     BaseDispatch_Init(&fimpl->baseDispatch, &IID_IMediaPosition);
270     return S_OK;
271 }
272
273 static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj)
274 {
275     PassThruImpl *This = impl_from_IMediaSeeking(iface);
276
277     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
278
279     return SeekOuter_QueryInterface(This, riid, ppvObj);
280 }
281
282 static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface)
283 {
284     PassThruImpl *This = impl_from_IMediaSeeking(iface);
285
286     TRACE("(%p/%p)->()\n", iface, This);
287
288     return SeekOuter_AddRef(This);
289 }
290
291 static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface)
292 {
293     PassThruImpl *This = impl_from_IMediaSeeking(iface);
294
295     TRACE("(%p/%p)->()\n", iface, This);
296
297     return SeekOuter_Release(This);
298 }
299
300 static HRESULT get_connected(PassThruImpl *This, REFIID riid, LPVOID *ppvObj) {
301     HRESULT hr;
302     IPin *pin;
303     *ppvObj = NULL;
304     hr = IPin_ConnectedTo(This->pin, &pin);
305     if (FAILED(hr))
306         return VFW_E_NOT_CONNECTED;
307     hr = IPin_QueryInterface(pin, riid, ppvObj);
308     IPin_Release(pin);
309     if (FAILED(hr))
310         hr = E_NOTIMPL;
311     return hr;
312 }
313
314 static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
315 {
316     PassThruImpl *This = impl_from_IMediaSeeking(iface);
317     IMediaSeeking *seek;
318     HRESULT hr;
319     TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
320     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
321     if (SUCCEEDED(hr)) {
322         hr = IMediaSeeking_GetCapabilities(seek, pCapabilities);
323         IMediaSeeking_Release(seek);
324     }
325     else
326         return E_NOTIMPL;
327     return hr;
328 }
329
330 static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
331 {
332     PassThruImpl *This = impl_from_IMediaSeeking(iface);
333     IMediaSeeking *seek;
334     HRESULT hr;
335     TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
336     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
337     if (SUCCEEDED(hr)) {
338         hr = IMediaSeeking_CheckCapabilities(seek, pCapabilities);
339         IMediaSeeking_Release(seek);
340     }
341     else
342         return E_NOTIMPL;
343     return hr;
344 }
345
346 static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
347 {
348     PassThruImpl *This = impl_from_IMediaSeeking(iface);
349     IMediaSeeking *seek;
350     HRESULT hr;
351     TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
352     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
353     if (SUCCEEDED(hr)) {
354         hr = IMediaSeeking_IsFormatSupported(seek, pFormat);
355         IMediaSeeking_Release(seek);
356     }
357     else
358         return E_NOTIMPL;
359     return hr;
360 }
361
362 static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
363 {
364     PassThruImpl *This = impl_from_IMediaSeeking(iface);
365     IMediaSeeking *seek;
366     HRESULT hr;
367     TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
368     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
369     if (SUCCEEDED(hr)) {
370         hr = IMediaSeeking_QueryPreferredFormat(seek, pFormat);
371         IMediaSeeking_Release(seek);
372     }
373     else
374         return E_NOTIMPL;
375     return hr;
376 }
377
378 static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
379 {
380     PassThruImpl *This = impl_from_IMediaSeeking(iface);
381     IMediaSeeking *seek;
382     HRESULT hr;
383     TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
384     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
385     if (SUCCEEDED(hr)) {
386         hr = IMediaSeeking_GetTimeFormat(seek, pFormat);
387         IMediaSeeking_Release(seek);
388     }
389     else
390         return E_NOTIMPL;
391     return hr;
392 }
393
394 static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
395 {
396     PassThruImpl *This = impl_from_IMediaSeeking(iface);
397     IMediaSeeking *seek;
398     HRESULT hr;
399     TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
400     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
401     if (SUCCEEDED(hr)) {
402         hr = IMediaSeeking_IsUsingTimeFormat(seek, pFormat);
403         IMediaSeeking_Release(seek);
404     }
405     else
406         return E_NOTIMPL;
407     return hr;
408 }
409
410 static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
411 {
412     PassThruImpl *This = impl_from_IMediaSeeking(iface);
413     IMediaSeeking *seek;
414     HRESULT hr;
415     TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
416     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
417     if (SUCCEEDED(hr)) {
418         hr = IMediaSeeking_SetTimeFormat(seek, pFormat);
419         IMediaSeeking_Release(seek);
420     }
421     else
422         return E_NOTIMPL;
423     return hr;
424 }
425
426 static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
427 {
428     PassThruImpl *This = impl_from_IMediaSeeking(iface);
429     IMediaSeeking *seek;
430     HRESULT hr;
431     TRACE("(%p/%p)->(%p)\n", iface, This, pDuration);
432     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
433     if (SUCCEEDED(hr)) {
434         hr = IMediaSeeking_GetDuration(seek, pDuration);
435         IMediaSeeking_Release(seek);
436     }
437     else
438         return E_NOTIMPL;
439     return hr;
440 }
441
442 static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
443 {
444     PassThruImpl *This = impl_from_IMediaSeeking(iface);
445     IMediaSeeking *seek;
446     HRESULT hr;
447     TRACE("(%p/%p)->(%p)\n", iface, This, pStop);
448     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
449     if (SUCCEEDED(hr)) {
450         hr = IMediaSeeking_GetStopPosition(seek, pStop);
451         IMediaSeeking_Release(seek);
452     }
453     else
454         return E_NOTIMPL;
455     return hr;
456 }
457
458 static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
459 {
460     PassThruImpl *This = impl_from_IMediaSeeking(iface);
461     IMediaSeeking *seek;
462     HRESULT hr = S_OK;
463     TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent);
464     if (!pCurrent)
465         return E_POINTER;
466     EnterCriticalSection(&This->time_cs);
467     if (This->timevalid)
468         *pCurrent = This->time_earliest;
469     else
470         hr = E_FAIL;
471     LeaveCriticalSection(&This->time_cs);
472     if (SUCCEEDED(hr)) {
473         hr = IMediaSeeking_ConvertTimeFormat(iface, pCurrent, NULL, *pCurrent, &TIME_FORMAT_MEDIA_TIME);
474         return hr;
475     }
476     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
477     if (SUCCEEDED(hr)) {
478         hr = IMediaSeeking_GetCurrentPosition(seek, pCurrent);
479         IMediaSeeking_Release(seek);
480     }
481     else
482         return E_NOTIMPL;
483     return hr;
484 }
485
486 static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
487 {
488     PassThruImpl *This = impl_from_IMediaSeeking(iface);
489     IMediaSeeking *seek;
490     HRESULT hr;
491     TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface, This, pTarget, debugstr_guid(pTargetFormat), (DWORD)(Source>>32), (DWORD)Source, debugstr_guid(pSourceFormat));
492     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
493     if (SUCCEEDED(hr)) {
494         hr = IMediaSeeking_ConvertTimeFormat(seek, pTarget, pTargetFormat, Source, pSourceFormat);
495         IMediaSeeking_Release(seek);
496     }
497     else
498         return E_NOTIMPL;
499     return hr;
500 }
501
502 static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
503 {
504     PassThruImpl *This = impl_from_IMediaSeeking(iface);
505     IMediaSeeking *seek;
506     HRESULT hr;
507     TRACE("(%p/%p)->(%p,%x,%p,%x)\n", iface, This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
508     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
509     if (SUCCEEDED(hr)) {
510         hr = IMediaSeeking_SetPositions(seek, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
511         IMediaSeeking_Release(seek);
512     } else if (hr == VFW_E_NOT_CONNECTED)
513         hr = S_OK;
514     return hr;
515 }
516
517 static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
518 {
519     PassThruImpl *This = impl_from_IMediaSeeking(iface);
520     IMediaSeeking *seek;
521     HRESULT hr;
522     TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop);
523     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
524     if (SUCCEEDED(hr)) {
525         hr = IMediaSeeking_GetPositions(seek, pCurrent, pStop);
526         IMediaSeeking_Release(seek);
527     }
528     else
529         return E_NOTIMPL;
530     return hr;
531 }
532
533 static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
534 {
535     PassThruImpl *This = impl_from_IMediaSeeking(iface);
536     IMediaSeeking *seek;
537     HRESULT hr;
538     TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest);
539     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
540     if (SUCCEEDED(hr)) {
541         hr = IMediaSeeking_GetAvailable(seek, pEarliest, pLatest);
542         IMediaSeeking_Release(seek);
543     }
544     else
545         return E_NOTIMPL;
546     return hr;
547 }
548
549 static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate)
550 {
551     PassThruImpl *This = impl_from_IMediaSeeking(iface);
552     IMediaSeeking *seek;
553     HRESULT hr;
554     TRACE("(%p/%p)->(%e)\n", iface, This, dRate);
555     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
556     if (SUCCEEDED(hr)) {
557         hr = IMediaSeeking_SetRate(seek, dRate);
558         IMediaSeeking_Release(seek);
559     }
560     else
561         return E_NOTIMPL;
562     return hr;
563 }
564
565 static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate)
566 {
567     PassThruImpl *This = impl_from_IMediaSeeking(iface);
568     IMediaSeeking *seek;
569     HRESULT hr;
570     TRACE("(%p/%p)->(%p)\n", iface, This, dRate);
571     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
572     if (SUCCEEDED(hr)) {
573         hr = IMediaSeeking_GetRate(seek, dRate);
574         IMediaSeeking_Release(seek);
575     }
576     else
577         return E_NOTIMPL;
578     return hr;
579 }
580
581 static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
582 {
583     PassThruImpl *This = impl_from_IMediaSeeking(iface);
584     IMediaSeeking *seek;
585     HRESULT hr;
586     TRACE("(%p)\n", pPreroll);
587     hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
588     if (SUCCEEDED(hr)) {
589         hr = IMediaSeeking_GetPreroll(seek, pPreroll);
590         IMediaSeeking_Release(seek);
591     }
592     else
593         return E_NOTIMPL;
594     return hr;
595 }
596
597 HRESULT WINAPI RendererPosPassThru_RegisterMediaTime(IUnknown *iface, REFERENCE_TIME start)
598 {
599     PassThruImpl *This = impl_from_IUnknown_inner(iface);
600     EnterCriticalSection(&This->time_cs);
601     This->time_earliest = start;
602     This->timevalid = 1;
603     LeaveCriticalSection(&This->time_cs);
604     return S_OK;
605 }
606
607 HRESULT WINAPI RendererPosPassThru_ResetMediaTime(IUnknown *iface)
608 {
609     PassThruImpl *This = impl_from_IUnknown_inner(iface);
610     EnterCriticalSection(&This->time_cs);
611     This->timevalid = 0;
612     LeaveCriticalSection(&This->time_cs);
613     return S_OK;
614 }
615
616 HRESULT WINAPI RendererPosPassThru_EOS(IUnknown *iface)
617 {
618     PassThruImpl *This = impl_from_IUnknown_inner(iface);
619     REFERENCE_TIME time;
620     HRESULT hr;
621     hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &time);
622     EnterCriticalSection(&This->time_cs);
623     if (SUCCEEDED(hr)) {
624         This->timevalid = 1;
625         This->time_earliest = time;
626     } else
627         This->timevalid = 0;
628     LeaveCriticalSection(&This->time_cs);
629     return hr;
630 }
631
632 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl =
633 {
634     MediaSeekingPassThru_QueryInterface,
635     MediaSeekingPassThru_AddRef,
636     MediaSeekingPassThru_Release,
637     MediaSeekingPassThru_GetCapabilities,
638     MediaSeekingPassThru_CheckCapabilities,
639     MediaSeekingPassThru_IsFormatSupported,
640     MediaSeekingPassThru_QueryPreferredFormat,
641     MediaSeekingPassThru_GetTimeFormat,
642     MediaSeekingPassThru_IsUsingTimeFormat,
643     MediaSeekingPassThru_SetTimeFormat,
644     MediaSeekingPassThru_GetDuration,
645     MediaSeekingPassThru_GetStopPosition,
646     MediaSeekingPassThru_GetCurrentPosition,
647     MediaSeekingPassThru_ConvertTimeFormat,
648     MediaSeekingPassThru_SetPositions,
649     MediaSeekingPassThru_GetPositions,
650     MediaSeekingPassThru_GetAvailable,
651     MediaSeekingPassThru_SetRate,
652     MediaSeekingPassThru_GetRate,
653     MediaSeekingPassThru_GetPreroll
654 };
655
656 static HRESULT WINAPI MediaPositionPassThru_QueryInterface(IMediaPosition *iface, REFIID riid, LPVOID *ppvObj)
657 {
658     PassThruImpl *This = impl_from_IMediaPosition(iface);
659
660     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
661
662     return SeekOuter_QueryInterface(This, riid, ppvObj);
663 }
664
665 static ULONG WINAPI MediaPositionPassThru_AddRef(IMediaPosition *iface)
666 {
667     PassThruImpl *This = impl_from_IMediaPosition(iface);
668
669     TRACE("(%p/%p)->()\n", iface, This);
670
671     return SeekOuter_AddRef(This);
672 }
673
674 static ULONG WINAPI MediaPositionPassThru_Release(IMediaPosition *iface)
675 {
676     PassThruImpl *This = impl_from_IMediaPosition(iface);
677
678     TRACE("(%p/%p)->()\n", iface, This);
679
680     return SeekOuter_Release(This);
681 }
682
683 static HRESULT WINAPI MediaPositionPassThru_GetTypeInfoCount(IMediaPosition *iface, UINT*pctinfo)
684 {
685     PassThruImpl *This = impl_from_IMediaPosition(iface);
686
687     return BaseDispatchImpl_GetTypeInfoCount(&This->baseDispatch, pctinfo);
688 }
689
690 static HRESULT WINAPI MediaPositionPassThru_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo**ppTInfo)
691 {
692     PassThruImpl *This = impl_from_IMediaPosition(iface);
693
694     return BaseDispatchImpl_GetTypeInfo(&This->baseDispatch, &IID_NULL, iTInfo, lcid, ppTInfo);
695 }
696
697 static HRESULT WINAPI MediaPositionPassThru_GetIDsOfNames(IMediaPosition *iface, REFIID riid, LPOLESTR*rgszNames, UINT cNames, LCID lcid, DISPID*rgDispId)
698 {
699     PassThruImpl *This = impl_from_IMediaPosition(iface);
700
701     return BaseDispatchImpl_GetIDsOfNames(&This->baseDispatch, riid, rgszNames, cNames, lcid, rgDispId);
702 }
703
704 static HRESULT WINAPI MediaPositionPassThru_Invoke(IMediaPosition *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS*pDispParams, VARIANT*pVarResult, EXCEPINFO*pExepInfo, UINT*puArgErr)
705 {
706     PassThruImpl *This = impl_from_IMediaPosition(iface);
707     HRESULT hr = S_OK;
708     ITypeInfo *pTypeInfo;
709
710     hr = BaseDispatchImpl_GetTypeInfo(&This->baseDispatch, riid, 1, lcid, &pTypeInfo);
711     if (SUCCEEDED(hr))
712     {
713         hr = ITypeInfo_Invoke(pTypeInfo, &This->IMediaPosition_iface, dispIdMember, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
714         ITypeInfo_Release(pTypeInfo);
715     }
716
717     return hr;
718 }
719
720 static HRESULT WINAPI MediaPositionPassThru_get_Duration(IMediaPosition *iface, REFTIME *plength)
721 {
722     PassThruImpl *This = impl_from_IMediaPosition(iface);
723     IMediaPosition *pos;
724     HRESULT hr;
725
726     TRACE("(%p)\n", plength);
727
728     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
729     if (SUCCEEDED(hr)) {
730         hr = IMediaPosition_get_Duration(pos, plength);
731         IMediaPosition_Release(pos);
732     }
733     else
734         return E_NOTIMPL;
735     return hr;
736 }
737
738 static HRESULT WINAPI MediaPositionPassThru_put_CurrentPosition(IMediaPosition *iface, REFTIME llTime)
739 {
740     PassThruImpl *This = impl_from_IMediaPosition(iface);
741     IMediaPosition *pos;
742     HRESULT hr;
743
744     TRACE("(%s)\n", wine_dbgstr_longlong(llTime));
745
746     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
747     if (SUCCEEDED(hr)) {
748         hr = IMediaPosition_put_CurrentPosition(pos, llTime);
749         IMediaPosition_Release(pos);
750     }
751     else
752         return E_NOTIMPL;
753     return hr;
754 }
755
756 static HRESULT WINAPI MediaPositionPassThru_get_CurrentPosition(IMediaPosition *iface, REFTIME *pllTime)
757 {
758     PassThruImpl *This = impl_from_IMediaPosition(iface);
759     IMediaPosition *pos;
760     HRESULT hr;
761
762     TRACE("(%p)\n", pllTime);
763
764     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
765     if (SUCCEEDED(hr)) {
766         hr = IMediaPosition_get_CurrentPosition(pos, pllTime);
767         IMediaPosition_Release(pos);
768     }
769     else
770         return E_NOTIMPL;
771     return hr;
772 }
773
774 static HRESULT WINAPI MediaPositionPassThru_get_StopTime(IMediaPosition *iface, REFTIME *pllTime)
775 {
776     PassThruImpl *This = impl_from_IMediaPosition(iface);
777     IMediaPosition *pos;
778     HRESULT hr;
779
780     TRACE("(%p)\n", pllTime);
781
782     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
783     if (SUCCEEDED(hr)) {
784         hr = IMediaPosition_get_StopTime(pos, pllTime);
785         IMediaPosition_Release(pos);
786     }
787     else
788         return E_NOTIMPL;
789     return hr;
790 }
791
792 static HRESULT WINAPI MediaPositionPassThru_put_StopTime(IMediaPosition *iface, REFTIME llTime)
793 {
794     PassThruImpl *This = impl_from_IMediaPosition(iface);
795     IMediaPosition *pos;
796     HRESULT hr;
797
798     TRACE("(%s)\n", wine_dbgstr_longlong(llTime));
799
800     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
801     if (SUCCEEDED(hr)) {
802         hr = IMediaPosition_put_StopTime(pos, llTime);
803         IMediaPosition_Release(pos);
804     }
805     else
806         return E_NOTIMPL;
807     return hr;
808 }
809
810 static HRESULT WINAPI MediaPositionPassThru_get_PrerollTime(IMediaPosition *iface, REFTIME *pllTime)
811 {
812     PassThruImpl *This = impl_from_IMediaPosition(iface);
813     IMediaPosition *pos;
814     HRESULT hr;
815
816     TRACE("(%p)\n", pllTime);
817
818     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
819     if (SUCCEEDED(hr)) {
820         hr = IMediaPosition_get_PrerollTime(pos, pllTime);
821         IMediaPosition_Release(pos);
822     }
823     else
824         return E_NOTIMPL;
825     return hr;
826 }
827
828 static HRESULT WINAPI MediaPositionPassThru_put_PrerollTime(IMediaPosition *iface, REFTIME llTime)
829 {
830     PassThruImpl *This = impl_from_IMediaPosition(iface);
831     IMediaPosition *pos;
832     HRESULT hr;
833
834     TRACE("(%s)\n", wine_dbgstr_longlong(llTime));
835
836     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
837     if (SUCCEEDED(hr)) {
838         hr = IMediaPosition_put_PrerollTime(pos, llTime);
839         IMediaPosition_Release(pos);
840     }
841     else
842         return E_NOTIMPL;
843     return hr;
844 }
845
846 static HRESULT WINAPI MediaPositionPassThru_put_Rate(IMediaPosition *iface, double dRate)
847 {
848     PassThruImpl *This = impl_from_IMediaPosition(iface);
849     IMediaPosition *pos;
850     HRESULT hr;
851
852     TRACE("(%f)\n", dRate);
853
854     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
855     if (SUCCEEDED(hr)) {
856         hr = IMediaPosition_put_Rate(pos, dRate);
857         IMediaPosition_Release(pos);
858     }
859     else
860         return E_NOTIMPL;
861     return hr;
862 }
863
864 static HRESULT WINAPI MediaPositionPassThru_get_Rate(IMediaPosition *iface, double *pdRate)
865 {
866     PassThruImpl *This = impl_from_IMediaPosition(iface);
867     IMediaPosition *pos;
868     HRESULT hr;
869
870     TRACE("(%p)\n", pdRate);
871
872     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
873     if (SUCCEEDED(hr)) {
874         hr = IMediaPosition_get_Rate(pos, pdRate);
875         IMediaPosition_Release(pos);
876     }
877     else
878         return E_NOTIMPL;
879     return hr;
880 }
881
882 static HRESULT WINAPI MediaPositionPassThru_CanSeekForward(IMediaPosition *iface, LONG *pCanSeekForward)
883 {
884     PassThruImpl *This = impl_from_IMediaPosition(iface);
885     IMediaPosition *pos;
886     HRESULT hr;
887
888     TRACE("(%p)\n", pCanSeekForward);
889
890     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
891     if (SUCCEEDED(hr)) {
892         hr = IMediaPosition_CanSeekForward(pos, pCanSeekForward);
893         IMediaPosition_Release(pos);
894     }
895     else
896         return E_NOTIMPL;
897     return hr;
898 }
899
900 static HRESULT WINAPI MediaPositionPassThru_CanSeekBackward(IMediaPosition *iface, LONG *pCanSeekBackward)
901 {
902     PassThruImpl *This = impl_from_IMediaPosition(iface);
903     IMediaPosition *pos;
904     HRESULT hr;
905
906     TRACE("(%p)\n", pCanSeekBackward);
907
908     hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
909     if (SUCCEEDED(hr)) {
910         hr = IMediaPosition_CanSeekBackward(pos, pCanSeekBackward);
911         IMediaPosition_Release(pos);
912     }
913     else
914         return E_NOTIMPL;
915     return hr;
916 }
917
918 static const IMediaPositionVtbl IMediaPositionPassThru_Vtbl =
919 {
920     MediaPositionPassThru_QueryInterface,
921     MediaPositionPassThru_AddRef,
922     MediaPositionPassThru_Release,
923     MediaPositionPassThru_GetTypeInfoCount,
924     MediaPositionPassThru_GetTypeInfo,
925     MediaPositionPassThru_GetIDsOfNames,
926     MediaPositionPassThru_Invoke,
927     MediaPositionPassThru_get_Duration,
928     MediaPositionPassThru_put_CurrentPosition,
929     MediaPositionPassThru_get_CurrentPosition,
930     MediaPositionPassThru_get_StopTime,
931     MediaPositionPassThru_put_StopTime,
932     MediaPositionPassThru_get_PrerollTime,
933     MediaPositionPassThru_put_PrerollTime,
934     MediaPositionPassThru_put_Rate,
935     MediaPositionPassThru_get_Rate,
936     MediaPositionPassThru_CanSeekForward,
937     MediaPositionPassThru_CanSeekBackward
938 };