xref: /reactos/sdk/lib/3rdparty/strmbase/seeking.c (revision c2c66aff)
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 }
316