Various cosmetic changes.
[wine] / dlls / quartz / aviparse.c
1 /*
2  * Implements AVI Parser(Splitter).
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "mmsystem.h"
14 #include "vfw.h"
15 #include "winerror.h"
16 #include "strmif.h"
17 #include "control.h"
18 #include "vfwmsgs.h"
19 #include "amvideo.h"
20 #include "uuids.h"
21
22 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(quartz);
24
25 #include "quartz_private.h"
26 #include "parser.h"
27 #include "mtype.h"
28
29
30
31 static const WCHAR QUARTZ_AVIParser_Name[] =
32 { 'A','V','I',' ','S','p','l','i','t','t','e','r',0 };
33 static const WCHAR QUARTZ_AVIParserInPin_Name[] =
34 { 'I','n',0 };
35 static const WCHAR QUARTZ_AVIParserOutPin_Basename[] =
36 { 'S','t','r','e','a','m',0 };
37
38 #define WINE_QUARTZ_AVIPINNAME_MAX      64
39
40 /****************************************************************************
41  *
42  *      CAVIParseImpl
43  */
44
45
46 typedef struct CAVIParseImpl CAVIParseImpl;
47 typedef struct CAVIParseStream CAVIParseStream;
48
49 struct CAVIParseImpl
50 {
51         MainAVIHeader   avih;
52         CAVIParseStream*        pStreamsBuf;
53         DWORD   cIndexEntries;
54         AVIINDEXENTRY*  pIndexEntriesBuf;
55         WCHAR   wchWork[ WINE_QUARTZ_AVIPINNAME_MAX ];
56 };
57
58 struct CAVIParseStream
59 {
60         AVIStreamHeader strh;
61         DWORD   cbFmt;
62         BYTE*   pFmtBuf;
63         DWORD   cIndexEntries;
64         AVIINDEXENTRY*  pIndexEntries;
65         DWORD   cIndexCur;
66         REFERENCE_TIME  rtCur;
67         REFERENCE_TIME  rtInternal;
68 };
69
70
71 static HRESULT CAVIParseImpl_ParseStreamList(
72         CParserImpl* pImpl, CAVIParseImpl* This, ULONG nStreamIndex,
73         LONGLONG llOfsTop, DWORD dwListLen, CAVIParseStream* pStream )
74 {
75         HRESULT hr;
76         LONGLONG        llOfs;
77         DWORD   dwChunkLength;
78
79         TRACE("search strh\n");
80         hr = RIFF_SearchChunk(
81                 pImpl, dwListLen,
82                 llOfsTop, PARSER_strh,
83                 &llOfs, &dwChunkLength );
84         if ( hr == S_OK )
85         {
86                 TRACE("strh has been detected\n");
87                 if ( dwChunkLength < sizeof(AVIStreamHeader) )
88                         hr = E_FAIL;
89                 else
90                         hr = IAsyncReader_SyncRead( pImpl->m_pReader,
91                                 llOfs, sizeof(AVIStreamHeader), (BYTE*)&pStream->strh );
92         }
93         if ( FAILED(hr) )
94                 return hr;
95         if ( hr != S_OK )
96                 return E_FAIL;
97
98         TRACE("search strf\n");
99         hr = RIFF_SearchChunk(
100                 pImpl, dwListLen,
101                 llOfsTop, PARSER_strf,
102                 &llOfs, &dwChunkLength );
103         if ( hr == S_OK && dwChunkLength > 0 )
104         {
105                 TRACE("strf has been detected\n");
106                 pStream->cbFmt = dwChunkLength;
107                 pStream->pFmtBuf = (BYTE*)QUARTZ_AllocMem( dwChunkLength );
108                 if ( pStream->pFmtBuf == NULL )
109                         hr = E_OUTOFMEMORY;
110                 else
111                         hr = IAsyncReader_SyncRead( pImpl->m_pReader,
112                                 llOfs, dwChunkLength, pStream->pFmtBuf );
113         }
114         if ( FAILED(hr) )
115                 return hr;
116
117         TRACE("search indx\n");
118         hr = RIFF_SearchChunk(
119                 pImpl, dwListLen,
120                 llOfsTop, PARSER_indx,
121                 &llOfs, &dwChunkLength );
122         if ( FAILED(hr) )
123                 return hr;
124         if ( hr == S_OK )
125         {
126                 FIXME( "'indx' has been detected - not implemented now!\n" );
127                 return E_FAIL;
128         }
129
130         return NOERROR;
131 }
132
133
134 static HRESULT CAVIParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
135 {
136         CAVIParseImpl*  This = NULL;
137         BYTE    riffhdr[12];
138         ULONG   i;
139         ULONG   nIndex;
140         HRESULT hr;
141         LONGLONG        llOfs_hdrl;
142         DWORD   dwLen_hdrl;
143         LONGLONG        llOfs;
144         DWORD   dwChunkId;
145         DWORD   dwChunkLength;
146         AVIINDEXENTRY*  pEntriesBuf = NULL;
147         ULONG   cEntries;
148         ULONG   cEntriesCur;
149
150         TRACE("(%p,%p)\n",pImpl,pcStreams);
151
152         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, riffhdr );
153         if ( FAILED(hr) )
154                 return hr;
155         if ( hr != S_OK )
156                 return E_FAIL;
157         if ( memcmp( &riffhdr[0], "RIFF", 4 ) != 0 ||
158                  memcmp( &riffhdr[8], "AVI ", 4 ) != 0 )
159                 return E_FAIL;
160
161         TRACE("it's AVI\n");
162
163         This = (CAVIParseImpl*)QUARTZ_AllocMem( sizeof(CAVIParseImpl) );
164         if ( This == NULL )
165                 return E_OUTOFMEMORY;
166         pImpl->m_pUserData = This;
167         ZeroMemory( This, sizeof(CAVIParseImpl) );
168         This->pStreamsBuf = NULL;
169         This->cIndexEntries = 0;
170         This->pIndexEntriesBuf = 0;
171
172         hr = RIFF_SearchList(
173                 pImpl, (DWORD)0xffffffff,
174                 PARSER_RIFF_OfsFirst, PARSER_hdrl,
175                 &llOfs_hdrl, &dwLen_hdrl );
176         if ( FAILED(hr) )
177                 return hr;
178         if ( hr != S_OK )
179                 return E_FAIL;
180
181         /* read 'avih' */
182         TRACE("read avih\n");
183         hr = RIFF_SearchChunk(
184                 pImpl, dwLen_hdrl,
185                 llOfs_hdrl, PARSER_avih,
186                 &llOfs, &dwChunkLength );
187         if ( FAILED(hr) )
188                 return hr;
189         if ( hr != S_OK )
190                 return E_FAIL;
191
192         if ( dwChunkLength > sizeof(MainAVIHeader) )
193                 dwChunkLength = sizeof(MainAVIHeader);
194         hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)&(This->avih) );
195         if ( FAILED(hr) )
196                 return hr;
197         if ( hr != S_OK )
198                 return E_FAIL;
199         if ( This->avih.dwStreams == 0 )
200                 return E_FAIL;
201
202         /* initialize streams. */
203         This->pStreamsBuf = (CAVIParseStream*)QUARTZ_AllocMem(
204                 sizeof(CAVIParseStream) * This->avih.dwStreams );
205         if ( This->pStreamsBuf == NULL )
206                 return E_OUTOFMEMORY;
207         ZeroMemory( This->pStreamsBuf,
208                 sizeof(CAVIParseStream) * This->avih.dwStreams );
209
210         llOfs = llOfs_hdrl;
211         for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
212         {
213                 TRACE("search strl for stream %lu\n",nIndex);
214                 hr = RIFF_SearchList(
215                         pImpl,
216                         dwLen_hdrl, llOfs, PARSER_strl,
217                         &llOfs, &dwChunkLength );
218                 if ( FAILED(hr) )
219                         return hr;
220                 if ( hr != S_OK )
221                         return E_FAIL;
222
223                 /* read 'strl'. */
224                 hr = CAVIParseImpl_ParseStreamList(
225                         pImpl, This, nIndex,
226                         llOfs, dwChunkLength, &This->pStreamsBuf[nIndex] );
227
228                 if ( FAILED(hr) )
229                         return hr;
230                 if ( hr != S_OK )
231                         return E_FAIL;
232                 llOfs += dwChunkLength;
233         }
234
235         /* initialize idx1. */
236         TRACE("search idx1\n");
237         hr = RIFF_SearchChunk(
238                 pImpl, (DWORD)0xffffffff,
239                 PARSER_RIFF_OfsFirst, PARSER_idx1,
240                 &llOfs, &dwChunkLength );
241         if ( FAILED(hr) )
242                 return hr;
243         if ( hr == S_OK )
244         {
245                 /* read idx1. */
246                 This->cIndexEntries = dwChunkLength / sizeof(AVIINDEXENTRY);
247                 This->pIndexEntriesBuf = (AVIINDEXENTRY*)QUARTZ_AllocMem(
248                         sizeof(AVIINDEXENTRY) * This->cIndexEntries );
249                 if ( This->pIndexEntriesBuf == NULL )
250                         return E_OUTOFMEMORY;
251                 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, sizeof(AVIINDEXENTRY) * This->cIndexEntries, (BYTE*)This->pIndexEntriesBuf );
252                 if ( FAILED(hr) )
253                         return hr;
254                 if ( hr != S_OK )
255                         return E_FAIL;
256
257                 pEntriesBuf = (AVIINDEXENTRY*)QUARTZ_AllocMem(
258                         sizeof(AVIINDEXENTRY) * This->cIndexEntries );
259                 if ( pEntriesBuf == NULL )
260                         return E_OUTOFMEMORY;
261                 cEntries = 0;
262                 for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
263                 {
264                         cEntriesCur = cEntries;
265                         dwChunkId = (((nIndex%10)+'0')<<8) | ((nIndex/10)+'0');
266                         for ( i = 0; i < This->cIndexEntries; i++ )
267                         {
268                                 if ( (This->pIndexEntriesBuf[i].ckid & 0xffff) == dwChunkId )
269                                         memcpy( &pEntriesBuf[cEntries++], &This->pIndexEntriesBuf[i], sizeof(AVIINDEXENTRY) );
270                         }
271                         This->pStreamsBuf[nIndex].pIndexEntries = &pEntriesBuf[cEntriesCur];
272                         This->pStreamsBuf[nIndex].cIndexEntries = cEntries - cEntriesCur;
273                         This->pStreamsBuf[nIndex].cIndexCur = 0;
274                         This->pStreamsBuf[nIndex].rtCur = 0;
275                         This->pStreamsBuf[nIndex].rtInternal = 0;
276                         TRACE("stream %lu - %lu entries\n",nIndex,This->pStreamsBuf[nIndex].cIndexEntries);
277                 }
278                 QUARTZ_FreeMem(This->pIndexEntriesBuf);
279                 This->pIndexEntriesBuf = pEntriesBuf;
280
281                 This->avih.dwSuggestedBufferSize = 0;
282                 for ( i = 0; i < This->cIndexEntries; i++ )
283                 {
284                         if ( This->avih.dwSuggestedBufferSize < This->pIndexEntriesBuf[i].dwChunkLength )
285                                 This->avih.dwSuggestedBufferSize = This->pIndexEntriesBuf[i].dwChunkLength;
286                 }
287         }
288         else
289         {
290                 return E_FAIL;
291         }
292
293         if ( This->avih.dwStreams > 100 )
294                 return E_FAIL;
295
296         *pcStreams = This->avih.dwStreams;
297
298         return NOERROR;
299 }
300
301 static HRESULT CAVIParseImpl_UninitParser( CParserImpl* pImpl )
302 {
303         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
304         ULONG   nIndex;
305
306         TRACE("(%p)\n",This);
307
308         if ( This == NULL )
309                 return NOERROR;
310
311         /* destruct */
312         if ( This->pStreamsBuf != NULL )
313         {
314                 for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
315                 {
316                         /* release this stream */
317                         if ( This->pStreamsBuf[nIndex].pFmtBuf != NULL )
318                                 QUARTZ_FreeMem(This->pStreamsBuf[nIndex].pFmtBuf);
319                 }
320                 QUARTZ_FreeMem( This->pStreamsBuf );
321                 This->pStreamsBuf = NULL;
322         }
323
324         if ( This->pIndexEntriesBuf != NULL )
325         {
326                 QUARTZ_FreeMem( This->pIndexEntriesBuf );
327                 This->pIndexEntriesBuf = NULL;
328         }
329
330         QUARTZ_FreeMem( This );
331         pImpl->m_pUserData = NULL;
332
333         return NOERROR;
334 }
335
336 static LPCWSTR CAVIParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
337 {
338         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
339         int wlen;
340
341         TRACE("(%p,%lu)\n",This,nStreamIndex);
342
343         if ( This == NULL || nStreamIndex >= This->avih.dwStreams )
344                 return NULL;
345
346         wlen = lstrlenW(QUARTZ_AVIParserOutPin_Basename);
347         memcpy( This->wchWork, QUARTZ_AVIParserOutPin_Basename, sizeof(WCHAR)*wlen );
348         This->wchWork[ wlen ] = (nStreamIndex/10) + '0';
349         This->wchWork[ wlen+1 ] = (nStreamIndex%10) + '0';
350         This->wchWork[ wlen+2 ] = 0;
351
352         return This->wchWork;
353 }
354
355 static HRESULT CAVIParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
356 {
357         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
358         VIDEOINFOHEADER*        pvi;
359         BITMAPINFOHEADER*       pbi;
360         WAVEFORMATEX*   pwfx;
361         DWORD   cbFmt;
362         DWORD   cb;
363         HRESULT hr;
364
365         TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt);
366
367         if ( This == NULL )
368                 return E_UNEXPECTED;
369         if ( nStreamIndex >= This->avih.dwStreams )
370                 return E_INVALIDARG;
371
372         cbFmt = This->pStreamsBuf[nStreamIndex].cbFmt;
373
374         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
375         switch ( This->pStreamsBuf[nStreamIndex].strh.fccType )
376         {
377         case PARSER_vids:
378                 pbi = (BITMAPINFOHEADER*)This->pStreamsBuf[nStreamIndex].pFmtBuf;
379                 if ( pbi == NULL || cbFmt < sizeof(BITMAPINFOHEADER) )
380                         goto unknown_format;
381
382                 memcpy( &pmt->majortype, &MEDIATYPE_Video, sizeof(GUID) );
383                 hr = QUARTZ_MediaSubType_FromBitmap( &pmt->subtype, pbi );
384                 if ( FAILED(hr) )
385                         goto unknown_format;
386                 if ( hr != S_OK )
387                         QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)pbi->biCompression );
388
389                 pmt->bFixedSizeSamples = QUARTZ_BitmapHasFixedSample( pbi ) ? 1 : 0;
390                 pmt->bTemporalCompression = 0; /* FIXME - 1 if inter-frame compression is used */
391                 pmt->lSampleSize = ( pbi->biCompression == 0 ) ? DIBSIZE(*pbi) : pbi->biSizeImage;
392                 memcpy( &pmt->formattype, &FORMAT_VideoInfo, sizeof(GUID) );
393
394                 cb = sizeof(VIDEOINFOHEADER) + cbFmt;
395                 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( cb );
396                 if ( pmt->pbFormat == NULL )
397                         return E_OUTOFMEMORY;
398                 ZeroMemory( pmt->pbFormat, cb );
399                 pvi = (VIDEOINFOHEADER*)pmt->pbFormat;
400                 pmt->cbFormat = cb;
401                 memcpy( &pvi->bmiHeader, pbi, cbFmt );
402                 break;
403         case PARSER_auds:
404                 pwfx = (WAVEFORMATEX*)This->pStreamsBuf[nStreamIndex].pFmtBuf;
405                 if ( pwfx == NULL || cbFmt < (sizeof(WAVEFORMATEX)-2) )
406                         goto unknown_format;
407
408                 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
409                 QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)pwfx->wFormatTag );
410                 pmt->bFixedSizeSamples = 1;
411                 pmt->bTemporalCompression = 0;
412                 pmt->lSampleSize = pwfx->nBlockAlign;
413                 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
414                 pmt->pUnk = NULL;
415
416                 cb = ( cbFmt < sizeof(WAVEFORMATEX) ) ? sizeof(WAVEFORMATEX) : cbFmt;
417                 pmt->pbFormat = (BYTE*)CoTaskMemAlloc( cb );
418                 if ( pmt->pbFormat == NULL )
419                         return E_OUTOFMEMORY;
420                 ZeroMemory( pmt->pbFormat, cb );
421                 pmt->cbFormat = cbFmt;
422                 memcpy( pmt->pbFormat, pwfx, cbFmt );
423                 break;
424         case PARSER_mids:
425                 /* FIXME? */
426                 memcpy( &pmt->majortype, &MEDIATYPE_Midi, sizeof(GUID) );
427                 memcpy( &pmt->subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
428                 pmt->bFixedSizeSamples = 0;
429                 pmt->bTemporalCompression = 0;
430                 pmt->lSampleSize = 1;
431                 memcpy( &pmt->formattype, &FORMAT_None, sizeof(GUID) );
432                 pmt->pUnk = NULL;
433                 pmt->cbFormat = 0;
434                 pmt->pbFormat = NULL;
435                 break;
436         case PARSER_txts:
437                 /* FIXME? */
438                 memcpy( &pmt->majortype, &MEDIATYPE_Text, sizeof(GUID) );
439                 memcpy( &pmt->subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
440                 pmt->bFixedSizeSamples = 0;
441                 pmt->bTemporalCompression = 0;
442                 pmt->lSampleSize = 1;
443                 memcpy( &pmt->formattype, &FORMAT_None, sizeof(GUID) );
444                 pmt->pUnk = NULL;
445                 pmt->cbFormat = 0;
446                 pmt->pbFormat = NULL;
447                 break;
448         default:
449                 goto unknown_format;
450         }
451
452         return NOERROR;
453
454 unknown_format:;
455         FIXME( "(%p) unsupported stream type %c%c%c%c\n",This,
456                         (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>> 0)&0xff),
457                         (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>> 8)&0xff),
458                         (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>>16)&0xff),
459                         (int)((This->pStreamsBuf[nStreamIndex].strh.fccType>>24)&0xff) );
460
461         memcpy( &pmt->majortype, &MEDIATYPE_NULL, sizeof(GUID) );
462         memcpy( &pmt->subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
463         pmt->bFixedSizeSamples = 0;
464         pmt->bTemporalCompression = 0;
465         pmt->lSampleSize = 1;
466         memcpy( &pmt->formattype, &FORMAT_None, sizeof(GUID) );
467         pmt->pUnk = NULL;
468         pmt->cbFormat = 0;
469         pmt->pbFormat = NULL;
470
471         return NOERROR;
472 }
473
474 static HRESULT CAVIParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
475 {
476         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
477         HRESULT hr;
478         AM_MEDIA_TYPE   mt;
479         VIDEOINFOHEADER*        pvi;
480         VIDEOINFOHEADER*        pviCheck;
481         WAVEFORMATEX*   pwfx;
482         WAVEFORMATEX*   pwfxCheck;
483
484         TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt);
485
486         hr = CAVIParseImpl_GetStreamType( pImpl, nStreamIndex, &mt );
487         if ( FAILED(hr) )
488                 return hr;
489
490         TRACE("check GUIDs - %s,%s\n",debugstr_guid(&pmt->majortype),debugstr_guid(&pmt->subtype));
491         if ( !IsEqualGUID( &pmt->majortype, &mt.majortype ) ||
492                  !IsEqualGUID( &pmt->subtype, &mt.subtype ) ||
493                  !IsEqualGUID( &pmt->formattype, &mt.formattype ) )
494         {
495                 hr = E_FAIL;
496                 goto end;
497         }
498
499         TRACE("check format\n");
500         hr = S_OK;
501         switch ( This->pStreamsBuf[nStreamIndex].strh.fccType )
502         {
503         case PARSER_vids:
504                 TRACE("check vids\n");
505                 pvi = (VIDEOINFOHEADER*)mt.pbFormat;
506                 pviCheck = (VIDEOINFOHEADER*)pmt->pbFormat;
507                 if ( pvi == NULL || pviCheck == NULL || pmt->cbFormat < sizeof(VIDEOINFOHEADER) )
508                         hr = E_FAIL;
509                 if ( pvi->bmiHeader.biWidth != pviCheck->bmiHeader.biWidth ||
510                          pvi->bmiHeader.biHeight != pviCheck->bmiHeader.biHeight ||
511                          pvi->bmiHeader.biPlanes != pviCheck->bmiHeader.biPlanes ||
512                          pvi->bmiHeader.biBitCount != pviCheck->bmiHeader.biBitCount ||
513                          pvi->bmiHeader.biCompression != pviCheck->bmiHeader.biCompression ||
514                          pvi->bmiHeader.biClrUsed != pviCheck->bmiHeader.biClrUsed )
515                         hr = E_FAIL;
516                 break;
517         case PARSER_auds:
518                 TRACE("check auds\n");
519                 pwfx = (WAVEFORMATEX*)mt.pbFormat;
520                 pwfxCheck = (WAVEFORMATEX*)pmt->pbFormat;
521                 if ( pwfx == NULL || pwfxCheck == NULL || pmt->cbFormat < (sizeof(WAVEFORMATEX)-2) )
522                         hr = E_FAIL;
523                 if ( pwfx->wFormatTag != pwfxCheck->wFormatTag ||
524                          pwfx->nBlockAlign != pwfxCheck->nBlockAlign ||
525                          pwfx->wBitsPerSample != pwfxCheck->wBitsPerSample ||
526                          pwfx->nChannels != pwfxCheck->nChannels ||
527                          pwfx->nSamplesPerSec != pwfxCheck->nSamplesPerSec )
528                         hr = E_FAIL;
529                 break;
530         case PARSER_mids:
531         case PARSER_txts:
532                 break;
533         default:
534                 break;
535         }
536 end:
537         QUARTZ_MediaType_Free( &mt );
538
539         TRACE("%08lx\n",hr);
540
541         return hr;
542 }
543
544 static HRESULT CAVIParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
545 {
546         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
547
548         TRACE("(%p,%p)\n",This,pReqProp);
549         if ( This == NULL )
550                 return E_UNEXPECTED;
551
552         ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
553         pReqProp->cBuffers = This->avih.dwStreams;
554         pReqProp->cbBuffer = This->avih.dwSuggestedBufferSize;
555
556         return NOERROR;
557 }
558
559 static HRESULT CAVIParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
560 {
561         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
562         REFERENCE_TIME  rtNext;
563         DWORD   nIndexNext;
564         DWORD   nIndex;
565         CAVIParseStream*        pStream;
566         const WAVEFORMATEX*     pwfx;
567
568         if ( This == NULL )
569                 return E_UNEXPECTED;
570
571         TRACE("(%p)\n",This);
572
573         nIndexNext = This->avih.dwStreams;
574         rtNext = ((REFERENCE_TIME)0x7fffffff<<32)|((REFERENCE_TIME)0xffffffff);
575         for ( nIndex = 0; nIndex < This->avih.dwStreams; nIndex++ )
576         {
577                 TRACE("stream %lu - %lu,%lu\n",nIndex,(unsigned long)(This->pStreamsBuf[nIndex].rtCur*1000/QUARTZ_TIMEUNITS),This->pStreamsBuf[nIndex].cIndexCur);
578                 if ( rtNext > This->pStreamsBuf[nIndex].rtCur &&
579                          This->pStreamsBuf[nIndex].cIndexCur < This->pStreamsBuf[nIndex].cIndexEntries )
580                 {
581                         nIndexNext = nIndex;
582                         rtNext = This->pStreamsBuf[nIndex].rtCur;
583                 }
584         }
585         if ( nIndexNext >= This->avih.dwStreams )
586                 return S_FALSE;
587
588         if ( This->pIndexEntriesBuf != NULL )
589         {
590                 pStream = &This->pStreamsBuf[nIndexNext];
591                 *pnStreamIndex = nIndexNext;
592                 *pllStart = (LONGLONG)pStream->pIndexEntries[pStream->cIndexCur].dwChunkOffset + 8;
593                 *plLength = (LONG)pStream->pIndexEntries[pStream->cIndexCur].dwChunkLength;
594                 *prtStart = rtNext;
595                 *prtStop = rtNext;
596
597                 switch ( pStream->strh.fccType )
598                 {
599                 case PARSER_vids:
600                         TRACE("vids\n");
601                         pStream->rtInternal ++;
602                         rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * (REFERENCE_TIME)pStream->strh.dwScale / (REFERENCE_TIME)pStream->strh.dwRate;
603                         /* FIXME - handle AVIPALCHANGE */
604                         break;
605                 case PARSER_auds:
606                         TRACE("auds\n");
607                         pwfx = (const WAVEFORMATEX*)pStream->pFmtBuf;
608                         if ( pwfx != NULL && pStream->cbFmt >= (sizeof(WAVEFORMATEX)-2) )
609                         {
610                                 pStream->rtInternal += (REFERENCE_TIME)*plLength;
611                                 rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS / (REFERENCE_TIME)pwfx->nAvgBytesPerSec;
612                         }
613                         else
614                         {
615                                 pStream->rtInternal += (REFERENCE_TIME)(*plLength);
616                                 rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * (REFERENCE_TIME)pStream->strh.dwScale / ((REFERENCE_TIME)pStream->strh.dwSampleSize * (REFERENCE_TIME)pStream->strh.dwRate);
617                         }
618                         break;
619                 case PARSER_mids:
620                 case PARSER_txts:
621                 default:
622                         pStream->rtInternal += (REFERENCE_TIME)(*plLength);
623                         rtNext = pStream->rtInternal * (REFERENCE_TIME)QUARTZ_TIMEUNITS * (REFERENCE_TIME)pStream->strh.dwScale / ((REFERENCE_TIME)pStream->strh.dwSampleSize * (REFERENCE_TIME)pStream->strh.dwRate);
624                         break;
625                 }
626                 pStream->cIndexCur ++;
627                 pStream->rtCur = rtNext;
628                 *prtStop = rtNext;
629         }
630         else
631         {
632                 ERR( "no idx1\n" );
633                 return E_NOTIMPL;
634         }
635
636         TRACE("return %lu / %ld-%ld / %lu-%lu\n",
637                 *pnStreamIndex,(long)*pllStart,*plLength,
638                 (unsigned long)((*prtStart)*1000/QUARTZ_TIMEUNITS),
639                 (unsigned long)((*prtStop)*1000/QUARTZ_TIMEUNITS));
640
641         return NOERROR;
642 }
643
644 static HRESULT CAVIParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
645 {
646         CAVIParseImpl*  This = (CAVIParseImpl*)pImpl->m_pUserData;
647
648         TRACE("(%p,%lu,%ld,%ld,%p)\n",This,nStreamIndex,(long)llStart,lLength,pSample);
649
650         if ( This == NULL )
651                 return E_UNEXPECTED;
652
653         return NOERROR;
654 }
655
656
657
658
659 static const struct ParserHandlers CAVIParseImpl_Handlers =
660 {
661         CAVIParseImpl_InitParser,
662         CAVIParseImpl_UninitParser,
663         CAVIParseImpl_GetOutPinName,
664         CAVIParseImpl_GetStreamType,
665         CAVIParseImpl_CheckStreamType,
666         CAVIParseImpl_GetAllocProp,
667         CAVIParseImpl_GetNextRequest,
668         CAVIParseImpl_ProcessSample,
669
670         /* for IQualityControl */
671         NULL, /* pQualityNotify */
672
673         /* for seeking */
674         NULL, /* pGetSeekingCaps */
675         NULL, /* pIsTimeFormatSupported */
676         NULL, /* pGetCurPos */
677         NULL, /* pSetCurPos */
678         NULL, /* pGetDuration */
679         NULL, /* pSetDuration */
680         NULL, /* pGetStopPos */
681         NULL, /* pSetStopPos */
682         NULL, /* pGetPreroll */
683         NULL, /* pSetPreroll */
684 };
685
686 HRESULT QUARTZ_CreateAVISplitter(IUnknown* punkOuter,void** ppobj)
687 {
688         return QUARTZ_CreateParser(
689                 punkOuter,ppobj,
690                 &CLSID_AviSplitter,
691                 QUARTZ_AVIParser_Name,
692                 QUARTZ_AVIParserInPin_Name,
693                 &CAVIParseImpl_Handlers );
694 }
695
696