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
123 #include "wine/unicode.h"
124 #include "wine/debug.h"
125 #include "wine/strmbase.h"
127 #include "qtprivate.h"
129 WINE_DEFAULT_DEBUG_CHANNEL(qtsplitter
);
130 extern CLSID CLSID_QTSplitter
;
132 typedef struct QTOutPin
{
134 IQualityControl IQualityControl_iface
;
140 typedef struct QTInPin
{
144 IAsyncReader
*pReader
;
145 IMemAllocator
*pAlloc
;
148 typedef struct QTSplitter
{
152 QTOutPin
*pVideo_Pin
;
153 QTOutPin
*pAudio_Pin
;
155 ALLOCATOR_PROPERTIES props
;
158 QTVisualContextRef vContext
;
160 MovieAudioExtractionRef aSession
;
165 CRITICAL_SECTION csReceive
;
167 SourceSeeking sourceSeeking
;
168 TimeValue movie_time
;
169 TimeValue movie_start
;
170 TimeScale movie_scale
;
173 static const IPinVtbl QT_OutputPin_Vtbl
;
174 static const IPinVtbl QT_InputPin_Vtbl
;
175 static const IBaseFilterVtbl QT_Vtbl
;
176 static const IMediaSeekingVtbl QT_Seeking_Vtbl
;
178 static HRESULT
QT_AddPin(QTSplitter
*This
, const PIN_INFO
*piOutput
, const AM_MEDIA_TYPE
*amt
, BOOL video
);
179 static HRESULT
QT_RemoveOutputPins(QTSplitter
*This
);
181 static HRESULT WINAPI
QTSplitter_ChangeStart(IMediaSeeking
*iface
);
182 static HRESULT WINAPI
QTSplitter_ChangeStop(IMediaSeeking
*iface
);
183 static HRESULT WINAPI
QTSplitter_ChangeRate(IMediaSeeking
*iface
);
185 static inline QTSplitter
*impl_from_IMediaSeeking( IMediaSeeking
*iface
)
187 return CONTAINING_RECORD(iface
, QTSplitter
, sourceSeeking
.IMediaSeeking_iface
);
190 static inline QTSplitter
*impl_from_BaseFilter( BaseFilter
*iface
)
192 return CONTAINING_RECORD(iface
, QTSplitter
, filter
);
195 static inline QTSplitter
*impl_from_IBaseFilter( IBaseFilter
*iface
)
197 return CONTAINING_RECORD(iface
, QTSplitter
, filter
.IBaseFilter_iface
);
204 static IPin
* WINAPI
QT_GetPin(BaseFilter
*iface
, int pos
)
206 QTSplitter
*This
= impl_from_BaseFilter(iface
);
207 TRACE("Asking for pos %x\n", pos
);
209 if (pos
> 2 || pos
< 0)
214 IPin_AddRef(&This
->pInputPin
.pin
.IPin_iface
);
215 return &This
->pInputPin
.pin
.IPin_iface
;
217 if (This
->pVideo_Pin
)
218 IPin_AddRef(&This
->pVideo_Pin
->pin
.pin
.IPin_iface
);
219 return &This
->pVideo_Pin
->pin
.pin
.IPin_iface
;
221 if (This
->pAudio_Pin
)
222 IPin_AddRef(&This
->pAudio_Pin
->pin
.pin
.IPin_iface
);
223 return &This
->pAudio_Pin
->pin
.pin
.IPin_iface
;
229 static LONG WINAPI
QT_GetPinCount(BaseFilter
*iface
)
231 QTSplitter
*This
= impl_from_BaseFilter(iface
);
233 if (This
->pAudio_Pin
) c
++;
234 if (This
->pVideo_Pin
) c
++;
238 static const BaseFilterFuncTable BaseFuncTable
= {
243 IUnknown
* CALLBACK
QTSplitter_create(IUnknown
*punkout
, HRESULT
*phr
)
245 IUnknown
*obj
= NULL
;
248 static const WCHAR wcsInputPinName
[] = {'I','n','p','u','t',' ','P','i','n',0};
252 RegisterWineDataHandler();
254 This
= CoTaskMemAlloc(sizeof(*This
));
255 obj
= (IUnknown
*)This
;
258 *phr
= E_OUTOFMEMORY
;
261 ZeroMemory(This
,sizeof(*This
));
263 BaseFilter_Init(&This
->filter
, &QT_Vtbl
, &CLSID_QTSplitter
, (DWORD_PTR
)(__FILE__
": QTSplitter.csFilter"), &BaseFuncTable
);
265 InitializeCriticalSection(&This
->csReceive
);
266 This
->csReceive
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": QTSplitter.csReceive");
268 This
->pVideo_Pin
= NULL
;
269 This
->pAudio_Pin
= NULL
;
270 This
->state
= State_Stopped
;
271 This
->aSession
= NULL
;
272 This
->runEvent
= CreateEventW(NULL
, 0, 0, NULL
);
274 piInput
= &This
->pInputPin
.pin
.pinInfo
;
275 piInput
->dir
= PINDIR_INPUT
;
276 piInput
->pFilter
= &This
->filter
.IBaseFilter_iface
;
277 lstrcpynW(piInput
->achName
, wcsInputPinName
, sizeof(piInput
->achName
) / sizeof(piInput
->achName
[0]));
278 This
->pInputPin
.pin
.IPin_iface
.lpVtbl
= &QT_InputPin_Vtbl
;
279 This
->pInputPin
.pin
.refCount
= 1;
280 This
->pInputPin
.pin
.pConnectedTo
= NULL
;
281 This
->pInputPin
.pin
.pCritSec
= &This
->filter
.csFilter
;
283 SourceSeeking_Init(&This
->sourceSeeking
, &QT_Seeking_Vtbl
, QTSplitter_ChangeStop
, QTSplitter_ChangeStart
, QTSplitter_ChangeRate
, &This
->filter
.csFilter
);
289 static void QT_Destroy(QTSplitter
*This
)
291 IPin
*connected
= NULL
;
294 TRACE("Destroying\n");
296 /* Don't need to clean up output pins, disconnecting input pin will do that */
297 IPin_ConnectedTo(&This
->pInputPin
.pin
.IPin_iface
, &connected
);
300 IPin_Disconnect(connected
);
301 IPin_Release(connected
);
303 pinref
= IPin_Release(&This
->pInputPin
.pin
.IPin_iface
);
306 ERR("pinref should be null, is %u, destroying anyway\n", pinref
);
307 assert((LONG
)pinref
> 0);
310 pinref
= IPin_Release(&This
->pInputPin
.pin
.IPin_iface
);
314 DisposeMovie(This
->pQTMovie
);
316 QTVisualContextRelease(This
->vContext
);
318 MovieAudioExtractionEnd(This
->aSession
);
319 CloseHandle(This
->runEvent
);
323 This
->csReceive
.DebugInfo
->Spare
[0] = 0;
324 DeleteCriticalSection(&This
->csReceive
);
329 static HRESULT WINAPI
QT_QueryInterface(IBaseFilter
*iface
, REFIID riid
, LPVOID
*ppv
)
331 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
332 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
336 if (IsEqualIID(riid
, &IID_IUnknown
))
338 else if (IsEqualIID(riid
, &IID_IPersist
))
340 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
342 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
344 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
345 *ppv
= &This
->sourceSeeking
;
349 IUnknown_AddRef((IUnknown
*)(*ppv
));
353 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
) &&
354 !IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
355 FIXME("No interface for %s!\n", debugstr_guid(riid
));
357 return E_NOINTERFACE
;
360 static ULONG WINAPI
QT_Release(IBaseFilter
*iface
)
362 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
363 ULONG refCount
= BaseFilterImpl_Release(iface
);
365 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
373 static HRESULT WINAPI
QT_Stop(IBaseFilter
*iface
)
375 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
379 EnterCriticalSection(&This
->csReceive
);
380 IAsyncReader_BeginFlush(This
->pInputPin
.pReader
);
381 IAsyncReader_EndFlush(This
->pInputPin
.pReader
);
382 LeaveCriticalSection(&This
->csReceive
);
387 static HRESULT WINAPI
QT_Pause(IBaseFilter
*iface
)
395 static OSErr
QT_Create_Extract_Session(QTSplitter
*filter
)
397 AudioStreamBasicDescription aDesc
;
401 pvi
= (WAVEFORMATEX
*)filter
->pAudio_Pin
->pmt
->pbFormat
;
403 err
= MovieAudioExtractionBegin(filter
->pQTMovie
, 0, &filter
->aSession
);
406 ERR("Failed to begin Extraction session %i\n",err
);
410 err
= MovieAudioExtractionGetProperty(filter
->aSession
,
411 kQTPropertyClass_MovieAudioExtraction_Audio
,
412 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription
,
413 sizeof(AudioStreamBasicDescription
), &aDesc
, NULL
);
417 MovieAudioExtractionEnd(filter
->aSession
);
418 filter
->aSession
= NULL
;
419 ERR("Failed to get session description %i\n",err
);
423 aDesc
.mFormatID
= kAudioFormatLinearPCM
;
424 aDesc
.mFormatFlags
= kLinearPCMFormatFlagIsSignedInteger
+
425 kAudioFormatFlagIsPacked
;
426 aDesc
.mFramesPerPacket
= 1;
427 aDesc
.mChannelsPerFrame
= pvi
->nChannels
;
428 aDesc
.mBitsPerChannel
= pvi
->wBitsPerSample
;
429 aDesc
.mSampleRate
= pvi
->nSamplesPerSec
;
430 aDesc
.mBytesPerFrame
= (aDesc
.mBitsPerChannel
* aDesc
.mChannelsPerFrame
) / 8;
431 aDesc
.mBytesPerPacket
= aDesc
.mBytesPerFrame
* aDesc
.mFramesPerPacket
;
433 err
= MovieAudioExtractionSetProperty(filter
->aSession
,
434 kQTPropertyClass_MovieAudioExtraction_Audio
,
435 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription
,
436 sizeof(AudioStreamBasicDescription
), &aDesc
);
438 if (aDesc
.mFormatID
!= kAudioFormatLinearPCM
)
440 ERR("Not PCM Wave\n");
443 if (aDesc
.mFormatFlags
!= kLinearPCMFormatFlagIsSignedInteger
+
444 kAudioFormatFlagIsPacked
)
446 ERR("Unhandled Flags\n");
449 if (aDesc
.mFramesPerPacket
!= 1)
451 ERR("Unhandled Frames per packet %li\n",aDesc
.mFramesPerPacket
);
454 if (aDesc
.mChannelsPerFrame
!= pvi
->nChannels
)
456 ERR("Unhandled channel count %li\n",aDesc
.mChannelsPerFrame
);
459 if (aDesc
.mBitsPerChannel
!= pvi
->wBitsPerSample
)
461 ERR("Unhandled bits per channel %li\n",aDesc
.mBitsPerChannel
);
464 if (aDesc
.mSampleRate
!= pvi
->nSamplesPerSec
)
466 ERR("Unhandled sample rate %f\n",aDesc
.mSampleRate
);
472 ERR("Failed to create Extraction Session\n");
473 MovieAudioExtractionEnd(filter
->aSession
);
474 filter
->aSession
= NULL
;
480 static DWORD WINAPI
QTSplitter_loading_thread(LPVOID data
)
482 QTSplitter
*This
= (QTSplitter
*)data
;
484 if (This
->pAudio_Pin
)
486 /* according to QA1469 a movie has to be fully loaded before we
487 can reliably start the Extraction session.
489 If loaded earlier, then we only get an extraction session for
490 the part of the movie that is loaded at that time.
492 We are trying to load as much of the movie as we can before we
493 start extracting. However we can recreate the extraction session
494 again when we run out of loaded extraction frames. But we want
495 to try to minimize that.
498 while(GetMovieLoadState(This
->pQTMovie
) < kMovieLoadStateComplete
)
500 EnterCriticalSection(&This
->csReceive
);
501 MoviesTask(This
->pQTMovie
, 100);
502 LeaveCriticalSection(&This
->csReceive
);
509 static DWORD WINAPI
QTSplitter_thread(LPVOID data
)
511 QTSplitter
*This
= (QTSplitter
*)data
;
514 CVPixelBufferRef pixelBuffer
= NULL
;
518 WaitForSingleObject(This
->runEvent
, -1);
520 EnterCriticalSection(&This
->csReceive
);
521 This
->state
= State_Running
;
522 /* Prime the pump: Needed for MPEG streams */
523 GetMovieNextInterestingTime(This
->pQTMovie
, nextTimeEdgeOK
| nextTimeStep
, 0, NULL
, This
->movie_time
, 1, &next_time
, NULL
);
525 GetMovieTime(This
->pQTMovie
, &tr
);
527 if (This
->pAudio_Pin
)
528 QT_Create_Extract_Session(This
);
530 LeaveCriticalSection(&This
->csReceive
);
534 LONGLONG tStart
=0, tStop
=0;
535 LONGLONG mStart
=0, mStop
=0;
538 EnterCriticalSection(&This
->csReceive
);
539 GetMovieNextInterestingTime(This
->pQTMovie
, nextTimeStep
, 0, NULL
, This
->movie_time
, 1, &next_time
, NULL
);
543 TRACE("No next time\n");
544 LeaveCriticalSection(&This
->csReceive
);
548 tr
.value
= SInt64ToWide(next_time
);
549 SetMovieTime(This
->pQTMovie
, &tr
);
550 MoviesTask(This
->pQTMovie
,0);
551 QTVisualContextTask(This
->vContext
);
553 TRACE("In loop at time %ld\n",This
->movie_time
);
554 TRACE("In Next time %ld\n",next_time
);
556 mStart
= This
->movie_time
;
559 time
= (float)(This
->movie_time
- This
->movie_start
) / This
->movie_scale
;
560 tStart
= time
* 10000000;
561 time
= (float)(next_time
- This
->movie_start
) / This
->movie_scale
;
562 tStop
= time
* 10000000;
565 if (This
->pAudio_Pin
&& This
->pAudio_Pin
->pin
.pin
.pConnectedTo
&& This
->aSession
)
569 IMediaSample
*sample
= NULL
;
570 AudioBufferList aData
;
576 pvi
= (WAVEFORMATEX
*)This
->pAudio_Pin
->pmt
->pbFormat
;
578 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&This
->pAudio_Pin
->pin
, &sample
, NULL
, NULL
, 0);
582 ERR("Audio: Unable to get delivery buffer (%x)\n", hr
);
586 hr
= IMediaSample_GetPointer(sample
, &ptr
);
589 ERR("Audio: Unable to get pointer to buffer (%x)\n", hr
);
593 duration
= (float)next_time
/ This
->movie_scale
;
594 time
= (float)This
->movie_time
/ This
->movie_scale
;
596 frames
= pvi
->nSamplesPerSec
* duration
;
597 TRACE("Need audio for %f seconds (%li frames)\n",duration
,frames
);
599 data_size
= IMediaSample_GetSize(sample
);
600 if (data_size
< frames
* pvi
->nBlockAlign
)
601 FIXME("Audio buffer is too small\n");
603 aData
.mNumberBuffers
= 1;
604 aData
.mBuffers
[0].mNumberChannels
= pvi
->nChannels
;
605 aData
.mBuffers
[0].mDataByteSize
= data_size
;
606 aData
.mBuffers
[0].mData
= ptr
;
608 err
= MovieAudioExtractionFillBuffer(This
->aSession
, &frames
, &aData
, &flags
);
613 /* Ran out of frames, Restart the extraction session */
614 TRACE("Restarting extraction session\n");
615 MovieAudioExtractionEnd(This
->aSession
);
616 This
->aSession
= NULL
;
617 QT_Create_Extract_Session(This
);
620 etr
.value
= SInt64ToWide(This
->movie_time
);
621 MovieAudioExtractionSetProperty(This
->aSession
,
622 kQTPropertyClass_MovieAudioExtraction_Movie
,
623 kQTMovieAudioExtractionMoviePropertyID_CurrentTime
,
624 sizeof(TimeRecord
), &etr
);
626 frames
= pvi
->nSamplesPerSec
* duration
;
627 aData
.mNumberBuffers
= 1;
628 aData
.mBuffers
[0].mNumberChannels
= pvi
->nChannels
;
629 aData
.mBuffers
[0].mDataByteSize
= data_size
;
630 aData
.mBuffers
[0].mData
= ptr
;
632 MovieAudioExtractionFillBuffer(This
->aSession
, &frames
, &aData
, &flags
);
635 TRACE("Got %i frames\n",(int)frames
);
637 IMediaSample_SetActualDataLength(sample
, frames
* pvi
->nBlockAlign
);
639 IMediaSample_SetMediaTime(sample
, &mStart
, &mStop
);
640 IMediaSample_SetTime(sample
, &tStart
, &tStop
);
642 hr
= OutputQueue_Receive(This
->pAudio_Pin
->queue
, sample
);
643 TRACE("Audio Delivered (%x)\n",hr
);
647 IMediaSample_Release(sample
);
650 TRACE("Audio Pin not connected or no Audio\n");
653 if (This
->pVideo_Pin
&& QTVisualContextIsNewImageAvailable(This
->vContext
,0))
655 err
= QTVisualContextCopyImageForTime(This
->vContext
, NULL
, NULL
, &pixelBuffer
);
660 IMediaSample
*sample
= NULL
;
662 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&This
->pVideo_Pin
->pin
, &sample
, NULL
, NULL
, 0);
665 ERR("Video: Unable to get delivery buffer (%x)\n", hr
);
669 data_size
= IMediaSample_GetSize(sample
);
670 if (data_size
< This
->outputSize
)
672 ERR("Sample size is too small %d < %d\n", data_size
, This
->outputSize
)
678 hr
= IMediaSample_GetPointer(sample
, &ptr
);
681 ERR("Video: Unable to get pointer to buffer (%x)\n", hr
);
685 hr
= AccessPixelBufferPixels( pixelBuffer
, ptr
);
688 ERR("Failed to access Pixels\n");
692 IMediaSample_SetActualDataLength(sample
, This
->outputSize
);
694 IMediaSample_SetMediaTime(sample
, &mStart
, &mStop
);
695 IMediaSample_SetTime(sample
, &tStart
, &tStop
);
697 hr
= OutputQueue_Receive(This
->pVideo_Pin
->queue
, sample
);
698 TRACE("Video Delivered (%x)\n",hr
);
702 IMediaSample_Release(sample
);
704 CVPixelBufferRelease(pixelBuffer
);
708 TRACE("No video to deliver\n");
710 This
->movie_time
= next_time
;
711 LeaveCriticalSection(&This
->csReceive
);
712 } while (hr
== S_OK
);
714 This
->state
= State_Stopped
;
715 if (This
->pAudio_Pin
)
716 OutputQueue_EOS(This
->pAudio_Pin
->queue
);
717 if (This
->pVideo_Pin
)
718 OutputQueue_EOS(This
->pVideo_Pin
->queue
);
723 static HRESULT WINAPI
QT_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
726 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
727 HRESULT hr_any
= VFW_E_NOT_CONNECTED
;
729 TRACE("(%s)\n", wine_dbgstr_longlong(tStart
));
731 EnterCriticalSection(&This
->csReceive
);
732 This
->filter
.rtStreamStart
= tStart
;
734 if (This
->pVideo_Pin
)
735 hr
= BaseOutputPinImpl_Active(&This
->pVideo_Pin
->pin
);
738 if (This
->pAudio_Pin
)
739 hr
= BaseOutputPinImpl_Active(&This
->pAudio_Pin
->pin
);
745 SetEvent(This
->runEvent
);
746 LeaveCriticalSection(&This
->csReceive
);
751 static HRESULT WINAPI
QT_GetState(IBaseFilter
*iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
753 QTSplitter
*This
= impl_from_IBaseFilter(iface
);
754 TRACE("(%d, %p)\n", dwMilliSecsTimeout
, pState
);
756 *pState
= This
->state
;
761 static HRESULT WINAPI
QT_FindPin(IBaseFilter
*iface
, LPCWSTR Id
, IPin
**ppPin
)
763 FIXME("(%p)->(%s,%p) stub\n", iface
, debugstr_w(Id
), ppPin
);
767 static const IBaseFilterVtbl QT_Vtbl
= {
769 BaseFilterImpl_AddRef
,
771 BaseFilterImpl_GetClassID
,
776 BaseFilterImpl_SetSyncSource
,
777 BaseFilterImpl_GetSyncSource
,
778 BaseFilterImpl_EnumPins
,
780 BaseFilterImpl_QueryFilterInfo
,
781 BaseFilterImpl_JoinFilterGraph
,
782 BaseFilterImpl_QueryVendorInfo
788 static HRESULT
QT_RemoveOutputPins(QTSplitter
*This
)
791 TRACE("(%p)\n", This
);
793 if (This
->pVideo_Pin
)
795 OutputQueue_Destroy(This
->pVideo_Pin
->queue
);
796 hr
= BaseOutputPinImpl_BreakConnect(&This
->pVideo_Pin
->pin
);
797 TRACE("Disconnect: %08x\n", hr
);
798 IPin_Release(&This
->pVideo_Pin
->pin
.pin
.IPin_iface
);
799 This
->pVideo_Pin
= NULL
;
801 if (This
->pAudio_Pin
)
803 OutputQueue_Destroy(This
->pAudio_Pin
->queue
);
804 hr
= BaseOutputPinImpl_BreakConnect(&This
->pAudio_Pin
->pin
);
805 TRACE("Disconnect: %08x\n", hr
);
806 IPin_Release(&This
->pAudio_Pin
->pin
.pin
.IPin_iface
);
807 This
->pAudio_Pin
= NULL
;
810 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
814 static inline QTInPin
*impl_from_IPin( IPin
*iface
)
816 return CONTAINING_RECORD(iface
, QTInPin
, pin
.IPin_iface
);
819 static ULONG WINAPI
QTInPin_Release(IPin
*iface
)
821 QTInPin
*This
= impl_from_IPin(iface
);
822 ULONG refCount
= InterlockedDecrement(&This
->pin
.refCount
);
824 TRACE("(%p)->() Release from %d\n", iface
, refCount
+ 1);
827 FreeMediaType(&This
->pin
.mtCurrent
);
829 IMemAllocator_Release(This
->pAlloc
);
831 This
->pin
.IPin_iface
.lpVtbl
= NULL
;
838 static HRESULT
QT_Process_Video_Track(QTSplitter
* filter
, Track trk
)
841 VIDEOINFOHEADER
* pvi
;
845 static const WCHAR szwVideoOut
[] = {'V','i','d','e','o',0};
846 CFMutableDictionaryRef pixelBufferOptions
= NULL
;
847 CFMutableDictionaryRef visualContextOptions
= NULL
;
848 CFNumberRef n
= NULL
;
850 DWORD outputWidth
, outputHeight
, outputDepth
;
851 Fixed trackWidth
, trackHeight
;
853 ZeroMemory(&amt
, sizeof(amt
));
854 amt
.formattype
= FORMAT_VideoInfo
;
855 amt
.majortype
= MEDIATYPE_Video
;
856 amt
.subtype
= MEDIASUBTYPE_RGB24
;
858 GetTrackDimensions(trk
, &trackWidth
, &trackHeight
);
861 outputWidth
= Fix2Long(trackWidth
);
862 outputHeight
= Fix2Long(trackHeight
);
863 TRACE("Width %i Height %i\n",outputWidth
, outputHeight
);
865 amt
.cbFormat
= sizeof(VIDEOINFOHEADER
);
866 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
867 ZeroMemory(amt
.pbFormat
, amt
.cbFormat
);
868 pvi
= (VIDEOINFOHEADER
*)amt
.pbFormat
;
869 pvi
->bmiHeader
.biSize
= sizeof (BITMAPINFOHEADER
);
870 pvi
->bmiHeader
.biWidth
= outputWidth
;
871 pvi
->bmiHeader
.biHeight
= outputHeight
;
872 pvi
->bmiHeader
.biPlanes
= 1;
873 pvi
->bmiHeader
.biBitCount
= 24;
874 pvi
->bmiHeader
.biCompression
= BI_RGB
;
875 pvi
->bmiHeader
.biSizeImage
= outputWidth
* outputHeight
* outputDepth
;
877 filter
->outputSize
= pvi
->bmiHeader
.biSizeImage
;
880 pixelBufferOptions
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
882 t
= k32ARGBPixelFormat
;
883 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &t
);
884 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferPixelFormatTypeKey
, n
);
887 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &outputWidth
);
888 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferWidthKey
, n
);
891 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &outputHeight
);
892 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferHeightKey
, n
);
896 n
= CFNumberCreate(NULL
, kCFNumberIntType
, &t
);
897 CFDictionaryAddValue(pixelBufferOptions
, kCVPixelBufferBytesPerRowAlignmentKey
, n
);
900 visualContextOptions
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
902 CFDictionarySetValue(visualContextOptions
, kQTVisualContextPixelBufferAttributesKey
, pixelBufferOptions
);
904 err
= QTPixelBufferContextCreate(NULL
, visualContextOptions
,&filter
->vContext
);
905 CFRelease(pixelBufferOptions
);
906 CFRelease(visualContextOptions
);
909 ERR("Failed to create Visual Context\n");
913 err
= SetMovieVisualContext(filter
->pQTMovie
, filter
->vContext
);
916 ERR("Failed to set Visual Context\n");
920 piOutput
.dir
= PINDIR_OUTPUT
;
921 piOutput
.pFilter
= &filter
->filter
.IBaseFilter_iface
;
922 lstrcpyW(piOutput
.achName
,szwVideoOut
);
924 hr
= QT_AddPin(filter
, &piOutput
, &amt
, TRUE
);
926 ERR("Failed to add Video Track\n");
928 TRACE("Video Pin %p\n",filter
->pVideo_Pin
);
933 static HRESULT
QT_Process_Audio_Track(QTSplitter
* filter
, Track trk
)
939 static const WCHAR szwAudioOut
[] = {'A','u','d','i','o',0};
942 SoundDescriptionHandle aDesc
= (SoundDescriptionHandle
) NewHandle(sizeof(SoundDescription
));
944 audioMedia
= GetTrackMedia(trk
);
945 GetMediaSampleDescription(audioMedia
, 1, (SampleDescriptionHandle
)aDesc
);
947 ZeroMemory(&amt
, sizeof(amt
));
948 amt
.formattype
= FORMAT_WaveFormatEx
;
949 amt
.majortype
= MEDIATYPE_Audio
;
950 amt
.subtype
= MEDIASUBTYPE_PCM
;
951 amt
.bTemporalCompression
= 0;
953 amt
.cbFormat
= sizeof(WAVEFORMATEX
);
954 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
955 ZeroMemory(amt
.pbFormat
, amt
.cbFormat
);
956 pvi
= (WAVEFORMATEX
*)amt
.pbFormat
;
958 pvi
->cbSize
= sizeof(WAVEFORMATEX
);
959 pvi
->wFormatTag
= WAVE_FORMAT_PCM
;
960 pvi
->nChannels
= ((SoundDescription
)**aDesc
).numChannels
;
961 if (pvi
->nChannels
< 1 || pvi
->nChannels
> 2)
963 pvi
->nSamplesPerSec
= (((SoundDescription
)**aDesc
).sampleRate
/65536);
964 if (pvi
->nSamplesPerSec
< 8000 || pvi
->nChannels
> 48000)
965 pvi
->nSamplesPerSec
= 44100;
966 pvi
->wBitsPerSample
= ((SoundDescription
)**aDesc
).sampleSize
;
967 if (pvi
->wBitsPerSample
< 8 || pvi
->wBitsPerSample
> 32)
968 pvi
->wBitsPerSample
= 16;
969 pvi
->nBlockAlign
= (pvi
->nChannels
* pvi
->wBitsPerSample
) / 8;
970 pvi
->nAvgBytesPerSec
= pvi
->nSamplesPerSec
* pvi
->nBlockAlign
;
972 DisposeHandle((Handle
)aDesc
);
974 piOutput
.dir
= PINDIR_OUTPUT
;
975 piOutput
.pFilter
= &filter
->filter
.IBaseFilter_iface
;
976 lstrcpyW(piOutput
.achName
,szwAudioOut
);
978 hr
= QT_AddPin(filter
, &piOutput
, &amt
, FALSE
);
980 ERR("Failed to add Audio Track\n");
982 TRACE("Audio Pin %p\n",filter
->pAudio_Pin
);
986 static HRESULT
QT_Process_Movie(QTSplitter
* filter
)
990 WineDataRefRecord ptrDataRefRec
;
991 Handle dataRef
= NULL
;
998 TRACE("Trying movie connect\n");
1000 ptrDataRefRec
.pReader
= filter
->pInputPin
.pReader
;
1001 ptrDataRefRec
.streamSubtype
= filter
->pInputPin
.subType
;
1002 PtrToHand( &ptrDataRefRec
, &dataRef
, sizeof(WineDataRefRecord
));
1004 err
= NewMovieFromDataRef(&filter
->pQTMovie
, newMovieActive
|newMovieDontInteractWithUser
|newMovieDontAutoUpdateClock
|newMovieDontAskUnresolvedDataRefs
|newMovieAsyncOK
, &id
, dataRef
, 'WINE');
1006 DisposeHandle(dataRef
);
1010 FIXME("QuickTime cannot handle media type(%i)\n",err
);
1011 return VFW_E_TYPE_NOT_ACCEPTED
;
1014 PrePrerollMovie(filter
->pQTMovie
, 0, fixed1
, NULL
, NULL
);
1015 PrerollMovie(filter
->pQTMovie
, 0, fixed1
);
1016 GoToBeginningOfMovie(filter
->pQTMovie
);
1017 SetMovieActive(filter
->pQTMovie
,TRUE
);
1019 if (GetMovieLoadState(filter
->pQTMovie
) < kMovieLoadStateLoaded
)
1020 MoviesTask(filter
->pQTMovie
,100);
1022 trk
= GetMovieIndTrackType(filter
->pQTMovie
, 1, VisualMediaCharacteristic
, movieTrackCharacteristic
| movieTrackEnabledOnly
);
1023 TRACE("%p is a video track\n",trk
);
1025 hr
= QT_Process_Video_Track(filter
, trk
);
1030 trk
= GetMovieIndTrackType(filter
->pQTMovie
, 1, AudioMediaCharacteristic
, movieTrackCharacteristic
| movieTrackEnabledOnly
);
1031 TRACE("%p is a audio track\n",trk
);
1033 hr
= QT_Process_Audio_Track(filter
, trk
);
1035 time
= GetMovieDuration(filter
->pQTMovie
);
1036 filter
->movie_scale
= GetMovieTimeScale(filter
->pQTMovie
);
1037 filter
->sourceSeeking
.llDuration
= ((double)time
/ filter
->movie_scale
) * 10000000;
1038 filter
->sourceSeeking
.llStop
= filter
->sourceSeeking
.llDuration
;
1040 TRACE("Movie duration is %s\n",wine_dbgstr_longlong(filter
->sourceSeeking
.llDuration
));
1042 thread
= CreateThread(NULL
, 0, QTSplitter_loading_thread
, filter
, 0, &tid
);
1045 TRACE("Created loading thread 0x%08x\n", tid
);
1046 CloseHandle(thread
);
1048 thread
= CreateThread(NULL
, 0, QTSplitter_thread
, filter
, 0, &tid
);
1051 TRACE("Created processing thread 0x%08x\n", tid
);
1052 CloseHandle(thread
);
1055 hr
= HRESULT_FROM_WIN32(GetLastError());
1060 static HRESULT WINAPI
QTInPin_ReceiveConnection(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1063 ALLOCATOR_PROPERTIES props
;
1064 QTInPin
*This
= impl_from_IPin(iface
);
1066 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
1068 EnterCriticalSection(This
->pin
.pCritSec
);
1069 This
->pReader
= NULL
;
1071 if (This
->pin
.pConnectedTo
)
1072 hr
= VFW_E_ALREADY_CONNECTED
;
1073 else if (IPin_QueryAccept(iface
, pmt
) != S_OK
)
1074 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
1077 PIN_DIRECTION pindirReceive
;
1078 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
1079 if (pindirReceive
!= PINDIR_OUTPUT
)
1080 hr
= VFW_E_INVALID_DIRECTION
;
1085 LeaveCriticalSection(This
->pin
.pCritSec
);
1089 hr
= IPin_QueryInterface(pReceivePin
, &IID_IAsyncReader
, (LPVOID
*)&This
->pReader
);
1092 LeaveCriticalSection(This
->pin
.pCritSec
);
1093 TRACE("Input source is not an AsyncReader\n");
1097 LeaveCriticalSection(This
->pin
.pCritSec
);
1098 EnterCriticalSection(&impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->filter
.csFilter
);
1099 hr
= QT_Process_Movie(impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
));
1102 LeaveCriticalSection(&impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->filter
.csFilter
);
1103 TRACE("Unable to process movie\n");
1107 This
->pAlloc
= NULL
;
1110 props
.cbBuffer
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->outputSize
+ props
.cbAlign
;
1113 hr
= IAsyncReader_RequestAllocator(This
->pReader
, NULL
, &props
, &This
->pAlloc
);
1116 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
1117 This
->pin
.pConnectedTo
= pReceivePin
;
1118 IPin_AddRef(pReceivePin
);
1119 hr
= IMemAllocator_Commit(This
->pAlloc
);
1123 QT_RemoveOutputPins(impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
));
1125 IAsyncReader_Release(This
->pReader
);
1126 This
->pReader
= NULL
;
1128 IMemAllocator_Release(This
->pAlloc
);
1129 This
->pAlloc
= NULL
;
1131 TRACE("Size: %i\n", props
.cbBuffer
);
1132 LeaveCriticalSection(&impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
)->filter
.csFilter
);
1137 static HRESULT WINAPI
QTInPin_Disconnect(IPin
*iface
)
1140 QTInPin
*This
= impl_from_IPin(iface
);
1144 hr
= IBaseFilter_GetState(This
->pin
.pinInfo
.pFilter
, INFINITE
, &state
);
1145 EnterCriticalSection(This
->pin
.pCritSec
);
1146 if (This
->pin
.pConnectedTo
)
1148 QTSplitter
*Parser
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
1150 if (SUCCEEDED(hr
) && state
== State_Stopped
)
1152 IMemAllocator_Decommit(This
->pAlloc
);
1153 IPin_Disconnect(This
->pin
.pConnectedTo
);
1154 This
->pin
.pConnectedTo
= NULL
;
1155 hr
= QT_RemoveOutputPins(Parser
);
1158 hr
= VFW_E_NOT_STOPPED
;
1162 LeaveCriticalSection(This
->pin
.pCritSec
);
1166 static HRESULT WINAPI
QTInPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*pmt
)
1168 QTInPin
*This
= impl_from_IPin(iface
);
1170 TRACE("(%p)->(%p)\n", This
, pmt
);
1172 if (IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Stream
))
1174 This
->subType
= pmt
->subtype
;
1180 static HRESULT WINAPI
QTInPin_EndOfStream(IPin
*iface
)
1182 QTInPin
*pin
= impl_from_IPin(iface
);
1183 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1185 FIXME("Propagate message on %p\n", This
);
1189 static HRESULT WINAPI
QTInPin_BeginFlush(IPin
*iface
)
1191 QTInPin
*pin
= impl_from_IPin(iface
);
1192 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1194 FIXME("Propagate message on %p\n", This
);
1198 static HRESULT WINAPI
QTInPin_EndFlush(IPin
*iface
)
1200 QTInPin
*pin
= impl_from_IPin(iface
);
1201 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1203 FIXME("Propagate message on %p\n", This
);
1207 static HRESULT WINAPI
QTInPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
1209 QTInPin
*pin
= impl_from_IPin(iface
);
1210 QTSplitter
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
1212 BasePinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
1213 FIXME("Propagate message on %p\n", This
);
1217 static HRESULT WINAPI
QTInPin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
1219 QTInPin
*This
= impl_from_IPin(iface
);
1221 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
1225 if (IsEqualIID(riid
, &IID_IUnknown
))
1227 else if (IsEqualIID(riid
, &IID_IPin
))
1229 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
1230 return IBaseFilter_QueryInterface(This
->pin
.pinInfo
.pFilter
, &IID_IMediaSeeking
, ppv
);
1234 IUnknown_AddRef((IUnknown
*)(*ppv
));
1238 FIXME("No interface for %s!\n", debugstr_guid(riid
));
1240 return E_NOINTERFACE
;
1243 static HRESULT WINAPI
QTInPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
1245 QTInPin
*This
= impl_from_IPin(iface
);
1247 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
1249 return EnumMediaTypes_Construct(&This
->pin
, BasePinImpl_GetMediaType
, BasePinImpl_GetMediaTypeVersion
, ppEnum
);
1252 static const IPinVtbl QT_InputPin_Vtbl
= {
1253 QTInPin_QueryInterface
,
1256 BaseInputPinImpl_Connect
,
1257 QTInPin_ReceiveConnection
,
1259 BasePinImpl_ConnectedTo
,
1260 BasePinImpl_ConnectionMediaType
,
1261 BasePinImpl_QueryPinInfo
,
1262 BasePinImpl_QueryDirection
,
1263 BasePinImpl_QueryId
,
1264 QTInPin_QueryAccept
,
1265 QTInPin_EnumMediaTypes
,
1266 BasePinImpl_QueryInternalConnections
,
1267 QTInPin_EndOfStream
,
1276 static inline QTOutPin
*impl_QTOutPin_from_IPin( IPin
*iface
)
1278 return CONTAINING_RECORD(iface
, QTOutPin
, pin
.pin
.IPin_iface
);
1281 static inline QTOutPin
*impl_QTOutPin_from_BasePin( BasePin
*iface
)
1283 return CONTAINING_RECORD(iface
, QTOutPin
, pin
.pin
);
1286 static inline QTOutPin
*impl_QTOutPin_from_BaseOutputPin( BaseOutputPin
*iface
)
1288 return CONTAINING_RECORD(iface
, QTOutPin
, pin
);
1291 static HRESULT WINAPI
QTOutPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
1293 QTOutPin
*This
= impl_QTOutPin_from_IPin(iface
);
1295 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
1299 if (IsEqualIID(riid
, &IID_IUnknown
))
1301 else if (IsEqualIID(riid
, &IID_IPin
))
1303 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
1304 return IBaseFilter_QueryInterface(This
->pin
.pin
.pinInfo
.pFilter
, &IID_IMediaSeeking
, ppv
);
1305 else if (IsEqualIID(riid
, &IID_IQualityControl
))
1306 *ppv
= &This
->IQualityControl_iface
;
1310 IUnknown_AddRef((IUnknown
*)(*ppv
));
1313 FIXME("No interface for %s!\n", debugstr_guid(riid
));
1314 return E_NOINTERFACE
;
1317 static ULONG WINAPI
QTOutPin_Release(IPin
*iface
)
1319 QTOutPin
*This
= impl_QTOutPin_from_IPin(iface
);
1320 ULONG refCount
= InterlockedDecrement(&This
->pin
.pin
.refCount
);
1321 TRACE("(%p)->() Release from %d\n", iface
, refCount
+ 1);
1325 DeleteMediaType(This
->pmt
);
1326 FreeMediaType(&This
->pin
.pin
.mtCurrent
);
1327 CoTaskMemFree(This
);
1333 static HRESULT WINAPI
QTOutPin_GetMediaType(BasePin
*iface
, int iPosition
, AM_MEDIA_TYPE
*pmt
)
1335 QTOutPin
*This
= impl_QTOutPin_from_BasePin(iface
);
1338 return E_INVALIDARG
;
1340 return VFW_S_NO_MORE_ITEMS
;
1341 CopyMediaType(pmt
, This
->pmt
);
1345 static HRESULT WINAPI
QTOutPin_DecideBufferSize(BaseOutputPin
*iface
, IMemAllocator
*pAlloc
, ALLOCATOR_PROPERTIES
*ppropInputRequest
)
1351 static HRESULT WINAPI
QTOutPin_DecideAllocator(BaseOutputPin
*iface
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
1354 QTOutPin
*This
= impl_QTOutPin_from_BaseOutputPin(iface
);
1355 QTSplitter
*QTfilter
= impl_from_IBaseFilter(This
->pin
.pin
.pinInfo
.pFilter
);
1358 if (QTfilter
->pInputPin
.pAlloc
)
1359 hr
= IMemInputPin_NotifyAllocator(pPin
, QTfilter
->pInputPin
.pAlloc
, FALSE
);
1361 hr
= VFW_E_NO_ALLOCATOR
;
1366 static HRESULT WINAPI
QTOutPin_BreakConnect(BaseOutputPin
*This
)
1370 TRACE("(%p)->()\n", This
);
1372 EnterCriticalSection(This
->pin
.pCritSec
);
1373 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
1374 hr
= VFW_E_NOT_CONNECTED
;
1377 hr
= IPin_Disconnect(This
->pin
.pConnectedTo
);
1378 IPin_Disconnect(&This
->pin
.IPin_iface
);
1380 LeaveCriticalSection(This
->pin
.pCritSec
);
1385 static const IPinVtbl QT_OutputPin_Vtbl
= {
1386 QTOutPin_QueryInterface
,
1389 BaseOutputPinImpl_Connect
,
1390 BaseOutputPinImpl_ReceiveConnection
,
1391 BaseOutputPinImpl_Disconnect
,
1392 BasePinImpl_ConnectedTo
,
1393 BasePinImpl_ConnectionMediaType
,
1394 BasePinImpl_QueryPinInfo
,
1395 BasePinImpl_QueryDirection
,
1396 BasePinImpl_QueryId
,
1397 BasePinImpl_QueryAccept
,
1398 BasePinImpl_EnumMediaTypes
,
1399 BasePinImpl_QueryInternalConnections
,
1400 BaseOutputPinImpl_EndOfStream
,
1401 BaseOutputPinImpl_BeginFlush
,
1402 BaseOutputPinImpl_EndFlush
,
1403 BasePinImpl_NewSegment
1406 static inline QTOutPin
*impl_from_IQualityControl( IQualityControl
*iface
)
1408 return CONTAINING_RECORD(iface
, QTOutPin
, IQualityControl_iface
);
1411 HRESULT WINAPI
QT_QualityControl_QueryInterface(IQualityControl
*iface
, REFIID riid
, void **ppv
)
1413 QTOutPin
*This
= impl_from_IQualityControl(iface
);
1414 return IPin_QueryInterface(&This
->pin
.pin
.IPin_iface
, riid
, ppv
);
1417 ULONG WINAPI
QT_QualityControl_AddRef(IQualityControl
*iface
)
1419 QTOutPin
*This
= impl_from_IQualityControl(iface
);
1420 return IPin_AddRef(&This
->pin
.pin
.IPin_iface
);
1423 ULONG WINAPI
QT_QualityControl_Release(IQualityControl
*iface
)
1425 QTOutPin
*This
= impl_from_IQualityControl(iface
);
1426 return IPin_Release(&This
->pin
.pin
.IPin_iface
);
1429 static HRESULT WINAPI
QT_QualityControl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality qm
)
1431 REFERENCE_TIME late
= qm
.Late
;
1432 if (qm
.Late
< 0 && -qm
.Late
> qm
.TimeStamp
)
1433 late
= -qm
.TimeStamp
;
1434 /* TODO: Do Something */
1438 HRESULT WINAPI
QT_QualityControl_SetSink(IQualityControl
*iface
, IQualityControl
*tonotify
)
1444 static const IQualityControlVtbl QTOutPin_QualityControl_Vtbl
= {
1445 QT_QualityControl_QueryInterface
,
1446 QT_QualityControl_AddRef
,
1447 QT_QualityControl_Release
,
1448 QT_QualityControl_Notify
,
1449 QT_QualityControl_SetSink
1452 static const BasePinFuncTable output_BaseFuncTable
= {
1454 BaseOutputPinImpl_AttemptConnection
,
1455 BasePinImpl_GetMediaTypeVersion
,
1456 QTOutPin_GetMediaType
1459 static const BaseOutputPinFuncTable output_BaseOutputFuncTable
= {
1460 QTOutPin_DecideBufferSize
,
1461 QTOutPin_DecideAllocator
,
1462 QTOutPin_BreakConnect
1465 static const OutputQueueFuncTable output_OutputQueueFuncTable
= {
1466 OutputQueueImpl_ThreadProc
1469 static HRESULT
QT_AddPin(QTSplitter
*This
, const PIN_INFO
*piOutput
, const AM_MEDIA_TYPE
*amt
, BOOL video
)
1475 target
= (IPin
**)&This
->pVideo_Pin
;
1477 target
= (IPin
**)&This
->pAudio_Pin
;
1479 if (*target
!= NULL
)
1481 FIXME("We already have a %s pin\n",(video
)?"video":"audio");
1485 hr
= BaseOutputPin_Construct(&QT_OutputPin_Vtbl
, sizeof(QTOutPin
), piOutput
, &output_BaseFuncTable
, &output_BaseOutputFuncTable
, &This
->filter
.csFilter
, (IPin
**)target
);
1488 QTOutPin
*pin
= (QTOutPin
*)*target
;
1489 pin
->pmt
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
1490 CopyMediaType(pin
->pmt
, amt
);
1491 pin
->pin
.pin
.pinInfo
.pFilter
= (LPVOID
)This
;
1492 pin
->IQualityControl_iface
.lpVtbl
= &QTOutPin_QualityControl_Vtbl
;
1494 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
1496 hr
= OutputQueue_Construct(&pin
->pin
, TRUE
, TRUE
, 5, FALSE
, THREAD_PRIORITY_NORMAL
, &output_OutputQueueFuncTable
, &pin
->queue
);
1499 ERR("Failed with error %x\n", hr
);
1503 static HRESULT WINAPI
QTSplitter_ChangeStart(IMediaSeeking
*iface
)
1505 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1506 TRACE("(%p)\n", iface
);
1507 EnterCriticalSection(&This
->csReceive
);
1508 This
->movie_time
= (This
->sourceSeeking
.llCurrent
* This
->movie_scale
)/10000000;
1509 This
->movie_start
= This
->movie_time
;
1510 LeaveCriticalSection(&This
->csReceive
);
1514 static HRESULT WINAPI
QTSplitter_ChangeStop(IMediaSeeking
*iface
)
1516 FIXME("(%p) filter hasn't implemented stop position change!\n", iface
);
1520 static HRESULT WINAPI
QTSplitter_ChangeRate(IMediaSeeking
*iface
)
1522 FIXME("(%p) filter hasn't implemented rate change!\n", iface
);
1526 static HRESULT WINAPI
QT_Seeking_QueryInterface(IMediaSeeking
* iface
, REFIID riid
, LPVOID
* ppv
)
1528 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1530 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1533 static ULONG WINAPI
QT_Seeking_AddRef(IMediaSeeking
* iface
)
1535 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1537 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1540 static ULONG WINAPI
QT_Seeking_Release(IMediaSeeking
* iface
)
1542 QTSplitter
*This
= impl_from_IMediaSeeking(iface
);
1544 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1547 static const IMediaSeekingVtbl QT_Seeking_Vtbl
=
1549 QT_Seeking_QueryInterface
,
1552 SourceSeekingImpl_GetCapabilities
,
1553 SourceSeekingImpl_CheckCapabilities
,
1554 SourceSeekingImpl_IsFormatSupported
,
1555 SourceSeekingImpl_QueryPreferredFormat
,
1556 SourceSeekingImpl_GetTimeFormat
,
1557 SourceSeekingImpl_IsUsingTimeFormat
,
1558 SourceSeekingImpl_SetTimeFormat
,
1559 SourceSeekingImpl_GetDuration
,
1560 SourceSeekingImpl_GetStopPosition
,
1561 SourceSeekingImpl_GetCurrentPosition
,
1562 SourceSeekingImpl_ConvertTimeFormat
,
1563 SourceSeekingImpl_SetPositions
,
1564 SourceSeekingImpl_GetPositions
,
1565 SourceSeekingImpl_GetAvailable
,
1566 SourceSeekingImpl_SetRate
,
1567 SourceSeekingImpl_GetRate
,
1568 SourceSeekingImpl_GetPreroll