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