po: Tweak the wrapping of a few Portuguese (Brazil) translations.
[wine/multimedia.git] / dlls / wineqtdecoder / qtsplitter.c
blob9f010944f57ddece96c2a40c3f7170b78568330c
1 /*
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
21 #include "config.h"
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>
66 #undef LoadResource
67 #undef CompareString
68 #undef GetCurrentThread
69 #undef _CDECL
70 #undef DPRINTF
71 #undef GetCurrentProcess
72 #undef AnimatePalette
73 #undef EqualRgn
74 #undef FillRgn
75 #undef FrameRgn
76 #undef GetPixel
77 #undef InvertRgn
78 #undef LineTo
79 #undef OffsetRgn
80 #undef PaintRgn
81 #undef Polygon
82 #undef ResizePalette
83 #undef SetRectRgn
84 #undef CheckMenuItem
85 #undef DeleteMenu
86 #undef DrawMenuBar
87 #undef EnableMenuItem
88 #undef EqualRect
89 #undef FillRect
90 #undef FrameRect
91 #undef GetCursor
92 #undef GetMenu
93 #undef InvertRect
94 #undef IsWindowVisible
95 #undef MoveWindow
96 #undef OffsetRect
97 #undef PtInRect
98 #undef SetCursor
99 #undef SetRect
100 #undef ShowCursor
101 #undef ShowWindow
102 #undef UnionRect
104 #undef ULONG
105 #undef HRESULT
106 #undef DPRINTF
107 #undef STDMETHODCALLTYPE
109 #include <assert.h>
110 #include <stdio.h>
111 #include <stdarg.h>
113 #define NONAMELESSSTRUCT
114 #define NONAMELESSUNION
115 #define COBJMACROS
117 #include "windef.h"
118 #include "winbase.h"
119 #include "wtypes.h"
120 #include "winuser.h"
121 #include "dshow.h"
123 #include <assert.h>
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 {
135 BaseOutputPin pin;
137 AM_MEDIA_TYPE * pmt;
138 OutputQueue * queue;
139 } QTOutPin;
141 typedef struct QTInPin {
142 BasePin pin;
143 GUID subType;
145 IAsyncReader *pReader;
146 IMemAllocator *pAlloc;
147 } QTInPin;
149 typedef struct QTSplitter {
150 BaseFilter filter;
152 QTInPin pInputPin;
153 QTOutPin *pVideo_Pin;
154 QTOutPin *pAudio_Pin;
156 ALLOCATOR_PROPERTIES props;
158 Movie pQTMovie;
159 QTVisualContextRef vContext;
161 MovieAudioExtractionRef aSession;
162 HANDLE runEvent;
164 DWORD outputSize;
165 FILTER_STATE state;
166 CRITICAL_SECTION csReceive;
168 SourceSeeking sourceSeeking;
169 TimeValue movie_time;
170 TimeValue movie_start;
171 TimeScale movie_scale;
172 } QTSplitter;
174 static const IPinVtbl QT_OutputPin_Vtbl;
175 static const IPinVtbl QT_InputPin_Vtbl;
176 static const IBaseFilterVtbl QT_Vtbl;
177 static const IMediaSeekingVtbl QT_Seeking_Vtbl;
179 static HRESULT QT_AddPin(QTSplitter *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt, BOOL video);
180 static HRESULT QT_RemoveOutputPins(QTSplitter *This);
182 static HRESULT WINAPI QTSplitter_ChangeStart(IMediaSeeking *iface);
183 static HRESULT WINAPI QTSplitter_ChangeStop(IMediaSeeking *iface);
184 static HRESULT WINAPI QTSplitter_ChangeRate(IMediaSeeking *iface);
186 static inline QTSplitter *impl_from_IMediaSeeking( IMediaSeeking *iface )
188 return (QTSplitter *)((char*)iface - FIELD_OFFSET(QTSplitter, sourceSeeking.lpVtbl));
192 * Base Filter
195 static IPin* WINAPI QT_GetPin(BaseFilter *iface, int pos)
197 QTSplitter *This = (QTSplitter *)iface;
198 TRACE("Asking for pos %x\n", pos);
200 if (pos > 2 || pos < 0)
201 return NULL;
202 switch (pos)
204 case 0:
205 IPin_AddRef((IPin*)&This->pInputPin);
206 return (IPin*)&This->pInputPin;
207 case 1:
208 if (This->pVideo_Pin)
209 IPin_AddRef((IPin*)This->pVideo_Pin);
210 return (IPin*)This->pVideo_Pin;
211 case 2:
212 if (This->pAudio_Pin)
213 IPin_AddRef((IPin*)This->pAudio_Pin);
214 return (IPin*)This->pAudio_Pin;
215 default:
216 return NULL;
220 static LONG WINAPI QT_GetPinCount(BaseFilter *iface)
222 QTSplitter *This = (QTSplitter *)iface;
223 int c = 1;
224 if (This->pAudio_Pin) c++;
225 if (This->pVideo_Pin) c++;
226 return c;
229 static const BaseFilterFuncTable BaseFuncTable = {
230 QT_GetPin,
231 QT_GetPinCount
234 IUnknown * CALLBACK QTSplitter_create(IUnknown *punkout, HRESULT *phr)
236 IUnknown *obj = NULL;
237 PIN_INFO *piInput;
238 QTSplitter *This;
239 static const WCHAR wcsInputPinName[] = {'I','n','p','u','t',' ','P','i','n',0};
241 EnterMovies();
243 RegisterWineDataHandler();
245 This = CoTaskMemAlloc(sizeof(*This));
246 obj = (IUnknown*)This;
247 if (!This)
249 *phr = E_OUTOFMEMORY;
250 return NULL;
252 ZeroMemory(This,sizeof(*This));
254 BaseFilter_Init(&This->filter, &QT_Vtbl, &CLSID_QTSplitter, (DWORD_PTR)(__FILE__ ": QTSplitter.csFilter"), &BaseFuncTable);
256 InitializeCriticalSection(&This->csReceive);
257 This->csReceive.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": QTSplitter.csReceive");
259 This->pVideo_Pin = NULL;
260 This->pAudio_Pin = NULL;
261 This->state = State_Stopped;
262 This->aSession = NULL;
263 This->runEvent = CreateEventW(NULL, 0, 0, NULL);
265 piInput = &This->pInputPin.pin.pinInfo;
266 piInput->dir = PINDIR_INPUT;
267 piInput->pFilter = (IBaseFilter *)This;
268 lstrcpynW(piInput->achName, wcsInputPinName, sizeof(piInput->achName) / sizeof(piInput->achName[0]));
269 This->pInputPin.pin.lpVtbl = &QT_InputPin_Vtbl;
270 This->pInputPin.pin.refCount = 1;
271 This->pInputPin.pin.pConnectedTo = NULL;
272 This->pInputPin.pin.pCritSec = &This->filter.csFilter;
274 SourceSeeking_Init(&This->sourceSeeking, &QT_Seeking_Vtbl, QTSplitter_ChangeStop, QTSplitter_ChangeStart, QTSplitter_ChangeRate, &This->filter.csFilter);
276 *phr = S_OK;
277 return obj;
280 static void QT_Destroy(QTSplitter *This)
282 IPin *connected = NULL;
283 ULONG pinref;
285 TRACE("Destroying\n");
287 /* Don't need to clean up output pins, disconnecting input pin will do that */
288 IPin_ConnectedTo((IPin *)&This->pInputPin, &connected);
289 if (connected)
291 IPin_Disconnect(connected);
292 IPin_Release(connected);
294 pinref = IPin_Release((IPin *)&This->pInputPin);
295 if (pinref)
297 ERR("pinref should be null, is %u, destroying anyway\n", pinref);
298 assert((LONG)pinref > 0);
300 while (pinref)
301 pinref = IPin_Release((IPin *)&This->pInputPin);
304 if (This->pQTMovie)
305 DisposeMovie(This->pQTMovie);
306 if (This->vContext)
307 QTVisualContextRelease(This->vContext);
308 if (This->aSession)
309 MovieAudioExtractionEnd(This->aSession);
310 CloseHandle(This->runEvent);
312 ExitMovies();
314 This->csReceive.DebugInfo->Spare[0] = 0;
315 DeleteCriticalSection(&This->csReceive);
317 CoTaskMemFree(This);
320 static HRESULT WINAPI QT_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID *ppv)
322 QTSplitter *This = (QTSplitter *)iface;
323 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
325 *ppv = NULL;
327 if (IsEqualIID(riid, &IID_IUnknown))
328 *ppv = This;
329 else if (IsEqualIID(riid, &IID_IPersist))
330 *ppv = This;
331 else if (IsEqualIID(riid, &IID_IMediaFilter))
332 *ppv = This;
333 else if (IsEqualIID(riid, &IID_IBaseFilter))
334 *ppv = This;
335 else if (IsEqualIID(riid, &IID_IMediaSeeking))
336 *ppv = &This->sourceSeeking;
338 if (*ppv)
340 IUnknown_AddRef((IUnknown *)(*ppv));
341 return S_OK;
344 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
345 FIXME("No interface for %s!\n", debugstr_guid(riid));
347 return E_NOINTERFACE;
350 static ULONG WINAPI QT_Release(IBaseFilter *iface)
352 QTSplitter *This = (QTSplitter *)iface;
353 ULONG refCount = BaseFilterImpl_Release(iface);
355 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
357 if (!refCount)
358 QT_Destroy(This);
360 return refCount;
363 static HRESULT WINAPI QT_Stop(IBaseFilter *iface)
365 QTSplitter *This = (QTSplitter *)iface;
367 TRACE("()\n");
369 EnterCriticalSection(&This->csReceive);
370 IAsyncReader_BeginFlush(This->pInputPin.pReader);
371 IAsyncReader_EndFlush(This->pInputPin.pReader);
372 LeaveCriticalSection(&This->csReceive);
374 return S_OK;
377 static HRESULT WINAPI QT_Pause(IBaseFilter *iface)
379 HRESULT hr = S_OK;
380 TRACE("()\n");
382 return hr;
385 static OSErr QT_Create_Extract_Session(QTSplitter *filter)
387 AudioStreamBasicDescription aDesc;
388 OSErr err;
389 WAVEFORMATEX* pvi;
391 pvi = (WAVEFORMATEX*)filter->pAudio_Pin->pmt->pbFormat;
393 err = MovieAudioExtractionBegin(filter->pQTMovie, 0, &filter->aSession);
394 if (err != noErr)
396 ERR("Failed to begin Extraction session %i\n",err);
397 return err;
400 err = MovieAudioExtractionGetProperty(filter->aSession,
401 kQTPropertyClass_MovieAudioExtraction_Audio,
402 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription,
403 sizeof(AudioStreamBasicDescription), &aDesc, NULL);
405 if (err != noErr)
407 MovieAudioExtractionEnd(filter->aSession);
408 filter->aSession = NULL;
409 ERR("Failed to get session description %i\n",err);
410 return err;
413 aDesc.mFormatID = kAudioFormatLinearPCM;
414 aDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger +
415 kAudioFormatFlagIsPacked;
416 aDesc.mFramesPerPacket = 1;
417 aDesc.mChannelsPerFrame = pvi->nChannels;
418 aDesc.mBitsPerChannel = pvi->wBitsPerSample;
419 aDesc.mSampleRate = pvi->nSamplesPerSec;
420 aDesc.mBytesPerFrame = (aDesc.mBitsPerChannel * aDesc.mChannelsPerFrame) / 8;
421 aDesc.mBytesPerPacket = aDesc.mBytesPerFrame * aDesc.mFramesPerPacket;
423 err = MovieAudioExtractionSetProperty(filter->aSession,
424 kQTPropertyClass_MovieAudioExtraction_Audio,
425 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription,
426 sizeof(AudioStreamBasicDescription), &aDesc);
428 if (aDesc.mFormatID != kAudioFormatLinearPCM)
430 ERR("Not PCM Wave\n");
431 err = -1;
433 if (aDesc.mFormatFlags != kLinearPCMFormatFlagIsSignedInteger +
434 kAudioFormatFlagIsPacked)
436 ERR("Unhandled Flags\n");
437 err = -1;
439 if (aDesc.mFramesPerPacket != 1)
441 ERR("Unhandled Frames per packet %li\n",aDesc.mFramesPerPacket);
442 err = -1;
444 if (aDesc.mChannelsPerFrame != pvi->nChannels)
446 ERR("Unhandled channel count %li\n",aDesc.mChannelsPerFrame);
447 err = -1;
449 if (aDesc.mBitsPerChannel != pvi->wBitsPerSample)
451 ERR("Unhandled bits per channel %li\n",aDesc.mBitsPerChannel);
452 err = -1;
454 if (aDesc.mSampleRate != pvi->nSamplesPerSec)
456 ERR("Unhandled sample rate %f\n",aDesc.mSampleRate);
457 err = -1;
460 if (err != noErr)
462 ERR("Failed to create Extraction Session\n");
463 MovieAudioExtractionEnd(filter->aSession);
464 filter->aSession = NULL;
467 return err;
470 static DWORD WINAPI QTSplitter_thread(LPVOID data)
472 QTSplitter *This = (QTSplitter *)data;
473 HRESULT hr = S_OK;
474 TimeValue next_time;
475 CVPixelBufferRef pixelBuffer = NULL;
476 OSStatus err;
477 TimeRecord tr;
479 if (This->pAudio_Pin)
481 /* according to QA1469 a movie has to be fully loaded before we
482 can reliably start the Extraction session */
484 while(GetMovieLoadState(This->pQTMovie) < kMovieLoadStateComplete)
485 MoviesTask(This->pQTMovie,1000);
487 QT_Create_Extract_Session(This);
490 WaitForSingleObject(This->runEvent, -1);
492 EnterCriticalSection(&This->csReceive);
493 This->state = State_Running;
494 /* Prime the pump: Needed for MPEG streams */
495 GetMovieNextInterestingTime(This->pQTMovie, nextTimeEdgeOK | nextTimeStep, 0, NULL, This->movie_time, 1, &next_time, NULL);
497 GetMovieTime(This->pQTMovie, &tr);
498 LeaveCriticalSection(&This->csReceive);
501 LONGLONG tStart=0, tStop=0;
502 LONGLONG mStart=0, mStop=0;
503 float time;
505 EnterCriticalSection(&This->csReceive);
506 GetMovieNextInterestingTime(This->pQTMovie, nextTimeStep, 0, NULL, This->movie_time, 1, &next_time, NULL);
508 if (next_time == -1)
510 TRACE("No next time\n");
511 LeaveCriticalSection(&This->csReceive);
512 break;
515 tr.value = SInt64ToWide(next_time);
516 SetMovieTime(This->pQTMovie, &tr);
517 MoviesTask(This->pQTMovie,0);
518 QTVisualContextTask(This->vContext);
520 TRACE("In loop at time %ld\n",This->movie_time);
521 TRACE("In Next time %ld\n",next_time);
523 mStart = This->movie_time;
524 mStop = next_time;
526 time = (float)(This->movie_time - This->movie_start) / This->movie_scale;
527 tStart = time * 10000000;
528 time = (float)(next_time - This->movie_start) / This->movie_scale;
529 tStop = time * 10000000;
531 /* Deliver Audio */
532 if (This->pAudio_Pin && ((BaseOutputPin*)This->pAudio_Pin)->pin.pConnectedTo && This->aSession)
534 int data_size=0;
535 BYTE* ptr;
536 IMediaSample *sample = NULL;
537 AudioBufferList aData;
538 UInt32 flags;
539 UInt32 frames;
540 WAVEFORMATEX* pvi;
541 float duration;
543 pvi = (WAVEFORMATEX*)This->pAudio_Pin->pmt->pbFormat;
545 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->pAudio_Pin, &sample, NULL, NULL, 0);
547 if (FAILED(hr))
549 ERR("Audio: Unable to get delivery buffer (%x)\n", hr);
550 goto audio_error;
553 hr = IMediaSample_GetPointer(sample, &ptr);
554 if (FAILED(hr))
556 ERR("Audio: Unable to get pointer to buffer (%x)\n", hr);
557 goto audio_error;
560 duration = (float)next_time / This->movie_scale;
561 time = (float)This->movie_time / This->movie_scale;
562 duration -= time;
563 frames = pvi->nSamplesPerSec * duration;
564 TRACE("Need audio for %f seconds (%li frames)\n",duration,frames);
566 data_size = IMediaSample_GetSize(sample);
567 if (data_size < frames * pvi->nBlockAlign)
568 FIXME("Audio buffer is too small\n");
570 aData.mNumberBuffers = 1;
571 aData.mBuffers[0].mNumberChannels = pvi->nChannels;
572 aData.mBuffers[0].mDataByteSize = data_size;
573 aData.mBuffers[0].mData = ptr;
575 err = MovieAudioExtractionFillBuffer(This->aSession, &frames, &aData, &flags);
576 TRACE("Got %i frames\n",(int)frames);
578 IMediaSample_SetActualDataLength(sample, frames * pvi->nBlockAlign);
580 IMediaSample_SetMediaTime(sample, &mStart, &mStop);
581 IMediaSample_SetTime(sample, &tStart, &tStop);
583 hr = OutputQueue_Receive(This->pAudio_Pin->queue, sample);
584 TRACE("Audio Delivered (%x)\n",hr);
586 audio_error:
587 if (sample)
588 IMediaSample_Release(sample);
590 else
591 TRACE("Audio Pin not connected or no Audio\n");
593 /* Deliver Video */
594 if (This->pVideo_Pin && QTVisualContextIsNewImageAvailable(This->vContext,0))
596 err = QTVisualContextCopyImageForTime(This->vContext, NULL, NULL, &pixelBuffer);
597 if (err == noErr)
599 int data_size=0;
600 BYTE* ptr;
601 IMediaSample *sample = NULL;
603 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->pVideo_Pin, &sample, NULL, NULL, 0);
604 if (FAILED(hr))
606 ERR("Video: Unable to get delivery buffer (%x)\n", hr);
607 goto video_error;
610 data_size = IMediaSample_GetSize(sample);
611 if (data_size < This->outputSize)
613 ERR("Sample size is too small %d < %d\n", data_size, This->outputSize)
615 hr = E_FAIL;
616 goto video_error;
619 hr = IMediaSample_GetPointer(sample, &ptr);
620 if (FAILED(hr))
622 ERR("Video: Unable to get pointer to buffer (%x)\n", hr);
623 goto video_error;
626 hr = AccessPixelBufferPixels( pixelBuffer, ptr);
627 if (FAILED(hr))
629 ERR("Failed to access Pixels\n");
630 goto video_error;
633 IMediaSample_SetActualDataLength(sample, This->outputSize);
635 IMediaSample_SetMediaTime(sample, &mStart, &mStop);
636 IMediaSample_SetTime(sample, &tStart, &tStop);
638 hr = OutputQueue_Receive(This->pVideo_Pin->queue, sample);
639 TRACE("Video Delivered (%x)\n",hr);
641 video_error:
642 if (sample)
643 IMediaSample_Release(sample);
644 if (pixelBuffer)
645 CVPixelBufferRelease(pixelBuffer);
648 else
649 TRACE("No video to deliver\n");
651 This->movie_time = next_time;
652 LeaveCriticalSection(&This->csReceive);
653 } while (hr == S_OK);
655 This->state = State_Stopped;
656 if (This->pAudio_Pin)
657 OutputQueue_EOS(This->pAudio_Pin->queue);
658 if (This->pVideo_Pin)
659 OutputQueue_EOS(This->pVideo_Pin->queue);
661 return hr;
664 static HRESULT WINAPI QT_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
666 HRESULT hr = S_OK;
667 QTSplitter *This = (QTSplitter *)iface;
668 HRESULT hr_any = VFW_E_NOT_CONNECTED;
670 TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
672 EnterCriticalSection(&This->csReceive);
673 This->filter.rtStreamStart = tStart;
675 if (This->pVideo_Pin)
676 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->pVideo_Pin);
677 if (SUCCEEDED(hr))
678 hr_any = hr;
679 if (This->pAudio_Pin)
680 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->pAudio_Pin);
681 if (SUCCEEDED(hr))
682 hr_any = hr;
684 hr = hr_any;
686 SetEvent(This->runEvent);
687 LeaveCriticalSection(&This->csReceive);
689 return hr;
692 static HRESULT WINAPI QT_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
694 QTSplitter *This = (QTSplitter *)iface;
695 TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
697 *pState = This->state;
699 return S_OK;
702 static HRESULT WINAPI QT_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
704 FIXME("(%p)->(%s,%p) stub\n", iface, debugstr_w(Id), ppPin);
705 return E_NOTIMPL;
708 static const IBaseFilterVtbl QT_Vtbl = {
709 QT_QueryInterface,
710 BaseFilterImpl_AddRef,
711 QT_Release,
712 BaseFilterImpl_GetClassID,
713 QT_Stop,
714 QT_Pause,
715 QT_Run,
716 QT_GetState,
717 BaseFilterImpl_SetSyncSource,
718 BaseFilterImpl_GetSyncSource,
719 BaseFilterImpl_EnumPins,
720 QT_FindPin,
721 BaseFilterImpl_QueryFilterInfo,
722 BaseFilterImpl_JoinFilterGraph,
723 BaseFilterImpl_QueryVendorInfo
727 * Input Pin
729 static HRESULT QT_RemoveOutputPins(QTSplitter *This)
731 HRESULT hr;
732 TRACE("(%p)\n", This);
734 if (This->pVideo_Pin)
736 hr = BaseOutputPinImpl_BreakConnect(&This->pVideo_Pin->pin);
737 TRACE("Disconnect: %08x\n", hr);
738 IPin_Release((IPin*)This->pVideo_Pin);
739 This->pVideo_Pin = NULL;
741 if (This->pAudio_Pin)
743 hr = BaseOutputPinImpl_BreakConnect(&This->pAudio_Pin->pin);
744 TRACE("Disconnect: %08x\n", hr);
745 IPin_Release((IPin*)This->pAudio_Pin);
746 This->pAudio_Pin = NULL;
749 BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
750 return S_OK;
753 static ULONG WINAPI QTInPin_Release(IPin *iface)
755 QTInPin *This = (QTInPin*)iface;
756 ULONG refCount = InterlockedDecrement(&This->pin.refCount);
758 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
759 if (!refCount)
761 FreeMediaType(&This->pin.mtCurrent);
762 if (This->pAlloc)
763 IMemAllocator_Release(This->pAlloc);
764 This->pAlloc = NULL;
765 This->pin.lpVtbl = NULL;
766 return 0;
768 else
769 return refCount;
772 static HRESULT QT_Process_Video_Track(QTSplitter* filter, Track trk)
774 AM_MEDIA_TYPE amt;
775 VIDEOINFOHEADER * pvi;
776 PIN_INFO piOutput;
777 HRESULT hr = S_OK;
778 OSErr err;
779 static const WCHAR szwVideoOut[] = {'V','i','d','e','o',0};
780 CFMutableDictionaryRef pixelBufferOptions = NULL;
781 CFMutableDictionaryRef visualContextOptions = NULL;
782 CFNumberRef n = NULL;
783 int t;
784 DWORD outputWidth, outputHeight, outputDepth;
785 Fixed trackWidth, trackHeight;
787 ZeroMemory(&amt, sizeof(amt));
788 amt.formattype = FORMAT_VideoInfo;
789 amt.majortype = MEDIATYPE_Video;
790 amt.subtype = MEDIASUBTYPE_RGB24;
792 GetTrackDimensions(trk, &trackWidth, &trackHeight);
794 outputDepth = 3;
795 outputWidth = Fix2Long(trackWidth);
796 outputHeight = Fix2Long(trackHeight);
797 TRACE("Width %i Height %i\n",outputWidth, outputHeight);
799 amt.cbFormat = sizeof(VIDEOINFOHEADER);
800 amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
801 ZeroMemory(amt.pbFormat, amt.cbFormat);
802 pvi = (VIDEOINFOHEADER *)amt.pbFormat;
803 pvi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
804 pvi->bmiHeader.biWidth = outputWidth;
805 pvi->bmiHeader.biHeight = outputHeight;
806 pvi->bmiHeader.biPlanes = 1;
807 pvi->bmiHeader.biBitCount = 24;
808 pvi->bmiHeader.biCompression = BI_RGB;
809 pvi->bmiHeader.biSizeImage = outputWidth * outputHeight * outputDepth;
811 filter->outputSize = pvi->bmiHeader.biSizeImage;
812 amt.lSampleSize = 0;
814 pixelBufferOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
816 t = k32ARGBPixelFormat;
817 n = CFNumberCreate(NULL, kCFNumberIntType, &t);
818 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, n);
819 CFRelease(n);
821 n = CFNumberCreate(NULL, kCFNumberIntType, &outputWidth);
822 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferWidthKey, n);
823 CFRelease(n);
825 n = CFNumberCreate(NULL, kCFNumberIntType, &outputHeight);
826 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferHeightKey, n);
827 CFRelease(n);
829 t = 16;
830 n = CFNumberCreate(NULL, kCFNumberIntType, &t);
831 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, n);
832 CFRelease(n);
834 visualContextOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
836 CFDictionarySetValue(visualContextOptions, kQTVisualContextPixelBufferAttributesKey, pixelBufferOptions);
838 err = QTPixelBufferContextCreate(NULL, visualContextOptions,&filter->vContext);
839 CFRelease(pixelBufferOptions);
840 CFRelease(visualContextOptions);
841 if (err != noErr)
843 ERR("Failed to create Visual Context\n");
844 return E_FAIL;
847 err = SetMovieVisualContext(filter->pQTMovie, filter->vContext);
848 if (err != noErr)
850 ERR("Failed to set Visual Context\n");
851 return E_FAIL;
854 piOutput.dir = PINDIR_OUTPUT;
855 piOutput.pFilter = (IBaseFilter *)filter;
856 lstrcpyW(piOutput.achName,szwVideoOut);
858 hr = QT_AddPin(filter, &piOutput, &amt, TRUE);
859 if (FAILED(hr))
860 ERR("Failed to add Video Track\n");
861 else
862 TRACE("Video Pin %p\n",filter->pVideo_Pin);
864 return hr;
867 static HRESULT QT_Process_Audio_Track(QTSplitter* filter, Track trk)
869 AM_MEDIA_TYPE amt;
870 WAVEFORMATEX* pvi;
871 PIN_INFO piOutput;
872 HRESULT hr = S_OK;
873 static const WCHAR szwAudioOut[] = {'A','u','d','i','o',0};
874 Media audioMedia;
876 SoundDescriptionHandle aDesc = (SoundDescriptionHandle) NewHandle(sizeof(SoundDescription));
878 audioMedia = GetTrackMedia(trk);
879 GetMediaSampleDescription(audioMedia, 1, (SampleDescriptionHandle)aDesc);
881 ZeroMemory(&amt, sizeof(amt));
882 amt.formattype = FORMAT_WaveFormatEx;
883 amt.majortype = MEDIATYPE_Audio;
884 amt.subtype = MEDIASUBTYPE_PCM;
885 amt.bTemporalCompression = 0;
887 amt.cbFormat = sizeof(WAVEFORMATEX);
888 amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
889 ZeroMemory(amt.pbFormat, amt.cbFormat);
890 pvi = (WAVEFORMATEX*)amt.pbFormat;
892 pvi->cbSize = sizeof(WAVEFORMATEX);
893 pvi->wFormatTag = WAVE_FORMAT_PCM;
894 pvi->nChannels = ((SoundDescription)**aDesc).numChannels;
895 if (pvi->nChannels < 1 || pvi->nChannels > 2)
896 pvi->nChannels = 2;
897 pvi->nSamplesPerSec = (((SoundDescription)**aDesc).sampleRate/65536);
898 if (pvi->nSamplesPerSec < 8000 || pvi->nChannels > 48000)
899 pvi->nSamplesPerSec = 44100;
900 pvi->wBitsPerSample = ((SoundDescription)**aDesc).sampleSize;
901 if (pvi->wBitsPerSample < 8 || pvi->wBitsPerSample > 32)
902 pvi->wBitsPerSample = 16;
903 pvi->nBlockAlign = (pvi->nChannels * pvi->wBitsPerSample) / 8;
904 pvi->nAvgBytesPerSec = pvi->nSamplesPerSec * pvi->nBlockAlign;
906 DisposeHandle((Handle)aDesc);
908 piOutput.dir = PINDIR_OUTPUT;
909 piOutput.pFilter = (IBaseFilter *)filter;
910 lstrcpyW(piOutput.achName,szwAudioOut);
912 hr = QT_AddPin(filter, &piOutput, &amt, FALSE);
913 if (FAILED(hr))
914 ERR("Failed to add Audio Track\n");
915 else
916 TRACE("Audio Pin %p\n",filter->pAudio_Pin);
917 return hr;
920 static HRESULT QT_Process_Movie(QTSplitter* filter)
922 HRESULT hr = S_OK;
923 OSErr err;
924 WineDataRefRecord ptrDataRefRec;
925 Handle dataRef = NULL;
926 Track trk;
927 short id = 0;
928 DWORD tid;
929 HANDLE thread;
930 LONGLONG time;
932 TRACE("Trying movie connect\n");
934 ptrDataRefRec.pReader = filter->pInputPin.pReader;
935 ptrDataRefRec.streamSubtype = filter->pInputPin.subType;
936 PtrToHand( &ptrDataRefRec, &dataRef, sizeof(WineDataRefRecord));
938 err = NewMovieFromDataRef(&filter->pQTMovie, newMovieActive|newMovieDontInteractWithUser|newMovieDontAutoUpdateClock|newMovieDontAskUnresolvedDataRefs|newMovieAsyncOK, &id, dataRef, 'WINE');
940 DisposeHandle(dataRef);
942 if (err != noErr)
944 FIXME("QuickTime cannot handle media type(%i)\n",err);
945 return VFW_E_TYPE_NOT_ACCEPTED;
948 PrePrerollMovie(filter->pQTMovie, 0, fixed1, NULL, NULL);
949 PrerollMovie(filter->pQTMovie, 0, fixed1);
950 GoToBeginningOfMovie(filter->pQTMovie);
951 SetMovieActive(filter->pQTMovie,TRUE);
953 if (GetMovieLoadState(filter->pQTMovie) < kMovieLoadStateLoaded)
954 MoviesTask(filter->pQTMovie,100);
956 trk = GetMovieIndTrackType(filter->pQTMovie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
957 TRACE("%p is a video track\n",trk);
958 if (trk)
959 hr = QT_Process_Video_Track(filter, trk);
961 if (FAILED(hr))
962 return hr;
964 trk = GetMovieIndTrackType(filter->pQTMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
965 TRACE("%p is a audio track\n",trk);
966 if (trk)
967 hr = QT_Process_Audio_Track(filter, trk);
969 time = GetMovieDuration(filter->pQTMovie);
970 filter->movie_scale = GetMovieTimeScale(filter->pQTMovie);
971 filter->sourceSeeking.llDuration = ((double)time / filter->movie_scale) * 10000000;
972 filter->sourceSeeking.llStop = filter->sourceSeeking.llDuration;
974 TRACE("Movie duration is %s\n",wine_dbgstr_longlong(filter->sourceSeeking.llDuration));
976 thread = CreateThread(NULL, 0, QTSplitter_thread, filter, 0, &tid);
977 if (thread)
979 TRACE("Created thread 0x%08x\n", tid);
980 CloseHandle(thread);
982 else
983 hr = HRESULT_FROM_WIN32(GetLastError());
985 return hr;
988 static HRESULT WINAPI QTInPin_ReceiveConnection(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
990 HRESULT hr = S_OK;
991 ALLOCATOR_PROPERTIES props;
992 QTInPin *This = (QTInPin*)iface;
994 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
996 EnterCriticalSection(This->pin.pCritSec);
997 This->pReader = NULL;
999 if (This->pin.pConnectedTo)
1000 hr = VFW_E_ALREADY_CONNECTED;
1001 else if (IPin_QueryAccept(iface, pmt) != S_OK)
1002 hr = VFW_E_TYPE_NOT_ACCEPTED;
1003 else
1005 PIN_DIRECTION pindirReceive;
1006 IPin_QueryDirection(pReceivePin, &pindirReceive);
1007 if (pindirReceive != PINDIR_OUTPUT)
1008 hr = VFW_E_INVALID_DIRECTION;
1011 if (FAILED(hr))
1013 LeaveCriticalSection(This->pin.pCritSec);
1014 return hr;
1017 hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1018 if (FAILED(hr))
1020 LeaveCriticalSection(This->pin.pCritSec);
1021 TRACE("Input source is not an AsyncReader\n");
1022 return hr;
1025 LeaveCriticalSection(This->pin.pCritSec);
1026 EnterCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
1027 hr = QT_Process_Movie((QTSplitter *)This->pin.pinInfo.pFilter);
1028 if (FAILED(hr))
1030 LeaveCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
1031 TRACE("Unable to process movie\n");
1032 return hr;
1035 This->pAlloc = NULL;
1036 props.cBuffers = 8;
1037 props.cbAlign = 1;
1038 props.cbBuffer = ((QTSplitter *)This->pin.pinInfo.pFilter)->outputSize + props.cbAlign;
1039 props.cbPrefix = 0;
1041 hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1042 if (SUCCEEDED(hr))
1044 CopyMediaType(&This->pin.mtCurrent, pmt);
1045 This->pin.pConnectedTo = pReceivePin;
1046 IPin_AddRef(pReceivePin);
1047 hr = IMemAllocator_Commit(This->pAlloc);
1049 else
1051 QT_RemoveOutputPins((QTSplitter *)This->pin.pinInfo.pFilter);
1052 if (This->pReader)
1053 IAsyncReader_Release(This->pReader);
1054 This->pReader = NULL;
1055 if (This->pAlloc)
1056 IMemAllocator_Release(This->pAlloc);
1057 This->pAlloc = NULL;
1059 TRACE("Size: %i\n", props.cbBuffer);
1060 LeaveCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
1062 return hr;
1065 static HRESULT WINAPI QTInPin_Disconnect(IPin *iface)
1067 HRESULT hr;
1068 QTInPin *This = (QTInPin*)iface;
1069 FILTER_STATE state;
1070 TRACE("()\n");
1072 hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1073 EnterCriticalSection(This->pin.pCritSec);
1074 if (This->pin.pConnectedTo)
1076 QTSplitter *Parser = (QTSplitter *)This->pin.pinInfo.pFilter;
1078 if (SUCCEEDED(hr) && state == State_Stopped)
1080 IMemAllocator_Decommit(This->pAlloc);
1081 IPin_Disconnect(This->pin.pConnectedTo);
1082 This->pin.pConnectedTo = NULL;
1083 hr = QT_RemoveOutputPins(Parser);
1085 else
1086 hr = VFW_E_NOT_STOPPED;
1088 else
1089 hr = S_FALSE;
1090 LeaveCriticalSection(This->pin.pCritSec);
1091 return hr;
1094 static HRESULT WINAPI QTInPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
1096 QTInPin *This = (QTInPin*)iface;
1098 TRACE("(%p)->(%p)\n", This, pmt);
1100 if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
1102 This->subType = pmt->subtype;
1103 return S_OK;
1105 return S_FALSE;
1108 static HRESULT WINAPI QTInPin_EndOfStream(IPin *iface)
1110 QTInPin *pin = (QTInPin*)iface;
1111 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1113 FIXME("Propagate message on %p\n", This);
1114 return S_OK;
1117 static HRESULT WINAPI QTInPin_BeginFlush(IPin *iface)
1119 QTInPin *pin = (QTInPin*)iface;
1120 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1122 FIXME("Propagate message on %p\n", This);
1123 return S_OK;
1126 static HRESULT WINAPI QTInPin_EndFlush(IPin *iface)
1128 QTInPin *pin = (QTInPin*)iface;
1129 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1131 FIXME("Propagate message on %p\n", This);
1132 return S_OK;
1135 static HRESULT WINAPI QTInPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1137 QTInPin *pin = (QTInPin*)iface;
1138 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1140 BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1141 FIXME("Propagate message on %p\n", This);
1142 return S_OK;
1145 static HRESULT WINAPI QTInPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1147 QTInPin *This = (QTInPin*)iface;
1149 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
1151 *ppv = NULL;
1153 if (IsEqualIID(riid, &IID_IUnknown))
1154 *ppv = iface;
1155 else if (IsEqualIID(riid, &IID_IPin))
1156 *ppv = iface;
1157 else if (IsEqualIID(riid, &IID_IMediaSeeking))
1158 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1160 if (*ppv)
1162 IUnknown_AddRef((IUnknown *)(*ppv));
1163 return S_OK;
1166 FIXME("No interface for %s!\n", debugstr_guid(riid));
1168 return E_NOINTERFACE;
1171 static HRESULT WINAPI QTInPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1173 BasePin *This = (BasePin *)iface;
1175 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
1177 return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
1180 static const IPinVtbl QT_InputPin_Vtbl = {
1181 QTInPin_QueryInterface,
1182 BasePinImpl_AddRef,
1183 QTInPin_Release,
1184 BaseInputPinImpl_Connect,
1185 QTInPin_ReceiveConnection,
1186 QTInPin_Disconnect,
1187 BasePinImpl_ConnectedTo,
1188 BasePinImpl_ConnectionMediaType,
1189 BasePinImpl_QueryPinInfo,
1190 BasePinImpl_QueryDirection,
1191 BasePinImpl_QueryId,
1192 QTInPin_QueryAccept,
1193 QTInPin_EnumMediaTypes,
1194 BasePinImpl_QueryInternalConnections,
1195 QTInPin_EndOfStream,
1196 QTInPin_BeginFlush,
1197 QTInPin_EndFlush,
1198 QTInPin_NewSegment
1202 * Output Pin
1205 static HRESULT WINAPI QTOutPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1207 QTOutPin *This = (QTOutPin *)iface;
1209 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1211 *ppv = NULL;
1213 if (IsEqualIID(riid, &IID_IUnknown))
1214 *ppv = iface;
1215 else if (IsEqualIID(riid, &IID_IPin))
1216 *ppv = iface;
1217 else if (IsEqualIID(riid, &IID_IMediaSeeking))
1218 return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1220 if (*ppv)
1222 IUnknown_AddRef((IUnknown *)(*ppv));
1223 return S_OK;
1225 FIXME("No interface for %s!\n", debugstr_guid(riid));
1226 return E_NOINTERFACE;
1229 static ULONG WINAPI QTOutPin_Release(IPin *iface)
1231 QTOutPin *This = (QTOutPin *)iface;
1232 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
1233 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
1235 if (!refCount)
1237 DeleteMediaType(This->pmt);
1238 FreeMediaType(&This->pin.pin.mtCurrent);
1239 OutputQueue_Destroy(This->queue);
1240 CoTaskMemFree(This);
1241 return 0;
1243 return refCount;
1246 static HRESULT WINAPI QTOutPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
1248 QTOutPin *This = (QTOutPin *)iface;
1250 if (iPosition < 0)
1251 return E_INVALIDARG;
1252 if (iPosition > 0)
1253 return VFW_S_NO_MORE_ITEMS;
1254 CopyMediaType(pmt, This->pmt);
1255 return S_OK;
1258 static HRESULT WINAPI QTOutPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
1260 /* Unused */
1261 return S_OK;
1264 static HRESULT WINAPI QTOutPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc)
1266 HRESULT hr;
1267 QTOutPin *This = (QTOutPin *)iface;
1268 QTSplitter *QTfilter = (QTSplitter*)This->pin.pin.pinInfo.pFilter;
1270 *pAlloc = NULL;
1271 if (QTfilter->pInputPin.pAlloc)
1272 hr = IMemInputPin_NotifyAllocator(pPin, QTfilter->pInputPin.pAlloc, FALSE);
1273 else
1274 hr = VFW_E_NO_ALLOCATOR;
1276 return hr;
1279 static HRESULT WINAPI QTOutPin_BreakConnect(BaseOutputPin *This)
1281 HRESULT hr;
1283 TRACE("(%p)->()\n", This);
1285 EnterCriticalSection(This->pin.pCritSec);
1286 if (!This->pin.pConnectedTo || !This->pMemInputPin)
1287 hr = VFW_E_NOT_CONNECTED;
1288 else
1290 hr = IPin_Disconnect(This->pin.pConnectedTo);
1291 IPin_Disconnect((IPin *)This);
1293 LeaveCriticalSection(This->pin.pCritSec);
1295 return hr;
1298 static const IPinVtbl QT_OutputPin_Vtbl = {
1299 QTOutPin_QueryInterface,
1300 BasePinImpl_AddRef,
1301 QTOutPin_Release,
1302 BaseOutputPinImpl_Connect,
1303 BaseOutputPinImpl_ReceiveConnection,
1304 BaseOutputPinImpl_Disconnect,
1305 BasePinImpl_ConnectedTo,
1306 BasePinImpl_ConnectionMediaType,
1307 BasePinImpl_QueryPinInfo,
1308 BasePinImpl_QueryDirection,
1309 BasePinImpl_QueryId,
1310 BasePinImpl_QueryAccept,
1311 BasePinImpl_EnumMediaTypes,
1312 BasePinImpl_QueryInternalConnections,
1313 BaseOutputPinImpl_EndOfStream,
1314 BaseOutputPinImpl_BeginFlush,
1315 BaseOutputPinImpl_EndFlush,
1316 BasePinImpl_NewSegment
1319 static const BasePinFuncTable output_BaseFuncTable = {
1320 NULL,
1321 BaseOutputPinImpl_AttemptConnection,
1322 BasePinImpl_GetMediaTypeVersion,
1323 QTOutPin_GetMediaType
1326 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
1327 QTOutPin_DecideBufferSize,
1328 QTOutPin_DecideAllocator,
1329 QTOutPin_BreakConnect
1332 static const OutputQueueFuncTable output_OutputQueueFuncTable = {
1333 OutputQueueImpl_ThreadProc
1336 static HRESULT QT_AddPin(QTSplitter *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt, BOOL video)
1338 HRESULT hr;
1339 IPin **target;
1341 if (video)
1342 target = (IPin**)&This->pVideo_Pin;
1343 else
1344 target = (IPin**)&This->pAudio_Pin;
1346 if (*target != NULL)
1348 FIXME("We already have a %s pin\n",(video)?"video":"audio");
1349 return E_FAIL;
1352 hr = BaseOutputPin_Construct(&QT_OutputPin_Vtbl, sizeof(QTOutPin), piOutput, &output_BaseFuncTable, &output_BaseOutputFuncTable, &This->filter.csFilter, (IPin**)target);
1353 if (SUCCEEDED(hr))
1355 QTOutPin *pin = (QTOutPin*)*target;
1356 pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1357 CopyMediaType(pin->pmt, amt);
1358 pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
1360 BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
1362 hr = OutputQueue_Construct((BaseOutputPin*)pin, TRUE, TRUE, 5, FALSE, THREAD_PRIORITY_NORMAL, &output_OutputQueueFuncTable, &pin->queue);
1364 else
1365 ERR("Failed with error %x\n", hr);
1366 return hr;
1369 static HRESULT WINAPI QTSplitter_ChangeStart(IMediaSeeking *iface)
1371 QTSplitter *This = impl_from_IMediaSeeking(iface);
1372 TRACE("(%p)\n", iface);
1373 EnterCriticalSection(&This->csReceive);
1374 This->movie_time = (This->sourceSeeking.llCurrent * This->movie_scale)/10000000;
1375 This->movie_start = This->movie_time;
1376 LeaveCriticalSection(&This->csReceive);
1377 return S_OK;
1380 static HRESULT WINAPI QTSplitter_ChangeStop(IMediaSeeking *iface)
1382 FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
1383 return S_OK;
1386 static HRESULT WINAPI QTSplitter_ChangeRate(IMediaSeeking *iface)
1388 FIXME("(%p) filter hasn't implemented rate change!\n", iface);
1389 return S_OK;
1392 static HRESULT WINAPI QT_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1394 QTSplitter *This = impl_from_IMediaSeeking(iface);
1396 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1399 static ULONG WINAPI QT_Seeking_AddRef(IMediaSeeking * iface)
1401 QTSplitter *This = impl_from_IMediaSeeking(iface);
1403 return IUnknown_AddRef((IUnknown *)This);
1406 static ULONG WINAPI QT_Seeking_Release(IMediaSeeking * iface)
1408 QTSplitter *This = impl_from_IMediaSeeking(iface);
1410 return IUnknown_Release((IUnknown *)This);
1413 static const IMediaSeekingVtbl QT_Seeking_Vtbl =
1415 QT_Seeking_QueryInterface,
1416 QT_Seeking_AddRef,
1417 QT_Seeking_Release,
1418 SourceSeekingImpl_GetCapabilities,
1419 SourceSeekingImpl_CheckCapabilities,
1420 SourceSeekingImpl_IsFormatSupported,
1421 SourceSeekingImpl_QueryPreferredFormat,
1422 SourceSeekingImpl_GetTimeFormat,
1423 SourceSeekingImpl_IsUsingTimeFormat,
1424 SourceSeekingImpl_SetTimeFormat,
1425 SourceSeekingImpl_GetDuration,
1426 SourceSeekingImpl_GetStopPosition,
1427 SourceSeekingImpl_GetCurrentPosition,
1428 SourceSeekingImpl_ConvertTimeFormat,
1429 SourceSeekingImpl_SetPositions,
1430 SourceSeekingImpl_GetPositions,
1431 SourceSeekingImpl_GetAvailable,
1432 SourceSeekingImpl_SetRate,
1433 SourceSeekingImpl_GetRate,
1434 SourceSeekingImpl_GetPreroll