2 * Implements WAVE/AU/AIFF Parser.
4 * hidenori@a2.ctktv.ne.jp
20 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(quartz);
23 #include "quartz_private.h"
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[] =
32 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
36 /****************************************************************************/
38 /* S_OK = found, S_FALSE = not found */
40 CParserImpl* pImpl, LONGLONG llOfs,
41 DWORD* pdwCode, DWORD* pdwLength )
46 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
49 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
50 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
61 /* S_OK = found, S_FALSE = not found */
62 HRESULT RIFF_SearchChunk(
64 DWORD dwSearchLengthMax,
65 LONGLONG llOfs, DWORD dwChunk,
66 LONGLONG* pllOfs, DWORD* pdwChunkLength )
75 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
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 )
86 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
88 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
90 if ( dwSearchLengthMax != (DWORD)0xffffffff )
91 dwSearchLengthMax -= (DWORD)llCurLen;
95 *pdwChunkLength = dwCurLen;
100 /* S_OK = found, S_FALSE = not found */
101 HRESULT RIFF_SearchList(
103 DWORD dwSearchLengthMax,
104 LONGLONG llOfs, DWORD dwListChunk,
105 LONGLONG* pllOfs, DWORD* pdwChunkLength )
114 hr = RIFF_SearchChunk(
115 pImpl, dwSearchLengthMax,
121 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
125 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
128 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
130 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
132 if ( dwSearchLengthMax != (DWORD)0xffffffff )
133 dwSearchLengthMax -= (DWORD)(llCurLen+8);
140 *pdwChunkLength = dwCurLen-4;
148 /****************************************************************************
153 typedef enum WavParseFmtType
157 WaveParse_Signed16BE,
158 WaveParse_Unsigned16LE,
159 WaveParse_Unsigned16BE,
162 typedef struct CWavParseImpl
167 LONGLONG llDataStart;
168 LONGLONG llBytesTotal;
169 LONGLONG llBytesProcessed;
170 WavParseFmtType iFmtType;
174 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
180 hr = RIFF_SearchChunk(
181 pImpl, (DWORD)0xffffffff,
182 PARSER_RIFF_OfsFirst, PARSER_fmt,
183 &llOfs, &dwChunkLength );
186 if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
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 );
197 hr = IAsyncReader_SyncRead(
198 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
207 hr = RIFF_SearchChunk(
208 pImpl, (DWORD)0xffffffff,
209 PARSER_RIFF_OfsFirst, PARSER_data,
210 &llOfs, &dwChunkLength );
213 if ( hr != S_OK || dwChunkLength == 0 )
216 This->llDataStart = llOfs;
217 This->llBytesTotal = (LONGLONG)dwChunkLength;
222 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
233 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
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]);
243 if ( dataofs < 24U || datalen == 0U )
245 if ( datachannels != 1 && datachannels != 2 )
248 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
249 wfx.nChannels = datachannels;
250 wfx.nSamplesPerSec = datarate;
255 wfx.wFormatTag = WAVE_FORMAT_MULAW;
256 wfx.nBlockAlign = datachannels;
257 wfx.wBitsPerSample = 8;
260 wfx.wFormatTag = WAVE_FORMAT_PCM;
261 wfx.nBlockAlign = datachannels;
262 wfx.wBitsPerSample = 8;
263 This->iFmtType = WaveParse_Signed8;
266 wfx.wFormatTag = WAVE_FORMAT_PCM;
267 wfx.nBlockAlign = datachannels;
268 wfx.wBitsPerSample = 16;
269 This->iFmtType = WaveParse_Signed16BE;
272 FIXME("audio/basic - unknown format %lu\n", datafmt );
275 wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
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) );
283 This->llDataStart = dataofs;
284 This->llBytesTotal = datalen;
289 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
291 FIXME( "AIFF is not supported now.\n" );
295 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
297 CWavParseImpl* This = NULL;
301 TRACE("(%p,%p)\n",pImpl,pcStreams);
303 if ( pImpl->m_pReader == NULL )
306 This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
308 return E_OUTOFMEMORY;
309 pImpl->m_pUserData = This;
314 This->dwBlockSize = 0;
315 This->llDataStart = 0;
316 This->llBytesTotal = 0;
317 This->llBytesProcessed = 0;
318 This->iFmtType = WaveParse_Native;
320 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
326 if ( !memcmp( &header[0], "RIFF", 4 ) &&
327 !memcmp( &header[8], "WAVE", 4 ) )
329 TRACE( "(%p) - it's audio/wav.\n", pImpl );
330 hr = CWavParseImpl_InitWAV( pImpl, This );
333 if ( !memcmp( &header[0], ".snd", 4 ) )
335 TRACE( "(%p) - it's audio/basic.\n", pImpl );
336 hr = CWavParseImpl_InitAU( pImpl, This );
339 if ( !memcmp( &header[0], "FORM", 4 ) &&
340 !memcmp( &header[8], "AIFF", 4 ) )
342 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
343 hr = CWavParseImpl_InitAIFF( pImpl, This );
347 FIXME( "(%p) - unknown format.\n", pImpl );
356 /* initialized successfully. */
359 This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
361 TRACE( "(%p) returned successfully.\n", pImpl );
366 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
368 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
370 TRACE("(%p)\n",This);
376 if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
378 QUARTZ_FreeMem( This );
379 pImpl->m_pUserData = NULL;
384 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
386 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
388 TRACE("(%p)\n",This);
390 return QUARTZ_WaveParserOutPin_Name;
393 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
395 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
397 TRACE("(%p)\n",This);
399 if ( This == NULL || This->pFmt == NULL )
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) );
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 );
420 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
422 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
423 !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
425 if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
431 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
433 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
435 TRACE("(%p)\n",This);
437 if ( This == NULL || This->pFmt == NULL )
440 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
441 pReqProp->cBuffers = 1;
442 pReqProp->cbBuffer = This->dwBlockSize;
447 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
449 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
454 TRACE("(%p)\n",This);
456 if ( This == NULL || This->pFmt == NULL )
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;
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;
474 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
476 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
481 TRACE("(%p)\n",This);
483 hr = IMediaSample_GetPointer(pSample,&pData);
486 lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
487 if ( lActLen != lLength )
490 switch ( This->iFmtType )
492 case WaveParse_Native:
494 case WaveParse_Signed8:
495 AUDIOUTL_ChangeSign8(pData,lActLen);
497 case WaveParse_Signed16BE:
498 AUDIOUTL_ByteSwap(pData,lActLen);
500 case WaveParse_Unsigned16LE:
501 AUDIOUTL_ChangeSign16LE(pData,lActLen);
503 case WaveParse_Unsigned16BE:
504 AUDIOUTL_ChangeSign16BE(pData,lActLen);
505 AUDIOUTL_ByteSwap(pData,lActLen);
508 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
516 static const struct ParserHandlers CWavParseImpl_Handlers =
518 CWavParseImpl_InitParser,
519 CWavParseImpl_UninitParser,
520 CWavParseImpl_GetOutPinName,
521 CWavParseImpl_GetStreamType,
522 CWavParseImpl_CheckStreamType,
523 CWavParseImpl_GetAllocProp,
524 CWavParseImpl_GetNextRequest,
525 CWavParseImpl_ProcessSample,
527 /* for IQualityControl */
528 NULL, /* pQualityNotify */
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 */
543 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
545 return QUARTZ_CreateParser(
547 &CLSID_quartzWaveParser,
548 QUARTZ_WaveParser_Name,
549 QUARTZ_WaveParserInPin_Name,
550 &CWavParseImpl_Handlers );