blob: 49fbe2cb6db69b4d12a686766179415d53d0abc3 [file] [log] [blame]
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +00001/*
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"
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000014#include "mmreg.h"
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000015#include "winerror.h"
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000016#include "strmif.h"
17#include "vfwmsgs.h"
18#include "uuids.h"
19
20#include "debugtools.h"
21DEFAULT_DEBUG_CHANNEL(quartz);
22
23#include "quartz_private.h"
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000024#include "audioutl.h"
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000025#include "parser.h"
26
27
28static const WCHAR QUARTZ_WaveParser_Name[] =
29{ 'W','a','v','e',' ','P','a','r','s','e','r',0 };
30static const WCHAR QUARTZ_WaveParserInPin_Name[] =
31{ 'I','n',0 };
32static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
33{ 'O','u','t',0 };
34
35
36/****************************************************************************/
37
38/* S_OK = found, S_FALSE = not found */
39HRESULT 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 */
62HRESULT RIFF_SearchChunk(
63 CParserImpl* pImpl,
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000064 DWORD dwSearchLengthMax,
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000065 LONGLONG llOfs, DWORD dwChunk,
66 LONGLONG* pllOfs, DWORD* pdwChunkLength )
67{
68 HRESULT hr;
69 DWORD dwCurCode;
70 DWORD dwCurLen;
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000071 LONGLONG llCurLen;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000072
73 while ( 1 )
74 {
75 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
76 if ( hr != S_OK )
77 break;
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000078 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);
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000084 if ( dwChunk == dwCurCode )
85 break;
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000086 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;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000092 }
93
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +000094 *pllOfs = llOfs + 8;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +000095 *pdwChunkLength = dwCurLen;
96
97 return hr;
98}
99
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000100/* S_OK = found, S_FALSE = not found */
101HRESULT 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
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000145
146
147
148/****************************************************************************
149 *
150 * CWavParseImpl
151 */
152
153typedef enum WavParseFmtType
154{
155 WaveParse_Native,
156 WaveParse_Signed8,
157 WaveParse_Signed16BE,
158 WaveParse_Unsigned16LE,
159 WaveParse_Unsigned16BE,
160} WavParseFmtType;
161
162typedef 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
174static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
175{
176 HRESULT hr;
177 LONGLONG llOfs;
178 DWORD dwChunkLength;
179
180 hr = RIFF_SearchChunk(
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000181 pImpl, (DWORD)0xffffffff,
182 PARSER_RIFF_OfsFirst, PARSER_fmt,
183 &llOfs, &dwChunkLength );
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000184 if ( FAILED(hr) )
185 return hr;
186 if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
187 return E_FAIL;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000188
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(
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000208 pImpl, (DWORD)0xffffffff,
209 PARSER_RIFF_OfsFirst, PARSER_data,
210 &llOfs, &dwChunkLength );
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000211 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
222static 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:
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000255 wfx.wFormatTag = WAVE_FORMAT_MULAW;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000256 wfx.nBlockAlign = datachannels;
257 wfx.wBitsPerSample = 8;
258 break;
259 case 2:
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000260 wfx.wFormatTag = WAVE_FORMAT_PCM;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000261 wfx.nBlockAlign = datachannels;
262 wfx.wBitsPerSample = 8;
263 This->iFmtType = WaveParse_Signed8;
264 break;
265 case 3:
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000266 wfx.wFormatTag = WAVE_FORMAT_PCM;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000267 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
289static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
290{
291 FIXME( "AIFF is not supported now.\n" );
292 return E_FAIL;
293}
294
295static 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
366static 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
384static 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
393static 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
420static 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
431static 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
447static 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
474static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
475{
476 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000477 BYTE* pData;
478 LONG lActLen;
479 HRESULT hr;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000480
481 TRACE("(%p)\n",This);
482
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000483 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
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000490 switch ( This->iFmtType )
491 {
492 case WaveParse_Native:
493 break;
Hidenori Takeshimabc7d0272001-10-14 16:13:14 +0000494 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;
Hidenori Takeshimabd3be7a2001-10-08 20:56:08 +0000507 default:
508 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
509 return E_FAIL;
510 }
511
512 return NOERROR;
513}
514
515
516static 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
543HRESULT 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