[STRMBASE]
[reactos.git] / reactos / lib / 3rdparty / strmbase / seeking.c
1 /*
2 * Filter Seeking and Control Interfaces
3 *
4 * Copyright 2003 Robert Shearman
5 * Copyright 2010 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 #include "strmbase_private.h"
24
25 static inline SourceSeeking *impl_from_IMediaSeeking(IMediaSeeking *iface)
26 {
27 return CONTAINING_RECORD(iface, SourceSeeking, IMediaSeeking_iface);
28 }
29
30 HRESULT SourceSeeking_Init(SourceSeeking *pSeeking, const IMediaSeekingVtbl *Vtbl, SourceSeeking_ChangeStop fnChangeStop, SourceSeeking_ChangeStart fnChangeStart, SourceSeeking_ChangeRate fnChangeRate, PCRITICAL_SECTION crit_sect)
31 {
32 assert(fnChangeStop && fnChangeStart && fnChangeRate);
33
34 pSeeking->IMediaSeeking_iface.lpVtbl = Vtbl;
35 pSeeking->refCount = 1;
36 pSeeking->fnChangeRate = fnChangeRate;
37 pSeeking->fnChangeStop = fnChangeStop;
38 pSeeking->fnChangeStart = fnChangeStart;
39 pSeeking->dwCapabilities = AM_SEEKING_CanSeekForwards |
40 AM_SEEKING_CanSeekBackwards |
41 AM_SEEKING_CanSeekAbsolute |
42 AM_SEEKING_CanGetStopPos |
43 AM_SEEKING_CanGetDuration;
44 pSeeking->llCurrent = 0;
45 pSeeking->llStop = ((ULONGLONG)0x80000000) << 32;
46 pSeeking->llDuration = pSeeking->llStop;
47 pSeeking->dRate = 1.0;
48 pSeeking->timeformat = TIME_FORMAT_MEDIA_TIME;
49 pSeeking->crst = crit_sect;
50 return S_OK;
51 }
52
53 HRESULT WINAPI SourceSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
54 {
55 SourceSeeking *This = impl_from_IMediaSeeking(iface);
56
57 TRACE("(%p)\n", pCapabilities);
58
59 *pCapabilities = This->dwCapabilities;
60
61 return S_OK;
62 }
63
64 HRESULT WINAPI SourceSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
65 {
66 SourceSeeking *This = impl_from_IMediaSeeking(iface);
67 HRESULT hr;
68 DWORD dwCommonCaps;
69
70 TRACE("(%p)\n", pCapabilities);
71
72 if (!pCapabilities)
73 return E_POINTER;
74
75 dwCommonCaps = *pCapabilities & This->dwCapabilities;
76
77 if (!dwCommonCaps)
78 hr = E_FAIL;
79 else
80 hr = (*pCapabilities == dwCommonCaps) ? S_OK : S_FALSE;
81 *pCapabilities = dwCommonCaps;
82 return hr;
83 }
84
85 HRESULT WINAPI SourceSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
86 {
87 TRACE("(%s)\n", debugstr_guid(pFormat));
88
89 return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE);
90 }
91
92 HRESULT WINAPI SourceSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
93 {
94 TRACE("(%s)\n", debugstr_guid(pFormat));
95
96 *pFormat = TIME_FORMAT_MEDIA_TIME;
97 return S_OK;
98 }
99
100 HRESULT WINAPI SourceSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
101 {
102 SourceSeeking *This = impl_from_IMediaSeeking(iface);
103 TRACE("(%s)\n", debugstr_guid(pFormat));
104
105 EnterCriticalSection(This->crst);
106 *pFormat = This->timeformat;
107 LeaveCriticalSection(This->crst);
108
109 return S_OK;
110 }
111
112 HRESULT WINAPI SourceSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
113 {
114 SourceSeeking *This = impl_from_IMediaSeeking(iface);
115 HRESULT hr = S_OK;
116
117 TRACE("(%s)\n", debugstr_guid(pFormat));
118
119 EnterCriticalSection(This->crst);
120 if (!IsEqualIID(pFormat, &This->timeformat))
121 hr = S_FALSE;
122 LeaveCriticalSection(This->crst);
123
124 return hr;
125 }
126
127 HRESULT WINAPI SourceSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
128 {
129 SourceSeeking *This = impl_from_IMediaSeeking(iface);
130 TRACE("%p %s\n", This, debugstr_guid(pFormat));
131 return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : E_INVALIDARG);
132 }
133
134
135 HRESULT WINAPI SourceSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
136 {
137 SourceSeeking *This = impl_from_IMediaSeeking(iface);
138
139 TRACE("(%p)\n", pDuration);
140
141 EnterCriticalSection(This->crst);
142 *pDuration = This->llDuration;
143 LeaveCriticalSection(This->crst);
144
145 return S_OK;
146 }
147
148 HRESULT WINAPI SourceSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
149 {
150 SourceSeeking *This = impl_from_IMediaSeeking(iface);
151
152 TRACE("(%p)\n", pStop);
153
154 EnterCriticalSection(This->crst);
155 *pStop = This->llStop;
156 LeaveCriticalSection(This->crst);
157
158 return S_OK;
159 }
160
161 /* FIXME: Make use of the info the filter should expose */
162 HRESULT WINAPI SourceSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
163 {
164 SourceSeeking *This = impl_from_IMediaSeeking(iface);
165
166 TRACE("(%p)\n", pCurrent);
167
168 EnterCriticalSection(This->crst);
169 *pCurrent = This->llCurrent;
170 LeaveCriticalSection(This->crst);
171
172 return S_OK;
173 }
174
175 HRESULT WINAPI SourceSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
176 {
177 SourceSeeking *This = impl_from_IMediaSeeking(iface);
178 if (!pTargetFormat)
179 pTargetFormat = &This->timeformat;
180 if (!pSourceFormat)
181 pSourceFormat = &This->timeformat;
182 if (IsEqualIID(pTargetFormat, &TIME_FORMAT_MEDIA_TIME) && IsEqualIID(pSourceFormat, &TIME_FORMAT_MEDIA_TIME))
183 {
184 *pTarget = Source;
185 return S_OK;
186 }
187 /* FIXME: clear pTarget? */
188 return E_INVALIDARG;
189 }
190
191 static inline LONGLONG Adjust(LONGLONG value, const LONGLONG * pModifier, DWORD dwFlags)
192 {
193 switch (dwFlags & AM_SEEKING_PositioningBitsMask)
194 {
195 case AM_SEEKING_NoPositioning:
196 return value;
197 case AM_SEEKING_AbsolutePositioning:
198 return *pModifier;
199 case AM_SEEKING_RelativePositioning:
200 case AM_SEEKING_IncrementalPositioning:
201 return value + *pModifier;
202 default:
203 assert(FALSE);
204 return 0;
205 }
206 }
207
208 HRESULT WINAPI SourceSeekingImpl_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
209 {
210 SourceSeeking *This = impl_from_IMediaSeeking(iface);
211 BOOL bChangeCurrent = FALSE, bChangeStop = FALSE;
212 LONGLONG llNewCurrent, llNewStop;
213
214 TRACE("(%p, %x, %p, %x)\n", pCurrent, dwCurrentFlags, pStop, dwStopFlags);
215 EnterCriticalSection(This->crst);
216
217 llNewCurrent = Adjust(This->llCurrent, pCurrent, dwCurrentFlags);
218 llNewStop = Adjust(This->llStop, pStop, dwStopFlags);
219
220 if (pCurrent)
221 bChangeCurrent = TRUE;
222 if (llNewStop != This->llStop)
223 bChangeStop = TRUE;
224
225 TRACE("Old: %u, New: %u\n", (DWORD)(This->llCurrent/10000000), (DWORD)(llNewCurrent/10000000));
226
227 This->llCurrent = llNewCurrent;
228 This->llStop = llNewStop;
229
230 if (pCurrent && (dwCurrentFlags & AM_SEEKING_ReturnTime))
231 *pCurrent = llNewCurrent;
232 if (pStop && (dwStopFlags & AM_SEEKING_ReturnTime))
233 *pStop = llNewStop;
234 LeaveCriticalSection(This->crst);
235
236 if (bChangeCurrent)
237 This->fnChangeStart(iface);
238 if (bChangeStop)
239 This->fnChangeStop(iface);
240
241 return S_OK;
242 }
243
244 HRESULT WINAPI SourceSeekingImpl_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
245 {
246 SourceSeeking *This = impl_from_IMediaSeeking(iface);
247
248 TRACE("(%p, %p)\n", pCurrent, pStop);
249
250 EnterCriticalSection(This->crst);
251 IMediaSeeking_GetCurrentPosition(iface, pCurrent);
252 IMediaSeeking_GetStopPosition(iface, pStop);
253 LeaveCriticalSection(This->crst);
254
255 return S_OK;
256 }
257
258 HRESULT WINAPI SourceSeekingImpl_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
259 {
260 SourceSeeking *This = impl_from_IMediaSeeking(iface);
261
262 TRACE("(%p, %p)\n", pEarliest, pLatest);
263
264 EnterCriticalSection(This->crst);
265 *pEarliest = 0;
266 *pLatest = This->llDuration;
267 LeaveCriticalSection(This->crst);
268
269 return S_OK;
270 }
271
272 HRESULT WINAPI SourceSeekingImpl_SetRate(IMediaSeeking * iface, double dRate)
273 {
274 SourceSeeking *This = impl_from_IMediaSeeking(iface);
275 BOOL bChangeRate = (dRate != This->dRate);
276 HRESULT hr = S_OK;
277
278 TRACE("(%e)\n", dRate);
279
280 if (dRate > 100 || dRate < .001)
281 {
282 FIXME("Excessive rate %e, ignoring\n", dRate);
283 return VFW_E_UNSUPPORTED_AUDIO;
284 }
285
286 EnterCriticalSection(This->crst);
287 This->dRate = dRate;
288 if (bChangeRate)
289 hr = This->fnChangeRate(iface);
290 LeaveCriticalSection(This->crst);
291
292 return hr;
293 }
294
295 HRESULT WINAPI SourceSeekingImpl_GetRate(IMediaSeeking * iface, double * dRate)
296 {
297 SourceSeeking *This = impl_from_IMediaSeeking(iface);
298
299 TRACE("(%p)\n", dRate);
300
301 EnterCriticalSection(This->crst);
302 /* Forward? */
303 *dRate = This->dRate;
304 LeaveCriticalSection(This->crst);
305
306 return S_OK;
307 }
308
309 HRESULT WINAPI SourceSeekingImpl_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
310 {
311 TRACE("(%p)\n", pPreroll);
312
313 *pPreroll = 0;
314 return S_OK;
315 }