2 * Implements WAVE/AU/AIFF Parser.
4 * hidenori@a2.ctktv.ne.jp
21 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(quartz);
24 #include "quartz_private.h"
29 static const WCHAR QUARTZ_WaveParser_Name[] =
30 { 'W','a','v','e',' ','P','a','r','s','e','r',0 };
31 static const WCHAR QUARTZ_WaveParserInPin_Name[] =
33 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
37 /****************************************************************************/
39 /* S_OK = found, S_FALSE = not found */
41 CParserImpl* pImpl, LONGLONG llOfs,
42 DWORD* pdwCode, DWORD* pdwLength )
47 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
50 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
51 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
62 /* S_OK = found, S_FALSE = not found */
63 HRESULT RIFF_SearchChunk(
65 DWORD dwSearchLengthMax,
66 LONGLONG llOfs, DWORD dwChunk,
67 LONGLONG* pllOfs, DWORD* pdwChunkLength )
76 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
79 TRACE("%c%c%c%c len %lu\n",
80 (int)(dwCurCode>> 0)&0xff,
81 (int)(dwCurCode>> 8)&0xff,
82 (int)(dwCurCode>>16)&0xff,
83 (int)(dwCurCode>>24)&0xff,
84 (unsigned long)dwCurLen);
85 if ( dwChunk == dwCurCode )
87 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
89 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
91 if ( dwSearchLengthMax != (DWORD)0xffffffff )
92 dwSearchLengthMax -= (DWORD)llCurLen;
96 *pdwChunkLength = dwCurLen;
101 /* S_OK = found, S_FALSE = not found */
102 HRESULT RIFF_SearchList(
104 DWORD dwSearchLengthMax,
105 LONGLONG llOfs, DWORD dwListChunk,
106 LONGLONG* pllOfs, DWORD* pdwChunkLength )
115 hr = RIFF_SearchChunk(
116 pImpl, dwSearchLengthMax,
122 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
126 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
129 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
131 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
133 if ( dwSearchLengthMax != (DWORD)0xffffffff )
134 dwSearchLengthMax -= (DWORD)(llCurLen+8);
141 *pdwChunkLength = dwCurLen-4;
149 /****************************************************************************
154 typedef enum WavParseFmtType
158 WaveParse_Signed16BE,
159 WaveParse_Unsigned16LE,
160 WaveParse_Unsigned16BE,
163 typedef struct CWavParseImpl
168 LONGLONG llDataStart;
169 LONGLONG llBytesTotal;
170 LONGLONG llBytesProcessed;
171 WavParseFmtType iFmtType;
175 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
181 hr = RIFF_SearchChunk(
182 pImpl, (DWORD)0xffffffff,
183 PARSER_RIFF_OfsFirst, PARSER_fmt,
184 &llOfs, &dwChunkLength );
187 if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
190 This->cbFmt = dwChunkLength;
191 if ( dwChunkLength < sizeof(WAVEFORMATEX) )
192 This->cbFmt = sizeof(WAVEFORMATEX);
193 This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
194 if ( This->pFmt == NULL )
195 return E_OUTOFMEMORY;
196 ZeroMemory( This->pFmt, This->cbFmt );
198 hr = IAsyncReader_SyncRead(
199 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
208 hr = RIFF_SearchChunk(
209 pImpl, (DWORD)0xffffffff,
210 PARSER_RIFF_OfsFirst, PARSER_data,
211 &llOfs, &dwChunkLength );
214 if ( hr != S_OK || dwChunkLength == 0 )
217 This->llDataStart = llOfs;
218 This->llBytesTotal = (LONGLONG)dwChunkLength;
223 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
234 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
238 dataofs = PARSER_BE_UINT32(&au_hdr[4]);
239 datalen = PARSER_BE_UINT32(&au_hdr[8]);
240 datafmt = PARSER_BE_UINT32(&au_hdr[12]);
241 datarate = PARSER_BE_UINT32(&au_hdr[16]);
242 datachannels = PARSER_BE_UINT32(&au_hdr[20]);
244 if ( dataofs < 24U || datalen == 0U )
246 if ( datachannels != 1 && datachannels != 2 )
249 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
250 wfx.nChannels = datachannels;
251 wfx.nSamplesPerSec = datarate;
256 wfx.wFormatTag = WAVE_FORMAT_MULAW;
257 wfx.nBlockAlign = datachannels;
258 wfx.wBitsPerSample = 8;
261 wfx.wFormatTag = WAVE_FORMAT_PCM;
262 wfx.nBlockAlign = datachannels;
263 wfx.wBitsPerSample = 8;
264 This->iFmtType = WaveParse_Signed8;
267 wfx.wFormatTag = WAVE_FORMAT_PCM;
268 wfx.nBlockAlign = datachannels;
269 wfx.wBitsPerSample = 16;
270 This->iFmtType = WaveParse_Signed16BE;
273 FIXME("audio/basic - unknown format %lu\n", datafmt );
276 wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
278 This->cbFmt = sizeof(WAVEFORMATEX);
279 This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
280 if ( This->pFmt == NULL )
281 return E_OUTOFMEMORY;
282 memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
284 This->llDataStart = dataofs;
285 This->llBytesTotal = datalen;
287 TRACE("offset %lu, length %lu\n",dataofs,datalen);
292 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
294 FIXME( "AIFF is not supported now.\n" );
298 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
300 CWavParseImpl* This = NULL;
304 TRACE("(%p,%p)\n",pImpl,pcStreams);
306 if ( pImpl->m_pReader == NULL )
309 This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
311 return E_OUTOFMEMORY;
312 pImpl->m_pUserData = This;
317 This->dwBlockSize = 0;
318 This->llDataStart = 0;
319 This->llBytesTotal = 0;
320 This->llBytesProcessed = 0;
321 This->iFmtType = WaveParse_Native;
323 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
329 if ( !memcmp( &header[0], "RIFF", 4 ) &&
330 !memcmp( &header[8], "WAVE", 4 ) )
332 TRACE( "(%p) - it's audio/wav.\n", pImpl );
333 hr = CWavParseImpl_InitWAV( pImpl, This );
336 if ( !memcmp( &header[0], ".snd", 4 ) )
338 TRACE( "(%p) - it's audio/basic.\n", pImpl );
339 hr = CWavParseImpl_InitAU( pImpl, This );
342 if ( !memcmp( &header[0], "FORM", 4 ) &&
343 !memcmp( &header[8], "AIFF", 4 ) )
345 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
346 hr = CWavParseImpl_InitAIFF( pImpl, This );
350 FIXME( "(%p) - unknown format.\n", pImpl );
359 /* initialized successfully. */
362 This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
364 TRACE( "(%p) returned successfully.\n", pImpl );
369 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
371 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
373 TRACE("(%p)\n",This);
379 if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
381 QUARTZ_FreeMem( This );
382 pImpl->m_pUserData = NULL;
387 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
389 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
391 TRACE("(%p)\n",This);
393 return QUARTZ_WaveParserOutPin_Name;
396 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
398 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
400 TRACE("(%p)\n",This);
402 if ( This == NULL || This->pFmt == NULL )
405 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
406 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
407 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
408 pmt->bFixedSizeSamples = 1;
409 pmt->bTemporalCompression = 0;
410 pmt->lSampleSize = This->pFmt->nBlockAlign;
411 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
414 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
415 if ( pmt->pbFormat == NULL )
416 return E_OUTOFMEMORY;
417 pmt->cbFormat = This->cbFmt;
418 memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
423 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
425 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
426 !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
428 if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
434 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
436 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
438 TRACE("(%p)\n",This);
440 if ( This == NULL || This->pFmt == NULL )
443 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
444 pReqProp->cBuffers = 1;
445 pReqProp->cbBuffer = This->dwBlockSize;
450 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
452 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
457 TRACE("(%p)\n",This);
459 if ( This == NULL || This->pFmt == NULL )
462 llAvail = This->llBytesTotal - This->llBytesProcessed;
463 if ( llAvail > (LONGLONG)This->dwBlockSize )
464 llAvail = (LONGLONG)This->dwBlockSize;
465 llStart = This->llDataStart + This->llBytesProcessed;
466 llEnd = llStart + llAvail;
467 This->llBytesProcessed = llEnd;
469 *pllStart = This->llBytesProcessed;
470 *plLength = (LONG)llAvail;
471 *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
472 *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
477 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
479 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
484 TRACE("(%p)\n",This);
486 hr = IMediaSample_GetPointer(pSample,&pData);
489 lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
490 if ( lActLen != lLength )
493 switch ( This->iFmtType )
495 case WaveParse_Native:
497 case WaveParse_Signed8:
498 AUDIOUTL_ChangeSign8(pData,lActLen);
500 case WaveParse_Signed16BE:
501 AUDIOUTL_ByteSwap(pData,lActLen);
503 case WaveParse_Unsigned16LE:
504 AUDIOUTL_ChangeSign16LE(pData,lActLen);
506 case WaveParse_Unsigned16BE:
507 AUDIOUTL_ChangeSign16BE(pData,lActLen);
508 AUDIOUTL_ByteSwap(pData,lActLen);
511 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
519 static const struct ParserHandlers CWavParseImpl_Handlers =
521 CWavParseImpl_InitParser,
522 CWavParseImpl_UninitParser,
523 CWavParseImpl_GetOutPinName,
524 CWavParseImpl_GetStreamType,
525 CWavParseImpl_CheckStreamType,
526 CWavParseImpl_GetAllocProp,
527 CWavParseImpl_GetNextRequest,
528 CWavParseImpl_ProcessSample,
530 /* for IQualityControl */
531 NULL, /* pQualityNotify */
534 NULL, /* pGetSeekingCaps */
535 NULL, /* pIsTimeFormatSupported */
536 NULL, /* pGetCurPos */
537 NULL, /* pSetCurPos */
538 NULL, /* pGetDuration */
539 NULL, /* pSetDuration */
540 NULL, /* pGetStopPos */
541 NULL, /* pSetStopPos */
542 NULL, /* pGetPreroll */
543 NULL, /* pSetPreroll */
546 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
548 return QUARTZ_CreateParser(
550 &CLSID_quartzWaveParser,
551 QUARTZ_WaveParser_Name,
552 QUARTZ_WaveParserInPin_Name,
553 &CWavParseImpl_Handlers );