2 * Filter Seeking and Control Interfaces
4 * Copyright 2003 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 /* FIXME: critical sections */
22 #include "quartz_private.h"
23 #include "control_private.h"
26 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
32 typedef struct PassThruImpl {
33 const ISeekingPassThruVtbl *IPassThru_vtbl;
34 const IUnknownVtbl * IInner_vtbl;
42 static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface,
45 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
46 TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
48 if (This->bAggregatable)
49 This->bUnkOuterValid = TRUE;
51 if (IsEqualGUID(&IID_IUnknown, riid))
53 *ppvObj = &(This->IInner_vtbl);
54 TRACE(" returning IUnknown interface (%p)\n", *ppvObj);
55 } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) {
56 *ppvObj = &(This->IPassThru_vtbl);
57 TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj);
60 FIXME("unknown interface %s\n", debugstr_guid(riid));
64 IUnknown_AddRef((IUnknown *)(*ppvObj));
68 static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) {
69 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
70 ULONG ref = InterlockedIncrement(&This->ref);
72 TRACE("(%p)->(): new ref = %d\n", This, ref);
77 static ULONG WINAPI SeekInner_Release(IUnknown * iface) {
78 ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface);
79 ULONG ref = InterlockedDecrement(&This->ref);
81 TRACE("(%p)->(): new ref = %d\n", This, ref);
90 static const IUnknownVtbl IInner_VTable =
92 SeekInner_QueryInterface,
97 /* Generic functions for aggegration */
98 static HRESULT WINAPI SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv)
100 if (This->bAggregatable)
101 This->bUnkOuterValid = TRUE;
105 if (This->bAggregatable)
106 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
108 if (IsEqualIID(riid, &IID_IUnknown))
112 IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
113 hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
114 IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
115 This->bAggregatable = TRUE;
120 return E_NOINTERFACE;
123 return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
126 static ULONG WINAPI SeekOuter_AddRef(PassThruImpl *This)
128 if (This->pUnkOuter && This->bUnkOuterValid)
129 return IUnknown_AddRef(This->pUnkOuter);
130 return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
133 static ULONG WINAPI SeekOuter_Release(PassThruImpl *This)
135 if (This->pUnkOuter && This->bUnkOuterValid)
136 return IUnknown_Release(This->pUnkOuter);
137 return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
140 static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj)
142 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
144 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
146 return SeekOuter_QueryInterface(This, riid, ppvObj);
149 static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface)
151 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
153 TRACE("(%p/%p)->()\n", This, iface);
155 return SeekOuter_AddRef(This);
158 static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface)
160 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
162 TRACE("(%p/%p)->()\n", This, iface);
164 return SeekOuter_Release(This);
167 static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin)
169 ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface);
171 FIXME("(%p/%p)->(%d, %p) stub\n", This, iface, renderer, pin);
176 static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl =
178 SeekingPassThru_QueryInterface,
179 SeekingPassThru_AddRef,
180 SeekingPassThru_Release,
184 HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj)
188 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
190 *ppObj = fimpl = CoTaskMemAlloc(sizeof(*fimpl));
192 return E_OUTOFMEMORY;
194 fimpl->pUnkOuter = pUnkOuter;
195 fimpl->bUnkOuterValid = FALSE;
196 fimpl->bAggregatable = FALSE;
197 fimpl->IInner_vtbl = &IInner_VTable;
198 fimpl->IPassThru_vtbl = &ISeekingPassThru_Vtbl;
203 typedef HRESULT (*SeekFunc)( IMediaSeeking *to, LPVOID arg );
205 static HRESULT ForwardCmdSeek( PCRITICAL_SECTION crit_sect, IBaseFilter* from, SeekFunc fnSeek, LPVOID arg )
208 HRESULT hr_return = S_OK;
209 IEnumPins *enumpins = NULL;
210 BOOL foundend = FALSE, allnotimpl = TRUE;
212 hr = IBaseFilter_EnumPins( from, &enumpins );
216 hr = IEnumPins_Reset( enumpins );
219 hr = IEnumPins_Next( enumpins, 1, &pin, NULL );
220 if (hr == VFW_E_ENUM_OUT_OF_SYNC)
222 hr = IEnumPins_Reset( enumpins );
229 IPin_QueryDirection( pin, &dir );
230 if (dir == PINDIR_INPUT)
232 IPin *connected = NULL;
234 IPin_ConnectedTo( pin, &connected );
238 IMediaSeeking *seek = NULL;
240 hr_local = IPin_QueryInterface( connected, &IID_IMediaSeeking, (void**)&seek );
244 LeaveCriticalSection( crit_sect );
245 hr_local = fnSeek( seek , arg );
246 EnterCriticalSection( crit_sect );
247 if (hr_local != E_NOTIMPL)
250 hr_return = updatehres( hr_return, hr_local );
251 IMediaSeeking_Release( seek );
253 IPin_Release(connected);
259 if (foundend && allnotimpl)
265 TRACE("Returning: %08x\n", hr);
270 HRESULT MediaSeekingImpl_Init(IBaseFilter *pUserData, CHANGEPROC fnChangeStop, CHANGEPROC fnChangeCurrent, CHANGEPROC fnChangeRate, MediaSeekingImpl * pSeeking, PCRITICAL_SECTION crit_sect)
272 assert(fnChangeStop && fnChangeCurrent && fnChangeRate);
274 pSeeking->refCount = 1;
275 pSeeking->pUserData = pUserData;
276 pSeeking->fnChangeRate = fnChangeRate;
277 pSeeking->fnChangeStop = fnChangeStop;
278 pSeeking->fnChangeCurrent = fnChangeCurrent;
279 pSeeking->dwCapabilities = AM_SEEKING_CanSeekForwards |
280 AM_SEEKING_CanSeekBackwards |
281 AM_SEEKING_CanSeekAbsolute |
282 AM_SEEKING_CanGetStopPos |
283 AM_SEEKING_CanGetDuration;
284 pSeeking->llCurrent = 0;
285 pSeeking->llStop = ((ULONGLONG)0x80000000) << 32;
286 pSeeking->llDuration = pSeeking->llStop;
287 pSeeking->dRate = 1.0;
288 pSeeking->timeformat = TIME_FORMAT_MEDIA_TIME;
289 pSeeking->crst = crit_sect;
295 HRESULT WINAPI MediaSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
297 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
299 TRACE("(%p)\n", pCapabilities);
301 *pCapabilities = This->dwCapabilities;
306 static HRESULT fwd_checkcaps(IMediaSeeking *iface, LPVOID pcaps)
309 return IMediaSeeking_CheckCapabilities(iface, caps);
312 HRESULT WINAPI MediaSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
314 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
318 TRACE("(%p)\n", pCapabilities);
323 EnterCriticalSection(This->crst);
324 hr = ForwardCmdSeek(This->crst, This->pUserData, fwd_checkcaps, pCapabilities);
325 LeaveCriticalSection(This->crst);
326 if (FAILED(hr) && hr != E_NOTIMPL)
329 dwCommonCaps = *pCapabilities & This->dwCapabilities;
334 hr = (*pCapabilities == dwCommonCaps) ? S_OK : S_FALSE;
335 *pCapabilities = dwCommonCaps;
340 HRESULT WINAPI MediaSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
342 TRACE("(%s)\n", qzdebugstr_guid(pFormat));
344 return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE);
347 HRESULT WINAPI MediaSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
349 TRACE("(%s)\n", qzdebugstr_guid(pFormat));
351 *pFormat = TIME_FORMAT_MEDIA_TIME;
355 HRESULT WINAPI MediaSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
357 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
358 TRACE("(%s)\n", qzdebugstr_guid(pFormat));
360 EnterCriticalSection(This->crst);
361 *pFormat = This->timeformat;
362 LeaveCriticalSection(This->crst);
367 HRESULT WINAPI MediaSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
369 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
372 TRACE("(%s)\n", qzdebugstr_guid(pFormat));
374 EnterCriticalSection(This->crst);
375 if (!IsEqualIID(pFormat, &This->timeformat))
377 LeaveCriticalSection(This->crst);
383 static HRESULT fwd_settimeformat(IMediaSeeking *iface, LPVOID pformat)
385 const GUID *format = pformat;
386 return IMediaSeeking_SetTimeFormat(iface, format);
389 HRESULT WINAPI MediaSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
391 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
392 TRACE("(%s)\n", qzdebugstr_guid(pFormat));
394 EnterCriticalSection(This->crst);
395 ForwardCmdSeek(This->crst, This->pUserData, fwd_settimeformat, (LPVOID)pFormat);
396 LeaveCriticalSection(This->crst);
398 return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE);
402 static HRESULT fwd_getduration(IMediaSeeking *iface, LPVOID pdur)
404 LONGLONG *duration = pdur;
405 LONGLONG mydur = *duration;
408 hr = IMediaSeeking_GetDuration(iface, &mydur);
412 if ((mydur < *duration) || (*duration < 0 && mydur > 0))
417 HRESULT WINAPI MediaSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
419 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
421 TRACE("(%p)\n", pDuration);
423 EnterCriticalSection(This->crst);
424 *pDuration = This->llDuration;
425 ForwardCmdSeek(This->crst, This->pUserData, fwd_getduration, pDuration);
426 LeaveCriticalSection(This->crst);
432 static HRESULT fwd_getstopposition(IMediaSeeking *iface, LPVOID pdur)
434 LONGLONG *duration = pdur;
435 LONGLONG mydur = *duration;
438 hr = IMediaSeeking_GetStopPosition(iface, &mydur);
442 if ((mydur < *duration) || (*duration < 0 && mydur > 0))
447 HRESULT WINAPI MediaSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
449 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
451 TRACE("(%p)\n", pStop);
453 EnterCriticalSection(This->crst);
454 *pStop = This->llStop;
455 ForwardCmdSeek(This->crst, This->pUserData, fwd_getstopposition, pStop);
456 LeaveCriticalSection(This->crst);
462 static HRESULT fwd_getcurposition(IMediaSeeking *iface, LPVOID pdur)
464 LONGLONG *duration = pdur;
465 LONGLONG mydur = *duration;
468 hr = IMediaSeeking_GetCurrentPosition(iface, &mydur);
472 if ((mydur < *duration) || (*duration < 0 && mydur > 0))
477 /* FIXME: Make use of the info the filter should expose */
478 HRESULT WINAPI MediaSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
480 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
482 TRACE("(%p)\n", pCurrent);
484 EnterCriticalSection(This->crst);
485 *pCurrent = This->llCurrent;
486 ForwardCmdSeek(This->crst, This->pUserData, fwd_getcurposition, pCurrent);
487 LeaveCriticalSection(This->crst);
492 HRESULT WINAPI MediaSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
494 if (IsEqualIID(pTargetFormat, &TIME_FORMAT_MEDIA_TIME) && IsEqualIID(pSourceFormat, &TIME_FORMAT_MEDIA_TIME))
499 /* FIXME: clear pTarget? */
503 static inline LONGLONG Adjust(LONGLONG value, const LONGLONG * pModifier, DWORD dwFlags)
505 switch (dwFlags & AM_SEEKING_PositioningBitsMask)
507 case AM_SEEKING_NoPositioning:
509 case AM_SEEKING_AbsolutePositioning:
511 case AM_SEEKING_RelativePositioning:
512 case AM_SEEKING_IncrementalPositioning:
513 return value + *pModifier;
521 LONGLONG* current, *stop;
522 DWORD curflags, stopflags;
525 static HRESULT fwd_setposition(IMediaSeeking *seek, LPVOID pargs)
527 struct pos_args *args = (void*)pargs;
529 return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
533 HRESULT WINAPI MediaSeekingImpl_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
535 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
536 BOOL bChangeCurrent = FALSE, bChangeStop = FALSE;
537 LONGLONG llNewCurrent, llNewStop;
538 struct pos_args args;
540 TRACE("(%p, %x, %p, %x)\n", pCurrent, dwCurrentFlags, pStop, dwStopFlags);
542 args.current = pCurrent;
544 args.curflags = dwCurrentFlags;
545 args.stopflags = dwStopFlags;
547 EnterCriticalSection(This->crst);
549 llNewCurrent = Adjust(This->llCurrent, pCurrent, dwCurrentFlags);
550 llNewStop = Adjust(This->llStop, pStop, dwStopFlags);
552 if (llNewCurrent != This->llCurrent)
553 bChangeCurrent = TRUE;
554 if (llNewStop != This->llStop)
557 TRACE("Old: %u, New: %u\n", (DWORD)(This->llCurrent/10000000), (DWORD)(llNewCurrent/10000000));
559 This->llCurrent = llNewCurrent;
560 This->llStop = llNewStop;
562 if (dwCurrentFlags & AM_SEEKING_ReturnTime)
563 *pCurrent = llNewCurrent;
564 if (dwStopFlags & AM_SEEKING_ReturnTime)
567 ForwardCmdSeek(This->crst, This->pUserData, fwd_setposition, &args);
568 LeaveCriticalSection(This->crst);
571 This->fnChangeCurrent(This->pUserData);
573 This->fnChangeStop(This->pUserData);
578 HRESULT WINAPI MediaSeekingImpl_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
580 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
582 TRACE("(%p, %p)\n", pCurrent, pStop);
584 EnterCriticalSection(This->crst);
585 *pCurrent = This->llCurrent;
586 *pStop = This->llStop;
587 LeaveCriticalSection(This->crst);
592 HRESULT WINAPI MediaSeekingImpl_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
594 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
596 TRACE("(%p, %p)\n", pEarliest, pLatest);
598 EnterCriticalSection(This->crst);
600 *pLatest = This->llDuration;
601 LeaveCriticalSection(This->crst);
606 static HRESULT fwd_setrate(IMediaSeeking *iface, LPVOID prate)
608 double *rate = prate;
612 hr = IMediaSeeking_SetRate(iface, *rate);
619 HRESULT WINAPI MediaSeekingImpl_SetRate(IMediaSeeking * iface, double dRate)
621 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
622 BOOL bChangeRate = (dRate != This->dRate);
625 TRACE("(%e)\n", dRate);
627 if (dRate > 100 || dRate < .001)
629 FIXME("Excessive rate %e, ignoring\n", dRate);
630 return VFW_E_UNSUPPORTED_AUDIO;
633 EnterCriticalSection(This->crst);
636 hr = This->fnChangeRate(This->pUserData);
637 ForwardCmdSeek(This->crst, This->pUserData, fwd_setrate, &dRate);
638 LeaveCriticalSection(This->crst);
643 HRESULT WINAPI MediaSeekingImpl_GetRate(IMediaSeeking * iface, double * dRate)
645 MediaSeekingImpl *This = (MediaSeekingImpl *)iface;
647 TRACE("(%p)\n", dRate);
649 EnterCriticalSection(This->crst);
651 *dRate = This->dRate;
652 LeaveCriticalSection(This->crst);
657 HRESULT WINAPI MediaSeekingImpl_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
659 TRACE("(%p)\n", pPreroll);