2 * Implements AVI Parser(Splitter).
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
38 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
41 #include "quartz_private.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
[] =
51 static const WCHAR QUARTZ_AVIParserOutPin_Basename
[] =
52 { 'S','t','r','e','a','m',0 };
54 #define WINE_QUARTZ_AVIPINNAME_MAX 64
56 /****************************************************************************
62 typedef struct CAVIParseImpl CAVIParseImpl
;
63 typedef struct CAVIParseStream CAVIParseStream
;
68 CAVIParseStream
* pStreamsBuf
;
70 AVIINDEXENTRY
* pIndexEntriesBuf
;
71 WCHAR wchWork
[ WINE_QUARTZ_AVIPINNAME_MAX
];
74 struct CAVIParseStream
80 AVIINDEXENTRY
* pIndexEntries
;
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
)
96 TRACE("search strh\n");
97 hr
= RIFF_SearchChunk(
99 llOfsTop
, PARSER_strh
,
100 &llOfs
, &dwChunkLength
);
103 TRACE("strh has been detected\n");
104 if ( dwChunkLength
< sizeof(AVIStreamHeader
) )
107 hr
= IAsyncReader_SyncRead( pImpl
->m_pReader
,
108 llOfs
, sizeof(AVIStreamHeader
), (BYTE
*)&pStream
->strh
);
115 TRACE("search strf\n");
116 hr
= RIFF_SearchChunk(
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
)
128 hr
= IAsyncReader_SyncRead( pImpl
->m_pReader
,
129 llOfs
, dwChunkLength
, pStream
->pFmtBuf
);
134 TRACE("search indx\n");
135 hr
= RIFF_SearchChunk(
137 llOfsTop
, PARSER_indx
,
138 &llOfs
, &dwChunkLength
);
143 FIXME( "'indx' has been detected - not implemented now!\n" );
151 static HRESULT
CAVIParseImpl_InitParser( CParserImpl
* pImpl
, ULONG
* pcStreams
)
153 CAVIParseImpl
* This
= NULL
;
163 AVIINDEXENTRY
* pEntriesBuf
= NULL
;
167 TRACE("(%p,%p)\n",pImpl
,pcStreams
);
169 hr
= IAsyncReader_SyncRead( pImpl
->m_pReader
, 0, 12, riffhdr
);
174 if ( memcmp( &riffhdr
[0], "RIFF", 4 ) != 0 ||
175 memcmp( &riffhdr
[8], "AVI ", 4 ) != 0 )
180 This
= (CAVIParseImpl
*)QUARTZ_AllocMem( sizeof(CAVIParseImpl
) );
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
);
199 TRACE("read avih\n");
200 hr
= RIFF_SearchChunk(
202 llOfs_hdrl
, PARSER_avih
,
203 &llOfs
, &dwChunkLength
);
209 if ( dwChunkLength
> sizeof(MainAVIHeader
) )
210 dwChunkLength
= sizeof(MainAVIHeader
);
211 hr
= IAsyncReader_SyncRead( pImpl
->m_pReader
, llOfs
, dwChunkLength
, (BYTE
*)&(This
->avih
) );
216 if ( This
->avih
.dwStreams
== 0 )
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
);
228 for ( nIndex
= 0; nIndex
< This
->avih
.dwStreams
; nIndex
++ )
230 TRACE("search strl for stream %lu\n",nIndex
);
231 hr
= RIFF_SearchList(
233 dwLen_hdrl
, llOfs
, PARSER_strl
,
234 &llOfs
, &dwChunkLength
);
241 hr
= CAVIParseImpl_ParseStreamList(
243 llOfs
, dwChunkLength
, &This
->pStreamsBuf
[nIndex
] );
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
);
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
);
274 pEntriesBuf
= (AVIINDEXENTRY
*)QUARTZ_AllocMem(
275 sizeof(AVIINDEXENTRY
) * This
->cIndexEntries
);
276 if ( pEntriesBuf
== NULL
)
277 return E_OUTOFMEMORY
;
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
;
311 if ( This
->avih
.dwStreams
> 100 )
314 *pcStreams
= This
->avih
.dwStreams
;
319 static HRESULT
CAVIParseImpl_UninitParser( CParserImpl
* pImpl
)
321 CAVIParseImpl
* This
= (CAVIParseImpl
*)pImpl
->m_pUserData
;
324 TRACE("(%p)\n",This
);
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
;
354 static LPCWSTR
CAVIParseImpl_GetOutPinName( CParserImpl
* pImpl
, ULONG nStreamIndex
)
356 CAVIParseImpl
* This
= (CAVIParseImpl
*)pImpl
->m_pUserData
;
359 TRACE("(%p,%lu)\n",This
,nStreamIndex
);
361 if ( This
== NULL
|| nStreamIndex
>= This
->avih
.dwStreams
)
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
;
383 TRACE("(%p,%lu,%p)\n",This
,nStreamIndex
,pmt
);
387 if ( nStreamIndex
>= This
->avih
.dwStreams
)
390 cbFmt
= This
->pStreamsBuf
[nStreamIndex
].cbFmt
;
392 ZeroMemory( pmt
, sizeof(AM_MEDIA_TYPE
) );
393 switch ( This
->pStreamsBuf
[nStreamIndex
].strh
.fccType
)
396 pbi
= (BITMAPINFOHEADER
*)This
->pStreamsBuf
[nStreamIndex
].pFmtBuf
;
397 if ( pbi
== NULL
|| cbFmt
< sizeof(BITMAPINFOHEADER
) )
400 memcpy( &pmt
->majortype
, &MEDIATYPE_Video
, sizeof(GUID
) );
401 hr
= QUARTZ_MediaSubType_FromBitmap( &pmt
->subtype
, pbi
);
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
;
419 memcpy( &pvi
->bmiHeader
, pbi
, cbFmt
);
422 pwfx
= (WAVEFORMATEX
*)This
->pStreamsBuf
[nStreamIndex
].pFmtBuf
;
423 if ( pwfx
== NULL
|| cbFmt
< (sizeof(WAVEFORMATEX
)-2) )
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
) );
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
);
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
) );
452 pmt
->pbFormat
= NULL
;
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
) );
464 pmt
->pbFormat
= NULL
;
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
) );
487 pmt
->pbFormat
= NULL
;
492 static HRESULT
CAVIParseImpl_CheckStreamType( CParserImpl
* pImpl
, ULONG nStreamIndex
, const AM_MEDIA_TYPE
* pmt
)
494 CAVIParseImpl
* This
= (CAVIParseImpl
*)pImpl
->m_pUserData
;
497 VIDEOINFOHEADER
* pvi
;
498 VIDEOINFOHEADER
* pviCheck
;
500 WAVEFORMATEX
* pwfxCheck
;
502 TRACE("(%p,%lu,%p)\n",This
,nStreamIndex
,pmt
);
504 hr
= CAVIParseImpl_GetStreamType( pImpl
, nStreamIndex
, &mt
);
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
) )
517 TRACE("check format\n");
519 switch ( This
->pStreamsBuf
[nStreamIndex
].strh
.fccType
)
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
) )
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
)
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) )
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
)
555 QUARTZ_MediaType_Free( &mt
);
562 static HRESULT
CAVIParseImpl_GetAllocProp( CParserImpl
* pImpl
, ALLOCATOR_PROPERTIES
* pReqProp
)
564 CAVIParseImpl
* This
= (CAVIParseImpl
*)pImpl
->m_pUserData
;
566 TRACE("(%p,%p)\n",This
,pReqProp
);
570 ZeroMemory( pReqProp
, sizeof(ALLOCATOR_PROPERTIES
) );
571 pReqProp
->cBuffers
= This
->avih
.dwStreams
;
572 pReqProp
->cbBuffer
= This
->avih
.dwSuggestedBufferSize
;
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
;
583 CAVIParseStream
* pStream
;
584 const WAVEFORMATEX
* pwfx
;
586 TRACE("(%p)\n",This
);
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
)
601 rtNext
= This
->pStreamsBuf
[nIndex
].rtCur
;
604 if ( nIndexNext
>= This
->avih
.dwStreams
)
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
;
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
)
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 */
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
;
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
);
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
);
652 pStream
->cIndexCur
++;
653 pStream
->rtCur
= rtNext
;
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
));
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
);
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 */
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(
715 QUARTZ_AVIParser_Name
,
716 QUARTZ_AVIParserInPin_Name
,
717 &CAVIParseImpl_Handlers
);