strmbase: Implement BaseControlVideo.
[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 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
36
37 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl;
38
39 typedef struct PassThruImpl {
40     const ISeekingPassThruVtbl *IPassThru_vtbl;
41     const IUnknownVtbl *IInner_vtbl;
42     const IMediaSeekingVtbl *IMediaSeeking_vtbl;
43
44     LONG ref;
45     IUnknown * pUnkOuter;
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 HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface,
56                                           REFIID riid,
57                                           LPVOID *ppvObj) {
58     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
59     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
60
61     if (This->bAggregatable)
62         This->bUnkOuterValid = TRUE;
63
64     if (IsEqualGUID(&IID_IUnknown, riid))
65     {
66         *ppvObj = &(This->IInner_vtbl);
67         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
68     } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) {
69         *ppvObj = &(This->IPassThru_vtbl);
70         TRACE("   returning ISeekingPassThru interface (%p)\n", *ppvObj);
71     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
72         *ppvObj = &(This->IMediaSeeking_vtbl);
73         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
74     } else {
75         *ppvObj = NULL;
76         FIXME("unknown interface %s\n", debugstr_guid(riid));
77         return E_NOINTERFACE;
78     }
79
80     IUnknown_AddRef((IUnknown *)(*ppvObj));
81     return S_OK;
82 }
83
84 static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) {
85     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
86     ULONG ref = InterlockedIncrement(&This->ref);
87
88     TRACE("(%p)->(): new ref = %d\n", This, ref);
89
90     return ref;
91 }
92
93 static ULONG WINAPI SeekInner_Release(IUnknown * iface) {
94     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
95     ULONG ref = InterlockedDecrement(&This->ref);
96
97     TRACE("(%p)->(): new ref = %d\n", This, ref);
98
99     if (ref == 0)
100     {
101         This->time_cs.DebugInfo->Spare[0] = 0;
102         DeleteCriticalSection(&This->time_cs);
103         CoTaskMemFree(This);
104     }
105     return ref;
106 }
107
108 static const IUnknownVtbl IInner_VTable =
109 {
110     SeekInner_QueryInterface,
111     SeekInner_AddRef,
112     SeekInner_Release
113 };
114
115 /* Generic functions for aggregation */
116 static HRESULT SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv)
117 {
118     if (This->bAggregatable)
119         This->bUnkOuterValid = TRUE;
120
121     if (This->pUnkOuter)
122     {
123         if (This->bAggregatable)
124             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
125
126         if (IsEqualIID(riid, &IID_IUnknown))
127         {
128             HRESULT hr;
129
130             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
131             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
132             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
133             This->bAggregatable = TRUE;
134             return hr;
135         }
136
137         *ppv = NULL;
138         return E_NOINTERFACE;
139     }
140
141     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
142 }
143
144 static ULONG SeekOuter_AddRef(PassThruImpl *This)
145 {
146     if (This->pUnkOuter && This->bUnkOuterValid)
147         return IUnknown_AddRef(This->pUnkOuter);
148     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
149 }
150
151 static ULONG SeekOuter_Release(PassThruImpl *This)
152 {
153     if (This->pUnkOuter && This->bUnkOuterValid)
154         return IUnknown_Release(This->pUnkOuter);
155     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
156 }
157
158 static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj)
159 {
160     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
161
162     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
163
164     return SeekOuter_QueryInterface(This, riid, ppvObj);
165 }
166
167 static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface)
168 {
169     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
170
171     TRACE("(%p/%p)->()\n", This, iface);
172
173     return SeekOuter_AddRef(This);
174 }
175
176 static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface)
177 {
178     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
179
180     TRACE("(%p/%p)->()\n", This, iface);
181
182     return SeekOuter_Release(This);
183 }
184
185 static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin)
186 {
187     ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
188
189     TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin);
190
191     if (This->pin)
192         FIXME("Re-initializing?\n");
193
194     This->renderer = renderer;
195     This->pin = pin;
196
197     return S_OK;
198 }
199
200 static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl =
201 {
202     SeekingPassThru_QueryInterface,
203     SeekingPassThru_AddRef,
204     SeekingPassThru_Release,
205     SeekingPassThru_Init
206 };
207
208 HRESULT WINAPI CreatePosPassThru(IUnknown* pUnkOuter, BOOL bRenderer, IPin *pPin, IUnknown **ppPassThru)
209 {
210     HRESULT hr;
211     ISeekingPassThru *passthru;
212
213     hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)ppPassThru);
214
215     IUnknown_QueryInterface(*ppPassThru, &IID_ISeekingPassThru, (void**)&passthru);
216     hr = ISeekingPassThru_Init(passthru, bRenderer, pPin);
217     ISeekingPassThru_Release(passthru);
218
219     return hr;
220 }
221
222 HRESULT WINAPI PosPassThru_Construct(IUnknown *pUnkOuter, LPVOID *ppPassThru)
223 {
224     PassThruImpl *fimpl;
225
226     TRACE("(%p,%p)\n", pUnkOuter, ppPassThru);
227
228     *ppPassThru = fimpl = CoTaskMemAlloc(sizeof(*fimpl));
229     if (!fimpl)
230         return E_OUTOFMEMORY;
231
232     fimpl->pUnkOuter = pUnkOuter;
233     fimpl->bUnkOuterValid = FALSE;
234     fimpl->bAggregatable = FALSE;
235     fimpl->IInner_vtbl = &IInner_VTable;
236     fimpl->IPassThru_vtbl = &ISeekingPassThru_Vtbl;
237     fimpl->IMediaSeeking_vtbl = &IMediaSeekingPassThru_Vtbl;
238     fimpl->ref = 1;
239     fimpl->pin = NULL;
240     fimpl->timevalid = 0;
241     InitializeCriticalSection(&fimpl->time_cs);
242     fimpl->time_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PassThruImpl.time_cs");
243     return S_OK;
244 }
245
246 static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj)
247 {
248     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
249
250     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
251
252     return SeekOuter_QueryInterface(This, riid, ppvObj);
253 }
254
255 static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface)
256 {
257     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
258
259     TRACE("(%p/%p)->()\n", iface, This);
260
261     return SeekOuter_AddRef(This);
262 }
263
264 static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface)
265 {
266     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
267
268     TRACE("(%p/%p)->()\n", iface, This);
269
270     return SeekOuter_Release(This);
271 }
272
273 static HRESULT get_connected(PassThruImpl *This, IMediaSeeking **seek) {
274     HRESULT hr;
275     IPin *pin;
276     *seek = NULL;
277     hr = IPin_ConnectedTo(This->pin, &pin);
278     if (FAILED(hr))
279         return VFW_E_NOT_CONNECTED;
280     hr = IPin_QueryInterface(pin, &IID_IMediaSeeking, (void**)seek);
281     IPin_Release(pin);
282     if (FAILED(hr))
283         hr = E_NOTIMPL;
284     return hr;
285 }
286
287 static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
288 {
289     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
290     IMediaSeeking *seek;
291     HRESULT hr;
292     TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
293     hr = get_connected(This, &seek);
294     if (SUCCEEDED(hr)) {
295         hr = IMediaSeeking_GetCapabilities(seek, pCapabilities);
296         IMediaSeeking_Release(seek);
297     }
298     else
299         return E_NOTIMPL;
300     return hr;
301 }
302
303 static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
304 {
305     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
306     IMediaSeeking *seek;
307     HRESULT hr;
308     TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
309     hr = get_connected(This, &seek);
310     if (SUCCEEDED(hr)) {
311         hr = IMediaSeeking_CheckCapabilities(seek, pCapabilities);
312         IMediaSeeking_Release(seek);
313     }
314     else
315         return E_NOTIMPL;
316     return hr;
317 }
318
319 static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
320 {
321     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
322     IMediaSeeking *seek;
323     HRESULT hr;
324     TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
325     hr = get_connected(This, &seek);
326     if (SUCCEEDED(hr)) {
327         hr = IMediaSeeking_IsFormatSupported(seek, pFormat);
328         IMediaSeeking_Release(seek);
329     }
330     else
331         return E_NOTIMPL;
332     return hr;
333 }
334
335 static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
336 {
337     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
338     IMediaSeeking *seek;
339     HRESULT hr;
340     TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
341     hr = get_connected(This, &seek);
342     if (SUCCEEDED(hr)) {
343         hr = IMediaSeeking_QueryPreferredFormat(seek, pFormat);
344         IMediaSeeking_Release(seek);
345     }
346     else
347         return E_NOTIMPL;
348     return hr;
349 }
350
351 static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
352 {
353     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
354     IMediaSeeking *seek;
355     HRESULT hr;
356     TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
357     hr = get_connected(This, &seek);
358     if (SUCCEEDED(hr)) {
359         hr = IMediaSeeking_GetTimeFormat(seek, pFormat);
360         IMediaSeeking_Release(seek);
361     }
362     else
363         return E_NOTIMPL;
364     return hr;
365 }
366
367 static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
368 {
369     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
370     IMediaSeeking *seek;
371     HRESULT hr;
372     TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
373     hr = get_connected(This, &seek);
374     if (SUCCEEDED(hr)) {
375         hr = IMediaSeeking_IsUsingTimeFormat(seek, pFormat);
376         IMediaSeeking_Release(seek);
377     }
378     else
379         return E_NOTIMPL;
380     return hr;
381 }
382
383 static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
384 {
385     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
386     IMediaSeeking *seek;
387     HRESULT hr;
388     TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
389     hr = get_connected(This, &seek);
390     if (SUCCEEDED(hr)) {
391         hr = IMediaSeeking_SetTimeFormat(seek, pFormat);
392         IMediaSeeking_Release(seek);
393     }
394     else
395         return E_NOTIMPL;
396     return hr;
397 }
398
399 static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
400 {
401     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
402     IMediaSeeking *seek;
403     HRESULT hr;
404     TRACE("(%p/%p)->(%p)\n", iface, This, pDuration);
405     hr = get_connected(This, &seek);
406     if (SUCCEEDED(hr)) {
407         hr = IMediaSeeking_GetDuration(seek, pDuration);
408         IMediaSeeking_Release(seek);
409     }
410     else
411         return E_NOTIMPL;
412     return hr;
413 }
414
415 static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
416 {
417     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
418     IMediaSeeking *seek;
419     HRESULT hr;
420     TRACE("(%p/%p)->(%p)\n", iface, This, pStop);
421     hr = get_connected(This, &seek);
422     if (SUCCEEDED(hr)) {
423         hr = IMediaSeeking_GetStopPosition(seek, pStop);
424         IMediaSeeking_Release(seek);
425     }
426     else
427         return E_NOTIMPL;
428     return hr;
429 }
430
431 static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
432 {
433     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
434     IMediaSeeking *seek;
435     HRESULT hr = S_OK;
436     TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent);
437     if (!pCurrent)
438         return E_POINTER;
439     EnterCriticalSection(&This->time_cs);
440     if (This->timevalid)
441         *pCurrent = This->time_earliest;
442     else
443         hr = E_FAIL;
444     LeaveCriticalSection(&This->time_cs);
445     if (SUCCEEDED(hr)) {
446         hr = IMediaSeeking_ConvertTimeFormat(iface, pCurrent, NULL, *pCurrent, &TIME_FORMAT_MEDIA_TIME);
447         return hr;
448     }
449     hr = get_connected(This, &seek);
450     if (SUCCEEDED(hr)) {
451         hr = IMediaSeeking_GetCurrentPosition(seek, pCurrent);
452         IMediaSeeking_Release(seek);
453     }
454     else
455         return E_NOTIMPL;
456     return hr;
457 }
458
459 static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
460 {
461     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
462     IMediaSeeking *seek;
463     HRESULT hr;
464     TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface, This, pTarget, debugstr_guid(pTargetFormat), (DWORD)(Source>>32), (DWORD)Source, debugstr_guid(pSourceFormat));
465     hr = get_connected(This, &seek);
466     if (SUCCEEDED(hr)) {
467         hr = IMediaSeeking_ConvertTimeFormat(seek, pTarget, pTargetFormat, Source, pSourceFormat);
468         IMediaSeeking_Release(seek);
469     }
470     else
471         return E_NOTIMPL;
472     return hr;
473 }
474
475 static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
476 {
477     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
478     IMediaSeeking *seek;
479     HRESULT hr;
480     TRACE("(%p/%p)->(%p,%x,%p,%x)\n", iface, This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
481     hr = get_connected(This, &seek);
482     if (SUCCEEDED(hr)) {
483         hr = IMediaSeeking_SetPositions(seek, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
484         IMediaSeeking_Release(seek);
485     } else if (hr == VFW_E_NOT_CONNECTED)
486         hr = S_OK;
487     return hr;
488 }
489
490 static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
491 {
492     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
493     IMediaSeeking *seek;
494     HRESULT hr;
495     TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop);
496     hr = get_connected(This, &seek);
497     if (SUCCEEDED(hr)) {
498         hr = IMediaSeeking_GetPositions(seek, pCurrent, pStop);
499         IMediaSeeking_Release(seek);
500     }
501     else
502         return E_NOTIMPL;
503     return hr;
504 }
505
506 static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
507 {
508     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
509     IMediaSeeking *seek;
510     HRESULT hr;
511     TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest);
512     hr = get_connected(This, &seek);
513     if (SUCCEEDED(hr)) {
514         hr = IMediaSeeking_GetAvailable(seek, pEarliest, pLatest);
515         IMediaSeeking_Release(seek);
516     }
517     else
518         return E_NOTIMPL;
519     return hr;
520 }
521
522 static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate)
523 {
524     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
525     IMediaSeeking *seek;
526     HRESULT hr;
527     TRACE("(%p/%p)->(%e)\n", iface, This, dRate);
528     hr = get_connected(This, &seek);
529     if (SUCCEEDED(hr)) {
530         hr = IMediaSeeking_SetRate(seek, dRate);
531         IMediaSeeking_Release(seek);
532     }
533     else
534         return E_NOTIMPL;
535     return hr;
536 }
537
538 static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate)
539 {
540     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
541     IMediaSeeking *seek;
542     HRESULT hr;
543     TRACE("(%p/%p)->(%p)\n", iface, This, dRate);
544     hr = get_connected(This, &seek);
545     if (SUCCEEDED(hr)) {
546         hr = IMediaSeeking_GetRate(seek, dRate);
547         IMediaSeeking_Release(seek);
548     }
549     else
550         return E_NOTIMPL;
551     return hr;
552 }
553
554 static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
555 {
556     ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
557     IMediaSeeking *seek;
558     HRESULT hr;
559     TRACE("(%p)\n", pPreroll);
560     hr = get_connected(This, &seek);
561     if (SUCCEEDED(hr)) {
562         hr = IMediaSeeking_GetPreroll(seek, pPreroll);
563         IMediaSeeking_Release(seek);
564     }
565     else
566         return E_NOTIMPL;
567     return hr;
568 }
569
570 HRESULT WINAPI RendererPosPassThru_RegisterMediaTime(IUnknown *iface, REFERENCE_TIME start)
571 {
572     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
573     EnterCriticalSection(&This->time_cs);
574     This->time_earliest = start;
575     This->timevalid = 1;
576     LeaveCriticalSection(&This->time_cs);
577     return S_OK;
578 }
579
580 HRESULT WINAPI RendererPosPassThru_ResetMediaTime(IUnknown *iface)
581 {
582     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
583     EnterCriticalSection(&This->time_cs);
584     This->timevalid = 0;
585     LeaveCriticalSection(&This->time_cs);
586     return S_OK;
587 }
588
589 HRESULT WINAPI RendererPosPassThru_EOS(IUnknown *iface)
590 {
591     ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
592     REFERENCE_TIME time;
593     HRESULT hr;
594     hr = IMediaSeeking_GetStopPosition((IMediaSeeking*)&This->IMediaSeeking_vtbl, &time);
595     EnterCriticalSection(&This->time_cs);
596     if (SUCCEEDED(hr)) {
597         This->timevalid = 1;
598         This->time_earliest = time;
599     } else
600         This->timevalid = 0;
601     LeaveCriticalSection(&This->time_cs);
602     return hr;
603 }
604
605 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl =
606 {
607     MediaSeekingPassThru_QueryInterface,
608     MediaSeekingPassThru_AddRef,
609     MediaSeekingPassThru_Release,
610     MediaSeekingPassThru_GetCapabilities,
611     MediaSeekingPassThru_CheckCapabilities,
612     MediaSeekingPassThru_IsFormatSupported,
613     MediaSeekingPassThru_QueryPreferredFormat,
614     MediaSeekingPassThru_GetTimeFormat,
615     MediaSeekingPassThru_IsUsingTimeFormat,
616     MediaSeekingPassThru_SetTimeFormat,
617     MediaSeekingPassThru_GetDuration,
618     MediaSeekingPassThru_GetStopPosition,
619     MediaSeekingPassThru_GetCurrentPosition,
620     MediaSeekingPassThru_ConvertTimeFormat,
621     MediaSeekingPassThru_SetPositions,
622     MediaSeekingPassThru_GetPositions,
623     MediaSeekingPassThru_GetAvailable,
624     MediaSeekingPassThru_SetRate,
625     MediaSeekingPassThru_GetRate,
626     MediaSeekingPassThru_GetPreroll
627 };