When including 'wine/port.h', include it first.
[wine] / dlls / quartz / wavparse.c
1 /*
2  * Implements WAVE/AU/AIFF Parser.
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "mmsystem.h"
14 #include "mmreg.h"
15 #include "winerror.h"
16 #include "strmif.h"
17 #include "vfwmsgs.h"
18 #include "uuids.h"
19
20 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(quartz);
22
23 #include "quartz_private.h"
24 #include "audioutl.h"
25 #include "parser.h"
26
27
28 static const WCHAR QUARTZ_WaveParser_Name[] =
29 { 'W','a','v','e',' ','P','a','r','s','e','r',0 };
30 static const WCHAR QUARTZ_WaveParserInPin_Name[] =
31 { 'I','n',0 };
32 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
33 { 'O','u','t',0 };
34
35
36 /****************************************************************************/
37
38 /* S_OK = found, S_FALSE = not found */
39 HRESULT RIFF_GetNext(
40         CParserImpl* pImpl, LONGLONG llOfs,
41         DWORD* pdwCode, DWORD* pdwLength )
42 {
43         BYTE bTemp[8];
44         HRESULT hr;
45
46         hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
47         if ( hr == S_OK )
48         {
49                 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
50                 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
51         }
52         else
53         {
54                 *pdwCode = 0;
55                 *pdwLength = 0;
56         }
57
58         return hr;
59 }
60
61 /* S_OK = found, S_FALSE = not found */
62 HRESULT RIFF_SearchChunk(
63         CParserImpl* pImpl,
64         DWORD dwSearchLengthMax,
65         LONGLONG llOfs, DWORD dwChunk,
66         LONGLONG* pllOfs, DWORD* pdwChunkLength )
67 {
68         HRESULT hr;
69         DWORD dwCurCode;
70         DWORD dwCurLen;
71         LONGLONG llCurLen;
72
73         while ( 1 )
74         {
75                 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
76                 if ( hr != S_OK )
77                         break;
78                 TRACE("%c%c%c%c len %lu\n",
79                         (int)(dwCurCode>> 0)&0xff,
80                         (int)(dwCurCode>> 8)&0xff,
81                         (int)(dwCurCode>>16)&0xff,
82                         (int)(dwCurCode>>24)&0xff,
83                         (unsigned long)dwCurLen);
84                 if ( dwChunk == dwCurCode )
85                         break;
86                 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
87                 llOfs += llCurLen;
88                 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
89                         return S_FALSE;
90                 if ( dwSearchLengthMax != (DWORD)0xffffffff )
91                         dwSearchLengthMax -= (DWORD)llCurLen;
92         }
93
94         *pllOfs = llOfs + 8;
95         *pdwChunkLength = dwCurLen;
96
97         return hr;
98 }
99
100 /* S_OK = found, S_FALSE = not found */
101 HRESULT RIFF_SearchList(
102         CParserImpl* pImpl,
103         DWORD dwSearchLengthMax,
104         LONGLONG llOfs, DWORD dwListChunk,
105         LONGLONG* pllOfs, DWORD* pdwChunkLength )
106 {
107         HRESULT hr;
108         DWORD dwCurLen;
109         LONGLONG llCurLen;
110         BYTE bTemp[4];
111
112         while ( 1 )
113         {
114                 hr = RIFF_SearchChunk(
115                         pImpl, dwSearchLengthMax,
116                         llOfs, PARSER_LIST,
117                         &llOfs, &dwCurLen );
118                 if ( hr != S_OK )
119                         break;
120
121                 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
122                 if ( hr != S_OK )
123                         break;
124
125                 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
126                         break;
127
128                 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
129                 llOfs += llCurLen;
130                 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
131                         return S_FALSE;
132                 if ( dwSearchLengthMax != (DWORD)0xffffffff )
133                         dwSearchLengthMax -= (DWORD)(llCurLen+8);
134         }
135
136         if ( dwCurLen < 12 )
137                 return E_FAIL;
138
139         *pllOfs = llOfs+4;
140         *pdwChunkLength = dwCurLen-4;
141
142         return hr;
143 }
144
145
146
147
148 /****************************************************************************
149  *
150  *      CWavParseImpl
151  */
152
153 typedef enum WavParseFmtType
154 {
155         WaveParse_Native,
156         WaveParse_Signed8,
157         WaveParse_Signed16BE,
158         WaveParse_Unsigned16LE,
159         WaveParse_Unsigned16BE,
160 } WavParseFmtType;
161
162 typedef struct CWavParseImpl
163 {
164         DWORD   cbFmt;
165         WAVEFORMATEX*   pFmt;
166         DWORD   dwBlockSize;
167         LONGLONG        llDataStart;
168         LONGLONG        llBytesTotal;
169         LONGLONG        llBytesProcessed;
170         WavParseFmtType iFmtType;
171 } CWavParseImpl;
172
173
174 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
175 {
176         HRESULT hr;
177         LONGLONG        llOfs;
178         DWORD   dwChunkLength;
179
180         hr = RIFF_SearchChunk(
181                 pImpl, (DWORD)0xffffffff,
182                 PARSER_RIFF_OfsFirst, PARSER_fmt,
183                 &llOfs, &dwChunkLength );
184         if ( FAILED(hr) )
185                 return hr;
186         if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
187                 return E_FAIL;
188
189         This->cbFmt = dwChunkLength;
190         if ( dwChunkLength < sizeof(WAVEFORMATEX) )
191                 This->cbFmt = sizeof(WAVEFORMATEX);
192         This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
193         if ( This->pFmt == NULL )
194                 return E_OUTOFMEMORY;
195         ZeroMemory( This->pFmt, This->cbFmt );
196
197         hr = IAsyncReader_SyncRead(
198                 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
199         if ( hr != S_OK )
200         {
201                 if ( SUCCEEDED(hr) )
202                         hr = E_FAIL;
203                 return hr;
204         }
205
206
207         hr = RIFF_SearchChunk(
208                 pImpl, (DWORD)0xffffffff,
209                 PARSER_RIFF_OfsFirst, PARSER_data,
210                 &llOfs, &dwChunkLength );
211         if ( FAILED(hr) )
212                 return hr;
213         if ( hr != S_OK || dwChunkLength == 0 )
214                 return E_FAIL;
215
216         This->llDataStart = llOfs;
217         This->llBytesTotal = (LONGLONG)dwChunkLength;
218
219         return NOERROR;
220 }
221
222 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
223 {
224         BYTE    au_hdr[24];
225         DWORD   dataofs;
226         DWORD   datalen;
227         DWORD   datafmt;
228         DWORD   datarate;
229         DWORD   datachannels;
230         HRESULT hr;
231         WAVEFORMATEX    wfx;
232
233         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
234         if ( FAILED(hr) )
235                 return hr;
236
237         dataofs = PARSER_BE_UINT32(&au_hdr[4]);
238         datalen = PARSER_BE_UINT32(&au_hdr[8]);
239         datafmt = PARSER_BE_UINT32(&au_hdr[12]);
240         datarate = PARSER_BE_UINT32(&au_hdr[16]);
241         datachannels = PARSER_BE_UINT32(&au_hdr[20]);
242
243         if ( dataofs < 24U || datalen == 0U )
244                 return E_FAIL;
245         if ( datachannels != 1 && datachannels != 2 )
246                 return E_FAIL;
247
248         ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
249         wfx.nChannels = datachannels;
250         wfx.nSamplesPerSec = datarate;
251
252         switch ( datafmt )
253         {
254         case 1:
255                 wfx.wFormatTag = WAVE_FORMAT_MULAW;
256                 wfx.nBlockAlign = datachannels;
257                 wfx.wBitsPerSample = 8;
258                 break;
259         case 2:
260                 wfx.wFormatTag = WAVE_FORMAT_PCM;
261                 wfx.nBlockAlign = datachannels;
262                 wfx.wBitsPerSample = 8;
263                 This->iFmtType = WaveParse_Signed8;
264                 break;
265         case 3:
266                 wfx.wFormatTag = WAVE_FORMAT_PCM;
267                 wfx.nBlockAlign = datachannels;
268                 wfx.wBitsPerSample = 16;
269                 This->iFmtType = WaveParse_Signed16BE;
270                 break;
271         default:
272                 FIXME("audio/basic - unknown format %lu\n", datafmt );
273                 return E_FAIL;
274         }
275         wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
276
277         This->cbFmt = sizeof(WAVEFORMATEX);
278         This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
279         if ( This->pFmt == NULL )
280                 return E_OUTOFMEMORY;
281         memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
282
283         This->llDataStart = dataofs;
284         This->llBytesTotal = datalen;
285
286         return NOERROR;
287 }
288
289 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
290 {
291         FIXME( "AIFF is not supported now.\n" );
292         return E_FAIL;
293 }
294
295 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
296 {
297         CWavParseImpl*  This = NULL;
298         HRESULT hr;
299         BYTE    header[12];
300
301         TRACE("(%p,%p)\n",pImpl,pcStreams);
302
303         if ( pImpl->m_pReader == NULL )
304                 return E_UNEXPECTED;
305
306         This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
307         if ( This == NULL )
308                 return E_OUTOFMEMORY;
309         pImpl->m_pUserData = This;
310
311         /* construct */
312         This->cbFmt = 0;
313         This->pFmt = NULL;
314         This->dwBlockSize = 0;
315         This->llDataStart = 0;
316         This->llBytesTotal = 0;
317         This->llBytesProcessed = 0;
318         This->iFmtType = WaveParse_Native;
319
320         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
321         if ( FAILED(hr) )
322                 return hr;
323         if ( hr != S_OK )
324                 return E_FAIL;
325
326         if ( !memcmp( &header[0], "RIFF", 4 ) &&
327                  !memcmp( &header[8], "WAVE", 4 ) )
328         {
329                 TRACE( "(%p) - it's audio/wav.\n", pImpl );
330                 hr = CWavParseImpl_InitWAV( pImpl, This );
331         }
332         else
333         if ( !memcmp( &header[0], ".snd", 4 ) )
334         {
335                 TRACE( "(%p) - it's audio/basic.\n", pImpl );
336                 hr = CWavParseImpl_InitAU( pImpl, This );
337         }
338         else
339         if ( !memcmp( &header[0], "FORM", 4 ) &&
340                  !memcmp( &header[8], "AIFF", 4 ) )
341         {
342                 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
343                 hr = CWavParseImpl_InitAIFF( pImpl, This );
344         }
345         else
346         {
347                 FIXME( "(%p) - unknown format.\n", pImpl );
348                 hr = E_FAIL;
349         }
350
351         if ( FAILED(hr) )
352         {
353                 return hr;
354         }
355
356         /* initialized successfully. */
357         *pcStreams = 1;
358
359         This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
360
361         TRACE( "(%p) returned successfully.\n", pImpl );
362
363         return NOERROR;
364 }
365
366 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
367 {
368         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
369
370         TRACE("(%p)\n",This);
371
372         if ( This == NULL )
373                 return NOERROR;
374
375         /* destruct */
376         if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
377
378         QUARTZ_FreeMem( This );
379         pImpl->m_pUserData = NULL;
380
381         return NOERROR;
382 }
383
384 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
385 {
386         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
387
388         TRACE("(%p)\n",This);
389
390         return QUARTZ_WaveParserOutPin_Name;
391 }
392
393 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
394 {
395         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
396
397         TRACE("(%p)\n",This);
398
399         if ( This == NULL || This->pFmt == NULL )
400                 return E_UNEXPECTED;
401
402         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
403         memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
404         QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
405         pmt->bFixedSizeSamples = 1;
406         pmt->bTemporalCompression = 0;
407         pmt->lSampleSize = This->pFmt->nBlockAlign;
408         memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
409         pmt->pUnk = NULL;
410
411         pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
412         if ( pmt->pbFormat == NULL )
413                 return E_OUTOFMEMORY;
414         pmt->cbFormat = This->cbFmt;
415         memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
416
417         return NOERROR;
418 }
419
420 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
421 {
422         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
423                  !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
424                 return E_FAIL;
425         if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
426                 return E_FAIL;
427
428         return NOERROR;
429 }
430
431 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
432 {
433         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
434
435         TRACE("(%p)\n",This);
436
437         if ( This == NULL || This->pFmt == NULL )
438                 return E_UNEXPECTED;
439
440         ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
441         pReqProp->cBuffers = 1;
442         pReqProp->cbBuffer = This->dwBlockSize;
443
444         return NOERROR;
445 }
446
447 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
448 {
449         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
450         LONGLONG        llAvail;
451         LONGLONG        llStart;
452         LONGLONG        llEnd;
453
454         TRACE("(%p)\n",This);
455
456         if ( This == NULL || This->pFmt == NULL )
457                 return E_UNEXPECTED;
458
459         llAvail = This->llBytesTotal - This->llBytesProcessed;
460         if ( llAvail > (LONGLONG)This->dwBlockSize )
461                 llAvail = (LONGLONG)This->dwBlockSize;
462         llStart = This->llBytesProcessed;
463         llEnd = llStart + llAvail;
464         This->llBytesProcessed = llEnd;
465
466         *pllStart = This->llBytesProcessed;
467         *plLength = (LONG)llAvail;
468         *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
469         *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
470
471         return NOERROR;
472 }
473
474 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
475 {
476         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
477         BYTE*   pData;
478         LONG    lActLen;
479         HRESULT hr;
480
481         TRACE("(%p)\n",This);
482
483         hr = IMediaSample_GetPointer(pSample,&pData);
484         if ( FAILED(hr) )
485                 return hr;
486         lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
487         if ( lActLen != lLength )
488                 return E_FAIL;
489
490         switch ( This->iFmtType )
491         {
492         case WaveParse_Native:
493                 break;
494         case WaveParse_Signed8:
495                 AUDIOUTL_ChangeSign8(pData,lActLen);
496                 break;
497         case WaveParse_Signed16BE:
498                 AUDIOUTL_ByteSwap(pData,lActLen);
499                 break;
500         case WaveParse_Unsigned16LE:
501                 AUDIOUTL_ChangeSign16LE(pData,lActLen);
502                 break;
503         case WaveParse_Unsigned16BE:
504                 AUDIOUTL_ChangeSign16BE(pData,lActLen);
505                 AUDIOUTL_ByteSwap(pData,lActLen);
506                 break;
507         default:
508                 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
509                 return E_FAIL;
510         }
511
512         return NOERROR;
513 }
514
515
516 static const struct ParserHandlers CWavParseImpl_Handlers =
517 {
518         CWavParseImpl_InitParser,
519         CWavParseImpl_UninitParser,
520         CWavParseImpl_GetOutPinName,
521         CWavParseImpl_GetStreamType,
522         CWavParseImpl_CheckStreamType,
523         CWavParseImpl_GetAllocProp,
524         CWavParseImpl_GetNextRequest,
525         CWavParseImpl_ProcessSample,
526
527         /* for IQualityControl */
528         NULL, /* pQualityNotify */
529
530         /* for seeking */
531         NULL, /* pGetSeekingCaps */
532         NULL, /* pIsTimeFormatSupported */
533         NULL, /* pGetCurPos */
534         NULL, /* pSetCurPos */
535         NULL, /* pGetDuration */
536         NULL, /* pSetDuration */
537         NULL, /* pGetStopPos */
538         NULL, /* pSetStopPos */
539         NULL, /* pGetPreroll */
540         NULL, /* pSetPreroll */
541 };
542
543 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
544 {
545         return QUARTZ_CreateParser(
546                 punkOuter,ppobj,
547                 &CLSID_quartzWaveParser,
548                 QUARTZ_WaveParser_Name,
549                 QUARTZ_WaveParserInPin_Name,
550                 &CWavParseImpl_Handlers );
551 }
552
553