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 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl
;
37 typedef struct PassThruImpl
{
38 IUnknown IUnknown_inner
;
39 ISeekingPassThru ISeekingPassThru_iface
;
40 IMediaSeeking IMediaSeeking_iface
;
48 CRITICAL_SECTION time_cs
;
50 REFERENCE_TIME time_earliest
;
53 static inline PassThruImpl
*impl_from_IUnknown_inner(IUnknown
*iface
)
55 return CONTAINING_RECORD(iface
, PassThruImpl
, IUnknown_inner
);
58 static inline PassThruImpl
*impl_from_ISeekingPassThru(ISeekingPassThru
*iface
)
60 return CONTAINING_RECORD(iface
, PassThruImpl
, ISeekingPassThru_iface
);
63 static inline PassThruImpl
*impl_from_IMediaSeeking(IMediaSeeking
*iface
)
65 return CONTAINING_RECORD(iface
, PassThruImpl
, IMediaSeeking_iface
);
68 static HRESULT WINAPI
SeekInner_QueryInterface(IUnknown
* iface
,
71 PassThruImpl
*This
= impl_from_IUnknown_inner(iface
);
72 TRACE("(%p)->(%s (%p), %p)\n", This
, debugstr_guid(riid
), riid
, ppvObj
);
74 if (This
->bAggregatable
)
75 This
->bUnkOuterValid
= TRUE
;
77 if (IsEqualGUID(&IID_IUnknown
, riid
))
79 *ppvObj
= &(This
->IUnknown_inner
);
80 TRACE(" returning IUnknown interface (%p)\n", *ppvObj
);
81 } else if (IsEqualGUID(&IID_ISeekingPassThru
, riid
)) {
82 *ppvObj
= &(This
->ISeekingPassThru_iface
);
83 TRACE(" returning ISeekingPassThru interface (%p)\n", *ppvObj
);
84 } else if (IsEqualGUID(&IID_IMediaSeeking
, riid
)) {
85 *ppvObj
= &(This
->IMediaSeeking_iface
);
86 TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj
);
89 FIXME("unknown interface %s\n", debugstr_guid(riid
));
93 IUnknown_AddRef((IUnknown
*)(*ppvObj
));
97 static ULONG WINAPI
SeekInner_AddRef(IUnknown
* iface
) {
98 PassThruImpl
*This
= impl_from_IUnknown_inner(iface
);
99 ULONG ref
= InterlockedIncrement(&This
->ref
);
101 TRACE("(%p)->(): new ref = %d\n", This
, ref
);
106 static ULONG WINAPI
SeekInner_Release(IUnknown
* iface
) {
107 PassThruImpl
*This
= impl_from_IUnknown_inner(iface
);
108 ULONG ref
= InterlockedDecrement(&This
->ref
);
110 TRACE("(%p)->(): new ref = %d\n", This
, ref
);
114 This
->time_cs
.DebugInfo
->Spare
[0] = 0;
115 DeleteCriticalSection(&This
->time_cs
);
121 static const IUnknownVtbl IInner_VTable
=
123 SeekInner_QueryInterface
,
128 /* Generic functions for aggregation */
129 static HRESULT
SeekOuter_QueryInterface(PassThruImpl
*This
, REFIID riid
, LPVOID
*ppv
)
131 if (This
->bAggregatable
)
132 This
->bUnkOuterValid
= TRUE
;
136 if (This
->bAggregatable
)
137 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
139 if (IsEqualIID(riid
, &IID_IUnknown
))
143 IUnknown_AddRef((IUnknown
*)&(This
->IUnknown_inner
));
144 hr
= IUnknown_QueryInterface((IUnknown
*)&(This
->IUnknown_inner
), riid
, ppv
);
145 IUnknown_Release((IUnknown
*)&(This
->IUnknown_inner
));
146 This
->bAggregatable
= TRUE
;
151 return E_NOINTERFACE
;
154 return IUnknown_QueryInterface((IUnknown
*)&(This
->IUnknown_inner
), riid
, ppv
);
157 static ULONG
SeekOuter_AddRef(PassThruImpl
*This
)
159 if (This
->outer_unk
&& This
->bUnkOuterValid
)
160 return IUnknown_AddRef(This
->outer_unk
);
161 return IUnknown_AddRef((IUnknown
*)&(This
->IUnknown_inner
));
164 static ULONG
SeekOuter_Release(PassThruImpl
*This
)
166 if (This
->outer_unk
&& This
->bUnkOuterValid
)
167 return IUnknown_Release(This
->outer_unk
);
168 return IUnknown_Release((IUnknown
*)&(This
->IUnknown_inner
));
171 static HRESULT WINAPI
SeekingPassThru_QueryInterface(ISeekingPassThru
*iface
, REFIID riid
, LPVOID
*ppvObj
)
173 PassThruImpl
*This
= impl_from_ISeekingPassThru(iface
);
175 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
177 return SeekOuter_QueryInterface(This
, riid
, ppvObj
);
180 static ULONG WINAPI
SeekingPassThru_AddRef(ISeekingPassThru
*iface
)
182 PassThruImpl
*This
= impl_from_ISeekingPassThru(iface
);
184 TRACE("(%p/%p)->()\n", This
, iface
);
186 return SeekOuter_AddRef(This
);
189 static ULONG WINAPI
SeekingPassThru_Release(ISeekingPassThru
*iface
)
191 PassThruImpl
*This
= impl_from_ISeekingPassThru(iface
);
193 TRACE("(%p/%p)->()\n", This
, iface
);
195 return SeekOuter_Release(This
);
198 static HRESULT WINAPI
SeekingPassThru_Init(ISeekingPassThru
*iface
, BOOL renderer
, IPin
*pin
)
200 PassThruImpl
*This
= impl_from_ISeekingPassThru(iface
);
202 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, renderer
, pin
);
205 FIXME("Re-initializing?\n");
207 This
->renderer
= renderer
;
213 static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl
=
215 SeekingPassThru_QueryInterface
,
216 SeekingPassThru_AddRef
,
217 SeekingPassThru_Release
,
221 HRESULT WINAPI
CreatePosPassThru(IUnknown
* pUnkOuter
, BOOL bRenderer
, IPin
*pPin
, IUnknown
**ppPassThru
)
224 ISeekingPassThru
*passthru
;
226 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, pUnkOuter
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)ppPassThru
);
228 IUnknown_QueryInterface(*ppPassThru
, &IID_ISeekingPassThru
, (void**)&passthru
);
229 hr
= ISeekingPassThru_Init(passthru
, bRenderer
, pPin
);
230 ISeekingPassThru_Release(passthru
);
235 HRESULT WINAPI
PosPassThru_Construct(IUnknown
*pUnkOuter
, LPVOID
*ppPassThru
)
239 TRACE("(%p,%p)\n", pUnkOuter
, ppPassThru
);
241 *ppPassThru
= fimpl
= CoTaskMemAlloc(sizeof(*fimpl
));
243 return E_OUTOFMEMORY
;
245 fimpl
->outer_unk
= pUnkOuter
;
246 fimpl
->bUnkOuterValid
= FALSE
;
247 fimpl
->bAggregatable
= FALSE
;
248 fimpl
->IUnknown_inner
.lpVtbl
= &IInner_VTable
;
249 fimpl
->ISeekingPassThru_iface
.lpVtbl
= &ISeekingPassThru_Vtbl
;
250 fimpl
->IMediaSeeking_iface
.lpVtbl
= &IMediaSeekingPassThru_Vtbl
;
253 fimpl
->timevalid
= 0;
254 InitializeCriticalSection(&fimpl
->time_cs
);
255 fimpl
->time_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PassThruImpl.time_cs");
259 static HRESULT WINAPI
MediaSeekingPassThru_QueryInterface(IMediaSeeking
*iface
, REFIID riid
, LPVOID
*ppvObj
)
261 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
263 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
265 return SeekOuter_QueryInterface(This
, riid
, ppvObj
);
268 static ULONG WINAPI
MediaSeekingPassThru_AddRef(IMediaSeeking
*iface
)
270 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
272 TRACE("(%p/%p)->()\n", iface
, This
);
274 return SeekOuter_AddRef(This
);
277 static ULONG WINAPI
MediaSeekingPassThru_Release(IMediaSeeking
*iface
)
279 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
281 TRACE("(%p/%p)->()\n", iface
, This
);
283 return SeekOuter_Release(This
);
286 static HRESULT
get_connected(PassThruImpl
*This
, IMediaSeeking
**seek
) {
290 hr
= IPin_ConnectedTo(This
->pin
, &pin
);
292 return VFW_E_NOT_CONNECTED
;
293 hr
= IPin_QueryInterface(pin
, &IID_IMediaSeeking
, (void**)seek
);
300 static HRESULT WINAPI
MediaSeekingPassThru_GetCapabilities(IMediaSeeking
* iface
, DWORD
* pCapabilities
)
302 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
305 TRACE("(%p/%p)->(%p)\n", iface
, This
, pCapabilities
);
306 hr
= get_connected(This
, &seek
);
308 hr
= IMediaSeeking_GetCapabilities(seek
, pCapabilities
);
309 IMediaSeeking_Release(seek
);
316 static HRESULT WINAPI
MediaSeekingPassThru_CheckCapabilities(IMediaSeeking
* iface
, DWORD
* pCapabilities
)
318 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
321 TRACE("(%p/%p)->(%p)\n", iface
, This
, pCapabilities
);
322 hr
= get_connected(This
, &seek
);
324 hr
= IMediaSeeking_CheckCapabilities(seek
, pCapabilities
);
325 IMediaSeeking_Release(seek
);
332 static HRESULT WINAPI
MediaSeekingPassThru_IsFormatSupported(IMediaSeeking
* iface
, const GUID
* pFormat
)
334 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
337 TRACE("(%p/%p)->(%s)\n", iface
, This
, debugstr_guid(pFormat
));
338 hr
= get_connected(This
, &seek
);
340 hr
= IMediaSeeking_IsFormatSupported(seek
, pFormat
);
341 IMediaSeeking_Release(seek
);
348 static HRESULT WINAPI
MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking
* iface
, GUID
* pFormat
)
350 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
353 TRACE("(%p/%p)->(%p)\n", iface
, This
, pFormat
);
354 hr
= get_connected(This
, &seek
);
356 hr
= IMediaSeeking_QueryPreferredFormat(seek
, pFormat
);
357 IMediaSeeking_Release(seek
);
364 static HRESULT WINAPI
MediaSeekingPassThru_GetTimeFormat(IMediaSeeking
* iface
, GUID
* pFormat
)
366 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
369 TRACE("(%p/%p)->(%p)\n", iface
, This
, pFormat
);
370 hr
= get_connected(This
, &seek
);
372 hr
= IMediaSeeking_GetTimeFormat(seek
, pFormat
);
373 IMediaSeeking_Release(seek
);
380 static HRESULT WINAPI
MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking
* iface
, const GUID
* pFormat
)
382 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
385 TRACE("(%p/%p)->(%s)\n", iface
, This
, debugstr_guid(pFormat
));
386 hr
= get_connected(This
, &seek
);
388 hr
= IMediaSeeking_IsUsingTimeFormat(seek
, pFormat
);
389 IMediaSeeking_Release(seek
);
396 static HRESULT WINAPI
MediaSeekingPassThru_SetTimeFormat(IMediaSeeking
* iface
, const GUID
* pFormat
)
398 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
401 TRACE("(%p/%p)->(%s)\n", iface
, This
, debugstr_guid(pFormat
));
402 hr
= get_connected(This
, &seek
);
404 hr
= IMediaSeeking_SetTimeFormat(seek
, pFormat
);
405 IMediaSeeking_Release(seek
);
412 static HRESULT WINAPI
MediaSeekingPassThru_GetDuration(IMediaSeeking
* iface
, LONGLONG
* pDuration
)
414 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
417 TRACE("(%p/%p)->(%p)\n", iface
, This
, pDuration
);
418 hr
= get_connected(This
, &seek
);
420 hr
= IMediaSeeking_GetDuration(seek
, pDuration
);
421 IMediaSeeking_Release(seek
);
428 static HRESULT WINAPI
MediaSeekingPassThru_GetStopPosition(IMediaSeeking
* iface
, LONGLONG
* pStop
)
430 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
433 TRACE("(%p/%p)->(%p)\n", iface
, This
, pStop
);
434 hr
= get_connected(This
, &seek
);
436 hr
= IMediaSeeking_GetStopPosition(seek
, pStop
);
437 IMediaSeeking_Release(seek
);
444 static HRESULT WINAPI
MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking
* iface
, LONGLONG
* pCurrent
)
446 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
449 TRACE("(%p/%p)->(%p)\n", iface
, This
, pCurrent
);
452 EnterCriticalSection(&This
->time_cs
);
454 *pCurrent
= This
->time_earliest
;
457 LeaveCriticalSection(&This
->time_cs
);
459 hr
= IMediaSeeking_ConvertTimeFormat(iface
, pCurrent
, NULL
, *pCurrent
, &TIME_FORMAT_MEDIA_TIME
);
462 hr
= get_connected(This
, &seek
);
464 hr
= IMediaSeeking_GetCurrentPosition(seek
, pCurrent
);
465 IMediaSeeking_Release(seek
);
472 static HRESULT WINAPI
MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking
* iface
, LONGLONG
* pTarget
, const GUID
* pTargetFormat
, LONGLONG Source
, const GUID
* pSourceFormat
)
474 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
477 TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface
, This
, pTarget
, debugstr_guid(pTargetFormat
), (DWORD
)(Source
>>32), (DWORD
)Source
, debugstr_guid(pSourceFormat
));
478 hr
= get_connected(This
, &seek
);
480 hr
= IMediaSeeking_ConvertTimeFormat(seek
, pTarget
, pTargetFormat
, Source
, pSourceFormat
);
481 IMediaSeeking_Release(seek
);
488 static HRESULT WINAPI
MediaSeekingPassThru_SetPositions(IMediaSeeking
* iface
, LONGLONG
* pCurrent
, DWORD dwCurrentFlags
, LONGLONG
* pStop
, DWORD dwStopFlags
)
490 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
493 TRACE("(%p/%p)->(%p,%x,%p,%x)\n", iface
, This
, pCurrent
, dwCurrentFlags
, pStop
, dwStopFlags
);
494 hr
= get_connected(This
, &seek
);
496 hr
= IMediaSeeking_SetPositions(seek
, pCurrent
, dwCurrentFlags
, pStop
, dwStopFlags
);
497 IMediaSeeking_Release(seek
);
498 } else if (hr
== VFW_E_NOT_CONNECTED
)
503 static HRESULT WINAPI
MediaSeekingPassThru_GetPositions(IMediaSeeking
* iface
, LONGLONG
* pCurrent
, LONGLONG
* pStop
)
505 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
508 TRACE("(%p/%p)->(%p, %p)\n", iface
, This
, pCurrent
, pStop
);
509 hr
= get_connected(This
, &seek
);
511 hr
= IMediaSeeking_GetPositions(seek
, pCurrent
, pStop
);
512 IMediaSeeking_Release(seek
);
519 static HRESULT WINAPI
MediaSeekingPassThru_GetAvailable(IMediaSeeking
* iface
, LONGLONG
* pEarliest
, LONGLONG
* pLatest
)
521 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
524 TRACE("(%p/%p)->(%p,%p)\n", iface
, This
, pEarliest
, pLatest
);
525 hr
= get_connected(This
, &seek
);
527 hr
= IMediaSeeking_GetAvailable(seek
, pEarliest
, pLatest
);
528 IMediaSeeking_Release(seek
);
535 static HRESULT WINAPI
MediaSeekingPassThru_SetRate(IMediaSeeking
* iface
, double dRate
)
537 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
540 TRACE("(%p/%p)->(%e)\n", iface
, This
, dRate
);
541 hr
= get_connected(This
, &seek
);
543 hr
= IMediaSeeking_SetRate(seek
, dRate
);
544 IMediaSeeking_Release(seek
);
551 static HRESULT WINAPI
MediaSeekingPassThru_GetRate(IMediaSeeking
* iface
, double * dRate
)
553 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
556 TRACE("(%p/%p)->(%p)\n", iface
, This
, dRate
);
557 hr
= get_connected(This
, &seek
);
559 hr
= IMediaSeeking_GetRate(seek
, dRate
);
560 IMediaSeeking_Release(seek
);
567 static HRESULT WINAPI
MediaSeekingPassThru_GetPreroll(IMediaSeeking
* iface
, LONGLONG
* pPreroll
)
569 PassThruImpl
*This
= impl_from_IMediaSeeking(iface
);
572 TRACE("(%p)\n", pPreroll
);
573 hr
= get_connected(This
, &seek
);
575 hr
= IMediaSeeking_GetPreroll(seek
, pPreroll
);
576 IMediaSeeking_Release(seek
);
583 HRESULT WINAPI
RendererPosPassThru_RegisterMediaTime(IUnknown
*iface
, REFERENCE_TIME start
)
585 PassThruImpl
*This
= impl_from_IUnknown_inner(iface
);
586 EnterCriticalSection(&This
->time_cs
);
587 This
->time_earliest
= start
;
589 LeaveCriticalSection(&This
->time_cs
);
593 HRESULT WINAPI
RendererPosPassThru_ResetMediaTime(IUnknown
*iface
)
595 PassThruImpl
*This
= impl_from_IUnknown_inner(iface
);
596 EnterCriticalSection(&This
->time_cs
);
598 LeaveCriticalSection(&This
->time_cs
);
602 HRESULT WINAPI
RendererPosPassThru_EOS(IUnknown
*iface
)
604 PassThruImpl
*This
= impl_from_IUnknown_inner(iface
);
607 hr
= IMediaSeeking_GetStopPosition(&This
->IMediaSeeking_iface
, &time
);
608 EnterCriticalSection(&This
->time_cs
);
611 This
->time_earliest
= time
;
614 LeaveCriticalSection(&This
->time_cs
);
618 static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl
=
620 MediaSeekingPassThru_QueryInterface
,
621 MediaSeekingPassThru_AddRef
,
622 MediaSeekingPassThru_Release
,
623 MediaSeekingPassThru_GetCapabilities
,
624 MediaSeekingPassThru_CheckCapabilities
,
625 MediaSeekingPassThru_IsFormatSupported
,
626 MediaSeekingPassThru_QueryPreferredFormat
,
627 MediaSeekingPassThru_GetTimeFormat
,
628 MediaSeekingPassThru_IsUsingTimeFormat
,
629 MediaSeekingPassThru_SetTimeFormat
,
630 MediaSeekingPassThru_GetDuration
,
631 MediaSeekingPassThru_GetStopPosition
,
632 MediaSeekingPassThru_GetCurrentPosition
,
633 MediaSeekingPassThru_ConvertTimeFormat
,
634 MediaSeekingPassThru_SetPositions
,
635 MediaSeekingPassThru_GetPositions
,
636 MediaSeekingPassThru_GetAvailable
,
637 MediaSeekingPassThru_SetRate
,
638 MediaSeekingPassThru_GetRate
,
639 MediaSeekingPassThru_GetPreroll