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 llBytesTotal;
184 LONGLONG llBytesProcessed;
185 WavParseFmtType iFmtType;
189 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
195 hr = RIFF_SearchChunk(
196 pImpl, (DWORD)0xffffffff,
197 PARSER_RIFF_OfsFirst, PARSER_fmt,
198 &llOfs, &dwChunkLength );
201 if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
204 This->cbFmt = dwChunkLength;
205 if ( dwChunkLength < sizeof(WAVEFORMATEX) )
206 This->cbFmt = sizeof(WAVEFORMATEX);
207 This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
208 if ( This->pFmt == NULL )
209 return E_OUTOFMEMORY;
210 ZeroMemory( This->pFmt, This->cbFmt );
212 hr = IAsyncReader_SyncRead(
213 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
222 hr = RIFF_SearchChunk(
223 pImpl, (DWORD)0xffffffff,
224 PARSER_RIFF_OfsFirst, PARSER_data,
225 &llOfs, &dwChunkLength );
228 if ( hr != S_OK || dwChunkLength == 0 )
231 This->llDataStart = llOfs;
232 This->llBytesTotal = (LONGLONG)dwChunkLength;
237 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
248 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
252 dataofs = PARSER_BE_UINT32(&au_hdr[4]);
253 datalen = PARSER_BE_UINT32(&au_hdr[8]);
254 datafmt = PARSER_BE_UINT32(&au_hdr[12]);
255 datarate = PARSER_BE_UINT32(&au_hdr[16]);
256 datachannels = PARSER_BE_UINT32(&au_hdr[20]);
258 if ( dataofs < 24U || datalen == 0U )
260 if ( datachannels != 1 && datachannels != 2 )
263 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
264 wfx.nChannels = datachannels;
265 wfx.nSamplesPerSec = datarate;
270 wfx.wFormatTag = WAVE_FORMAT_MULAW;
271 wfx.nBlockAlign = datachannels;
272 wfx.wBitsPerSample = 8;
275 wfx.wFormatTag = WAVE_FORMAT_PCM;
276 wfx.nBlockAlign = datachannels;
277 wfx.wBitsPerSample = 8;
278 This->iFmtType = WaveParse_Signed8;
281 wfx.wFormatTag = WAVE_FORMAT_PCM;
282 wfx.nBlockAlign = datachannels;
283 wfx.wBitsPerSample = 16;
284 This->iFmtType = WaveParse_Signed16BE;
287 FIXME("audio/basic - unknown format %lu\n", datafmt );
290 wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
292 This->cbFmt = sizeof(WAVEFORMATEX);
293 This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
294 if ( This->pFmt == NULL )
295 return E_OUTOFMEMORY;
296 memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
298 This->llDataStart = dataofs;
299 This->llBytesTotal = datalen;
301 TRACE("offset %lu, length %lu\n",dataofs,datalen);
306 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
308 FIXME( "AIFF is not supported now.\n" );
312 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
314 CWavParseImpl* This = NULL;
318 TRACE("(%p,%p)\n",pImpl,pcStreams);
320 if ( pImpl->m_pReader == NULL )
323 This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
325 return E_OUTOFMEMORY;
326 pImpl->m_pUserData = This;
331 This->dwBlockSize = 0;
332 This->llDataStart = 0;
333 This->llBytesTotal = 0;
334 This->llBytesProcessed = 0;
335 This->iFmtType = WaveParse_Native;
337 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
343 if ( !memcmp( &header[0], "RIFF", 4 ) &&
344 !memcmp( &header[8], "WAVE", 4 ) )
346 TRACE( "(%p) - it's audio/wav.\n", pImpl );
347 hr = CWavParseImpl_InitWAV( pImpl, This );
350 if ( !memcmp( &header[0], ".snd", 4 ) )
352 TRACE( "(%p) - it's audio/basic.\n", pImpl );
353 hr = CWavParseImpl_InitAU( pImpl, This );
356 if ( !memcmp( &header[0], "FORM", 4 ) &&
357 !memcmp( &header[8], "AIFF", 4 ) )
359 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
360 hr = CWavParseImpl_InitAIFF( pImpl, This );
364 FIXME( "(%p) - unknown format.\n", pImpl );
373 /* initialized successfully. */
376 This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
378 TRACE( "(%p) returned successfully.\n", pImpl );
383 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
385 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
387 TRACE("(%p)\n",This);
393 if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
395 QUARTZ_FreeMem( This );
396 pImpl->m_pUserData = NULL;
401 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
403 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
405 TRACE("(%p)\n",This);
407 return QUARTZ_WaveParserOutPin_Name;
410 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
412 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
414 TRACE("(%p)\n",This);
416 if ( This == NULL || This->pFmt == NULL )
419 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
420 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
421 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
422 pmt->bFixedSizeSamples = 1;
423 pmt->bTemporalCompression = 0;
424 pmt->lSampleSize = This->pFmt->nBlockAlign;
425 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
428 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
429 if ( pmt->pbFormat == NULL )
430 return E_OUTOFMEMORY;
431 pmt->cbFormat = This->cbFmt;
432 memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
437 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
439 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
440 !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
442 if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
448 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
450 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
452 TRACE("(%p)\n",This);
454 if ( This == NULL || This->pFmt == NULL )
457 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
458 pReqProp->cBuffers = 1;
459 pReqProp->cbBuffer = This->dwBlockSize;
464 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
466 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
471 TRACE("(%p)\n",This);
473 if ( This == NULL || This->pFmt == NULL )
476 llAvail = This->llBytesTotal - This->llBytesProcessed;
477 if ( llAvail > (LONGLONG)This->dwBlockSize )
478 llAvail = (LONGLONG)This->dwBlockSize;
479 llStart = This->llDataStart + This->llBytesProcessed;
480 llEnd = llStart + llAvail;
481 This->llBytesProcessed = llEnd;
483 *pllStart = This->llBytesProcessed;
484 *plLength = (LONG)llAvail;
485 *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
486 *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
491 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
493 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
498 TRACE("(%p)\n",This);
500 hr = IMediaSample_GetPointer(pSample,&pData);
503 lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
504 if ( lActLen != lLength )
507 switch ( This->iFmtType )
509 case WaveParse_Native:
511 case WaveParse_Signed8:
512 AUDIOUTL_ChangeSign8(pData,lActLen);
514 case WaveParse_Signed16BE:
515 AUDIOUTL_ByteSwap(pData,lActLen);
517 case WaveParse_Unsigned16LE:
518 AUDIOUTL_ChangeSign16LE(pData,lActLen);
520 case WaveParse_Unsigned16BE:
521 AUDIOUTL_ChangeSign16BE(pData,lActLen);
522 AUDIOUTL_ByteSwap(pData,lActLen);
525 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
533 static const struct ParserHandlers CWavParseImpl_Handlers =
535 CWavParseImpl_InitParser,
536 CWavParseImpl_UninitParser,
537 CWavParseImpl_GetOutPinName,
538 CWavParseImpl_GetStreamType,
539 CWavParseImpl_CheckStreamType,
540 CWavParseImpl_GetAllocProp,
541 CWavParseImpl_GetNextRequest,
542 CWavParseImpl_ProcessSample,
544 /* for IQualityControl */
545 NULL, /* pQualityNotify */
548 NULL, /* pGetSeekingCaps */
549 NULL, /* pIsTimeFormatSupported */
550 NULL, /* pGetCurPos */
551 NULL, /* pSetCurPos */
552 NULL, /* pGetDuration */
553 NULL, /* pSetDuration */
554 NULL, /* pGetStopPos */
555 NULL, /* pSetStopPos */
556 NULL, /* pGetPreroll */
557 NULL, /* pSetPreroll */
560 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
562 return QUARTZ_CreateParser(
564 &CLSID_quartzWaveParser,
565 QUARTZ_WaveParser_Name,
566 QUARTZ_WaveParserInPin_Name,
567 &CWavParseImpl_Handlers );