Added some stubs.
[wine/multimedia.git] / dlls / quartz / aviparse.c
blobec5c3fbce16647697eafb25a5a2bb675b6c77a5c
1 /*
2 * Implements AVI Parser(Splitter).
4 * FIXME - no seeking
6 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "vfw.h"
31 #include "winerror.h"
32 #include "strmif.h"
33 #include "control.h"
34 #include "vfwmsgs.h"
35 #include "amvideo.h"
36 #include "uuids.h"
38 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
41 #include "quartz_private.h"
42 #include "parser.h"
43 #include "mtype.h"
47 static const WCHAR QUARTZ_AVIParser_Name[] =
48 { 'A','V','I',' ','S','p','l','i','t','t','e','r',0 };
49 static const WCHAR QUARTZ_AVIParserInPin_Name[] =
50 { 'I','n',0 };
51 static const WCHAR QUARTZ_AVIParserOutPin_Basename[] =
52 { 'S','t','r','e','a','m',0 };
54 #define WINE_QUARTZ_AVIPINNAME_MAX 64
56 /****************************************************************************
58 * CAVIParseImpl
62 typedef struct CAVIParseImpl CAVIParseImpl;
63 typedef struct CAVIParseStream CAVIParseStream;
65 struct CAVIParseImpl
67 MainAVIHeader avih;
68 CAVIParseStream* pStreamsBuf;
69 DWORD cIndexEntries;
70 AVIINDEXENTRY* pIndexEntriesBuf;
71 WCHAR wchWork[ WINE_QUARTZ_AVIPINNAME_MAX ];
74 struct CAVIParseStream
76 AVIStreamHeader strh;
77 DWORD cbFmt;
78 BYTE* pFmtBuf;
79 DWORD cIndexEntries;
80 AVIINDEXENTRY* pIndexEntries;
81 DWORD cIndexCur;
82 REFERENCE_TIME rtCur;
83 REFERENCE_TIME rtInternal;
84 BOOL bDataDiscontinuity;
88 static HRESULT CAVIParseImpl_ParseStreamList(
89 CParserImpl* pImpl, CAVIParseImpl* This, ULONG nStreamIndex,
90 LONGLONG llOfsTop, DWORD dwListLen, CAVIParseStream* pStream )
92 HRESULT hr;
93 LONGLONG llOfs;
94 DWORD dwChunkLength;
96 TRACE("search strh\n");
97 hr = RIFF_SearchChunk(
98 pImpl, dwListLen,
99 llOfsTop, PARSER_strh,
100 &llOfs, &dwChunkLength );
101 if ( hr == S_OK )
103 TRACE("strh has been detected\n");
104 if ( dwChunkLength < sizeof(AVIStreamHeader) )
105 hr = E_FAIL;
106 else
107 hr = IAsyncReader_SyncRead( pImpl->m_pReader,
108 llOfs, sizeof(AVIStreamHeader), (BYTE*)&pStream->strh );
110 if ( FAILED(hr) )
111 return hr;
112 if ( hr != S_OK )
113 return E_FAIL;
115 TRACE("search strf\n");
116 hr = RIFF_SearchChunk(
117 pImpl, dwListLen,
118 llOfsTop, PARSER_strf,
119 &llOfs, &dwChunkLength );
120 if ( hr == S_OK && dwChunkLength > 0 )
122 TRACE("strf has been detected\n");
123 pStream->cbFmt = dwChunkLength;
124 pStream->pFmtBuf = (BYTE*)QUARTZ_AllocMem( dwChunkLength );
125 if ( pStream->pFmtBuf == NULL )
126 hr = E_OUTOFMEMORY;
127 else
128 hr = IAsyncReader_SyncRead( pImpl->m_pReader,
129 llOfs, dwChunkLength, pStream->pFmtBuf );
131 if ( FAILED(hr) )
132 return hr;
134 TRACE("search indx\n");
135 hr = RIFF_SearchChunk(
136 pImpl, dwListLen,
137 llOfsTop, PARSER_indx,
138 &llOfs, &dwChunkLength );
139 if ( FAILED(hr) )
140 return hr;
141 if ( hr == S_OK )
143 FIXME( "'indx' has been detected - not implemented now!\n" );
144 return E_FAIL;
147 return NOERROR;
151 static HRESULT CAVIParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
153 CAVIParseImpl* This = NULL;
154 BYTE riffhdr[12];
155 ULONG i;
156 ULONG nIndex;
157 HRESULT hr;
158 LONGLONG llOfs_hdrl;
159 DWORD dwLen_hdrl;
160 LONGLONG llOfs;
161 DWORD dwChunkId;
162 DWORD dwChunkLength;
163 AVIINDEXENTRY* pEntriesBuf = NULL;
164 ULONG cEntries;
165 ULONG cEntriesCur;
167 TRACE("(%p,%p)\n",pImpl,pcStreams);
169 hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, riffhdr );
170 if ( FAILED(hr) )
171 return hr;
172 if ( hr != S_OK )
173 return E_FAIL;
174 if ( memcmp( &riffhdr[0], "RIFF", 4 ) != 0 ||
175 memcmp( &riffhdr[8], "AVI ", 4 ) != 0 )
176 return E_FAIL;
178 TRACE("it's AVI\n");
180 This = (CAVIParseImpl*)QUARTZ_AllocMem( sizeof(CAVIParseImpl) );
181 if ( This == NULL )
182 return E_OUTOFMEMORY;
183 pImpl->m_pUserData = This;
184 ZeroMemory( This, sizeof(CAVIParseImpl) );
185 This->pStreamsBuf = NULL;
186 This->cIndexEntries = 0;
187 This->pIndexEntriesBuf = 0;
189 hr = RIFF_SearchList(
190 pImpl, (DWORD)0xffffffff,
191 PARSER_RIFF_OfsFirst, PARSER_hdrl,
192 &llOfs_hdrl, &dwLen_hdrl );
193 if ( FAILED(hr) )
194 return hr;
195 if ( hr != S_OK )
196 return E_FAIL;
198 /* read 'avih' */
199 TRACE("read avih\n");
200 hr = RIFF_SearchChunk(
201 pImpl, dwLen_hdrl,
202 llOfs_hdrl, PARSER_avih,
203 &llOfs, &dwChunkLength );
204 if ( FAILED(hr) )
205 return hr;
206 if ( hr != S_OK )
207 return E_FAIL;
209 if ( dwChunkLength > sizeof(MainAVIHeader) )
210 dwChunkLength = sizeof(MainAVIHeader);
211 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)&(This->avih) );
212 if ( FAILED(hr) )
213 return hr;
214 if ( hr != S_OK )
215 return E_FAIL;
216 if ( This->avih.dwStreams == 0 )
217 return E_FAIL;
219 /* initialize streams. */
220 This->pStreamsBuf = (CAVIParseStream*)QUARTZ_AllocMem(
221 sizeof(CAVIParseStream) * This->avih.dwStreams );
222 if ( This->pStreamsBuf == NULL )
223 return E_OUTOFMEMORY;
224 ZeroMemory( This->pStreamsBuf,
225 sizeof(CAVIParseStream) * This->avih.dwStreams );
227 llOfs = llOfs_hdrl;
228 for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
230 TRACE("search strl for stream %lu\n",nIndex);
231 hr = RIFF_SearchList(
232 pImpl,
233 dwLen_hdrl, llOfs, PARSER_strl,
234 &llOfs, &dwChunkLength );
235 if ( FAILED(hr) )
236 return hr;
237 if ( hr != S_OK )
238 return E_FAIL;
240 /* read 'strl'. */
241 hr = CAVIParseImpl_ParseStreamList(
242 pImpl, This, nIndex,
243 llOfs, dwChunkLength, &This->pStreamsBuf[nIndex] );
245 if ( FAILED(hr) )
246 return hr;
247 if ( hr != S_OK )
248 return E_FAIL;
249 llOfs += dwChunkLength;
252 /* initialize idx1. */
253 TRACE("search idx1\n");
254 hr = RIFF_SearchChunk(
255 pImpl, (DWORD)0xffffffff,
256 PARSER_RIFF_OfsFirst, PARSER_idx1,
257 &llOfs, &dwChunkLength );
258 if ( FAILED(hr) )
259 return hr;
260 if ( hr == S_OK )
262 /* read idx1. */
263 This->cIndexEntries = dwChunkLength / sizeof(AVIINDEXENTRY);
264 This->pIndexEntriesBuf = (AVIINDEXENTRY*)QUARTZ_AllocMem(
265 sizeof(AVIINDEXENTRY) * This->cIndexEntries );
266 if ( This->pIndexEntriesBuf == NULL )
267 return E_OUTOFMEMORY;
268 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, sizeof(AVIINDEXENTRY) * This->cIndexEntries, (BYTE*)This->pIndexEntriesBuf );
269 if ( FAILED(hr) )
270 return hr;
271 if ( hr != S_OK )
272 return E_FAIL;
274 pEntriesBuf = (AVIINDEXENTRY*)QUARTZ_AllocMem(
275 sizeof(AVIINDEXENTRY) * This->cIndexEntries );
276 if ( pEntriesBuf == NULL )
277 return E_OUTOFMEMORY;
278 cEntries = 0;
279 for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
281 cEntriesCur = cEntries;
282 dwChunkId = (((nIndex%10)+'0')<<8) | ((nIndex/10)+'0');
283 for ( i = 0; i < This->cIndexEntries; i++ )
285 if ( (This->pIndexEntriesBuf[i].ckid & 0xffff) == dwChunkId )
286 memcpy( &pEntriesBuf[cEntries++], &This->pIndexEntriesBuf[i], sizeof(AVIINDEXENTRY) );
288 This->pStreamsBuf[nIndex].pIndexEntries = &pEntriesBuf[cEntriesCur];
289 This->pStreamsBuf[nIndex].cIndexEntries = cEntries - cEntriesCur;
290 This->pStreamsBuf[nIndex].cIndexCur = 0;
291 This->pStreamsBuf[nIndex].rtCur = 0;
292 This->pStreamsBuf[nIndex].rtInternal = 0;
293 TRACE("stream %lu - %lu entries\n",nIndex,This->pStreamsBuf[nIndex].cIndexEntries);
294 This->pStreamsBuf[nIndex].bDataDiscontinuity = TRUE;
296 QUARTZ_FreeMem(This->pIndexEntriesBuf);
297 This->pIndexEntriesBuf = pEntriesBuf;
299 This->avih.dwSuggestedBufferSize = 0;
300 for ( i = 0; i < This->cIndexEntries; i++ )
302 if ( This->avih.dwSuggestedBufferSize < This->pIndexEntriesBuf[i].dwChunkLength )
303 This->avih.dwSuggestedBufferSize = This->pIndexEntriesBuf[i].dwChunkLength;
306 else
308 return E_FAIL;
311 if ( This->avih.dwStreams > 100 )
312 return E_FAIL;
314 *pcStreams = This->avih.dwStreams;
316 return NOERROR;
319 static HRESULT CAVIParseImpl_UninitParser( CParserImpl* pImpl )
321 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
322 ULONG nIndex;
324 TRACE("(%p)\n",This);
326 if ( This == NULL )
327 return NOERROR;
329 /* destruct */
330 if ( This->pStreamsBuf != NULL )
332 for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
334 /* release this stream */
335 if ( This->pStreamsBuf[nIndex].pFmtBuf != NULL )
336 QUARTZ_FreeMem(This->pStreamsBuf[nIndex].pFmtBuf);
338 QUARTZ_FreeMem( This->pStreamsBuf );
339 This->pStreamsBuf = NULL;
342 if ( This->pIndexEntriesBuf != NULL )
344 QUARTZ_FreeMem( This->pIndexEntriesBuf );
345 This->pIndexEntriesBuf = NULL;
348 QUARTZ_FreeMem( This );
349 pImpl->m_pUserData = NULL;
351 return NOERROR;
354 static LPCWSTR CAVIParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
356 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
357 int wlen;
359 TRACE("(%p,%lu)\n",This,nStreamIndex);
361 if ( This == NULL || nStreamIndex >= This->avih.dwStreams )
362 return NULL;
364 wlen = lstrlenW(QUARTZ_AVIParserOutPin_Basename);
365 memcpy( This->wchWork, QUARTZ_AVIParserOutPin_Basename, sizeof(WCHAR)*wlen );
366 This->wchWork[ wlen ] = (nStreamIndex/10) + '0';
367 This->wchWork[ wlen+1 ] = (nStreamIndex%10) + '0';
368 This->wchWork[ wlen+2 ] = 0;
370 return This->wchWork;
373 static HRESULT CAVIParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
375 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
376 VIDEOINFOHEADER* pvi;
377 BITMAPINFOHEADER* pbi;
378 WAVEFORMATEX* pwfx;
379 DWORD cbFmt;
380 DWORD cb;
381 HRESULT hr;
383 TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt);
385 if ( This == NULL )
386 return E_UNEXPECTED;
387 if ( nStreamIndex >= This->avih.dwStreams )
388 return E_INVALIDARG;
390 cbFmt = This->pStreamsBuf[nStreamIndex].cbFmt;
392 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
393 switch ( This->pStreamsBuf[nStreamIndex].strh.fccType )
395 case PARSER_vids:
396 pbi = (BITMAPINFOHEADER*)This->pStreamsBuf[nStreamIndex].pFmtBuf;
397 if ( pbi == NULL || cbFmt < sizeof(BITMAPINFOHEADER) )
398 goto unknown_format;
400 memcpy( &pmt->majortype, &MEDIATYPE_Video, sizeof(GUID) );
401 hr = QUARTZ_MediaSubType_FromBitmap( &pmt->subtype, pbi );
402 if ( FAILED(hr) )
403 goto unknown_format;
404 if ( hr != S_OK )
405 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)pbi->biCompression );
407 pmt->bFixedSizeSamples = QUARTZ_BitmapHasFixedSample( pbi ) ? 1 : 0;
408 pmt->bTemporalCompression = 0; /* FIXME - 1 if inter-frame compression is used */
409 pmt->lSampleSize = ( pbi->biCompression == 0 ) ? DIBSIZE(*pbi) : pbi->biSizeImage;
410 memcpy( &pmt->formattype, &FORMAT_VideoInfo, sizeof(GUID) );
412 cb = sizeof(VIDEOINFOHEADER) + cbFmt;
413 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( cb );
414 if ( pmt->pbFormat == NULL )
415 return E_OUTOFMEMORY;
416 ZeroMemory( pmt->pbFormat, cb );
417 pvi = (VIDEOINFOHEADER*)pmt->pbFormat;
418 pmt->cbFormat = cb;
419 memcpy( &pvi->bmiHeader, pbi, cbFmt );
420 break;
421 case PARSER_auds:
422 pwfx = (WAVEFORMATEX*)This->pStreamsBuf[nStreamIndex].pFmtBuf;
423 if ( pwfx == NULL || cbFmt < (sizeof(WAVEFORMATEX)-2) )
424 goto unknown_format;
426 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
427 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)pwfx->wFormatTag );
428 pmt->bFixedSizeSamples = 1;
429 pmt->bTemporalCompression = 0;
430 pmt->lSampleSize = pwfx->nBlockAlign;
431 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
432 pmt->pUnk = NULL;
434 cb = ( cbFmt < sizeof(WAVEFORMATEX) ) ? sizeof(WAVEFORMATEX) : cbFmt;
435 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( cb );
436 if ( pmt->pbFormat == NULL )
437 return E_OUTOFMEMORY;
438 ZeroMemory( pmt->pbFormat, cb );
439 pmt->cbFormat = cbFmt;
440 memcpy( pmt->pbFormat, pwfx, cbFmt );
441 break;
442 case PARSER_mids:
443 /* FIXME? */
444 memcpy( &pmt->majortype, &MEDIATYPE_Midi, sizeof(GUID) );
445 memcpy( &pmt->subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
446 pmt->bFixedSizeSamples = 0;
447 pmt->bTemporalCompression = 0;
448 pmt->lSampleSize = 1;
449 memcpy( &pmt->formattype, &FORMAT_None, sizeof(GUID) );
450 pmt->pUnk = NULL;
451 pmt->cbFormat = 0;
452 pmt->pbFormat = NULL;
453 break;
454 case PARSER_txts:
455 /* FIXME? */
456 memcpy( &pmt->majortype, &MEDIATYPE_Text, sizeof(GUID) );
457 memcpy( &pmt->subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
458 pmt->bFixedSizeSamples = 0;
459 pmt->bTemporalCompression = 0;
460 pmt->lSampleSize = 1;
461 memcpy( &pmt->formattype, &FORMAT_None, sizeof(GUID) );
462 pmt->pUnk = NULL;
463 pmt->cbFormat = 0;
464 pmt->pbFormat = NULL;
465 break;
466 default:
467 goto unknown_format;
470 return NOERROR;
472 unknown_format:;
473 FIXME( "(%p) unsupported stream type %c%c%c%c\n",This,
474 (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>> 0)&0xff),
475 (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>> 8)&0xff),
476 (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>>16)&0xff),
477 (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>>24)&0xff) );
479 memcpy( &pmt->majortype, &MEDIATYPE_NULL, sizeof(GUID) );
480 memcpy( &pmt->subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
481 pmt->bFixedSizeSamples = 0;
482 pmt->bTemporalCompression = 0;
483 pmt->lSampleSize = 1;
484 memcpy( &pmt->formattype, &FORMAT_None, sizeof(GUID) );
485 pmt->pUnk = NULL;
486 pmt->cbFormat = 0;
487 pmt->pbFormat = NULL;
489 return NOERROR;
492 static HRESULT CAVIParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
494 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
495 HRESULT hr;
496 AM_MEDIA_TYPE mt;
497 VIDEOINFOHEADER* pvi;
498 VIDEOINFOHEADER* pviCheck;
499 WAVEFORMATEX* pwfx;
500 WAVEFORMATEX* pwfxCheck;
502 TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt);
504 hr = CAVIParseImpl_GetStreamType( pImpl, nStreamIndex, &mt );
505 if ( FAILED(hr) )
506 return hr;
508 TRACE("check GUIDs - %s,%s\n",debugstr_guid(&pmt->majortype),debugstr_guid(&pmt->subtype));
509 if ( !IsEqualGUID( &pmt->majortype, &mt.majortype ) ||
510 !IsEqualGUID( &pmt->subtype, &mt.subtype ) ||
511 !IsEqualGUID( &pmt->formattype, &mt.formattype ) )
513 hr = E_FAIL;
514 goto end;
517 TRACE("check format\n");
518 hr = S_OK;
519 switch ( This->pStreamsBuf[nStreamIndex].strh.fccType )
521 case PARSER_vids:
522 TRACE("check vids\n");
523 pvi = (VIDEOINFOHEADER*)mt.pbFormat;
524 pviCheck = (VIDEOINFOHEADER*)pmt->pbFormat;
525 if ( pvi == NULL || pviCheck == NULL || pmt->cbFormat < sizeof(VIDEOINFOHEADER) )
526 hr = E_FAIL;
527 if ( pvi->bmiHeader.biWidth != pviCheck->bmiHeader.biWidth ||
528 pvi->bmiHeader.biHeight != pviCheck->bmiHeader.biHeight ||
529 pvi->bmiHeader.biPlanes != pviCheck->bmiHeader.biPlanes ||
530 pvi->bmiHeader.biBitCount != pviCheck->bmiHeader.biBitCount ||
531 pvi->bmiHeader.biCompression != pviCheck->bmiHeader.biCompression ||
532 pvi->bmiHeader.biClrUsed != pviCheck->bmiHeader.biClrUsed )
533 hr = E_FAIL;
534 break;
535 case PARSER_auds:
536 TRACE("check auds\n");
537 pwfx = (WAVEFORMATEX*)mt.pbFormat;
538 pwfxCheck = (WAVEFORMATEX*)pmt->pbFormat;
539 if ( pwfx == NULL || pwfxCheck == NULL || pmt->cbFormat < (sizeof(WAVEFORMATEX)-2) )
540 hr = E_FAIL;
541 if ( pwfx->wFormatTag != pwfxCheck->wFormatTag ||
542 pwfx->nBlockAlign != pwfxCheck->nBlockAlign ||
543 pwfx->wBitsPerSample != pwfxCheck->wBitsPerSample ||
544 pwfx->nChannels != pwfxCheck->nChannels ||
545 pwfx->nSamplesPerSec != pwfxCheck->nSamplesPerSec )
546 hr = E_FAIL;
547 break;
548 case PARSER_mids:
549 case PARSER_txts:
550 break;
551 default:
552 break;
554 end:
555 QUARTZ_MediaType_Free( &mt );
557 TRACE("%08lx\n",hr);
559 return hr;
562 static HRESULT CAVIParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
564 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
566 TRACE("(%p,%p)\n",This,pReqProp);
567 if ( This == NULL )
568 return E_UNEXPECTED;
570 ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
571 pReqProp->cBuffers = This->avih.dwStreams;
572 pReqProp->cbBuffer = This->avih.dwSuggestedBufferSize;
574 return NOERROR;
577 static HRESULT CAVIParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop, DWORD* pdwSampleFlags )
579 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
580 REFERENCE_TIME rtNext;
581 DWORD nIndexNext;
582 DWORD nIndex;
583 CAVIParseStream* pStream;
584 const WAVEFORMATEX* pwfx;
586 TRACE("(%p)\n",This);
588 if ( This == NULL )
589 return E_UNEXPECTED;
590 *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT;
592 nIndexNext = This->avih.dwStreams;
593 rtNext = ((REFERENCE_TIME)0x7fffffff<<32)|((REFERENCE_TIME)0xffffffff);
594 for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
596 TRACE("stream %lu - %lu,%lu\n",nIndex,(unsigned long)(This->pStreamsBuf[nIndex].rtCur*1000/QUARTZ_TIMEUNITS),This->pStreamsBuf[nIndex].cIndexCur);
597 if ( rtNext > This->pStreamsBuf[nIndex].rtCur &&
598 This->pStreamsBuf[nIndex].cIndexCur < This->pStreamsBuf[nIndex].cIndexEntries )
600 nIndexNext = nIndex;
601 rtNext = This->pStreamsBuf[nIndex].rtCur;
604 if ( nIndexNext >= This->avih.dwStreams )
605 return S_FALSE;
607 if ( This->pIndexEntriesBuf != NULL )
609 pStream = &This->pStreamsBuf[nIndexNext];
610 *pnStreamIndex = nIndexNext;
611 *pllStart = (LONGLONG)pStream->pIndexEntries[pStream->cIndexCur].dwChunkOffset + 8;
612 *plLength = (LONG)pStream->pIndexEntries[pStream->cIndexCur].dwChunkLength;
613 *prtStart = rtNext;
614 *prtStop = rtNext;
615 /* FIXME - is this frame keyframe?? */
616 *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT;
617 if ( pStream->bDataDiscontinuity )
619 *pdwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
620 pStream->bDataDiscontinuity = FALSE;
623 switch ( pStream->strh.fccType )
625 case PARSER_vids:
626 TRACE("vids\n");
627 pStream->rtInternal ++;
628 rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * (REFERENCE_TIME)pStream->strh.dwScale / (REFERENCE_TIME)pStream->strh.dwRate;
629 /* FIXME - handle AVIPALCHANGE */
630 break;
631 case PARSER_auds:
632 TRACE("auds\n");
633 pwfx = (const WAVEFORMATEX*)pStream->pFmtBuf;
634 if ( pwfx != NULL && pStream->cbFmt >= (sizeof(WAVEFORMATEX)-2) )
636 pStream->rtInternal += (REFERENCE_TIME)*plLength;
637 rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS / (REFERENCE_TIME)pwfx->nAvgBytesPerSec;
639 else
641 pStream->rtInternal += (REFERENCE_TIME)(*plLength);
642 rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * (REFERENCE_TIME)pStream->strh.dwScale / ((REFERENCE_TIME)pStream->strh.dwSampleSize * (REFERENCE_TIME)pStream->strh.dwRate);
644 break;
645 case PARSER_mids:
646 case PARSER_txts:
647 default:
648 pStream->rtInternal += (REFERENCE_TIME)(*plLength);
649 rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * (REFERENCE_TIME)pStream->strh.dwScale / ((REFERENCE_TIME)pStream->strh.dwSampleSize * (REFERENCE_TIME)pStream->strh.dwRate);
650 break;
652 pStream->cIndexCur ++;
653 pStream->rtCur = rtNext;
654 *prtStop = rtNext;
656 else
658 ERR( "no idx1\n" );
659 return E_NOTIMPL;
662 TRACE("return %lu / %ld-%ld / %lu-%lu\n",
663 *pnStreamIndex,(long)*pllStart,*plLength,
664 (unsigned long)((*prtStart)*1000/QUARTZ_TIMEUNITS),
665 (unsigned long)((*prtStop)*1000/QUARTZ_TIMEUNITS));
667 return NOERROR;
670 static HRESULT CAVIParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
672 CAVIParseImpl* This = (CAVIParseImpl*)pImpl->m_pUserData;
674 TRACE("(%p,%lu,%ld,%ld,%p)\n",This,nStreamIndex,(long)llStart,lLength,pSample);
676 if ( This == NULL )
677 return E_UNEXPECTED;
679 return NOERROR;
685 static const struct ParserHandlers CAVIParseImpl_Handlers =
687 CAVIParseImpl_InitParser,
688 CAVIParseImpl_UninitParser,
689 CAVIParseImpl_GetOutPinName,
690 CAVIParseImpl_GetStreamType,
691 CAVIParseImpl_CheckStreamType,
692 CAVIParseImpl_GetAllocProp,
693 CAVIParseImpl_GetNextRequest,
694 CAVIParseImpl_ProcessSample,
696 /* for IQualityControl */
697 NULL, /* pQualityNotify */
699 /* for seeking */
700 NULL, /* pGetSeekingCaps */
701 NULL, /* pIsTimeFormatSupported */
702 NULL, /* pGetCurPos */
703 NULL, /* pSetCurPos */
704 NULL, /* pGetDuration */
705 NULL, /* pGetStopPos */
706 NULL, /* pSetStopPos */
707 NULL, /* pGetPreroll */
710 HRESULT QUARTZ_CreateAVISplitter(IUnknown* punkOuter,void** ppobj)
712 return QUARTZ_CreateParser(
713 punkOuter,ppobj,
714 &CLSID_AviSplitter,
715 QUARTZ_AVIParser_Name,
716 QUARTZ_AVIParserInPin_Name,
717 &CAVIParseImpl_Handlers );