2 * Filter Seeking and Control Interfaces
4 * Copyright 2003 Robert Shearman
5 * Copyright 2012 Aric Stewart, CodeWeavers
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.
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.
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
21 /* FIXME: critical sections */
28 #include "wine/debug.h"
29 #include "wine/strmbase.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
35 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
37 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl;
39 typedef struct PassThruImpl {
40 const ISeekingPassThruVtbl *IPassThru_vtbl;
41 const IUnknownVtbl *IInner_vtbl;
42 const IMediaSeekingVtbl *IMediaSeeking_vtbl;
50 CRITICAL_SECTION time_cs;
52 REFERENCE_TIME time_earliest;
55 static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface,
58 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
59 TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
61 if (This->bAggregatable)
62 This->bUnkOuterValid = TRUE;
64 if (IsEqualGUID(&IID_IUnknown, riid))
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);
76 FIXME("unknown interface %s\n", debugstr_guid(riid));
80 IUnknown_AddRef((IUnknown *)(*ppvObj));
84 static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) {
85 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
86 ULONG ref = InterlockedIncrement(&This->ref);
88 TRACE("(%p)->(): new ref = %d\n", This, ref);
93 static ULONG WINAPI SeekInner_Release(IUnknown * iface) {
94 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
95 ULONG ref = InterlockedDecrement(&This->ref);
97 TRACE("(%p)->(): new ref = %d\n", This, ref);
101 This->time_cs.DebugInfo->Spare[0] = 0;
102 DeleteCriticalSection(&This->time_cs);
108 static const IUnknownVtbl IInner_VTable =
110 SeekInner_QueryInterface,
115 /* Generic functions for aggregation */
116 static HRESULT SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv)
118 if (This->bAggregatable)
119 This->bUnkOuterValid = TRUE;
123 if (This->bAggregatable)
124 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
126 if (IsEqualIID(riid, &IID_IUnknown))
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;
138 return E_NOINTERFACE;
141 return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
144 static ULONG SeekOuter_AddRef(PassThruImpl *This)
146 if (This->pUnkOuter && This->bUnkOuterValid)
147 return IUnknown_AddRef(This->pUnkOuter);
148 return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
151 static ULONG SeekOuter_Release(PassThruImpl *This)
153 if (This->pUnkOuter && This->bUnkOuterValid)
154 return IUnknown_Release(This->pUnkOuter);
155 return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
158 static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj)
160 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
162 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
164 return SeekOuter_QueryInterface(This, riid, ppvObj);
167 static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface)
169 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
171 TRACE("(%p/%p)->()\n", This, iface);
173 return SeekOuter_AddRef(This);
176 static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface)
178 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
180 TRACE("(%p/%p)->()\n", This, iface);
182 return SeekOuter_Release(This);
185 static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin)
187 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
189 TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin);
192 FIXME("Re-initializing?\n");
194 This->renderer = renderer;
200 static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl =
202 SeekingPassThru_QueryInterface,
203 SeekingPassThru_AddRef,
204 SeekingPassThru_Release,
208 HRESULT WINAPI CreatePosPassThru(IUnknown* pUnkOuter, BOOL bRenderer, IPin *pPin, IUnknown **ppPassThru)
211 ISeekingPassThru *passthru;
213 hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)ppPassThru);
215 IUnknown_QueryInterface(*ppPassThru, &IID_ISeekingPassThru, (void**)&passthru);
216 hr = ISeekingPassThru_Init(passthru, bRenderer, pPin);
217 ISeekingPassThru_Release(passthru);
222 HRESULT WINAPI PosPassThru_Construct(IUnknown *pUnkOuter, LPVOID *ppPassThru)
226 TRACE("(%p,%p)\n", pUnkOuter, ppPassThru);
228 *ppPassThru = fimpl = CoTaskMemAlloc(sizeof(*fimpl));
230 return E_OUTOFMEMORY;
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;
240 fimpl->timevalid = 0;
241 InitializeCriticalSection(&fimpl->time_cs);
242 fimpl->time_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PassThruImpl.time_cs");
246 static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj)
248 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
250 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
252 return SeekOuter_QueryInterface(This, riid, ppvObj);
255 static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface)
257 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
259 TRACE("(%p/%p)->()\n", iface, This);
261 return SeekOuter_AddRef(This);
264 static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface)
266 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
268 TRACE("(%p/%p)->()\n", iface, This);
270 return SeekOuter_Release(This);
273 static HRESULT get_connected(PassThruImpl *This, IMediaSeeking **seek) {
277 hr = IPin_ConnectedTo(This->pin, &pin);
279 return VFW_E_NOT_CONNECTED;
280 hr = IPin_QueryInterface(pin, &IID_IMediaSeeking, (void**)seek);
287 static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
289 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
292 TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
293 hr = get_connected(This, &seek);
295 hr = IMediaSeeking_GetCapabilities(seek, pCapabilities);
296 IMediaSeeking_Release(seek);
303 static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
305 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
308 TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
309 hr = get_connected(This, &seek);
311 hr = IMediaSeeking_CheckCapabilities(seek, pCapabilities);
312 IMediaSeeking_Release(seek);
319 static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
321 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
324 TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
325 hr = get_connected(This, &seek);
327 hr = IMediaSeeking_IsFormatSupported(seek, pFormat);
328 IMediaSeeking_Release(seek);
335 static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
337 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
340 TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
341 hr = get_connected(This, &seek);
343 hr = IMediaSeeking_QueryPreferredFormat(seek, pFormat);
344 IMediaSeeking_Release(seek);
351 static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
353 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
356 TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
357 hr = get_connected(This, &seek);
359 hr = IMediaSeeking_GetTimeFormat(seek, pFormat);
360 IMediaSeeking_Release(seek);
367 static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
369 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
372 TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
373 hr = get_connected(This, &seek);
375 hr = IMediaSeeking_IsUsingTimeFormat(seek, pFormat);
376 IMediaSeeking_Release(seek);
383 static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
385 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
388 TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
389 hr = get_connected(This, &seek);
391 hr = IMediaSeeking_SetTimeFormat(seek, pFormat);
392 IMediaSeeking_Release(seek);
399 static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
401 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
404 TRACE("(%p/%p)->(%p)\n", iface, This, pDuration);
405 hr = get_connected(This, &seek);
407 hr = IMediaSeeking_GetDuration(seek, pDuration);
408 IMediaSeeking_Release(seek);
415 static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
417 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
420 TRACE("(%p/%p)->(%p)\n", iface, This, pStop);
421 hr = get_connected(This, &seek);
423 hr = IMediaSeeking_GetStopPosition(seek, pStop);
424 IMediaSeeking_Release(seek);
431 static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
433 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
436 TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent);
439 EnterCriticalSection(&This->time_cs);
441 *pCurrent = This->time_earliest;
444 LeaveCriticalSection(&This->time_cs);
446 hr = IMediaSeeking_ConvertTimeFormat(iface, pCurrent, NULL, *pCurrent, &TIME_FORMAT_MEDIA_TIME);
449 hr = get_connected(This, &seek);
451 hr = IMediaSeeking_GetCurrentPosition(seek, pCurrent);
452 IMediaSeeking_Release(seek);
459 static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
461 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
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);
467 hr = IMediaSeeking_ConvertTimeFormat(seek, pTarget, pTargetFormat, Source, pSourceFormat);
468 IMediaSeeking_Release(seek);
475 static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
477 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
480 TRACE("(%p/%p)->(%p,%x,%p,%x)\n", iface, This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
481 hr = get_connected(This, &seek);
483 hr = IMediaSeeking_SetPositions(seek, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
484 IMediaSeeking_Release(seek);
485 } else if (hr == VFW_E_NOT_CONNECTED)
490 static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
492 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
495 TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop);
496 hr = get_connected(This, &seek);
498 hr = IMediaSeeking_GetPositions(seek, pCurrent, pStop);
499 IMediaSeeking_Release(seek);
506 static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
508 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
511 TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest);
512 hr = get_connected(This, &seek);
514 hr = IMediaSeeking_GetAvailable(seek, pEarliest, pLatest);
515 IMediaSeeking_Release(seek);
522 static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate)
524 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
527 TRACE("(%p/%p)->(%e)\n", iface, This, dRate);
528 hr = get_connected(This, &seek);
530 hr = IMediaSeeking_SetRate(seek, dRate);
531 IMediaSeeking_Release(seek);
538 static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate)
540 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
543 TRACE("(%p/%p)->(%p)\n", iface, This, dRate);
544 hr = get_connected(This, &seek);
546 hr = IMediaSeeking_GetRate(seek, dRate);
547 IMediaSeeking_Release(seek);
554 static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
556 ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface);
559 TRACE("(%p)\n", pPreroll);
560 hr = get_connected(This, &seek);
562 hr = IMediaSeeking_GetPreroll(seek, pPreroll);
563 IMediaSeeking_Release(seek);
570 HRESULT WINAPI RendererPosPassThru_RegisterMediaTime(IUnknown *iface, REFERENCE_TIME start)
572 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
573 EnterCriticalSection(&This->time_cs);
574 This->time_earliest = start;
576 LeaveCriticalSection(&This->time_cs);
580 HRESULT WINAPI RendererPosPassThru_ResetMediaTime(IUnknown *iface)
582 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
583 EnterCriticalSection(&This->time_cs);
585 LeaveCriticalSection(&This->time_cs);
589 HRESULT WINAPI RendererPosPassThru_EOS(IUnknown *iface)
591 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
594 hr = IMediaSeeking_GetStopPosition((IMediaSeeking*)&This->IMediaSeeking_vtbl, &time);
595 EnterCriticalSection(&This->time_cs);
598 This->time_earliest = time;
601 LeaveCriticalSection(&This->time_cs);
605 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl =
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