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;
290 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
292 FIXME( "AIFF is not supported now.\n" );
296 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
298 CWavParseImpl* This = NULL;
302 TRACE("(%p,%p)\n",pImpl,pcStreams);
304 if ( pImpl->m_pReader == NULL )
307 This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
309 return E_OUTOFMEMORY;
310 pImpl->m_pUserData = This;
315 This->dwBlockSize = 0;
316 This->llDataStart = 0;
317 This->llBytesTotal = 0;
318 This->llBytesProcessed = 0;
319 This->iFmtType = WaveParse_Native;
321 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
327 if ( !memcmp( &header[0], "RIFF", 4 ) &&
328 !memcmp( &header[8], "WAVE", 4 ) )
330 TRACE( "(%p) - it's audio/wav.\n", pImpl );
331 hr = CWavParseImpl_InitWAV( pImpl, This );
334 if ( !memcmp( &header[0], ".snd", 4 ) )
336 TRACE( "(%p) - it's audio/basic.\n", pImpl );
337 hr = CWavParseImpl_InitAU( pImpl, This );
340 if ( !memcmp( &header[0], "FORM", 4 ) &&
341 !memcmp( &header[8], "AIFF", 4 ) )
343 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
344 hr = CWavParseImpl_InitAIFF( pImpl, This );
348 FIXME( "(%p) - unknown format.\n", pImpl );
357 /* initialized successfully. */
360 This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
362 TRACE( "(%p) returned successfully.\n", pImpl );
367 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
369 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
371 TRACE("(%p)\n",This);
377 if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
379 QUARTZ_FreeMem( This );
380 pImpl->m_pUserData = NULL;
385 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
387 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
389 TRACE("(%p)\n",This);
391 return QUARTZ_WaveParserOutPin_Name;
394 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
396 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
398 TRACE("(%p)\n",This);
400 if ( This == NULL || This->pFmt == NULL )
403 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
404 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
405 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
406 pmt->bFixedSizeSamples = 1;
407 pmt->bTemporalCompression = 0;
408 pmt->lSampleSize = This->pFmt->nBlockAlign;
409 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
412 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
413 if ( pmt->pbFormat == NULL )
414 return E_OUTOFMEMORY;
415 pmt->cbFormat = This->cbFmt;
416 memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
421 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
423 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
424 !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
426 if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
432 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
434 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
436 TRACE("(%p)\n",This);
438 if ( This == NULL || This->pFmt == NULL )
441 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
442 pReqProp->cBuffers = 1;
443 pReqProp->cbBuffer = This->dwBlockSize;
448 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
450 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
455 TRACE("(%p)\n",This);
457 if ( This == NULL || This->pFmt == NULL )
460 llAvail = This->llBytesTotal - This->llBytesProcessed;
461 if ( llAvail > (LONGLONG)This->dwBlockSize )
462 llAvail = (LONGLONG)This->dwBlockSize;
463 llStart = This->llBytesProcessed;
464 llEnd = llStart + llAvail;
465 This->llBytesProcessed = llEnd;
467 *pllStart = This->llBytesProcessed;
468 *plLength = (LONG)llAvail;
469 *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
470 *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
475 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
477 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
482 TRACE("(%p)\n",This);
484 hr = IMediaSample_GetPointer(pSample,&pData);
487 lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
488 if ( lActLen != lLength )
491 switch ( This->iFmtType )
493 case WaveParse_Native:
495 case WaveParse_Signed8:
496 AUDIOUTL_ChangeSign8(pData,lActLen);
498 case WaveParse_Signed16BE:
499 AUDIOUTL_ByteSwap(pData,lActLen);
501 case WaveParse_Unsigned16LE:
502 AUDIOUTL_ChangeSign16LE(pData,lActLen);
504 case WaveParse_Unsigned16BE:
505 AUDIOUTL_ChangeSign16BE(pData,lActLen);
506 AUDIOUTL_ByteSwap(pData,lActLen);
509 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
517 static const struct ParserHandlers CWavParseImpl_Handlers =
519 CWavParseImpl_InitParser,
520 CWavParseImpl_UninitParser,
521 CWavParseImpl_GetOutPinName,
522 CWavParseImpl_GetStreamType,
523 CWavParseImpl_CheckStreamType,
524 CWavParseImpl_GetAllocProp,
525 CWavParseImpl_GetNextRequest,
526 CWavParseImpl_ProcessSample,
528 /* for IQualityControl */
529 NULL, /* pQualityNotify */
532 NULL, /* pGetSeekingCaps */
533 NULL, /* pIsTimeFormatSupported */
534 NULL, /* pGetCurPos */
535 NULL, /* pSetCurPos */
536 NULL, /* pGetDuration */
537 NULL, /* pSetDuration */
538 NULL, /* pGetStopPos */
539 NULL, /* pSetStopPos */
540 NULL, /* pGetPreroll */
541 NULL, /* pSetPreroll */
544 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
546 return QUARTZ_CreateParser(
548 &CLSID_quartzWaveParser,
549 QUARTZ_WaveParser_Name,
550 QUARTZ_WaveParserInPin_Name,
551 &CWavParseImpl_Handlers );