2 * Implements WAVE/AU/AIFF Parser.
4 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
38 #include "quartz_private.h"
43 static const WCHAR QUARTZ_WaveParser_Name[] =
44 { 'W','a','v','e',' ','P','a','r','s','e','r',0 };
45 static const WCHAR QUARTZ_WaveParserInPin_Name[] =
47 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
51 /****************************************************************************/
53 /* S_OK = found, S_FALSE = not found */
55 CParserImpl* pImpl, LONGLONG llOfs,
56 DWORD* pdwCode, DWORD* pdwLength )
61 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
64 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
65 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
76 /* S_OK = found, S_FALSE = not found */
77 HRESULT RIFF_SearchChunk(
79 DWORD dwSearchLengthMax,
80 LONGLONG llOfs, DWORD dwChunk,
81 LONGLONG* pllOfs, DWORD* pdwChunkLength )
90 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
93 TRACE("%c%c%c%c len %lu\n",
94 (int)(dwCurCode>> 0)&0xff,
95 (int)(dwCurCode>> 8)&0xff,
96 (int)(dwCurCode>>16)&0xff,
97 (int)(dwCurCode>>24)&0xff,
98 (unsigned long)dwCurLen);
99 if ( dwChunk == dwCurCode )
101 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
103 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
105 if ( dwSearchLengthMax != (DWORD)0xffffffff )
106 dwSearchLengthMax -= (DWORD)llCurLen;
110 *pdwChunkLength = dwCurLen;
115 /* S_OK = found, S_FALSE = not found */
116 HRESULT RIFF_SearchList(
118 DWORD dwSearchLengthMax,
119 LONGLONG llOfs, DWORD dwListChunk,
120 LONGLONG* pllOfs, DWORD* pdwChunkLength )
129 hr = RIFF_SearchChunk(
130 pImpl, dwSearchLengthMax,
136 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
140 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
143 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
145 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
147 if ( dwSearchLengthMax != (DWORD)0xffffffff )
148 dwSearchLengthMax -= (DWORD)(llCurLen+8);
155 *pdwChunkLength = dwCurLen-4;
163 /****************************************************************************
168 typedef enum WavParseFmtType
172 WaveParse_Signed16BE,
173 WaveParse_Unsigned16LE,
174 WaveParse_Unsigned16BE,
177 typedef struct CWavParseImpl
182 LONGLONG llDataStart;
183 LONGLONG llBytesStop;
184 LONGLONG llBytesTotal;
185 LONGLONG llBytesProcessed;
186 BOOL bDataDiscontinuity;
187 WavParseFmtType iFmtType;
191 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
197 hr = RIFF_SearchChunk(
198 pImpl, (DWORD)0xffffffff,
199 PARSER_RIFF_OfsFirst, PARSER_fmt,
200 &llOfs, &dwChunkLength );
203 if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
206 This->cbFmt = dwChunkLength;
207 if ( dwChunkLength < sizeof(WAVEFORMATEX) )
208 This->cbFmt = sizeof(WAVEFORMATEX);
209 This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
210 if ( This->pFmt == NULL )
211 return E_OUTOFMEMORY;
212 ZeroMemory( This->pFmt, This->cbFmt );
214 hr = IAsyncReader_SyncRead(
215 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
224 hr = RIFF_SearchChunk(
225 pImpl, (DWORD)0xffffffff,
226 PARSER_RIFF_OfsFirst, PARSER_data,
227 &llOfs, &dwChunkLength );
230 if ( hr != S_OK || dwChunkLength == 0 )
233 This->llDataStart = llOfs;
234 This->llBytesTotal = (LONGLONG)dwChunkLength;
239 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
250 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
254 dataofs = PARSER_BE_UINT32(&au_hdr[4]);
255 datalen = PARSER_BE_UINT32(&au_hdr[8]);
256 datafmt = PARSER_BE_UINT32(&au_hdr[12]);
257 datarate = PARSER_BE_UINT32(&au_hdr[16]);
258 datachannels = PARSER_BE_UINT32(&au_hdr[20]);
260 if ( dataofs < 24U || datalen == 0U )
262 if ( datachannels != 1 && datachannels != 2 )
265 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
266 wfx.nChannels = datachannels;
267 wfx.nSamplesPerSec = datarate;
272 wfx.wFormatTag = WAVE_FORMAT_MULAW;
273 wfx.nBlockAlign = datachannels;
274 wfx.wBitsPerSample = 8;
277 wfx.wFormatTag = WAVE_FORMAT_PCM;
278 wfx.nBlockAlign = datachannels;
279 wfx.wBitsPerSample = 8;
280 This->iFmtType = WaveParse_Signed8;
283 wfx.wFormatTag = WAVE_FORMAT_PCM;
284 wfx.nBlockAlign = datachannels;
285 wfx.wBitsPerSample = 16;
286 This->iFmtType = WaveParse_Signed16BE;
289 FIXME("audio/basic - unknown format %lu\n", datafmt );
292 wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
294 This->cbFmt = sizeof(WAVEFORMATEX);
295 This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
296 if ( This->pFmt == NULL )
297 return E_OUTOFMEMORY;
298 memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
300 This->llDataStart = dataofs;
301 This->llBytesTotal = datalen;
303 TRACE("offset %lu, length %lu\n",dataofs,datalen);
308 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
310 FIXME( "AIFF is not supported now.\n" );
314 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
316 CWavParseImpl* This = NULL;
320 TRACE("(%p,%p)\n",pImpl,pcStreams);
322 if ( pImpl->m_pReader == NULL )
325 This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
327 return E_OUTOFMEMORY;
328 pImpl->m_pUserData = This;
333 This->dwBlockSize = 0;
334 This->llDataStart = 0;
335 This->llBytesStop = 0;
336 This->llBytesTotal = 0;
337 This->llBytesProcessed = 0;
338 This->bDataDiscontinuity = TRUE;
339 This->iFmtType = WaveParse_Native;
341 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
347 if ( !memcmp( &header[0], "RIFF", 4 ) &&
348 !memcmp( &header[8], "WAVE", 4 ) )
350 TRACE( "(%p) - it's audio/wav.\n", pImpl );
351 hr = CWavParseImpl_InitWAV( pImpl, This );
354 if ( !memcmp( &header[0], ".snd", 4 ) )
356 TRACE( "(%p) - it's audio/basic.\n", pImpl );
357 hr = CWavParseImpl_InitAU( pImpl, This );
360 if ( !memcmp( &header[0], "FORM", 4 ) &&
361 !memcmp( &header[8], "AIFF", 4 ) )
363 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
364 hr = CWavParseImpl_InitAIFF( pImpl, This );
368 FIXME( "(%p) - unknown format.\n", pImpl );
377 This->llBytesStop = This->llBytesTotal;
379 /* initialized successfully. */
382 This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
384 TRACE( "(%p) returned successfully.\n", pImpl );
389 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
391 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
393 TRACE("(%p)\n",This);
399 if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
401 QUARTZ_FreeMem( This );
402 pImpl->m_pUserData = NULL;
407 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
409 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
411 TRACE("(%p)\n",This);
413 return QUARTZ_WaveParserOutPin_Name;
416 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
418 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
420 TRACE("(%p)\n",This);
422 if ( This == NULL || This->pFmt == NULL )
425 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
426 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
427 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
428 pmt->bFixedSizeSamples = 1;
429 pmt->bTemporalCompression = 0;
430 pmt->lSampleSize = This->pFmt->nBlockAlign;
431 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
434 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
435 if ( pmt->pbFormat == NULL )
436 return E_OUTOFMEMORY;
437 pmt->cbFormat = This->cbFmt;
438 memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
443 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
445 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
446 !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
448 if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
454 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
456 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
458 TRACE("(%p)\n",This);
460 if ( This == NULL || This->pFmt == NULL )
463 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
464 pReqProp->cBuffers = 1;
465 pReqProp->cbBuffer = This->dwBlockSize;
470 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop, DWORD* pdwSampleFlags )
472 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
477 TRACE("(%p)\n",This);
479 if ( This == NULL || This->pFmt == NULL )
481 *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT;
482 if ( This->bDataDiscontinuity )
484 *pdwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
485 This->bDataDiscontinuity = FALSE;
488 llAvail = This->llBytesStop - This->llBytesProcessed;
489 if ( llAvail > (LONGLONG)This->dwBlockSize )
490 llAvail = (LONGLONG)This->dwBlockSize;
491 llStart = This->llDataStart + This->llBytesProcessed;
492 llEnd = llStart + llAvail;
493 This->llBytesProcessed = llEnd;
495 *pllStart = This->llBytesProcessed;
496 *plLength = (LONG)llAvail;
497 *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
498 *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
503 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
505 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
510 TRACE("(%p)\n",This);
512 hr = IMediaSample_GetPointer(pSample,&pData);
515 lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
516 if ( lActLen != lLength )
519 switch ( This->iFmtType )
521 case WaveParse_Native:
523 case WaveParse_Signed8:
524 AUDIOUTL_ChangeSign8(pData,lActLen);
526 case WaveParse_Signed16BE:
527 AUDIOUTL_ByteSwap(pData,lActLen);
529 case WaveParse_Unsigned16LE:
530 AUDIOUTL_ChangeSign16LE(pData,lActLen);
532 case WaveParse_Unsigned16BE:
533 AUDIOUTL_ChangeSign16BE(pData,lActLen);
534 AUDIOUTL_ByteSwap(pData,lActLen);
537 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
544 /***************************************************************************/
546 static HRESULT CWavParseImpl_GetSeekingCaps( CParserImpl* pImpl, DWORD* pdwCaps )
548 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
550 TRACE("(%p,%p)\n",This,pdwCaps);
553 AM_SEEKING_CanSeekAbsolute |
554 AM_SEEKING_CanSeekForwards |
555 AM_SEEKING_CanSeekBackwards |
556 AM_SEEKING_CanGetCurrentPos |
557 AM_SEEKING_CanGetStopPos |
558 AM_SEEKING_CanGetDuration;
563 static HRESULT CWavParseImpl_IsTimeFormatSupported( CParserImpl* pImpl, const GUID* pTimeFormat )
565 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
567 TRACE("(%p,%s)\n",This,debugstr_guid(pTimeFormat));
569 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
575 static HRESULT CWavParseImpl_GetCurPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos )
577 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
579 TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
581 if ( This == NULL || This->pFmt == NULL )
584 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
586 if ( This->pFmt->nAvgBytesPerSec == 0 )
588 *pllPos = This->llBytesProcessed * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
589 TRACE("curpos %f\n",(double)(*pllPos/QUARTZ_TIMEUNITS));
596 static HRESULT CWavParseImpl_SetCurPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos )
598 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
601 TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
603 if ( This == NULL || This->pFmt == NULL )
606 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
608 if ( This->pFmt->nAvgBytesPerSec == 0 )
610 llBytesCur = llPos * This->pFmt->nAvgBytesPerSec / QUARTZ_TIMEUNITS;
611 if ( llBytesCur > This->llBytesTotal )
612 llBytesCur = This->llBytesTotal;
613 This->llBytesProcessed = llBytesCur;
614 This->bDataDiscontinuity = TRUE;
622 static HRESULT CWavParseImpl_GetDuration( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllDuration )
624 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
626 TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
628 if ( This == NULL || This->pFmt == NULL )
631 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
633 if ( This->pFmt->nAvgBytesPerSec == 0 )
635 *pllDuration = This->llBytesTotal * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
636 TRACE("duration %f\n",(double)(*pllDuration/QUARTZ_TIMEUNITS));
643 static HRESULT CWavParseImpl_GetStopPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos )
645 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
647 TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
649 if ( This == NULL || This->pFmt == NULL )
652 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
654 if ( This->pFmt->nAvgBytesPerSec == 0 )
656 *pllPos = This->llBytesStop * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
663 static HRESULT CWavParseImpl_SetStopPos( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos )
665 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
666 LONGLONG llBytesStop;
668 TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
670 if ( This == NULL || This->pFmt == NULL )
673 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
675 if ( This->pFmt->nAvgBytesPerSec == 0 )
677 llBytesStop = llPos * This->pFmt->nAvgBytesPerSec / QUARTZ_TIMEUNITS;
678 if ( llBytesStop > This->llBytesTotal )
679 llBytesStop = This->llBytesTotal;
680 This->llBytesStop = llBytesStop;
688 static HRESULT CWavParseImpl_GetPreroll( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPreroll )
690 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
692 TRACE("(%p,%s,%lu,...)\n",This,debugstr_guid(pTimeFormat),nStreamIndex);
694 if ( This == NULL || This->pFmt == NULL )
697 if ( IsEqualGUID(pTimeFormat,&TIME_FORMAT_MEDIA_TIME) )
709 /***************************************************************************/
711 static const struct ParserHandlers CWavParseImpl_Handlers =
713 CWavParseImpl_InitParser,
714 CWavParseImpl_UninitParser,
715 CWavParseImpl_GetOutPinName,
716 CWavParseImpl_GetStreamType,
717 CWavParseImpl_CheckStreamType,
718 CWavParseImpl_GetAllocProp,
719 CWavParseImpl_GetNextRequest,
720 CWavParseImpl_ProcessSample,
722 /* for IQualityControl */
723 NULL, /* pQualityNotify */
726 CWavParseImpl_GetSeekingCaps,
727 CWavParseImpl_IsTimeFormatSupported,
728 CWavParseImpl_GetCurPos,
729 CWavParseImpl_SetCurPos,
730 CWavParseImpl_GetDuration,
731 CWavParseImpl_GetStopPos,
732 CWavParseImpl_SetStopPos,
733 CWavParseImpl_GetPreroll,
736 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
738 return QUARTZ_CreateParser(
740 &CLSID_quartzWaveParser,
741 QUARTZ_WaveParser_Name,
742 QUARTZ_WaveParserInPin_Name,
743 &CWavParseImpl_Handlers );