4 * Copyright 2003 Robert Shearman
5 * Copyright 2004-2005 Christian Costa
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * - we don't do anything with indices yet (we could use them when seeking)
23 * - we don't support multiple RIFF sections (i.e. large AVI files > 2Gb)
26 #include "quartz_private.h"
27 #include "control_private.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
47 typedef struct AVISplitterImpl
50 IMediaSample
* pCurrentSample
;
51 RIFFCHUNK CurrentChunk
;
52 LONGLONG CurrentChunkOffset
; /* in media time */
54 AVIMAINHEADER AviHeader
;
57 static HRESULT
AVISplitter_NextChunk(LONGLONG
* pllCurrentChunkOffset
, RIFFCHUNK
* pCurrentChunk
, const REFERENCE_TIME
* tStart
, const REFERENCE_TIME
* tStop
, const BYTE
* pbSrcStream
, int inner
)
60 *pllCurrentChunkOffset
+= MEDIATIME_FROM_BYTES(sizeof(RIFFLIST
));
62 *pllCurrentChunkOffset
+= MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK
) + RIFFROUND(pCurrentChunk
->cb
));
64 if (*pllCurrentChunkOffset
>= *tStop
)
65 return S_FALSE
; /* no more data - we couldn't even get the next chunk header! */
66 else if (*pllCurrentChunkOffset
+ MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK
)) >= *tStop
)
68 memcpy(pCurrentChunk
, pbSrcStream
+ (DWORD
)BYTES_FROM_MEDIATIME(*pllCurrentChunkOffset
- *tStart
), (DWORD
)BYTES_FROM_MEDIATIME(*tStop
- *pllCurrentChunkOffset
));
69 return S_FALSE
; /* no more data */
72 memcpy(pCurrentChunk
, pbSrcStream
+ (DWORD
)BYTES_FROM_MEDIATIME(*pllCurrentChunkOffset
- *tStart
), sizeof(RIFFCHUNK
));
77 static HRESULT
AVISplitter_Sample(LPVOID iface
, IMediaSample
* pSample
)
79 AVISplitterImpl
*This
= (AVISplitterImpl
*)iface
;
80 LPBYTE pbSrcStream
= NULL
;
82 REFERENCE_TIME tStart
, tStop
;
84 BOOL bMoreData
= TRUE
;
86 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
88 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
90 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
92 /* trace removed for performance reasons */
93 /* TRACE("(%p)\n", pSample); */
95 assert(BYTES_FROM_MEDIATIME(tStop
- tStart
) == cbSrcStream
);
97 if (This
->CurrentChunkOffset
<= tStart
&& This
->CurrentChunkOffset
+ MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK
)) > tStart
)
99 DWORD offset
= (DWORD
)BYTES_FROM_MEDIATIME(tStart
- This
->CurrentChunkOffset
);
100 assert(offset
<= sizeof(RIFFCHUNK
));
101 memcpy((BYTE
*)&This
->CurrentChunk
+ offset
, pbSrcStream
, sizeof(RIFFCHUNK
) - offset
);
103 else if (This
->CurrentChunkOffset
> tStart
)
105 DWORD offset
= (DWORD
)BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
- tStart
);
106 if (offset
>= (DWORD
)cbSrcStream
)
108 FIXME("large offset\n");
113 memcpy(&This
->CurrentChunk
, pbSrcStream
+ offset
, sizeof(RIFFCHUNK
));
116 assert(This
->CurrentChunkOffset
+ MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK
)) < tStop
);
122 long chunk_remaining_bytes
= 0;
125 Parser_OutputPin
* pOutputPin
;
126 BOOL bSyncPoint
= TRUE
;
128 if (This
->CurrentChunkOffset
>= tStart
)
129 offset_src
= (long)BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
- tStart
) + sizeof(RIFFCHUNK
);
133 switch (This
->CurrentChunk
.fcc
)
136 case aviFCC('i','d','x','1'): /* Index is not handled */
137 /* silently ignore */
138 if (S_FALSE
== AVISplitter_NextChunk(&This
->CurrentChunkOffset
, &This
->CurrentChunk
, &tStart
, &tStop
, pbSrcStream
, FALSE
))
142 /* We only handle the 'rec ' list which contains the stream data */
143 if ((*(DWORD
*)(pbSrcStream
+ BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
-tStart
) + sizeof(RIFFCHUNK
))) == aviFCC('r','e','c',' '))
145 /* FIXME: We only advanced to the first chunk inside the list without keeping track that we are in it.
146 * This is not clean and the parser should be improved for that but it is enough for most AVI files. */
147 if (S_FALSE
== AVISplitter_NextChunk(&This
->CurrentChunkOffset
, &This
->CurrentChunk
, &tStart
, &tStop
, pbSrcStream
, TRUE
))
152 This
->CurrentChunk
= *(RIFFCHUNK
*) (pbSrcStream
+ BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
-tStart
));
153 offset_src
= (long)BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
- tStart
) + sizeof(RIFFCHUNK
);
156 else if (S_FALSE
== AVISplitter_NextChunk(&This
->CurrentChunkOffset
, &This
->CurrentChunk
, &tStart
, &tStop
, pbSrcStream
, FALSE
))
161 #if 0 /* According to the AVI specs, a stream data chunk should be ABXX where AB is the stream number and X means don't care */
162 switch (TWOCCFromFOURCC(This
->CurrentChunk
.fcc
))
164 case cktypeDIBcompressed
:
168 /* FIXME: check that pin is of type video */
170 case cktypeWAVEbytes
:
171 /* FIXME: check that pin is of type audio */
173 case cktypePALchange
:
174 FIXME("handle palette change\n");
177 FIXME("Skipping unknown chunk type: %s at file offset 0x%x\n", debugstr_an((LPSTR
)&This
->CurrentChunk
.fcc
, 4), (DWORD
)BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
));
178 if (S_FALSE
== AVISplitter_NextChunk(&This
->CurrentChunkOffset
, &This
->CurrentChunk
, &tStart
, &tStop
, pbSrcStream
, FALSE
))
185 streamId
= StreamFromFOURCC(This
->CurrentChunk
.fcc
);
187 if (streamId
> This
->Parser
.cStreams
)
189 ERR("Corrupted AVI file (contains stream id %d, but supposed to only have %d streams)\n", streamId
, This
->Parser
.cStreams
);
194 pOutputPin
= (Parser_OutputPin
*)This
->Parser
.ppPins
[streamId
+ 1];
196 if (!This
->pCurrentSample
)
198 /* cache media sample until it is ready to be despatched
199 * (i.e. we reach the end of the chunk) */
200 hr
= OutputPin_GetDeliveryBuffer(&pOutputPin
->pin
, &This
->pCurrentSample
, NULL
, NULL
, 0);
204 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, 0);
209 TRACE("Skipping sending sample for stream %02d due to error (%x)\n", streamId
, hr
);
210 This
->pCurrentSample
= NULL
;
211 if (S_FALSE
== AVISplitter_NextChunk(&This
->CurrentChunkOffset
, &This
->CurrentChunk
, &tStart
, &tStop
, pbSrcStream
, FALSE
))
217 hr
= IMediaSample_GetPointer(This
->pCurrentSample
, &pbDstStream
);
221 cbDstStream
= IMediaSample_GetSize(This
->pCurrentSample
);
223 chunk_remaining_bytes
= (long)BYTES_FROM_MEDIATIME(This
->CurrentChunkOffset
+ MEDIATIME_FROM_BYTES(This
->CurrentChunk
.cb
+ sizeof(RIFFCHUNK
)) - tStart
) - offset_src
;
225 assert(chunk_remaining_bytes
>= 0);
226 assert(chunk_remaining_bytes
<= cbDstStream
- IMediaSample_GetActualDataLength(This
->pCurrentSample
));
228 /* trace removed for performance reasons */
229 /* TRACE("chunk_remaining_bytes: 0x%x, cbSrcStream: 0x%x, offset_src: 0x%x\n", chunk_remaining_bytes, cbSrcStream, offset_src); */
232 if (chunk_remaining_bytes
<= cbSrcStream
- offset_src
)
236 memcpy(pbDstStream
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
), pbSrcStream
+ offset_src
, chunk_remaining_bytes
);
237 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, chunk_remaining_bytes
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
));
243 REFERENCE_TIME tAviStart
, tAviStop
;
246 if (pOutputPin
->dwSamplesProcessed
== 0)
247 IMediaSample_SetDiscontinuity(This
->pCurrentSample
, TRUE
);
249 IMediaSample_SetSyncPoint(This
->pCurrentSample
, bSyncPoint
);
251 pOutputPin
->dwSamplesProcessed
++;
253 if (pOutputPin
->dwSampleSize
)
254 tAviStart
= (LONGLONG
)ceil(10000000.0 * (float)(pOutputPin
->dwSamplesProcessed
- 1) * (float)IMediaSample_GetActualDataLength(This
->pCurrentSample
) / ((float)pOutputPin
->dwSampleSize
* pOutputPin
->fSamplesPerSec
));
256 tAviStart
= (LONGLONG
)ceil(10000000.0 * (float)(pOutputPin
->dwSamplesProcessed
- 1) / (float)pOutputPin
->fSamplesPerSec
);
257 if (pOutputPin
->dwSampleSize
)
258 tAviStop
= (LONGLONG
)ceil(10000000.0 * (float)pOutputPin
->dwSamplesProcessed
* (float)IMediaSample_GetActualDataLength(This
->pCurrentSample
) / ((float)pOutputPin
->dwSampleSize
* pOutputPin
->fSamplesPerSec
));
260 tAviStop
= (LONGLONG
)ceil(10000000.0 * (float)pOutputPin
->dwSamplesProcessed
/ (float)pOutputPin
->fSamplesPerSec
);
262 IMediaSample_SetTime(This
->pCurrentSample
, &tAviStart
, &tAviStop
);
264 hr
= OutputPin_SendSample(&pOutputPin
->pin
, This
->pCurrentSample
);
265 if (hr
!= S_OK
&& hr
!= VFW_E_NOT_CONNECTED
)
266 ERR("Error sending sample (%x)\n", hr
);
269 if (This
->pCurrentSample
)
270 IMediaSample_Release(This
->pCurrentSample
);
272 This
->pCurrentSample
= NULL
;
274 if (S_FALSE
== AVISplitter_NextChunk(&This
->CurrentChunkOffset
, &This
->CurrentChunk
, &tStart
, &tStop
, pbSrcStream
, FALSE
))
281 memcpy(pbDstStream
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
), pbSrcStream
+ offset_src
, cbSrcStream
- offset_src
);
282 IMediaSample_SetActualDataLength(This
->pCurrentSample
, cbSrcStream
- offset_src
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
));
289 if (tStop
>= This
->EndOfFile
)
293 TRACE("End of file reached\n");
295 for (i
= 0; i
< This
->Parser
.cStreams
; i
++)
300 TRACE("Send End Of Stream to output pin %d\n", i
);
302 hr
= IPin_ConnectedTo(This
->Parser
.ppPins
[i
+1], &ppin
);
305 hr
= IPin_EndOfStream(ppin
);
315 /* Force the pullpin thread to stop */
322 static HRESULT
AVISplitter_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
324 if (IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Stream
) && IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_Avi
))
329 static HRESULT
AVISplitter_ProcessStreamList(AVISplitterImpl
* This
, const BYTE
* pData
, DWORD cb
)
332 const RIFFCHUNK
* pChunk
;
335 float fSamplesPerSec
= 0.0f
;
336 DWORD dwSampleSize
= 0;
338 ALLOCATOR_PROPERTIES props
;
339 static const WCHAR wszStreamTemplate
[] = {'S','t','r','e','a','m',' ','%','0','2','d',0};
343 props
.cbBuffer
= 0x20000;
346 ZeroMemory(&amt
, sizeof(amt
));
347 piOutput
.dir
= PINDIR_OUTPUT
;
348 piOutput
.pFilter
= (IBaseFilter
*)This
;
349 wsprintfW(piOutput
.achName
, wszStreamTemplate
, This
->Parser
.cStreams
);
351 for (pChunk
= (const RIFFCHUNK
*)pData
;
352 ((const BYTE
*)pChunk
>= pData
) && ((const BYTE
*)pChunk
+ sizeof(RIFFCHUNK
) < pData
+ cb
) && (pChunk
->cb
> 0);
353 pChunk
= (const RIFFCHUNK
*)((const BYTE
*)pChunk
+ sizeof(RIFFCHUNK
) + pChunk
->cb
)
358 case ckidSTREAMHEADER
:
360 const AVISTREAMHEADER
* pStrHdr
= (const AVISTREAMHEADER
*)pChunk
;
361 TRACE("processing stream header\n");
363 fSamplesPerSec
= (float)pStrHdr
->dwRate
/ (float)pStrHdr
->dwScale
;
365 switch (pStrHdr
->fccType
)
367 case streamtypeVIDEO
:
368 memcpy(&amt
.formattype
, &FORMAT_VideoInfo
, sizeof(GUID
));
372 case streamtypeAUDIO
:
373 memcpy(&amt
.formattype
, &FORMAT_WaveFormatEx
, sizeof(GUID
));
376 memcpy(&amt
.formattype
, &FORMAT_None
, sizeof(GUID
));
378 memcpy(&amt
.majortype
, &MEDIATYPE_Video
, sizeof(GUID
));
379 amt
.majortype
.Data1
= pStrHdr
->fccType
;
380 memcpy(&amt
.subtype
, &MEDIATYPE_Video
, sizeof(GUID
));
381 amt
.subtype
.Data1
= pStrHdr
->fccHandler
;
382 TRACE("Subtype FCC: %.04s\n", (LPCSTR
)&pStrHdr
->fccHandler
);
383 amt
.lSampleSize
= pStrHdr
->dwSampleSize
;
384 amt
.bFixedSizeSamples
= (amt
.lSampleSize
!= 0);
386 /* FIXME: Is this right? */
387 if (!amt
.lSampleSize
)
393 amt
.bTemporalCompression
= IsEqualGUID(&amt
.majortype
, &MEDIATYPE_Video
); /* FIXME? */
394 dwSampleSize
= pStrHdr
->dwSampleSize
;
395 dwLength
= pStrHdr
->dwLength
;
397 dwLength
= This
->AviHeader
.dwTotalFrames
;
399 if (pStrHdr
->dwSuggestedBufferSize
)
400 props
.cbBuffer
= pStrHdr
->dwSuggestedBufferSize
;
404 case ckidSTREAMFORMAT
:
405 TRACE("processing stream format data\n");
406 if (IsEqualIID(&amt
.formattype
, &FORMAT_VideoInfo
))
408 VIDEOINFOHEADER
* pvi
;
409 /* biCompression member appears to override the value in the stream header.
410 * i.e. the stream header can say something completely contradictory to what
411 * is in the BITMAPINFOHEADER! */
412 if (pChunk
->cb
< sizeof(BITMAPINFOHEADER
))
414 ERR("Not enough bytes for BITMAPINFOHEADER\n");
417 amt
.cbFormat
= sizeof(VIDEOINFOHEADER
) - sizeof(BITMAPINFOHEADER
) + pChunk
->cb
;
418 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
419 ZeroMemory(amt
.pbFormat
, amt
.cbFormat
);
420 pvi
= (VIDEOINFOHEADER
*)amt
.pbFormat
;
421 pvi
->AvgTimePerFrame
= (LONGLONG
)(10000000.0 / fSamplesPerSec
);
422 CopyMemory(&pvi
->bmiHeader
, (const BYTE
*)(pChunk
+ 1), pChunk
->cb
);
423 if (pvi
->bmiHeader
.biCompression
)
424 amt
.subtype
.Data1
= pvi
->bmiHeader
.biCompression
;
428 amt
.cbFormat
= pChunk
->cb
;
429 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
430 CopyMemory(amt
.pbFormat
, (const BYTE
*)(pChunk
+ 1), amt
.cbFormat
);
434 TRACE("processing stream name\n");
435 /* FIXME: this doesn't exactly match native version (we omit the "##)" prefix), but hey... */
436 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)(pChunk
+ 1), pChunk
->cb
, piOutput
.achName
, sizeof(piOutput
.achName
) / sizeof(piOutput
.achName
[0]));
438 case ckidSTREAMHANDLERDATA
:
439 FIXME("process stream handler data\n");
442 TRACE("JUNK chunk ignored\n");
445 FIXME("unknown chunk type \"%.04s\" ignored\n", (LPCSTR
)&pChunk
->fcc
);
449 if (IsEqualGUID(&amt
.formattype
, &FORMAT_WaveFormatEx
))
451 memcpy(&amt
.subtype
, &MEDIATYPE_Video
, sizeof(GUID
));
452 amt
.subtype
.Data1
= ((WAVEFORMATEX
*)amt
.pbFormat
)->wFormatTag
;
455 dump_AM_MEDIA_TYPE(&amt
);
456 TRACE("fSamplesPerSec = %f\n", (double)fSamplesPerSec
);
457 TRACE("dwSampleSize = %x\n", dwSampleSize
);
458 TRACE("dwLength = %x\n", dwLength
);
460 hr
= Parser_AddPin(&(This
->Parser
), &piOutput
, &props
, &amt
, fSamplesPerSec
, dwSampleSize
, dwLength
);
465 /* FIXME: fix leaks on failure here */
466 static HRESULT
AVISplitter_InputPin_PreConnect(IPin
* iface
, IPin
* pConnectPin
)
468 PullPin
*This
= (PullPin
*)iface
;
471 LONGLONG pos
= 0; /* in bytes */
473 RIFFCHUNK
* pCurrentChunk
;
474 AVISplitterImpl
* pAviSplit
= (AVISplitterImpl
*)This
->pin
.pinInfo
.pFilter
;
476 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(list
), (BYTE
*)&list
);
479 if (list
.fcc
!= ckidRIFF
)
481 ERR("Input stream not a RIFF file\n");
484 if (list
.fccListType
!= ckidAVI
)
486 ERR("Input stream not an AVI RIFF file\n");
490 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(list
), (BYTE
*)&list
);
491 if (list
.fcc
!= ckidLIST
)
493 ERR("Expected LIST chunk, but got %.04s\n", (LPSTR
)&list
.fcc
);
496 if (list
.fccListType
!= ckidHEADERLIST
)
498 ERR("Header list expected. Got: %.04s\n", (LPSTR
)&list
.fccListType
);
502 pBuffer
= HeapAlloc(GetProcessHeap(), 0, list
.cb
- sizeof(RIFFLIST
) + sizeof(RIFFCHUNK
));
503 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
+ sizeof(list
), list
.cb
- sizeof(RIFFLIST
) + sizeof(RIFFCHUNK
), pBuffer
);
505 pAviSplit
->AviHeader
.cb
= 0;
507 for (pCurrentChunk
= (RIFFCHUNK
*)pBuffer
; (BYTE
*)pCurrentChunk
+ sizeof(*pCurrentChunk
) < pBuffer
+ list
.cb
; pCurrentChunk
= (RIFFCHUNK
*)(((BYTE
*)pCurrentChunk
) + sizeof(*pCurrentChunk
) + pCurrentChunk
->cb
))
511 switch (pCurrentChunk
->fcc
)
513 case ckidMAINAVIHEADER
:
514 /* AVIMAINHEADER includes the structure that is pCurrentChunk at the moment */
515 memcpy(&pAviSplit
->AviHeader
, pCurrentChunk
, sizeof(pAviSplit
->AviHeader
));
518 pList
= (RIFFLIST
*)pCurrentChunk
;
519 switch (pList
->fccListType
)
522 hr
= AVISplitter_ProcessStreamList(pAviSplit
, (BYTE
*)pCurrentChunk
+ sizeof(RIFFLIST
), pCurrentChunk
->cb
+ sizeof(RIFFCHUNK
) - sizeof(RIFFLIST
));
525 FIXME("process ODML header\n");
533 FIXME("unrecognised header list type: %.04s\n", (LPSTR
)&pCurrentChunk
->fcc
);
536 HeapFree(GetProcessHeap(), 0, pBuffer
);
538 if (pAviSplit
->AviHeader
.cb
!= sizeof(pAviSplit
->AviHeader
) - sizeof(RIFFCHUNK
))
540 ERR("Avi Header wrong size!\n");
544 pos
+= sizeof(RIFFCHUNK
) + list
.cb
;
545 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(list
), (BYTE
*)&list
);
547 while (list
.fcc
== ckidJUNK
|| (list
.fcc
== ckidLIST
&& list
.fccListType
== ckidINFO
))
549 pos
+= sizeof(RIFFCHUNK
) + list
.cb
;
550 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(list
), (BYTE
*)&list
);
553 if (list
.fcc
!= ckidLIST
)
555 ERR("Expected LIST, but got %.04s\n", (LPSTR
)&list
.fcc
);
558 if (list
.fccListType
!= ckidAVIMOVIE
)
560 ERR("Expected AVI movie list, but got %.04s\n", (LPSTR
)&list
.fccListType
);
566 pAviSplit
->CurrentChunkOffset
= MEDIATIME_FROM_BYTES(pos
+ sizeof(RIFFLIST
));
567 pAviSplit
->EndOfFile
= MEDIATIME_FROM_BYTES(pos
+ list
.cb
+ sizeof(RIFFLIST
));
568 hr
= IAsyncReader_SyncRead(This
->pReader
, BYTES_FROM_MEDIATIME(pAviSplit
->CurrentChunkOffset
), sizeof(pAviSplit
->CurrentChunk
), (BYTE
*)&pAviSplit
->CurrentChunk
);
574 TRACE("AVI File ok\n");
579 static HRESULT
AVISplitter_Cleanup(LPVOID iface
)
581 AVISplitterImpl
*This
= (AVISplitterImpl
*)iface
;
583 TRACE("(%p)->()\n", This
);
585 if (This
->pCurrentSample
)
586 IMediaSample_Release(This
->pCurrentSample
);
587 This
->pCurrentSample
= NULL
;
592 HRESULT
AVISplitter_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
595 AVISplitterImpl
* This
;
597 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
602 return CLASS_E_NOAGGREGATION
;
604 /* Note: This memory is managed by the transform filter once created */
605 This
= CoTaskMemAlloc(sizeof(AVISplitterImpl
));
607 This
->pCurrentSample
= NULL
;
609 hr
= Parser_Create(&(This
->Parser
), &CLSID_AviSplitter
, AVISplitter_Sample
, AVISplitter_QueryAccept
, AVISplitter_InputPin_PreConnect
, AVISplitter_Cleanup
);