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