2 * QuickTime splitter + decoder
4 * Copyright 2011 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
26 #define LoadResource __carbon_LoadResource
27 #define CompareString __carbon_CompareString
28 #define GetCurrentThread __carbon_GetCurrentThread
29 #define GetCurrentProcess __carbon_GetCurrentProcess
30 #define AnimatePalette __carbon_AnimatePalette
31 #define EqualRgn __carbon_EqualRgn
32 #define FillRgn __carbon_FillRgn
33 #define FrameRgn __carbon_FrameRgn
34 #define GetPixel __carbon_GetPixel
35 #define InvertRgn __carbon_InvertRgn
36 #define LineTo __carbon_LineTo
37 #define OffsetRgn __carbon_OffsetRgn
38 #define PaintRgn __carbon_PaintRgn
39 #define Polygon __carbon_Polygon
40 #define ResizePalette __carbon_ResizePalette
41 #define SetRectRgn __carbon_SetRectRgn
43 #define CheckMenuItem __carbon_CheckMenuItem
44 #define DeleteMenu __carbon_DeleteMenu
45 #define DrawMenuBar __carbon_DrawMenuBar
46 #define EnableMenuItem __carbon_EnableMenuItem
47 #define EqualRect __carbon_EqualRect
48 #define FillRect __carbon_FillRect
49 #define FrameRect __carbon_FrameRect
50 #define GetCursor __carbon_GetCursor
51 #define GetMenu __carbon_GetMenu
52 #define InvertRect __carbon_InvertRect
53 #define IsWindowVisible __carbon_IsWindowVisible
54 #define MoveWindow __carbon_MoveWindow
55 #define OffsetRect __carbon_OffsetRect
56 #define PtInRect __carbon_PtInRect
57 #define SetCursor __carbon_SetCursor
58 #define SetRect __carbon_SetRect
59 #define ShowCursor __carbon_ShowCursor
60 #define ShowWindow __carbon_ShowWindow
61 #define UnionRect __carbon_UnionRect
63 #include <QuickTime/Movies.h>
64 #include <QuickTime/QuickTimeComponents.h>
68 #undef GetCurrentThread
71 #undef GetCurrentProcess
94 #undef IsWindowVisible
107 #undef STDMETHODCALLTYPE
113 #define NONAMELESSSTRUCT
114 #define NONAMELESSUNION
125 #include "wine/unicode.h"
126 #include "wine/debug.h"
127 #include "wine/strmbase.h"
129 #include "qtprivate.h"
131 WINE_DEFAULT_DEBUG_CHANNEL(qtsplitter
);
132 extern CLSID CLSID_QTSplitter
;
134 typedef struct QTOutPin
{
136 IQualityControl IQualityControl_iface
;
142 typedef struct QTInPin
{
146 IAsyncReader
*pReader
;
147 IMemAllocator
*pAlloc
;
150 typedef struct QTSplitter
{
154 QTOutPin
*pVideo_Pin
;
155 QTOutPin
*pAudio_Pin
;
157 ALLOCATOR_PROPERTIES props
;
160 QTVisualContextRef vContext
;
162 MovieAudioExtractionRef aSession
;
167 CRITICAL_SECTION csReceive
;
169 SourceSeeking sourceSeeking
;
170 TimeValue movie_time
;
171 TimeValue movie_start
;
172 TimeScale movie_scale
;
175 static const IPinVtbl QT_OutputPin_Vtbl
;
176 static const IPinVtbl QT_InputPin_Vtbl
;
177 static const IBaseFilterVtbl QT_Vtbl
;
178 static const IMediaSeekingVtbl QT_Seeking_Vtbl
;
180 static HRESULT
QT_AddPin(QTSplitter
*This
, const PIN_INFO
*piOutput
, const AM_MEDIA_TYPE
*amt
, BOOL video
);
181 static HRESULT
QT_RemoveOutputPins(QTSplitter
*This
);
183 static HRESULT WINAPI
QTSplitter_ChangeStart(IMediaSeeking
*iface
);
184 static HRESULT WINAPI
QTSplitter_ChangeStop(IMediaSeeking
*iface
);
185 static HRESULT WINAPI
QTSplitter_ChangeRate(IMediaSeeking
*iface
);
187 static inline QTSplitter
*impl_from_IMediaSeeking( IMediaSeeking
*iface
)
189 return CONTAINING_RECORD(iface
, QTSplitter
, sourceSeeking
.IMediaSeeking_iface
);
192 static inline QTSplitter
*impl_from_BaseFilter( BaseFilter
*iface
)
194 return CONTAINING_RECORD(iface
, QTSplitter
, filter
);
197 static inline QTSplitter
*impl_from_IBaseFilter( IBaseFilter
*iface
)
199 return CONTAINING_RECORD(iface
, QTSplitter
, filter
.IBaseFilter_iface
);
206 static IPin
* WINAPI
QT_GetPin(BaseFilter
*iface
, int pos
)
208 QTSplitter
*This
= impl_from_BaseFilter(iface
);
209 TRACE("Asking for pos %x\n", pos
);
211 if (pos
> 2 || pos
< 0)
216 IPin_AddRef(&This
->pInputPin
.pin
.IPin_iface
);
217 return &This
->pInputPin
.pin
.IPin_iface
;
219 if (This
->pVideo_Pin
)
220 IPin_AddRef(&This
->pVideo_Pin
->pin
.pin
.IPin_iface
);
221 return &This
->pVideo_Pin
->pin
.pin
.IPin_iface
;
223 if (This
->pAudio_Pin
)
224 IPin_AddRef(&This
->pAudio_Pin
->pin
.pin
.IPin_iface
);
225 return &This
->pAudio_Pin
->pin
.pin
.IPin_iface
;
231 static LONG WINAPI
QT_GetPinCount(BaseFilter
*iface
)
233 QTSplitter
*This
= impl_from_BaseFilter(iface
);
235 if (This
->pAudio_Pin
) c
++;
236 if (This
->pVideo_Pin
) c
++;
240 static const BaseFilterFuncTable BaseFuncTable
= {
245 IUnknown
* CALLBACK
QTSplitter_create(IUnknown
*punkout
, HRESULT
*phr
)
247 IUnknown
*obj
= NULL
;
250 static const WCHAR wcsInputPinName
[] = {'I','n','p','u','t',' ','P','i','n',0};
254 RegisterWineDataHandler();
256 This
= CoTaskMemAlloc(sizeof(*This
));
257 obj
= (IUnknown
*)This
;
260 *phr
= E_OUTOFMEMORY
;
263 ZeroMemory(This
,sizeof(*This
));
265 BaseFilter_Init(&This
->filter
, &QT_Vtbl
, &CLSID_QTSplitter
, (DWORD_PTR
)(__FILE__
": QTSplitter.csFilter"), &BaseFuncTable
);
267 InitializeCriticalSection(&This
->csReceive
);
268 This
->csReceive
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": QTSplitter.csReceive");
270 This
->pVideo_Pin
= NULL
;
271 This
->pAudio_Pin
= NULL
;
272 This
->state
= State_Stopped
;
273 This
->aSession
= NULL
;
274 This
->runEvent
= CreateEventW(NULL
, 0, 0, NULL
);
276 piInput
= &This
->pInputPin
.pin
.pinInfo
;
277 piInput
->dir
= PINDIR_INPUT
;
278 piInput
->pFilter
= &This
->filter
.IBaseFilter_iface
;
279 lstrcpynW(piInput
->achName
, wcsInputPinName
, sizeof(piInput
->achName
) / sizeof(piInput
->achName
[0]));
280 This
->pInputPin
.pin
.IPin_iface
.lpVtbl
= &QT_InputPin_Vtbl
;
281 This
->pInputPin
.pin
.refCount
= 1;
282 This
->pInputPin
.pin
.pConnectedTo
= NULL
;
283 This
->pInputPin
.pin
.pCritSec
= &This
->filter
.csFilter
;
285 SourceSeeking_Init(&This
->sourceSeeking
, &QT_Seeking_Vtbl
, QTSplitter_ChangeStop
, QTSplitter_ChangeStart
, QTSplitter_ChangeRate
, &This
->filter
.csFilter
);
291 static void QT_Destroy(QTSplitter
*This
)
293 IPin
*connected
= NULL
;
296 TRACE("Destroying\n");
298 /* Don't need to clean up output pins, disconnecting input pin will do that */
299 IPin_ConnectedTo(&This
->pInputPin
.pin
.IPin_iface
, &connected
);
302 IPin_Disconnect(connected
);
303 IPin_Release(connected
);
305 pinref
= IPin_Release(&This
->pInputPin
.pin
.IPin_iface
);
308 ERR("pinref should be null, is %u, destroying anyway\n", pinref
);
309 assert((LONG
)pinref
> 0);
312 pinref
= IPin_Release(&This
->pInputPin
.pin
.IPin_iface
);
316 DisposeMovie(This
->pQTMovie
);
318 QTVisualContextRelease(This
->vContext
);
320 MovieAudioExtractionEnd(This
->aSession
);
321 CloseHandle(This
->runEvent
);
325 This
->csReceive
.DebugInfo
->Spare
[0] = 0;
326 DeleteCriticalSection(&This
->csReceive
);
331 static HRESULT WINAPI
QT_QueryInterface(IBaseFilter
*iface
, REFIID riid
, LPVOID
*ppv
)
333 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
334 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
338 if (IsEqualIID(riid
, &IID_IUnknown
))
340 else if (IsEqualIID(riid
, &IID_IPersist
))
342 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
344 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
346 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
347 *ppv
= &This
->sourceSeeking
;
351 IUnknown_AddRef((IUnknown
*)(*ppv
));
355 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
) &&
356 !IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
357 FIXME("No interface for %s!\n", debugstr_guid(riid
));
359 return E_NOINTERFACE
;
362 static ULONG WINAPI
QT_Release(IBaseFilter
*iface
)
364 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
365 ULONG refCount
= BaseFilterImpl_Release(iface
);
367 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
375 static HRESULT WINAPI
QT_Stop(IBaseFilter
*iface
)
377 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
381 EnterCriticalSection(&This
->csReceive
);
382 IAsyncReader_BeginFlush(This
->pInputPin
.pReader
);
383 IAsyncReader_EndFlush(This
->pInputPin
.pReader
);
384 LeaveCriticalSection(&This
->csReceive
);
389 static HRESULT WINAPI
QT_Pause(IBaseFilter
*iface
)
397 static OSErr
QT_Create_Extract_Session(QTSplitter
*filter
)
399 AudioStreamBasicDescription aDesc
;
403 pvi
= (WAVEFORMATEX
*)filter
->pAudio_Pin
->pmt
->pbFormat
;
405 err
= MovieAudioExtractionBegin(filter
->pQTMovie
, 0, &filter
->aSession
);
408 ERR("Failed to begin Extraction session %i\n",err
);
412 err
= MovieAudioExtractionGetProperty(filter
->aSession
,
413 kQTPropertyClass_MovieAudioExtraction_Audio
,
414 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription
,
415 sizeof(AudioStreamBasicDescription
), &aDesc
, NULL
);
419 MovieAudioExtractionEnd(filter
->aSession
);
420 filter
->aSession
= NULL
;
421 ERR("Failed to get session description %i\n",err
);
425 aDesc
.mFormatID
= kAudioFormatLinearPCM
;
426 aDesc
.mFormatFlags
= kLinearPCMFormatFlagIsSignedInteger
+
427 kAudioFormatFlagIsPacked
;
428 aDesc
.mFramesPerPacket
= 1;
429 aDesc
.mChannelsPerFrame
= pvi
->nChannels
;
430 aDesc
.mBitsPerChannel
= pvi
->wBitsPerSample
;
431 aDesc
.mSampleRate
= pvi
->nSamplesPerSec
;
432 aDesc
.mBytesPerFrame
= (aDesc
.mBitsPerChannel
* aDesc
.mChannelsPerFrame
) / 8;
433 aDesc
.mBytesPerPacket
= aDesc
.mBytesPerFrame
* aDesc
.mFramesPerPacket
;
435 err
= MovieAudioExtractionSetProperty(filter
->aSession
,
436 kQTPropertyClass_MovieAudioExtraction_Audio
,
437 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription
,
438 sizeof(AudioStreamBasicDescription
), &aDesc
);
440 if (aDesc
.mFormatID
!= kAudioFormatLinearPCM
)
442 ERR("Not PCM Wave\n");
445 if (aDesc
.mFormatFlags
!= kLinearPCMFormatFlagIsSignedInteger
+
446 kAudioFormatFlagIsPacked
)
448 ERR("Unhandled Flags\n");
451 if (aDesc
.mFramesPerPacket
!= 1)
453 ERR("Unhandled Frames per packet %li\n",aDesc
.mFramesPerPacket
);
456 if (aDesc
.mChannelsPerFrame
!= pvi
->nChannels
)
458 ERR("Unhandled channel count %li\n",aDesc
.mChannelsPerFrame
);
461 if (aDesc
.mBitsPerChannel
!= pvi
->wBitsPerSample
)
463 ERR("Unhandled bits per channel %li\n",aDesc
.mBitsPerChannel
);
466 if (aDesc
.mSampleRate
!= pvi
->nSamplesPerSec
)
468 ERR("Unhandled sample rate %f\n",aDesc
.mSampleRate
);
474 ERR("Failed to create Extraction Session\n");
475 MovieAudioExtractionEnd(filter
->aSession
);
476 filter
->aSession
= NULL
;
482 static DWORD WINAPI
QTSplitter_thread(LPVOID data
)
484 QTSplitter
*This
= (QTSplitter
*)data
;
487 CVPixelBufferRef pixelBuffer
= NULL
;
491 if (This
->pAudio_Pin
)
493 /* according to QA1469 a movie has to be fully loaded before we
494 can reliably start the Extraction session */
496 while(GetMovieLoadState(This
->pQTMovie
) < kMovieLoadStateComplete
)
497 MoviesTask(This
->pQTMovie
,1000);
499 QT_Create_Extract_Session(This
);
502 WaitForSingleObject(This
->runEvent
, -1);
504 EnterCriticalSection(&This
->csReceive
);
505 This
->state
= State_Running
;
506 /* Prime the pump: Needed for MPEG streams */
507 GetMovieNextInterestingTime(This
->pQTMovie
, nextTimeEdgeOK
| nextTimeStep
, 0, NULL
, This
->movie_time
, 1, &next_time
, NULL
);
509 GetMovieTime(This
->pQTMovie
, &tr
);
510 LeaveCriticalSection(&This
->csReceive
);
513 LONGLONG tStart
=0, tStop
=0;
514 LONGLONG mStart
=0, mStop
=0;
517 EnterCriticalSection(&This
->csReceive
);
518 GetMovieNextInterestingTime(This
->pQTMovie
, nextTimeStep
, 0, NULL
, This
->movie_time
, 1, &next_time
, NULL
);
522 TRACE("No next time\n");
523 LeaveCriticalSection(&This
->csReceive
);
527 tr
.value
= SInt64ToWide(next_time
);
528 SetMovieTime(This
->pQTMovie
, &tr
);
529 MoviesTask(This
->pQTMovie
,0);
530 QTVisualContextTask(This
->vContext
);
532 TRACE("In loop at time %ld\n",This
->movie_time
);
533 TRACE("In Next time %ld\n",next_time
);
535 mStart
= This
->movie_time
;
538 time
= (float)(This
->movie_time
- This
->movie_start
) / This
->movie_scale
;
539 tStart
= time
* 10000000;
540 time
= (float)(next_time
- This
->movie_start
) / This
->movie_scale
;
541 tStop
= time
* 10000000;
544 if (This
->pAudio_Pin
&& This
->pAudio_Pin
->pin
.pin
.pConnectedTo
&& This
->aSession
)
548 IMediaSample
*sample
= NULL
;
549 AudioBufferList aData
;
555 pvi
= (WAVEFORMATEX
*)This
->pAudio_Pin
->pmt
->pbFormat
;
557 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&This
->pAudio_Pin
->pin
, &sample
, NULL
, NULL
, 0);
561 ERR("Audio: Unable to get delivery buffer (%x)\n", hr
);
565 hr
= IMediaSample_GetPointer(sample
, &ptr
);
568 ERR("Audio: Unable to get pointer to buffer (%x)\n", hr
);
572 duration
= (float)next_time
/ This
->movie_scale
;
573 time
= (float)This
->movie_time
/ This
->movie_scale
;
575 frames
= pvi
->nSamplesPerSec
* duration
;
576 TRACE("Need audio for %f seconds (%li frames)\n",duration
,frames
);
578 data_size
= IMediaSample_GetSize(sample
);
579 if (data_size
< frames
* pvi
->nBlockAlign
)
580 FIXME("Audio buffer is too small\n");
582 aData
.mNumberBuffers
= 1;
583 aData
.mBuffers
[0].mNumberChannels
= pvi
->nChannels
;
584 aData
.mBuffers
[0].mDataByteSize
= data_size
;
585 aData
.mBuffers
[0].mData
= ptr
;
587 err
= MovieAudioExtractionFillBuffer(This
->aSession
, &frames
, &aData
, &flags
);
588 TRACE("Got %i frames\n",(int)frames
);
590 IMediaSample_SetActualDataLength(sample
, frames
* pvi
->nBlockAlign
);
592 IMediaSample_SetMediaTime(sample
, &mStart
, &mStop
);
593 IMediaSample_SetTime(sample
, &tStart
, &tStop
);
595 hr
= OutputQueue_Receive(This
->pAudio_Pin
->queue
, sample
);
596 TRACE("Audio Delivered (%x)\n",hr
);
600 IMediaSample_Release(sample
);
603 TRACE("Audio Pin not connected or no Audio\n");
606 if (This
->pVideo_Pin
&& QTVisualContextIsNewImageAvailable(This
->vContext
,0))
608 err
= QTVisualContextCopyImageForTime(This
->vContext
, NULL
, NULL
, &pixelBuffer
);
613 IMediaSample
*sample
= NULL
;
615 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&This
->pVideo_Pin
->pin
, &sample
, NULL
, NULL
, 0);
618 ERR("Video: Unable to get delivery buffer (%x)\n", hr
);
622 data_size
= IMediaSample_GetSize(sample
);
623 if (data_size
< This
->outputSize
)
625 ERR("Sample size is too small %d < %d\n", data_size
, This
->outputSize
)
631 hr
= IMediaSample_GetPointer(sample
, &ptr
);
634 ERR("Video: Unable to get pointer to buffer (%x)\n", hr
);
638 hr
= AccessPixelBufferPixels( pixelBuffer
, ptr
);
641 ERR("Failed to access Pixels\n");
645 IMediaSample_SetActualDataLength(sample
, This
->outputSize
);
647 IMediaSample_SetMediaTime(sample
, &mStart
, &mStop
);
648 IMediaSample_SetTime(sample
, &tStart
, &tStop
);
650 hr
= OutputQueue_Receive(This
->pVideo_Pin
->queue
, sample
);
651 TRACE("Video Delivered (%x)\n",hr
);
655 IMediaSample_Release(sample
);
657 CVPixelBufferRelease(pixelBuffer
);
661 TRACE("No video to deliver\n");
663 This
->movie_time
= next_time
;
664 LeaveCriticalSection(&This
->csReceive
);
665 } while (hr
== S_OK
);
667 This
->state
= State_Stopped
;
668 if (This
->pAudio_Pin
)
669 OutputQueue_EOS(This
->pAudio_Pin
->queue
);
670 if (This
->pVideo_Pin
)
671 OutputQueue_EOS(This
->pVideo_Pin
->queue
);
676 static HRESULT WINAPI
QT_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
679 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
680 HRESULT hr_any
= VFW_E_NOT_CONNECTED
;
682 TRACE("(%s)\n", wine_dbgstr_longlong(tStart
));
684 EnterCriticalSection(&This
->csReceive
);
685 This
->filter
.rtStreamStart
= tStart
;
687 if (This
->pVideo_Pin
)
688 hr
= BaseOutputPinImpl_Active(&This
->pVideo_Pin
->pin
);
691 if (This
->pAudio_Pin
)
692 hr
= BaseOutputPinImpl_Active(&This
->pAudio_Pin
->pin
);
698 SetEvent(This
->runEvent
);
699 LeaveCriticalSection(&This
->csReceive
);
704 static HRESULT WINAPI
QT_GetState(IBaseFilter
*iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
706 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
707 TRACE("(%d, %p)\n", dwMilliSecsTimeout
, pState
);
709 *pState
= This
->state
;
714 static HRESULT WINAPI
QT_FindPin(IBaseFilter
*iface
, LPCWSTR Id
, IPin
**ppPin
)
716 FIXME("(%p)->(%s,%p) stub\n", iface
, debugstr_w(Id
), ppPin
);
720 static const IBaseFilterVtbl QT_Vtbl
= {
722 BaseFilterImpl_AddRef
,
724 BaseFilterImpl_GetClassID
,
729 BaseFilterImpl_SetSyncSource
,
730 BaseFilterImpl_GetSyncSource
,
731 BaseFilterImpl_EnumPins
,
733 BaseFilterImpl_QueryFilterInfo
,
734 BaseFilterImpl_JoinFilterGraph
,
735 BaseFilterImpl_QueryVendorInfo
741 static HRESULT
QT_RemoveOutputPins(QTSplitter
*This
)
744 TRACE("(%p)\n", This
);
746 if (This
->pVideo_Pin
)
748 OutputQueue_Destroy(This
->pVideo_Pin
->queue
);
749 hr
= BaseOutputPinImpl_BreakConnect(&This
->pVideo_Pin
->pin
);
750 TRACE("Disconnect: %08x\n", hr
);
751 IPin_Release(&This
->pVideo_Pin
->pin
.pin
.IPin_iface
);
752 This
->pVideo_Pin
= NULL
;
754 if (This
->pAudio_Pin
)
756 OutputQueue_Destroy(This
->pAudio_Pin
->queue
);
757 hr
= BaseOutputPinImpl_BreakConnect(&This
->pAudio_Pin
->pin
);
758 TRACE("Disconnect: %08x\n", hr
);
759 IPin_Release(&This
->pAudio_Pin
->pin
.pin
.IPin_iface
);
760 This
->pAudio_Pin
= NULL
;
763 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
767 static inline QTInPin
*impl_from_IPin( IPin
*iface
)
769 return CONTAINING_RECORD(iface
, QTInPin
, pin
.IPin_iface
);
772 static ULONG WINAPI
QTInPin_Release(IPin
*iface
)
774 QTInPin
*This
= impl_from_IPin(iface
);
775 ULONG refCount
= InterlockedDecrement(&This
->pin
.refCount
);
777 TRACE("(%p)->() Release from %d\n", iface
, refCount
+ 1);
780 FreeMediaType(&This
->pin
.mtCurrent
);
782 IMemAllocator_Release(This
->pAlloc
);
784 This
->pin
.IPin_iface
.lpVtbl
= NULL
;
791 static HRESULT
QT_Process_Video_Track(QTSplitter
* filter
, Track trk
)
794 VIDEOINFOHEADER
* pvi
;
798 static const WCHAR szwVideoOut
[] = {'V','i','d','e','o',0};
799 CFMutableDictionaryRef pixelBufferOptions
= NULL
;
800 CFMutableDictionaryRef visualContextOptions
= NULL
;
801 CFNumberRef n
= NULL
;
803 DWORD outputWidth
, outputHeight
, outputDepth
;
804 Fixed trackWidth
, trackHeight
;
806 ZeroMemory(&amt
, sizeof(amt
));
807 amt
.formattype
= FORMAT_VideoInfo
;
808 amt
.majortype
= MEDIATYPE_Video
;
809 amt
.subtype
= MEDIASUBTYPE_RGB24
;
811 GetTrackDimensions(trk
, &trackWidth
, &trackHeight
);
814 outputWidth
= Fix2Long(trackWidth
);
815 outputHeight
= Fix2Long(trackHeight
);
816 TRACE("Width %i Height %i\n",outputWidth
, outputHeight
);
818 amt
.cbFormat
= sizeof(VIDEOINFOHEADER
);
819 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
820 ZeroMemory(amt
.pbFormat
, amt
.cbFormat
);
821 pvi
= (VIDEOINFOHEADER
*)amt
.pbFormat
;
822 pvi
->bmiHeader
.biSize
= sizeof (BITMAPINFOHEADER
);
823 pvi
->bmiHeader
.biWidth
= outputWidth
;
824 pvi
->bmiHeader
.biHeight
= outputHeight
;
825 pvi
->bmiHeader
.biPlanes
= 1;
826 pvi
->bmiHeader
.biBitCount
= 24;
827 pvi
->bmiHeader
.biCompression
= BI_RGB
;
828 pvi
->bmiHeader
.biSizeImage
= outputWidth
* outputHeight
* outputDepth
;
830 filter
->outputSize
= pvi
->bmiHeader
.biSizeImage
;
833 pixelBufferOptions
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
835 t
= k32ARGBPixelFormat
;
836 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &t
);
837 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferPixelFormatTypeKey
, n
);
840 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &outputWidth
);
841 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferWidthKey
, n
);
844 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &outputHeight
);
845 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferHeightKey
, n
);
849 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &t
);
850 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferBytesPerRowAlignmentKey
, n
);
853 visualContextOptions
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
855 CFDictionarySetValue(visualContextOptions
, kQTVisualContextPixelBufferAttributesKey
, pixelBufferOptions
);
857 err
= QTPixelBufferContextCreate(NULL
, visualContextOptions
,&filter
->vContext
);
858 CFRelease(pixelBufferOptions
);
859 CFRelease(visualContextOptions
);
862 ERR("Failed to create Visual Context\n");
866 err
= SetMovieVisualContext(filter
->pQTMovie
, filter
->vContext
);
869 ERR("Failed to set Visual Context\n");
873 piOutput
.dir
= PINDIR_OUTPUT
;
874 piOutput
.pFilter
= &filter
->filter
.IBaseFilter_iface
;
875 lstrcpyW(piOutput
.achName
,szwVideoOut
);
877 hr
= QT_AddPin(filter
, &piOutput
, &amt
, TRUE
);
879 ERR("Failed to add Video Track\n");
881 TRACE("Video Pin %p\n",filter
->pVideo_Pin
);
886 static HRESULT
QT_Process_Audio_Track(QTSplitter
* filter
, Track trk
)
892 static const WCHAR szwAudioOut
[] = {'A','u','d','i','o',0};
895 SoundDescriptionHandle aDesc
= (SoundDescriptionHandle
) NewHandle(sizeof(SoundDescription
));
897 audioMedia
= GetTrackMedia(trk
);
898 GetMediaSampleDescription(audioMedia
, 1, (SampleDescriptionHandle
)aDesc
);
900 ZeroMemory(&amt
, sizeof(amt
));
901 amt
.formattype
= FORMAT_WaveFormatEx
;
902 amt
.majortype
= MEDIATYPE_Audio
;
903 amt
.subtype
= MEDIASUBTYPE_PCM
;
904 amt
.bTemporalCompression
= 0;
906 amt
.cbFormat
= sizeof(WAVEFORMATEX
);
907 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
908 ZeroMemory(amt
.pbFormat
, amt
.cbFormat
);
909 pvi
= (WAVEFORMATEX
*)amt
.pbFormat
;
911 pvi
->cbSize
= sizeof(WAVEFORMATEX
);
912 pvi
->wFormatTag
= WAVE_FORMAT_PCM
;
913 pvi
->nChannels
= ((SoundDescription
)**aDesc
).numChannels
;
914 if (pvi
->nChannels
< 1 || pvi
->nChannels
> 2)
916 pvi
->nSamplesPerSec
= (((SoundDescription
)**aDesc
).sampleRate
/65536);
917 if (pvi
->nSamplesPerSec
< 8000 || pvi
->nChannels
> 48000)
918 pvi
->nSamplesPerSec
= 44100;
919 pvi
->wBitsPerSample
= ((SoundDescription
)**aDesc
).sampleSize
;
920 if (pvi
->wBitsPerSample
< 8 || pvi
->wBitsPerSample
> 32)
921 pvi
->wBitsPerSample
= 16;
922 pvi
->nBlockAlign
= (pvi
->nChannels
* pvi
->wBitsPerSample
) / 8;
923 pvi
->nAvgBytesPerSec
= pvi
->nSamplesPerSec
* pvi
->nBlockAlign
;
925 DisposeHandle((Handle
)aDesc
);
927 piOutput
.dir
= PINDIR_OUTPUT
;
928 piOutput
.pFilter
= &filter
->filter
.IBaseFilter_iface
;
929 lstrcpyW(piOutput
.achName
,szwAudioOut
);
931 hr
= QT_AddPin(filter
, &piOutput
, &amt
, FALSE
);
933 ERR("Failed to add Audio Track\n");
935 TRACE("Audio Pin %p\n",filter
->pAudio_Pin
);
939 static HRESULT
QT_Process_Movie(QTSplitter
* filter
)
943 WineDataRefRecord ptrDataRefRec
;
944 Handle dataRef
= NULL
;
951 TRACE("Trying movie connect\n");
953 ptrDataRefRec
.pReader
= filter
->pInputPin
.pReader
;
954 ptrDataRefRec
.streamSubtype
= filter
->pInputPin
.subType
;
955 PtrToHand( &ptrDataRefRec
, &dataRef
, sizeof(WineDataRefRecord
));
957 err
= NewMovieFromDataRef(&filter
->pQTMovie
, newMovieActive
|newMovieDontInteractWithUser
|newMovieDontAutoUpdateClock
|newMovieDontAskUnresolvedDataRefs
|newMovieAsyncOK
, &id
, dataRef
, 'WINE');
959 DisposeHandle(dataRef
);
963 FIXME("QuickTime cannot handle media type(%i)\n",err
);
964 return VFW_E_TYPE_NOT_ACCEPTED
;
967 PrePrerollMovie(filter
->pQTMovie
, 0, fixed1
, NULL
, NULL
);
968 PrerollMovie(filter
->pQTMovie
, 0, fixed1
);
969 GoToBeginningOfMovie(filter
->pQTMovie
);
970 SetMovieActive(filter
->pQTMovie
,TRUE
);
972 if (GetMovieLoadState(filter
->pQTMovie
) < kMovieLoadStateLoaded
)
973 MoviesTask(filter
->pQTMovie
,100);
975 trk
= GetMovieIndTrackType(filter
->pQTMovie
, 1, VisualMediaCharacteristic
, movieTrackCharacteristic
| movieTrackEnabledOnly
);
976 TRACE("%p is a video track\n",trk
);
978 hr
= QT_Process_Video_Track(filter
, trk
);
983 trk
= GetMovieIndTrackType(filter
->pQTMovie
, 1, AudioMediaCharacteristic
, movieTrackCharacteristic
| movieTrackEnabledOnly
);
984 TRACE("%p is a audio track\n",trk
);
986 hr
= QT_Process_Audio_Track(filter
, trk
);
988 time
= GetMovieDuration(filter
->pQTMovie
);
989 filter
->movie_scale
= GetMovieTimeScale(filter
->pQTMovie
);
990 filter
->sourceSeeking
.llDuration
= ((double)time
/ filter
->movie_scale
) * 10000000;
991 filter
->sourceSeeking
.llStop
= filter
->sourceSeeking
.llDuration
;
993 TRACE("Movie duration is %s\n",wine_dbgstr_longlong(filter
->sourceSeeking
.llDuration
));
995 thread
= CreateThread(NULL
, 0, QTSplitter_thread
, filter
, 0, &tid
);
998 TRACE("Created thread 0x%08x\n", tid
);
1002 hr
= HRESULT_FROM_WIN32(GetLastError());
1007 static HRESULT WINAPI
QTInPin_ReceiveConnection(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1010 ALLOCATOR_PROPERTIES props
;
1011 QTInPin
*This
= impl_from_IPin(iface
);
1013 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
1015 EnterCriticalSection(This
->pin
.pCritSec
);
1016 This
->pReader
= NULL
;
1018 if (This
->pin
.pConnectedTo
)
1019 hr
= VFW_E_ALREADY_CONNECTED
;
1020 else if (IPin_QueryAccept(iface
, pmt
) != S_OK
)
1021 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
1024 PIN_DIRECTION pindirReceive
;
1025 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
1026 if (pindirReceive
!= PINDIR_OUTPUT
)
1027 hr
= VFW_E_INVALID_DIRECTION
;
1032 LeaveCriticalSection(This
->pin
.pCritSec
);
1036 hr
= IPin_QueryInterface(pReceivePin
, &IID_IAsyncReader
, (LPVOID
*)&This
->pReader
);
1039 LeaveCriticalSection(This
->pin
.pCritSec
);
1040 TRACE("Input source is not an AsyncReader\n");
1044 LeaveCriticalSection(This
->pin
.pCritSec
);
1045 EnterCriticalSection(&impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->filter
.csFilter
);
1046 hr
= QT_Process_Movie(impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
));
1049 LeaveCriticalSection(&impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->filter
.csFilter
);
1050 TRACE("Unable to process movie\n");
1054 This
->pAlloc
= NULL
;
1057 props
.cbBuffer
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->outputSize
+ props
.cbAlign
;
1060 hr
= IAsyncReader_RequestAllocator(This
->pReader
, NULL
, &props
, &This
->pAlloc
);
1063 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
1064 This
->pin
.pConnectedTo
= pReceivePin
;
1065 IPin_AddRef(pReceivePin
);
1066 hr
= IMemAllocator_Commit(This
->pAlloc
);
1070 QT_RemoveOutputPins(impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
));
1072 IAsyncReader_Release(This
->pReader
);
1073 This
->pReader
= NULL
;
1075 IMemAllocator_Release(This
->pAlloc
);
1076 This
->pAlloc
= NULL
;
1078 TRACE("Size: %i\n", props
.cbBuffer
);
1079 LeaveCriticalSection(&impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->filter
.csFilter
);
1084 static HRESULT WINAPI
QTInPin_Disconnect(IPin
*iface
)
1087 QTInPin
*This
= impl_from_IPin(iface
);
1091 hr
= IBaseFilter_GetState(This
->pin
.pinInfo
.pFilter
, INFINITE
, &state
);
1092 EnterCriticalSection(This
->pin
.pCritSec
);
1093 if (This
->pin
.pConnectedTo
)
1095 QTSplitter
*Parser
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
1097 if (SUCCEEDED(hr
) && state
== State_Stopped
)
1099 IMemAllocator_Decommit(This
->pAlloc
);
1100 IPin_Disconnect(This
->pin
.pConnectedTo
);
1101 This
->pin
.pConnectedTo
= NULL
;
1102 hr
= QT_RemoveOutputPins(Parser
);
1105 hr
= VFW_E_NOT_STOPPED
;
1109 LeaveCriticalSection(This
->pin
.pCritSec
);
1113 static HRESULT WINAPI
QTInPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*pmt
)
1115 QTInPin
*This
= impl_from_IPin(iface
);
1117 TRACE("(%p)->(%p)\n", This
, pmt
);
1119 if (IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Stream
))
1121 This
->subType
= pmt
->subtype
;
1127 static HRESULT WINAPI
QTInPin_EndOfStream(IPin
*iface
)
1129 QTInPin
*pin
= impl_from_IPin(iface
);
1130 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1132 FIXME("Propagate message on %p\n", This
);
1136 static HRESULT WINAPI
QTInPin_BeginFlush(IPin
*iface
)
1138 QTInPin
*pin
= impl_from_IPin(iface
);
1139 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1141 FIXME("Propagate message on %p\n", This
);
1145 static HRESULT WINAPI
QTInPin_EndFlush(IPin
*iface
)
1147 QTInPin
*pin
= impl_from_IPin(iface
);
1148 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1150 FIXME("Propagate message on %p\n", This
);
1154 static HRESULT WINAPI
QTInPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
1156 QTInPin
*pin
= impl_from_IPin(iface
);
1157 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1159 BasePinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
1160 FIXME("Propagate message on %p\n", This
);
1164 static HRESULT WINAPI
QTInPin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
1166 QTInPin
*This
= impl_from_IPin(iface
);
1168 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
1172 if (IsEqualIID(riid
, &IID_IUnknown
))
1174 else if (IsEqualIID(riid
, &IID_IPin
))
1176 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
1177 return IBaseFilter_QueryInterface(This
->pin
.pinInfo
.pFilter
, &IID_IMediaSeeking
, ppv
);
1181 IUnknown_AddRef((IUnknown
*)(*ppv
));
1185 FIXME("No interface for %s!\n", debugstr_guid(riid
));
1187 return E_NOINTERFACE
;
1190 static HRESULT WINAPI
QTInPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
1192 QTInPin
*This
= impl_from_IPin(iface
);
1194 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
1196 return EnumMediaTypes_Construct(&This
->pin
, BasePinImpl_GetMediaType
, BasePinImpl_GetMediaTypeVersion
, ppEnum
);
1199 static const IPinVtbl QT_InputPin_Vtbl
= {
1200 QTInPin_QueryInterface
,
1203 BaseInputPinImpl_Connect
,
1204 QTInPin_ReceiveConnection
,
1206 BasePinImpl_ConnectedTo
,
1207 BasePinImpl_ConnectionMediaType
,
1208 BasePinImpl_QueryPinInfo
,
1209 BasePinImpl_QueryDirection
,
1210 BasePinImpl_QueryId
,
1211 QTInPin_QueryAccept
,
1212 QTInPin_EnumMediaTypes
,
1213 BasePinImpl_QueryInternalConnections
,
1214 QTInPin_EndOfStream
,
1223 static inline QTOutPin
*impl_QTOutPin_from_IPin( IPin
*iface
)
1225 return CONTAINING_RECORD(iface
, QTOutPin
, pin
.pin
.IPin_iface
);
1228 static inline QTOutPin
*impl_QTOutPin_from_BasePin( BasePin
*iface
)
1230 return CONTAINING_RECORD(iface
, QTOutPin
, pin
.pin
);
1233 static inline QTOutPin
*impl_QTOutPin_from_BaseOutputPin( BaseOutputPin
*iface
)
1235 return CONTAINING_RECORD(iface
, QTOutPin
, pin
);
1238 static HRESULT WINAPI
QTOutPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
1240 QTOutPin
*This
= impl_QTOutPin_from_IPin(iface
);
1242 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
1246 if (IsEqualIID(riid
, &IID_IUnknown
))
1248 else if (IsEqualIID(riid
, &IID_IPin
))
1250 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
1251 return IBaseFilter_QueryInterface(This
->pin
.pin
.pinInfo
.pFilter
, &IID_IMediaSeeking
, ppv
);
1252 else if (IsEqualIID(riid
, &IID_IQualityControl
))
1253 *ppv
= &This
->IQualityControl_iface
;
1257 IUnknown_AddRef((IUnknown
*)(*ppv
));
1260 FIXME("No interface for %s!\n", debugstr_guid(riid
));
1261 return E_NOINTERFACE
;
1264 static ULONG WINAPI
QTOutPin_Release(IPin
*iface
)
1266 QTOutPin
*This
= impl_QTOutPin_from_IPin(iface
);
1267 ULONG refCount
= InterlockedDecrement(&This
->pin
.pin
.refCount
);
1268 TRACE("(%p)->() Release from %d\n", iface
, refCount
+ 1);
1272 DeleteMediaType(This
->pmt
);
1273 FreeMediaType(&This
->pin
.pin
.mtCurrent
);
1274 CoTaskMemFree(This
);
1280 static HRESULT WINAPI
QTOutPin_GetMediaType(BasePin
*iface
, int iPosition
, AM_MEDIA_TYPE
*pmt
)
1282 QTOutPin
*This
= impl_QTOutPin_from_BasePin(iface
);
1285 return E_INVALIDARG
;
1287 return VFW_S_NO_MORE_ITEMS
;
1288 CopyMediaType(pmt
, This
->pmt
);
1292 static HRESULT WINAPI
QTOutPin_DecideBufferSize(BaseOutputPin
*iface
, IMemAllocator
*pAlloc
, ALLOCATOR_PROPERTIES
*ppropInputRequest
)
1298 static HRESULT WINAPI
QTOutPin_DecideAllocator(BaseOutputPin
*iface
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
1301 QTOutPin
*This
= impl_QTOutPin_from_BaseOutputPin(iface
);
1302 QTSplitter
*QTfilter
= impl_from_IBaseFilter(This
->pin
.pin
.pinInfo
.pFilter
);
1305 if (QTfilter
->pInputPin
.pAlloc
)
1306 hr
= IMemInputPin_NotifyAllocator(pPin
, QTfilter
->pInputPin
.pAlloc
, FALSE
);
1308 hr
= VFW_E_NO_ALLOCATOR
;
1313 static HRESULT WINAPI
QTOutPin_BreakConnect(BaseOutputPin
*This
)
1317 TRACE("(%p)->()\n", This
);
1319 EnterCriticalSection(This
->pin
.pCritSec
);
1320 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
1321 hr
= VFW_E_NOT_CONNECTED
;
1324 hr
= IPin_Disconnect(This
->pin
.pConnectedTo
);
1325 IPin_Disconnect(&This
->pin
.IPin_iface
);
1327 LeaveCriticalSection(This
->pin
.pCritSec
);
1332 static const IPinVtbl QT_OutputPin_Vtbl
= {
1333 QTOutPin_QueryInterface
,
1336 BaseOutputPinImpl_Connect
,
1337 BaseOutputPinImpl_ReceiveConnection
,
1338 BaseOutputPinImpl_Disconnect
,
1339 BasePinImpl_ConnectedTo
,
1340 BasePinImpl_ConnectionMediaType
,
1341 BasePinImpl_QueryPinInfo
,
1342 BasePinImpl_QueryDirection
,
1343 BasePinImpl_QueryId
,
1344 BasePinImpl_QueryAccept
,
1345 BasePinImpl_EnumMediaTypes
,
1346 BasePinImpl_QueryInternalConnections
,
1347 BaseOutputPinImpl_EndOfStream
,
1348 BaseOutputPinImpl_BeginFlush
,
1349 BaseOutputPinImpl_EndFlush
,
1350 BasePinImpl_NewSegment
1353 static inline QTOutPin
*impl_from_IQualityControl( IQualityControl
*iface
)
1355 return CONTAINING_RECORD(iface
, QTOutPin
, IQualityControl_iface
);
1358 HRESULT WINAPI
QT_QualityControl_QueryInterface(IQualityControl
*iface
, REFIID riid
, void **ppv
)
1360 QTOutPin
*This
= impl_from_IQualityControl(iface
);
1361 return IPin_QueryInterface(&This
->pin
.pin
.IPin_iface
, riid
, ppv
);
1364 ULONG WINAPI
QT_QualityControl_AddRef(IQualityControl
*iface
)
1366 QTOutPin
*This
= impl_from_IQualityControl(iface
);
1367 return IPin_AddRef(&This
->pin
.pin
.IPin_iface
);
1370 ULONG WINAPI
QT_QualityControl_Release(IQualityControl
*iface
)
1372 QTOutPin
*This
= impl_from_IQualityControl(iface
);
1373 return IPin_Release(&This
->pin
.pin
.IPin_iface
);
1376 static HRESULT WINAPI
QT_QualityControl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality qm
)
1378 REFERENCE_TIME late
= qm
.Late
;
1379 if (qm
.Late
< 0 && -qm
.Late
> qm
.TimeStamp
)
1380 late
= -qm
.TimeStamp
;
1381 /* TODO: Do Something */
1385 HRESULT WINAPI
QT_QualityControl_SetSink(IQualityControl
*iface
, IQualityControl
*tonotify
)
1391 static const IQualityControlVtbl QTOutPin_QualityControl_Vtbl
= {
1392 QT_QualityControl_QueryInterface
,
1393 QT_QualityControl_AddRef
,
1394 QT_QualityControl_Release
,
1395 QT_QualityControl_Notify
,
1396 QT_QualityControl_SetSink
1399 static const BasePinFuncTable output_BaseFuncTable
= {
1401 BaseOutputPinImpl_AttemptConnection
,
1402 BasePinImpl_GetMediaTypeVersion
,
1403 QTOutPin_GetMediaType
1406 static const BaseOutputPinFuncTable output_BaseOutputFuncTable
= {
1407 QTOutPin_DecideBufferSize
,
1408 QTOutPin_DecideAllocator
,
1409 QTOutPin_BreakConnect
1412 static const OutputQueueFuncTable output_OutputQueueFuncTable
= {
1413 OutputQueueImpl_ThreadProc
1416 static HRESULT
QT_AddPin(QTSplitter
*This
, const PIN_INFO
*piOutput
, const AM_MEDIA_TYPE
*amt
, BOOL video
)
1422 target
= (IPin
**)&This
->pVideo_Pin
;
1424 target
= (IPin
**)&This
->pAudio_Pin
;
1426 if (*target
!= NULL
)
1428 FIXME("We already have a %s pin\n",(video
)?"video":"audio");
1432 hr
= BaseOutputPin_Construct(&QT_OutputPin_Vtbl
, sizeof(QTOutPin
), piOutput
, &output_BaseFuncTable
, &output_BaseOutputFuncTable
, &This
->filter
.csFilter
, (IPin
**)target
);
1435 QTOutPin
*pin
= (QTOutPin
*)*target
;
1436 pin
->pmt
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
1437 CopyMediaType(pin
->pmt
, amt
);
1438 pin
->pin
.pin
.pinInfo
.pFilter
= (LPVOID
)This
;
1439 pin
->IQualityControl_iface
.lpVtbl
= &QTOutPin_QualityControl_Vtbl
;
1441 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
1443 hr
= OutputQueue_Construct(&pin
->pin
, TRUE
, TRUE
, 5, FALSE
, THREAD_PRIORITY_NORMAL
, &output_OutputQueueFuncTable
, &pin
->queue
);
1446 ERR("Failed with error %x\n", hr
);
1450 static HRESULT WINAPI
QTSplitter_ChangeStart(IMediaSeeking
*iface
)
1452 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1453 TRACE("(%p)\n", iface
);
1454 EnterCriticalSection(&This
->csReceive
);
1455 This
->movie_time
= (This
->sourceSeeking
.llCurrent
* This
->movie_scale
)/10000000;
1456 This
->movie_start
= This
->movie_time
;
1457 LeaveCriticalSection(&This
->csReceive
);
1461 static HRESULT WINAPI
QTSplitter_ChangeStop(IMediaSeeking
*iface
)
1463 FIXME("(%p) filter hasn't implemented stop position change!\n", iface
);
1467 static HRESULT WINAPI
QTSplitter_ChangeRate(IMediaSeeking
*iface
)
1469 FIXME("(%p) filter hasn't implemented rate change!\n", iface
);
1473 static HRESULT WINAPI
QT_Seeking_QueryInterface(IMediaSeeking
* iface
, REFIID riid
, LPVOID
* ppv
)
1475 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1477 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1480 static ULONG WINAPI
QT_Seeking_AddRef(IMediaSeeking
* iface
)
1482 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1484 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1487 static ULONG WINAPI
QT_Seeking_Release(IMediaSeeking
* iface
)
1489 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1491 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1494 static const IMediaSeekingVtbl QT_Seeking_Vtbl
=
1496 QT_Seeking_QueryInterface
,
1499 SourceSeekingImpl_GetCapabilities
,
1500 SourceSeekingImpl_CheckCapabilities
,
1501 SourceSeekingImpl_IsFormatSupported
,
1502 SourceSeekingImpl_QueryPreferredFormat
,
1503 SourceSeekingImpl_GetTimeFormat
,
1504 SourceSeekingImpl_IsUsingTimeFormat
,
1505 SourceSeekingImpl_SetTimeFormat
,
1506 SourceSeekingImpl_GetDuration
,
1507 SourceSeekingImpl_GetStopPosition
,
1508 SourceSeekingImpl_GetCurrentPosition
,
1509 SourceSeekingImpl_ConvertTimeFormat
,
1510 SourceSeekingImpl_SetPositions
,
1511 SourceSeekingImpl_GetPositions
,
1512 SourceSeekingImpl_GetAvailable
,
1513 SourceSeekingImpl_SetRate
,
1514 SourceSeekingImpl_GetRate
,
1515 SourceSeekingImpl_GetPreroll