mpr: Added Hebrew translation.
[wine] / dlls / 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 #define COBJMACROS
24
25 #include "dshow.h"
26 #include "wine/strmbase.h"
27
28 #include "uuids.h"
29 #include "wine/debug.h"
30
31 #include <assert.h>
32
33 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
34
35 HRESULT SourceSeeking_Init(SourceSeeking *pSeeking, const IMediaSeekingVtbl *Vtbl, SourceSeeking_ChangeStop fnChangeStop, SourceSeeking_ChangeStart fnChangeStart, SourceSeeking_ChangeRate fnChangeRate, PCRITICAL_SECTION crit_sect)
36 {
37     assert(fnChangeStop && fnChangeStart && fnChangeRate);
38
39     pSeeking->lpVtbl = Vtbl;
40     pSeeking->refCount = 1;
41     pSeeking->fnChangeRate = fnChangeRate;
42     pSeeking->fnChangeStop = fnChangeStop;
43     pSeeking->fnChangeStart = fnChangeStart;
44     pSeeking->dwCapabilities = AM_SEEKING_CanSeekForwards |
45         AM_SEEKING_CanSeekBackwards |
46         AM_SEEKING_CanSeekAbsolute |
47         AM_SEEKING_CanGetStopPos |
48         AM_SEEKING_CanGetDuration;
49     pSeeking->llCurrent = 0;
50     pSeeking->llStop = ((ULONGLONG)0x80000000) << 32;
51     pSeeking->llDuration = pSeeking->llStop;
52     pSeeking->dRate = 1.0;
53     pSeeking->timeformat = TIME_FORMAT_MEDIA_TIME;
54     pSeeking->crst = crit_sect;
55     return S_OK;
56 }
57
58 HRESULT WINAPI SourceSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
59 {
60     SourceSeeking *This = (SourceSeeking *)iface;
61
62     TRACE("(%p)\n", pCapabilities);
63
64     *pCapabilities = This->dwCapabilities;
65
66     return S_OK;
67 }
68
69 HRESULT WINAPI SourceSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
70 {
71     SourceSeeking *This = (SourceSeeking *)iface;
72     HRESULT hr;
73     DWORD dwCommonCaps;
74
75     TRACE("(%p)\n", pCapabilities);
76
77     if (!pCapabilities)
78         return E_POINTER;
79
80     dwCommonCaps = *pCapabilities & This->dwCapabilities;
81
82     if (!dwCommonCaps)
83         hr = E_FAIL;
84     else
85         hr = (*pCapabilities == dwCommonCaps) ?  S_OK : S_FALSE;
86     *pCapabilities = dwCommonCaps;
87     return hr;
88 }
89
90 HRESULT WINAPI SourceSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
91 {
92     TRACE("(%s)\n", debugstr_guid(pFormat));
93
94     return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE);
95 }
96
97 HRESULT WINAPI SourceSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
98 {
99     TRACE("(%s)\n", debugstr_guid(pFormat));
100
101     *pFormat = TIME_FORMAT_MEDIA_TIME;
102     return S_OK;
103 }
104
105 HRESULT WINAPI SourceSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
106 {
107     SourceSeeking *This = (SourceSeeking *)iface;
108     TRACE("(%s)\n", debugstr_guid(pFormat));
109
110     EnterCriticalSection(This->crst);
111     *pFormat = This->timeformat;
112     LeaveCriticalSection(This->crst);
113
114     return S_OK;
115 }
116
117 HRESULT WINAPI SourceSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
118 {
119     SourceSeeking *This = (SourceSeeking *)iface;
120     HRESULT hr = S_OK;
121
122     TRACE("(%s)\n", debugstr_guid(pFormat));
123
124     EnterCriticalSection(This->crst);
125     if (!IsEqualIID(pFormat, &This->timeformat))
126         hr = S_FALSE;
127     LeaveCriticalSection(This->crst);
128
129     return hr;
130 }
131
132 HRESULT WINAPI SourceSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
133 {
134     SourceSeeking *This = (SourceSeeking *)iface;
135     TRACE("%p %s\n", This, debugstr_guid(pFormat));
136     return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : E_INVALIDARG);
137 }
138
139
140 HRESULT WINAPI SourceSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
141 {
142     SourceSeeking *This = (SourceSeeking *)iface;
143
144     TRACE("(%p)\n", pDuration);
145
146     EnterCriticalSection(This->crst);
147     *pDuration = This->llDuration;
148     LeaveCriticalSection(This->crst);
149
150     return S_OK;
151 }
152
153 HRESULT WINAPI SourceSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
154 {
155     SourceSeeking *This = (SourceSeeking *)iface;
156
157     TRACE("(%p)\n", pStop);
158
159     EnterCriticalSection(This->crst);
160     *pStop = This->llStop;
161     LeaveCriticalSection(This->crst);
162
163     return S_OK;
164 }
165
166 /* FIXME: Make use of the info the filter should expose */
167 HRESULT WINAPI SourceSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
168 {
169     SourceSeeking *This = (SourceSeeking *)iface;
170
171     TRACE("(%p)\n", pCurrent);
172
173     EnterCriticalSection(This->crst);
174     *pCurrent = This->llCurrent;
175     LeaveCriticalSection(This->crst);
176
177     return S_OK;
178 }
179
180 HRESULT WINAPI SourceSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
181 {
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 = (SourceSeeking *)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 = (SourceSeeking *)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 = (SourceSeeking *)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 = (SourceSeeking *)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 = (SourceSeeking *)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 }