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
);
33 typedef HRESULT (*SeekFunc
)( IMediaSeeking
*to
, LPVOID arg
);
35 static HRESULT
ForwardCmdSeek( PCRITICAL_SECTION crit_sect
, IBaseFilter
* from
, SeekFunc fnSeek
, LPVOID arg
)
38 HRESULT hr_return
= S_OK
;
39 IEnumPins
*enumpins
= NULL
;
40 BOOL foundend
= FALSE
, allnotimpl
= TRUE
;
42 hr
= IBaseFilter_EnumPins( from
, &enumpins
);
46 hr
= IEnumPins_Reset( enumpins
);
49 hr
= IEnumPins_Next( enumpins
, 1, &pin
, NULL
);
50 if (hr
== VFW_E_ENUM_OUT_OF_SYNC
)
52 hr
= IEnumPins_Reset( enumpins
);
59 IPin_QueryDirection( pin
, &dir
);
60 if (dir
== PINDIR_INPUT
)
62 IPin
*connected
= NULL
;
64 IPin_ConnectedTo( pin
, &connected
);
68 IMediaSeeking
*seek
= NULL
;
70 hr_local
= IPin_QueryInterface( connected
, &IID_IMediaSeeking
, (void**)&seek
);
74 LeaveCriticalSection( crit_sect
);
75 hr_local
= fnSeek( seek
, arg
);
76 EnterCriticalSection( crit_sect
);
77 if (hr_local
!= E_NOTIMPL
)
80 hr_return
= updatehres( hr_return
, hr_local
);
81 IMediaSeeking_Release( seek
);
83 IPin_Release(connected
);
89 if (foundend
&& allnotimpl
)
95 TRACE("Returning: %08x\n", hr
);
100 HRESULT
MediaSeekingImpl_Init(IBaseFilter
*pUserData
, CHANGEPROC fnChangeStop
, CHANGEPROC fnChangeCurrent
, CHANGEPROC fnChangeRate
, MediaSeekingImpl
* pSeeking
, PCRITICAL_SECTION crit_sect
)
102 assert(fnChangeStop
&& fnChangeCurrent
&& fnChangeRate
);
104 pSeeking
->refCount
= 1;
105 pSeeking
->pUserData
= pUserData
;
106 pSeeking
->fnChangeRate
= fnChangeRate
;
107 pSeeking
->fnChangeStop
= fnChangeStop
;
108 pSeeking
->fnChangeCurrent
= fnChangeCurrent
;
109 pSeeking
->dwCapabilities
= AM_SEEKING_CanSeekForwards
|
110 AM_SEEKING_CanSeekBackwards
|
111 AM_SEEKING_CanSeekAbsolute
|
112 AM_SEEKING_CanGetStopPos
|
113 AM_SEEKING_CanGetDuration
;
114 pSeeking
->llCurrent
= 0;
115 pSeeking
->llStop
= ((ULONGLONG
)0x80000000) << 32;
116 pSeeking
->llDuration
= pSeeking
->llStop
;
117 pSeeking
->dRate
= 1.0;
118 pSeeking
->timeformat
= TIME_FORMAT_MEDIA_TIME
;
119 pSeeking
->crst
= crit_sect
;
125 HRESULT WINAPI
MediaSeekingImpl_GetCapabilities(IMediaSeeking
* iface
, DWORD
* pCapabilities
)
127 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
129 TRACE("(%p)\n", pCapabilities
);
131 *pCapabilities
= This
->dwCapabilities
;
136 static HRESULT
fwd_checkcaps(IMediaSeeking
*iface
, LPVOID pcaps
)
139 return IMediaSeeking_CheckCapabilities(iface
, caps
);
142 HRESULT WINAPI
MediaSeekingImpl_CheckCapabilities(IMediaSeeking
* iface
, DWORD
* pCapabilities
)
144 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
148 TRACE("(%p)\n", pCapabilities
);
153 EnterCriticalSection(This
->crst
);
154 hr
= ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_checkcaps
, pCapabilities
);
155 LeaveCriticalSection(This
->crst
);
156 if (FAILED(hr
) && hr
!= E_NOTIMPL
)
159 dwCommonCaps
= *pCapabilities
& This
->dwCapabilities
;
164 hr
= (*pCapabilities
== dwCommonCaps
) ? S_OK
: S_FALSE
;
165 *pCapabilities
= dwCommonCaps
;
170 HRESULT WINAPI
MediaSeekingImpl_IsFormatSupported(IMediaSeeking
* iface
, const GUID
* pFormat
)
172 TRACE("(%s)\n", qzdebugstr_guid(pFormat
));
174 return (IsEqualIID(pFormat
, &TIME_FORMAT_MEDIA_TIME
) ? S_OK
: S_FALSE
);
177 HRESULT WINAPI
MediaSeekingImpl_QueryPreferredFormat(IMediaSeeking
* iface
, GUID
* pFormat
)
179 TRACE("(%s)\n", qzdebugstr_guid(pFormat
));
181 *pFormat
= TIME_FORMAT_MEDIA_TIME
;
185 HRESULT WINAPI
MediaSeekingImpl_GetTimeFormat(IMediaSeeking
* iface
, GUID
* pFormat
)
187 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
188 TRACE("(%s)\n", qzdebugstr_guid(pFormat
));
190 EnterCriticalSection(This
->crst
);
191 *pFormat
= This
->timeformat
;
192 LeaveCriticalSection(This
->crst
);
197 HRESULT WINAPI
MediaSeekingImpl_IsUsingTimeFormat(IMediaSeeking
* iface
, const GUID
* pFormat
)
199 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
202 TRACE("(%s)\n", qzdebugstr_guid(pFormat
));
204 EnterCriticalSection(This
->crst
);
205 if (!IsEqualIID(pFormat
, &This
->timeformat
))
207 LeaveCriticalSection(This
->crst
);
213 static HRESULT
fwd_settimeformat(IMediaSeeking
*iface
, LPVOID pformat
)
215 const GUID
*format
= pformat
;
216 return IMediaSeeking_SetTimeFormat(iface
, format
);
219 HRESULT WINAPI
MediaSeekingImpl_SetTimeFormat(IMediaSeeking
* iface
, const GUID
* pFormat
)
221 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
222 TRACE("(%s)\n", qzdebugstr_guid(pFormat
));
224 EnterCriticalSection(This
->crst
);
225 ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_settimeformat
, (LPVOID
)pFormat
);
226 LeaveCriticalSection(This
->crst
);
228 return (IsEqualIID(pFormat
, &TIME_FORMAT_MEDIA_TIME
) ? S_OK
: S_FALSE
);
232 static HRESULT
fwd_getduration(IMediaSeeking
*iface
, LPVOID pdur
)
234 LONGLONG
*duration
= pdur
;
235 LONGLONG mydur
= *duration
;
238 hr
= IMediaSeeking_GetDuration(iface
, &mydur
);
242 if ((mydur
< *duration
) || (*duration
< 0 && mydur
> 0))
247 HRESULT WINAPI
MediaSeekingImpl_GetDuration(IMediaSeeking
* iface
, LONGLONG
* pDuration
)
249 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
251 TRACE("(%p)\n", pDuration
);
253 EnterCriticalSection(This
->crst
);
254 *pDuration
= This
->llDuration
;
255 ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_getduration
, pDuration
);
256 LeaveCriticalSection(This
->crst
);
262 static HRESULT
fwd_getstopposition(IMediaSeeking
*iface
, LPVOID pdur
)
264 LONGLONG
*duration
= pdur
;
265 LONGLONG mydur
= *duration
;
268 hr
= IMediaSeeking_GetStopPosition(iface
, &mydur
);
272 if ((mydur
< *duration
) || (*duration
< 0 && mydur
> 0))
277 HRESULT WINAPI
MediaSeekingImpl_GetStopPosition(IMediaSeeking
* iface
, LONGLONG
* pStop
)
279 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
281 TRACE("(%p)\n", pStop
);
283 EnterCriticalSection(This
->crst
);
284 *pStop
= This
->llStop
;
285 ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_getstopposition
, pStop
);
286 LeaveCriticalSection(This
->crst
);
292 static HRESULT
fwd_getcurposition(IMediaSeeking
*iface
, LPVOID pdur
)
294 LONGLONG
*duration
= pdur
;
295 LONGLONG mydur
= *duration
;
298 hr
= IMediaSeeking_GetCurrentPosition(iface
, &mydur
);
302 if ((mydur
< *duration
) || (*duration
< 0 && mydur
> 0))
307 /* FIXME: Make use of the info the filter should expose */
308 HRESULT WINAPI
MediaSeekingImpl_GetCurrentPosition(IMediaSeeking
* iface
, LONGLONG
* pCurrent
)
310 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
312 TRACE("(%p)\n", pCurrent
);
314 EnterCriticalSection(This
->crst
);
315 *pCurrent
= This
->llCurrent
;
316 ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_getcurposition
, pCurrent
);
317 LeaveCriticalSection(This
->crst
);
322 HRESULT WINAPI
MediaSeekingImpl_ConvertTimeFormat(IMediaSeeking
* iface
, LONGLONG
* pTarget
, const GUID
* pTargetFormat
, LONGLONG Source
, const GUID
* pSourceFormat
)
324 if (IsEqualIID(pTargetFormat
, &TIME_FORMAT_MEDIA_TIME
) && IsEqualIID(pSourceFormat
, &TIME_FORMAT_MEDIA_TIME
))
329 /* FIXME: clear pTarget? */
333 static inline LONGLONG
Adjust(LONGLONG value
, const LONGLONG
* pModifier
, DWORD dwFlags
)
335 switch (dwFlags
& AM_SEEKING_PositioningBitsMask
)
337 case AM_SEEKING_NoPositioning
:
339 case AM_SEEKING_AbsolutePositioning
:
341 case AM_SEEKING_RelativePositioning
:
342 case AM_SEEKING_IncrementalPositioning
:
343 return value
+ *pModifier
;
351 LONGLONG
* current
, *stop
;
352 DWORD curflags
, stopflags
;
355 static HRESULT
fwd_setposition(IMediaSeeking
*seek
, LPVOID pargs
)
357 struct pos_args
*args
= (void*)pargs
;
359 return IMediaSeeking_SetPositions(seek
, args
->current
, args
->curflags
, args
->stop
, args
->stopflags
);
363 HRESULT WINAPI
MediaSeekingImpl_SetPositions(IMediaSeeking
* iface
, LONGLONG
* pCurrent
, DWORD dwCurrentFlags
, LONGLONG
* pStop
, DWORD dwStopFlags
)
365 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
366 BOOL bChangeCurrent
= FALSE
, bChangeStop
= FALSE
;
367 LONGLONG llNewCurrent
, llNewStop
;
368 struct pos_args args
;
370 TRACE("(%p, %x, %p, %x)\n", pCurrent
, dwCurrentFlags
, pStop
, dwStopFlags
);
372 args
.current
= pCurrent
;
374 args
.curflags
= dwCurrentFlags
;
375 args
.stopflags
= dwStopFlags
;
377 EnterCriticalSection(This
->crst
);
379 llNewCurrent
= Adjust(This
->llCurrent
, pCurrent
, dwCurrentFlags
);
380 llNewStop
= Adjust(This
->llStop
, pStop
, dwStopFlags
);
382 if (llNewCurrent
!= This
->llCurrent
)
383 bChangeCurrent
= TRUE
;
384 if (llNewStop
!= This
->llStop
)
387 TRACE("Old: %u, New: %u\n", (DWORD
)(This
->llCurrent
/10000000), (DWORD
)(llNewCurrent
/10000000));
389 This
->llCurrent
= llNewCurrent
;
390 This
->llStop
= llNewStop
;
392 if (dwCurrentFlags
& AM_SEEKING_ReturnTime
)
393 *pCurrent
= llNewCurrent
;
394 if (dwStopFlags
& AM_SEEKING_ReturnTime
)
397 ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_setposition
, &args
);
398 LeaveCriticalSection(This
->crst
);
401 This
->fnChangeCurrent(This
->pUserData
);
403 This
->fnChangeStop(This
->pUserData
);
408 HRESULT WINAPI
MediaSeekingImpl_GetPositions(IMediaSeeking
* iface
, LONGLONG
* pCurrent
, LONGLONG
* pStop
)
410 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
412 TRACE("(%p, %p)\n", pCurrent
, pStop
);
414 EnterCriticalSection(This
->crst
);
415 *pCurrent
= This
->llCurrent
;
416 *pStop
= This
->llStop
;
417 LeaveCriticalSection(This
->crst
);
422 HRESULT WINAPI
MediaSeekingImpl_GetAvailable(IMediaSeeking
* iface
, LONGLONG
* pEarliest
, LONGLONG
* pLatest
)
424 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
426 TRACE("(%p, %p)\n", pEarliest
, pLatest
);
428 EnterCriticalSection(This
->crst
);
430 *pLatest
= This
->llDuration
;
431 LeaveCriticalSection(This
->crst
);
436 static HRESULT
fwd_setrate(IMediaSeeking
*iface
, LPVOID prate
)
438 double *rate
= prate
;
442 hr
= IMediaSeeking_SetRate(iface
, *rate
);
449 HRESULT WINAPI
MediaSeekingImpl_SetRate(IMediaSeeking
* iface
, double dRate
)
451 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
452 BOOL bChangeRate
= (dRate
!= This
->dRate
);
455 TRACE("(%e)\n", dRate
);
457 if (dRate
> 100 || dRate
< .001)
459 FIXME("Excessive rate %e, ignoring\n", dRate
);
460 return VFW_E_UNSUPPORTED_AUDIO
;
463 EnterCriticalSection(This
->crst
);
466 hr
= This
->fnChangeRate(This
->pUserData
);
467 ForwardCmdSeek(This
->crst
, This
->pUserData
, fwd_setrate
, &dRate
);
468 LeaveCriticalSection(This
->crst
);
473 HRESULT WINAPI
MediaSeekingImpl_GetRate(IMediaSeeking
* iface
, double * dRate
)
475 MediaSeekingImpl
*This
= (MediaSeekingImpl
*)iface
;
477 TRACE("(%p)\n", dRate
);
479 EnterCriticalSection(This
->crst
);
481 *dRate
= This
->dRate
;
482 LeaveCriticalSection(This
->crst
);
487 HRESULT WINAPI
MediaSeekingImpl_GetPreroll(IMediaSeeking
* iface
, LONGLONG
* pPreroll
)
489 TRACE("(%p)\n", pPreroll
);