Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / quartz / wavparse.c
1 /*
2  * Implements WAVE/AU/AIFF Parser.
3  *
4  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "mmsystem.h"
28 #include "mmreg.h"
29 #include "winerror.h"
30 #include "strmif.h"
31 #include "control.h"
32 #include "vfwmsgs.h"
33 #include "uuids.h"
34
35 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
37
38 #include "quartz_private.h"
39 #include "audioutl.h"
40 #include "parser.h"
41
42
43 static const WCHAR QUARTZ_WaveParser_Name[] =
44 { 'W','a','v','e',' ','P','a','r','s','e','r',0 };
45 static const WCHAR QUARTZ_WaveParserInPin_Name[] =
46 { 'I','n',0 };
47 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
48 { 'O','u','t',0 };
49
50
51 /****************************************************************************/
52
53 /* S_OK = found, S_FALSE = not found */
54 HRESULT RIFF_GetNext(
55         CParserImpl* pImpl, LONGLONG llOfs,
56         DWORD* pdwCode, DWORD* pdwLength )
57 {
58         BYTE bTemp[8];
59         HRESULT hr;
60
61         hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
62         if ( hr == S_OK )
63         {
64                 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
65                 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
66         }
67         else
68         {
69                 *pdwCode = 0;
70                 *pdwLength = 0;
71         }
72
73         return hr;
74 }
75
76 /* S_OK = found, S_FALSE = not found */
77 HRESULT RIFF_SearchChunk(
78         CParserImpl* pImpl,
79         DWORD dwSearchLengthMax,
80         LONGLONG llOfs, DWORD dwChunk,
81         LONGLONG* pllOfs, DWORD* pdwChunkLength )
82 {
83         HRESULT hr;
84         DWORD dwCurCode;
85         DWORD dwCurLen;
86         LONGLONG llCurLen;
87
88         while ( 1 )
89         {
90                 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
91                 if ( hr != S_OK )
92                         break;
93                 TRACE("%c%c%c%c len %lu\n",
94                         (int)(dwCurCode>> 0)&0xff,
95                         (int)(dwCurCode>> 8)&0xff,
96                         (int)(dwCurCode>>16)&0xff,
97                         (int)(dwCurCode>>24)&0xff,
98                         (unsigned long)dwCurLen);
99                 if ( dwChunk == dwCurCode )
100                         break;
101                 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
102                 llOfs += llCurLen;
103                 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
104                         return S_FALSE;
105                 if ( dwSearchLengthMax != (DWORD)0xffffffff )
106                         dwSearchLengthMax -= (DWORD)llCurLen;
107         }
108
109         *pllOfs = llOfs + 8;
110         *pdwChunkLength = dwCurLen;
111
112         return hr;
113 }
114
115 /* S_OK = found, S_FALSE = not found */
116 HRESULT RIFF_SearchList(
117         CParserImpl* pImpl,
118         DWORD dwSearchLengthMax,
119         LONGLONG llOfs, DWORD dwListChunk,
120         LONGLONG* pllOfs, DWORD* pdwChunkLength )
121 {
122         HRESULT hr;
123         DWORD dwCurLen;
124         LONGLONG llCurLen;
125         BYTE bTemp[4];
126
127         while ( 1 )
128         {
129                 hr = RIFF_SearchChunk(
130                         pImpl, dwSearchLengthMax,
131                         llOfs, PARSER_LIST,
132                         &llOfs, &dwCurLen );
133                 if ( hr != S_OK )
134                         break;
135
136                 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
137                 if ( hr != S_OK )
138                         break;
139
140                 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
141                         break;
142
143                 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
144                 llOfs += llCurLen;
145                 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
146                         return S_FALSE;
147                 if ( dwSearchLengthMax != (DWORD)0xffffffff )
148                         dwSearchLengthMax -= (DWORD)(llCurLen+8);
149         }
150
151         if ( dwCurLen < 12 )
152                 return E_FAIL;
153
154         *pllOfs = llOfs+4;
155         *pdwChunkLength = dwCurLen-4;
156
157         return hr;
158 }
159
160
161
162
163 /****************************************************************************
164  *
165  *      CWavParseImpl
166  */
167
168 typedef enum WavParseFmtType
169 {
170         WaveParse_Native,
171         WaveParse_Signed8,
172         WaveParse_Signed16BE,
173         WaveParse_Unsigned16LE,
174         WaveParse_Unsigned16BE,
175 } WavParseFmtType;
176
177 typedef struct CWavParseImpl
178 {
179         DWORD   cbFmt;
180         WAVEFORMATEX*   pFmt;
181         DWORD   dwBlockSize;
182         LONGLONG        llDataStart;
183         LONGLONG        llBytesStop;
184         LONGLONG        llBytesTotal;
185         LONGLONG        llBytesProcessed;
186         BOOL    bDataDiscontinuity;
187         WavParseFmtType iFmtType;
188 } CWavParseImpl;
189
190
191 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
192 {
193         HRESULT hr;
194         LONGLONG        llOfs;
195         DWORD   dwChunkLength;
196
197         hr = RIFF_SearchChunk(
198                 pImpl, (DWORD)0xffffffff,
199                 PARSER_RIFF_OfsFirst, PARSER_fmt,
200                 &llOfs, &dwChunkLength );
201         if ( FAILED(hr) )
202                 return hr;
203         if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
204                 return E_FAIL;
205
206         This->cbFmt = dwChunkLength;
207         if ( dwChunkLength < sizeof(WAVEFORMATEX) )
208                 This->cbFmt = sizeof(WAVEFORMATEX);
209         This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
210         if ( This->pFmt == NULL )
211                 return E_OUTOFMEMORY;
212         ZeroMemory( This->pFmt, This->cbFmt );
213
214         hr = IAsyncReader_SyncRead(
215                 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
216         if ( hr != S_OK )
217         {
218                 if ( SUCCEEDED(hr) )
219                         hr = E_FAIL;
220                 return hr;
221         }
222
223
224         hr = RIFF_SearchChunk(
225                 pImpl, (DWORD)0xffffffff,
226                 PARSER_RIFF_OfsFirst, PARSER_data,
227                 &llOfs, &dwChunkLength );
228         if ( FAILED(hr) )
229                 return hr;
230         if ( hr != S_OK || dwChunkLength == 0 )
231                 return E_FAIL;
232
233         This->llDataStart = llOfs;
234         This->llBytesTotal = (LONGLONG)dwChunkLength;
235
236         return NOERROR;
237 }
238
239 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
240 {
241         BYTE    au_hdr[24];
242         DWORD   dataofs;
243         DWORD   datalen;
244         DWORD   datafmt;
245         DWORD   datarate;
246         DWORD   datachannels;
247         HRESULT hr;
248         WAVEFORMATEX    wfx;
249
250         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
251         if ( FAILED(hr) )
252                 return hr;
253
254         dataofs = PARSER_BE_UINT32(&au_hdr[4]);
255         datalen = PARSER_BE_UINT32(&au_hdr[8]);
256         datafmt = PARSER_BE_UINT32(&au_hdr[12]);
257         datarate = PARSER_BE_UINT32(&au_hdr[16]);
258         datachannels = PARSER_BE_UINT32(&au_hdr[20]);
259
260         if ( dataofs < 24U || datalen == 0U )
261                 return E_FAIL;
262         if ( datachannels != 1 && datachannels != 2 )
263                 return E_FAIL;
264
265         ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
266         wfx.nChannels = datachannels;
267         wfx.nSamplesPerSec = datarate;
268
269         switch ( datafmt )
270         {
271         case 1:
272                 wfx.wFormatTag = WAVE_FORMAT_MULAW;
273                 wfx.nBlockAlign = datachannels;
274                 wfx.wBitsPerSample = 8;
275                 break;
276         case 2:
277                 wfx.wFormatTag = WAVE_FORMAT_PCM;
278                 wfx.nBlockAlign = datachannels;
279                 wfx.wBitsPerSample = 8;
280                 This->iFmtType = WaveParse_Signed8;
281                 break;
282         case 3:
283                 wfx.wFormatTag = WAVE_FORMAT_PCM;
284                 wfx.nBlockAlign = datachannels;
285                 wfx.wBitsPerSample = 16;
286                 This->iFmtType = WaveParse_Signed16BE;
287                 break;
288         default:
289                 FIXME("audio/basic - unknown format %lu\n", datafmt );
290                 return E_FAIL;
291         }
292         wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
293
294         This->cbFmt = sizeof(WAVEFORMATEX);
295         This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
296         if ( This->pFmt == NULL )
297                 return E_OUTOFMEMORY;
298         memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
299
300         This->llDataStart = dataofs;
301         This->llBytesTotal = datalen;
302
303         TRACE("offset %lu, length %lu\n",dataofs,datalen);
304
305         return NOERROR;
306 }
307
308 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
309 {
310         FIXME( "AIFF is not supported now.\n" );
311         return E_FAIL;
312 }
313
314 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
315 {
316         CWavParseImpl*  This = NULL;
317         HRESULT hr;
318         BYTE    header[12];
319
320         TRACE("(%p,%p)\n",pImpl,pcStreams);
321
322         if ( pImpl->m_pReader == NULL )
323                 return E_UNEXPECTED;
324
325         This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
326         if ( This == NULL )
327                 return E_OUTOFMEMORY;
328         pImpl->m_pUserData = This;
329
330         /* construct */
331         This->cbFmt = 0;
332         This->pFmt = NULL;
333         This->dwBlockSize = 0;
334         This->llDataStart = 0;
335         This->llBytesStop = 0;
336         This->llBytesTotal = 0;
337         This->llBytesProcessed = 0;
338         This->bDataDiscontinuity = TRUE;
339         This->iFmtType = WaveParse_Native;
340
341         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
342         if ( FAILED(hr) )
343                 return hr;
344         if ( hr != S_OK )
345                 return E_FAIL;
346
347         if ( !memcmp( &header[0], "RIFF", 4 ) &&
348                  !memcmp( &header[8], "WAVE", 4 ) )
349         {
350                 TRACE( "(%p) - it's audio/wav.\n", pImpl );
351                 hr = CWavParseImpl_InitWAV( pImpl, This );
352         }
353         else
354         if ( !memcmp( &header[0], ".snd", 4 ) )
355         {
356                 TRACE( "(%p) - it's audio/basic.\n", pImpl );
357                 hr = CWavParseImpl_InitAU( pImpl, This );
358         }
359         else
360         if ( !memcmp( &header[0], "FORM", 4 ) &&
361                  !memcmp( &header[8], "AIFF", 4 ) )
362         {
363                 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
364                 hr = CWavParseImpl_InitAIFF( pImpl, This );
365         }
366         else
367         {
368                 FIXME( "(%p) - unknown format.\n", pImpl );
369                 hr = E_FAIL;
370         }
371
372         if ( FAILED(hr) )
373         {
374                 return hr;
375         }
376
377         This->llBytesStop = This->llBytesTotal;
378
379         /* initialized successfully. */
380         *pcStreams = 1;
381
382         This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
383
384         TRACE( "(%p) returned successfully.\n", pImpl );
385
386         return NOERROR;
387 }
388
389 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
390 {
391         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
392
393         TRACE("(%p)\n",This);
394
395         if ( This == NULL )
396                 return NOERROR;
397
398         /* destruct */
399         if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
400
401         QUARTZ_FreeMem( This );
402         pImpl->m_pUserData = NULL;
403
404         return NOERROR;
405 }
406
407 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
408 {
409         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
410
411         TRACE("(%p)\n",This);
412
413         return QUARTZ_WaveParserOutPin_Name;
414 }
415
416 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
417 {
418         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
419
420         TRACE("(%p)\n",This);
421
422         if ( This == NULL || This->pFmt == NULL )
423                 return E_UNEXPECTED;
424
425         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
426         memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
427         QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
428         pmt->bFixedSizeSamples = 1;
429         pmt->bTemporalCompression = 0;
430         pmt->lSampleSize = This->pFmt->nBlockAlign;
431         memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
432         pmt->pUnk = NULL;
433
434         pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
435         if ( pmt->pbFormat == NULL )
436                 return E_OUTOFMEMORY;
437         pmt->cbFormat = This->cbFmt;
438         memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
439
440         return NOERROR;
441 }
442
443 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
444 {
445         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
446                  !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
447                 return E_FAIL;
448         if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
449                 return E_FAIL;
450
451         return NOERROR;
452 }
453
454 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
455 {
456         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
457
458         TRACE("(%p)\n",This);
459
460         if ( This == NULL || This->pFmt == NULL )
461                 return E_UNEXPECTED;
462
463         ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
464         pReqProp->cBuffers = 1;
465         pReqProp->cbBuffer = This->dwBlockSize;
466
467         return NOERROR;
468 }
469
470 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop, DWORD* pdwSampleFlags )
471 {
472         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
473         LONGLONG        llAvail;
474         LONGLONG        llStart;
475         LONGLONG        llEnd;
476
477         TRACE("(%p)\n",This);
478
479         if ( This == NULL || This->pFmt == NULL )
480                 return E_UNEXPECTED;
481         *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT;
482         if ( This->bDataDiscontinuity )
483         {
484                 *pdwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
485                 This->bDataDiscontinuity = FALSE;
486         }
487
488         llAvail = This->llBytesStop - This->llBytesProcessed;
489         if ( llAvail > (LONGLONG)This->dwBlockSize )
490                 llAvail = (LONGLONG)This->dwBlockSize;
491         llStart = This->llDataStart + This->llBytesProcessed;
492         llEnd = llStart + llAvail;
493         This->llBytesProcessed = llEnd;
494
495         *pllStart = This->llBytesProcessed;
496         *plLength = (LONG)llAvail;
497         *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
498         *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
499
500         return NOERROR;
501 }
502
503 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
504 {
505         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
506         BYTE*   pData;
507         LONG    lActLen;
508         HRESULT hr;
509
510         TRACE("(%p)\n",This);
511
512         hr = IMediaSample_GetPointer(pSample,&pData);
513         if ( FAILED(hr) )
514                 return hr;
515         lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
516         if ( lActLen != lLength )
517                 return E_FAIL;
518
519         switch ( This->iFmtType )
520         {
521         case WaveParse_Native:
522                 break;
523         case WaveParse_Signed8:
524                 AUDIOUTL_ChangeSign8(pData,lActLen);
525                 break;
526         case WaveParse_Signed16BE:
527                 AUDIOUTL_ByteSwap(pData,lActLen);
528                 break;
529         case WaveParse_Unsigned16LE:
530                 AUDIOUTL_ChangeSign16LE(pData,lActLen);
531                 break;
532         case WaveParse_Unsigned16BE:
533                 AUDIOUTL_ChangeSign16BE(pData,lActLen);
534                 AUDIOUTL_ByteSwap(pData,lActLen);
535                 break;
536         default:
537                 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
538                 return E_FAIL;
539         }
540
541         return NOERROR;
542 }
543
544 /***************************************************************************/
545
546 static HRESULT CWavParseImpl_GetSeekingCaps( CParserImpl* pImpl, DWORD* pdwCaps )
547 {
548         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
549
550         TRACE("(%p,%p)\n",This,pdwCaps);
551
552         *pdwCaps =
553                 AM_SEEKING_CanSeekAbsolute |
554                 AM_SEEKING_CanSeekForwards |
555                 AM_SEEKING_CanSeekBackwards |
556                 AM_SEEKING_CanGetCurrentPos |
557                 AM_SEEKING_CanGetStopPos |
558                 AM_SEEKING_CanGetDuration;
559
560         return S_OK;
561 }
562
563 static HRESULT CWavParseImpl_IsTimeFormatSupported( CParserImpl* pImpl, const GUID* pTimeFormat )
564 {
565         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
566
567         TRACE("(%p,%s)\n",This,debugstr_guid(pTimeFormat));
568
569         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
570                 return S_OK;
571
572         return S_FALSE;
573 }
574
575 static HRESULT CWavParseImpl_GetCurPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos )
576 {
577         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
578
579         TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
580
581         if ( This == NULL || This->pFmt == NULL )
582                 return E_UNEXPECTED;
583
584         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
585         {
586                 if ( This->pFmt->nAvgBytesPerSec == 0 )
587                         return E_FAIL;
588                 *pllPos = This->llBytesProcessed * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
589                 TRACE("curpos %f\n",(double)(*pllPos/QUARTZ_TIMEUNITS));
590                 return S_OK;
591         }
592
593         return E_NOTIMPL;
594 }
595
596 static HRESULT CWavParseImpl_SetCurPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos )
597 {
598         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
599         LONGLONG        llBytesCur;
600
601         TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
602
603         if ( This == NULL || This->pFmt == NULL )
604                 return E_UNEXPECTED;
605
606         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
607         {
608                 if ( This->pFmt->nAvgBytesPerSec == 0 )
609                         return E_FAIL;
610                 llBytesCur = llPos * This->pFmt->nAvgBytesPerSec / QUARTZ_TIMEUNITS;
611                 if ( llBytesCur > This->llBytesTotal )
612                         llBytesCur = This->llBytesTotal;
613                 This->llBytesProcessed = llBytesCur;
614                 This->bDataDiscontinuity = TRUE;
615
616                 return S_OK;
617         }
618
619         return E_NOTIMPL;
620 }
621
622 static HRESULT CWavParseImpl_GetDuration( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllDuration )
623 {
624         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
625
626         TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
627
628         if ( This == NULL || This->pFmt == NULL )
629                 return E_UNEXPECTED;
630
631         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
632         {
633                 if ( This->pFmt->nAvgBytesPerSec == 0 )
634                         return E_FAIL;
635                 *pllDuration = This->llBytesTotal * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
636                 TRACE("duration %f\n",(double)(*pllDuration/QUARTZ_TIMEUNITS));
637                 return S_OK;
638         }
639
640         return E_NOTIMPL;
641 }
642
643 static HRESULT CWavParseImpl_GetStopPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos )
644 {
645         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
646
647         TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
648
649         if ( This == NULL || This->pFmt == NULL )
650                 return E_UNEXPECTED;
651
652         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
653         {
654                 if ( This->pFmt->nAvgBytesPerSec == 0 )
655                         return E_FAIL;
656                 *pllPos = This->llBytesStop * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
657                 return S_OK;
658         }
659
660         return E_NOTIMPL;
661 }
662
663 static HRESULT CWavParseImpl_SetStopPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos )
664 {
665         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
666         LONGLONG        llBytesStop;
667
668         TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
669
670         if ( This == NULL || This->pFmt == NULL )
671                 return E_UNEXPECTED;
672
673         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
674         {
675                 if ( This->pFmt->nAvgBytesPerSec == 0 )
676                         return E_FAIL;
677                 llBytesStop = llPos * This->pFmt->nAvgBytesPerSec / QUARTZ_TIMEUNITS;
678                 if ( llBytesStop > This->llBytesTotal )
679                         llBytesStop = This->llBytesTotal;
680                 This->llBytesStop = llBytesStop;
681
682                 return S_OK;
683         }
684
685         return E_NOTIMPL;
686 }
687
688 static HRESULT CWavParseImpl_GetPreroll( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPreroll )
689 {
690         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
691
692         TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
693
694         if ( This == NULL || This->pFmt == NULL )
695                 return E_UNEXPECTED;
696
697         if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
698         {
699                 *pllPreroll = 0;
700                 return S_OK;
701         }
702
703         return E_NOTIMPL;
704 }
705
706
707
708
709 /***************************************************************************/
710
711 static const struct ParserHandlers CWavParseImpl_Handlers =
712 {
713         CWavParseImpl_InitParser,
714         CWavParseImpl_UninitParser,
715         CWavParseImpl_GetOutPinName,
716         CWavParseImpl_GetStreamType,
717         CWavParseImpl_CheckStreamType,
718         CWavParseImpl_GetAllocProp,
719         CWavParseImpl_GetNextRequest,
720         CWavParseImpl_ProcessSample,
721
722         /* for IQualityControl */
723         NULL, /* pQualityNotify */
724
725         /* for seeking */
726         CWavParseImpl_GetSeekingCaps,
727         CWavParseImpl_IsTimeFormatSupported,
728         CWavParseImpl_GetCurPos,
729         CWavParseImpl_SetCurPos,
730         CWavParseImpl_GetDuration,
731         CWavParseImpl_GetStopPos,
732         CWavParseImpl_SetStopPos,
733         CWavParseImpl_GetPreroll,
734 };
735
736 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
737 {
738         return QUARTZ_CreateParser(
739                 punkOuter,ppobj,
740                 &CLSID_quartzWaveParser,
741                 QUARTZ_WaveParser_Name,
742                 QUARTZ_WaveParserInPin_Name,
743                 &CWavParseImpl_Handlers );
744 }
745
746