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