Add $X_LIBS path while searching for libfreetype.
[wine/gsoc_dplay.git] / dlls / quartz / wavparse.c
bloba7706bbfe26f5ce174e9436b8ac1fdc420dc9691
1 /*
2 * Implements WAVE/AU/AIFF Parser.
4 * hidenori@a2.ctktv.ne.jp
5 */
7 #include "config.h"
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "mmsystem.h"
14 #include "mmreg.h"
15 #include "winerror.h"
16 #include "strmif.h"
17 #include "control.h"
18 #include "vfwmsgs.h"
19 #include "uuids.h"
21 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(quartz);
24 #include "quartz_private.h"
25 #include "audioutl.h"
26 #include "parser.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[] =
32 { 'I','n',0 };
33 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
34 { 'O','u','t',0 };
37 /****************************************************************************/
39 /* S_OK = found, S_FALSE = not found */
40 HRESULT RIFF_GetNext(
41 CParserImpl* pImpl, LONGLONG llOfs,
42 DWORD* pdwCode, DWORD* pdwLength )
44 BYTE bTemp[8];
45 HRESULT hr;
47 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
48 if ( hr == S_OK )
50 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
51 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
53 else
55 *pdwCode = 0;
56 *pdwLength = 0;
59 return hr;
62 /* S_OK = found, S_FALSE = not found */
63 HRESULT RIFF_SearchChunk(
64 CParserImpl* pImpl,
65 DWORD dwSearchLengthMax,
66 LONGLONG llOfs, DWORD dwChunk,
67 LONGLONG* pllOfs, DWORD* pdwChunkLength )
69 HRESULT hr;
70 DWORD dwCurCode;
71 DWORD dwCurLen;
72 LONGLONG llCurLen;
74 while ( 1 )
76 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
77 if ( hr != S_OK )
78 break;
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 )
86 break;
87 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
88 llOfs += llCurLen;
89 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
90 return S_FALSE;
91 if ( dwSearchLengthMax != (DWORD)0xffffffff )
92 dwSearchLengthMax -= (DWORD)llCurLen;
95 *pllOfs = llOfs + 8;
96 *pdwChunkLength = dwCurLen;
98 return hr;
101 /* S_OK = found, S_FALSE = not found */
102 HRESULT RIFF_SearchList(
103 CParserImpl* pImpl,
104 DWORD dwSearchLengthMax,
105 LONGLONG llOfs, DWORD dwListChunk,
106 LONGLONG* pllOfs, DWORD* pdwChunkLength )
108 HRESULT hr;
109 DWORD dwCurLen;
110 LONGLONG llCurLen;
111 BYTE bTemp[4];
113 while ( 1 )
115 hr = RIFF_SearchChunk(
116 pImpl, dwSearchLengthMax,
117 llOfs, PARSER_LIST,
118 &llOfs, &dwCurLen );
119 if ( hr != S_OK )
120 break;
122 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
123 if ( hr != S_OK )
124 break;
126 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
127 break;
129 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
130 llOfs += llCurLen;
131 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
132 return S_FALSE;
133 if ( dwSearchLengthMax != (DWORD)0xffffffff )
134 dwSearchLengthMax -= (DWORD)(llCurLen+8);
137 if ( dwCurLen < 12 )
138 return E_FAIL;
140 *pllOfs = llOfs+4;
141 *pdwChunkLength = dwCurLen-4;
143 return hr;
149 /****************************************************************************
151 * CWavParseImpl
154 typedef enum WavParseFmtType
156 WaveParse_Native,
157 WaveParse_Signed8,
158 WaveParse_Signed16BE,
159 WaveParse_Unsigned16LE,
160 WaveParse_Unsigned16BE,
161 } WavParseFmtType;
163 typedef struct CWavParseImpl
165 DWORD cbFmt;
166 WAVEFORMATEX* pFmt;
167 DWORD dwBlockSize;
168 LONGLONG llDataStart;
169 LONGLONG llBytesTotal;
170 LONGLONG llBytesProcessed;
171 WavParseFmtType iFmtType;
172 } CWavParseImpl;
175 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
177 HRESULT hr;
178 LONGLONG llOfs;
179 DWORD dwChunkLength;
181 hr = RIFF_SearchChunk(
182 pImpl, (DWORD)0xffffffff,
183 PARSER_RIFF_OfsFirst, PARSER_fmt,
184 &llOfs, &dwChunkLength );
185 if ( FAILED(hr) )
186 return hr;
187 if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
188 return E_FAIL;
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 );
200 if ( hr != S_OK )
202 if ( SUCCEEDED(hr) )
203 hr = E_FAIL;
204 return hr;
208 hr = RIFF_SearchChunk(
209 pImpl, (DWORD)0xffffffff,
210 PARSER_RIFF_OfsFirst, PARSER_data,
211 &llOfs, &dwChunkLength );
212 if ( FAILED(hr) )
213 return hr;
214 if ( hr != S_OK || dwChunkLength == 0 )
215 return E_FAIL;
217 This->llDataStart = llOfs;
218 This->llBytesTotal = (LONGLONG)dwChunkLength;
220 return NOERROR;
223 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
225 BYTE au_hdr[24];
226 DWORD dataofs;
227 DWORD datalen;
228 DWORD datafmt;
229 DWORD datarate;
230 DWORD datachannels;
231 HRESULT hr;
232 WAVEFORMATEX wfx;
234 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
235 if ( FAILED(hr) )
236 return hr;
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 )
245 return E_FAIL;
246 if ( datachannels != 1 && datachannels != 2 )
247 return E_FAIL;
249 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
250 wfx.nChannels = datachannels;
251 wfx.nSamplesPerSec = datarate;
253 switch ( datafmt )
255 case 1:
256 wfx.wFormatTag = WAVE_FORMAT_MULAW;
257 wfx.nBlockAlign = datachannels;
258 wfx.wBitsPerSample = 8;
259 break;
260 case 2:
261 wfx.wFormatTag = WAVE_FORMAT_PCM;
262 wfx.nBlockAlign = datachannels;
263 wfx.wBitsPerSample = 8;
264 This->iFmtType = WaveParse_Signed8;
265 break;
266 case 3:
267 wfx.wFormatTag = WAVE_FORMAT_PCM;
268 wfx.nBlockAlign = datachannels;
269 wfx.wBitsPerSample = 16;
270 This->iFmtType = WaveParse_Signed16BE;
271 break;
272 default:
273 FIXME("audio/basic - unknown format %lu\n", datafmt );
274 return E_FAIL;
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);
289 return NOERROR;
292 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
294 FIXME( "AIFF is not supported now.\n" );
295 return E_FAIL;
298 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
300 CWavParseImpl* This = NULL;
301 HRESULT hr;
302 BYTE header[12];
304 TRACE("(%p,%p)\n",pImpl,pcStreams);
306 if ( pImpl->m_pReader == NULL )
307 return E_UNEXPECTED;
309 This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
310 if ( This == NULL )
311 return E_OUTOFMEMORY;
312 pImpl->m_pUserData = This;
314 /* construct */
315 This->cbFmt = 0;
316 This->pFmt = NULL;
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 );
324 if ( FAILED(hr) )
325 return hr;
326 if ( hr != S_OK )
327 return E_FAIL;
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 );
335 else
336 if ( !memcmp( &header[0], ".snd", 4 ) )
338 TRACE( "(%p) - it's audio/basic.\n", pImpl );
339 hr = CWavParseImpl_InitAU( pImpl, This );
341 else
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 );
348 else
350 FIXME( "(%p) - unknown format.\n", pImpl );
351 hr = E_FAIL;
354 if ( FAILED(hr) )
356 return hr;
359 /* initialized successfully. */
360 *pcStreams = 1;
362 This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
364 TRACE( "(%p) returned successfully.\n", pImpl );
366 return NOERROR;
369 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
371 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
373 TRACE("(%p)\n",This);
375 if ( This == NULL )
376 return NOERROR;
378 /* destruct */
379 if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
381 QUARTZ_FreeMem( This );
382 pImpl->m_pUserData = NULL;
384 return NOERROR;
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 )
403 return E_UNEXPECTED;
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) );
412 pmt->pUnk = NULL;
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 );
420 return NOERROR;
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 ) )
427 return E_FAIL;
428 if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
429 return E_FAIL;
431 return NOERROR;
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 )
441 return E_UNEXPECTED;
443 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
444 pReqProp->cBuffers = 1;
445 pReqProp->cbBuffer = This->dwBlockSize;
447 return NOERROR;
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;
453 LONGLONG llAvail;
454 LONGLONG llStart;
455 LONGLONG llEnd;
457 TRACE("(%p)\n",This);
459 if ( This == NULL || This->pFmt == NULL )
460 return E_UNEXPECTED;
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;
474 return NOERROR;
477 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
479 CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
480 BYTE* pData;
481 LONG lActLen;
482 HRESULT hr;
484 TRACE("(%p)\n",This);
486 hr = IMediaSample_GetPointer(pSample,&pData);
487 if ( FAILED(hr) )
488 return hr;
489 lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
490 if ( lActLen != lLength )
491 return E_FAIL;
493 switch ( This->iFmtType )
495 case WaveParse_Native:
496 break;
497 case WaveParse_Signed8:
498 AUDIOUTL_ChangeSign8(pData,lActLen);
499 break;
500 case WaveParse_Signed16BE:
501 AUDIOUTL_ByteSwap(pData,lActLen);
502 break;
503 case WaveParse_Unsigned16LE:
504 AUDIOUTL_ChangeSign16LE(pData,lActLen);
505 break;
506 case WaveParse_Unsigned16BE:
507 AUDIOUTL_ChangeSign16BE(pData,lActLen);
508 AUDIOUTL_ByteSwap(pData,lActLen);
509 break;
510 default:
511 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
512 return E_FAIL;
515 return NOERROR;
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 */
533 /* for seeking */
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(
549 punkOuter,ppobj,
550 &CLSID_quartzWaveParser,
551 QUARTZ_WaveParser_Name,
552 QUARTZ_WaveParserInPin_Name,
553 &CWavParseImpl_Handlers );