wineqtdecoder: Lock thing involved in streaming state in a csReceive critical section.
[wine/multimedia.git] / dlls / wineqtdecoder / qtsplitter.c
blobc206b23e9de6cba0d1c3b69ea824ae9b87c969c4
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 } QTSplitter;
170 static const IPinVtbl QT_OutputPin_Vtbl;
171 static const IPinVtbl QT_InputPin_Vtbl;
172 static const IBaseFilterVtbl QT_Vtbl;
174 static HRESULT QT_AddPin(QTSplitter *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt, BOOL video);
175 static HRESULT QT_RemoveOutputPins(QTSplitter *This);
178 * Base Filter
181 static IPin* WINAPI QT_GetPin(BaseFilter *iface, int pos)
183 QTSplitter *This = (QTSplitter *)iface;
184 TRACE("Asking for pos %x\n", pos);
186 if (pos > 2 || pos < 0)
187 return NULL;
188 switch (pos)
190 case 0:
191 IPin_AddRef((IPin*)&This->pInputPin);
192 return (IPin*)&This->pInputPin;
193 case 1:
194 if (This->pVideo_Pin)
195 IPin_AddRef((IPin*)This->pVideo_Pin);
196 return (IPin*)This->pVideo_Pin;
197 case 2:
198 if (This->pAudio_Pin)
199 IPin_AddRef((IPin*)This->pAudio_Pin);
200 return (IPin*)This->pAudio_Pin;
201 default:
202 return NULL;
206 static LONG WINAPI QT_GetPinCount(BaseFilter *iface)
208 QTSplitter *This = (QTSplitter *)iface;
209 int c = 1;
210 if (This->pAudio_Pin) c++;
211 if (This->pVideo_Pin) c++;
212 return c;
215 static const BaseFilterFuncTable BaseFuncTable = {
216 QT_GetPin,
217 QT_GetPinCount
220 IUnknown * CALLBACK QTSplitter_create(IUnknown *punkout, HRESULT *phr)
222 IUnknown *obj = NULL;
223 PIN_INFO *piInput;
224 QTSplitter *This;
225 static const WCHAR wcsInputPinName[] = {'I','n','p','u','t',' ','P','i','n',0};
227 EnterMovies();
229 RegisterWineDataHandler();
231 This = CoTaskMemAlloc(sizeof(*This));
232 obj = (IUnknown*)This;
233 if (!This)
235 *phr = E_OUTOFMEMORY;
236 return NULL;
238 ZeroMemory(This,sizeof(*This));
240 BaseFilter_Init(&This->filter, &QT_Vtbl, &CLSID_QTSplitter, (DWORD_PTR)(__FILE__ ": QTSplitter.csFilter"), &BaseFuncTable);
242 InitializeCriticalSection(&This->csReceive);
243 This->csReceive.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": QTSplitter.csReceive");
245 This->pVideo_Pin = NULL;
246 This->pAudio_Pin = NULL;
247 This->state = State_Stopped;
248 This->aSession = NULL;
249 This->runEvent = CreateEventW(NULL, 0, 0, NULL);
251 piInput = &This->pInputPin.pin.pinInfo;
252 piInput->dir = PINDIR_INPUT;
253 piInput->pFilter = (IBaseFilter *)This;
254 lstrcpynW(piInput->achName, wcsInputPinName, sizeof(piInput->achName) / sizeof(piInput->achName[0]));
255 This->pInputPin.pin.lpVtbl = &QT_InputPin_Vtbl;
256 This->pInputPin.pin.refCount = 1;
257 This->pInputPin.pin.pConnectedTo = NULL;
258 This->pInputPin.pin.pCritSec = &This->filter.csFilter;
259 *phr = S_OK;
260 return obj;
263 static void QT_Destroy(QTSplitter *This)
265 IPin *connected = NULL;
266 ULONG pinref;
268 TRACE("Destroying\n");
270 /* Don't need to clean up output pins, disconnecting input pin will do that */
271 IPin_ConnectedTo((IPin *)&This->pInputPin, &connected);
272 if (connected)
274 IPin_Disconnect(connected);
275 IPin_Release(connected);
277 pinref = IPin_Release((IPin *)&This->pInputPin);
278 if (pinref)
280 ERR("pinref should be null, is %u, destroying anyway\n", pinref);
281 assert((LONG)pinref > 0);
283 while (pinref)
284 pinref = IPin_Release((IPin *)&This->pInputPin);
287 if (This->pQTMovie)
288 DisposeMovie(This->pQTMovie);
289 if (This->vContext)
290 QTVisualContextRelease(This->vContext);
291 if (This->aSession)
292 MovieAudioExtractionEnd(This->aSession);
293 CloseHandle(This->runEvent);
295 ExitMovies();
297 This->csReceive.DebugInfo->Spare[0] = 0;
298 DeleteCriticalSection(&This->csReceive);
300 CoTaskMemFree(This);
303 static HRESULT WINAPI QT_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID *ppv)
305 QTSplitter *This = (QTSplitter *)iface;
306 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
308 *ppv = NULL;
310 if (IsEqualIID(riid, &IID_IUnknown))
311 *ppv = This;
312 else if (IsEqualIID(riid, &IID_IPersist))
313 *ppv = This;
314 else if (IsEqualIID(riid, &IID_IMediaFilter))
315 *ppv = This;
316 else if (IsEqualIID(riid, &IID_IBaseFilter))
317 *ppv = This;
319 if (*ppv)
321 IUnknown_AddRef((IUnknown *)(*ppv));
322 return S_OK;
325 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
326 FIXME("No interface for %s!\n", debugstr_guid(riid));
328 return E_NOINTERFACE;
331 static ULONG WINAPI QT_Release(IBaseFilter *iface)
333 QTSplitter *This = (QTSplitter *)iface;
334 ULONG refCount = BaseFilterImpl_Release(iface);
336 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
338 if (!refCount)
339 QT_Destroy(This);
341 return refCount;
344 static HRESULT WINAPI QT_Stop(IBaseFilter *iface)
346 QTSplitter *This = (QTSplitter *)iface;
348 TRACE("()\n");
350 EnterCriticalSection(&This->csReceive);
351 IAsyncReader_BeginFlush(This->pInputPin.pReader);
352 IAsyncReader_EndFlush(This->pInputPin.pReader);
353 LeaveCriticalSection(&This->csReceive);
355 return S_OK;
358 static HRESULT WINAPI QT_Pause(IBaseFilter *iface)
360 HRESULT hr = S_OK;
361 TRACE("()\n");
363 return hr;
366 static OSErr QT_Create_Extract_Session(QTSplitter *filter)
368 AudioStreamBasicDescription aDesc;
369 OSErr err;
370 WAVEFORMATEX* pvi;
372 pvi = (WAVEFORMATEX*)filter->pAudio_Pin->pmt->pbFormat;
374 err = MovieAudioExtractionBegin(filter->pQTMovie, 0, &filter->aSession);
375 if (err != noErr)
377 ERR("Failed to begin Extraction session %i\n",err);
378 return err;
381 err = MovieAudioExtractionGetProperty(filter->aSession,
382 kQTPropertyClass_MovieAudioExtraction_Audio,
383 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription,
384 sizeof(AudioStreamBasicDescription), &aDesc, NULL);
386 if (err != noErr)
388 MovieAudioExtractionEnd(filter->aSession);
389 filter->aSession = NULL;
390 ERR("Failed to get session description %i\n",err);
391 return err;
394 aDesc.mFormatID = kAudioFormatLinearPCM;
395 aDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger +
396 kAudioFormatFlagIsPacked;
397 aDesc.mFramesPerPacket = 1;
398 aDesc.mChannelsPerFrame = pvi->nChannels;
399 aDesc.mBitsPerChannel = pvi->wBitsPerSample;
400 aDesc.mSampleRate = pvi->nSamplesPerSec;
401 aDesc.mBytesPerFrame = (aDesc.mBitsPerChannel * aDesc.mChannelsPerFrame) / 8;
402 aDesc.mBytesPerPacket = aDesc.mBytesPerFrame * aDesc.mFramesPerPacket;
404 err = MovieAudioExtractionSetProperty(filter->aSession,
405 kQTPropertyClass_MovieAudioExtraction_Audio,
406 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription,
407 sizeof(AudioStreamBasicDescription), &aDesc);
409 if (aDesc.mFormatID != kAudioFormatLinearPCM)
411 ERR("Not PCM Wave\n");
412 err = -1;
414 if (aDesc.mFormatFlags != kLinearPCMFormatFlagIsSignedInteger +
415 kAudioFormatFlagIsPacked)
417 ERR("Unhandled Flags\n");
418 err = -1;
420 if (aDesc.mFramesPerPacket != 1)
422 ERR("Unhandled Frames per packet %li\n",aDesc.mFramesPerPacket);
423 err = -1;
425 if (aDesc.mChannelsPerFrame != pvi->nChannels)
427 ERR("Unhandled channel count %li\n",aDesc.mChannelsPerFrame);
428 err = -1;
430 if (aDesc.mBitsPerChannel != pvi->wBitsPerSample)
432 ERR("Unhandled bits per channel %li\n",aDesc.mBitsPerChannel);
433 err = -1;
435 if (aDesc.mSampleRate != pvi->nSamplesPerSec)
437 ERR("Unhandled sample rate %f\n",aDesc.mSampleRate);
438 err = -1;
441 if (err != noErr)
443 ERR("Failed to create Extraction Session\n");
444 MovieAudioExtractionEnd(filter->aSession);
445 filter->aSession = NULL;
448 return err;
451 static DWORD WINAPI QTSplitter_thread(LPVOID data)
453 QTSplitter *This = (QTSplitter *)data;
454 HRESULT hr = S_OK;
455 TimeValue movie_time=0, next_time;
456 CVPixelBufferRef pixelBuffer = NULL;
457 OSStatus err;
458 TimeRecord tr;
460 if (This->pAudio_Pin)
462 /* according to QA1469 a movie has to be fully loaded before we
463 can reliably start the Extraction session */
465 while(GetMovieLoadState(This->pQTMovie) < kMovieLoadStateComplete)
466 MoviesTask(This->pQTMovie,1000);
468 QT_Create_Extract_Session(This);
471 WaitForSingleObject(This->runEvent, -1);
473 This->state = State_Running;
474 /* Prime the pump: Needed for MPEG streams */
475 GetMovieNextInterestingTime(This->pQTMovie, nextTimeEdgeOK | nextTimeStep, 0, NULL, movie_time, 1, &next_time, NULL);
477 GetMovieTime(This->pQTMovie, &tr);
480 LONGLONG tStart=0, tStop=0;
481 LONGLONG mStart=0, mStop=0;
482 float time;
484 EnterCriticalSection(&This->csReceive);
485 GetMovieNextInterestingTime(This->pQTMovie, nextTimeStep, 0, NULL, movie_time, 1, &next_time, NULL);
487 if (next_time == -1)
489 TRACE("No next time\n");
490 LeaveCriticalSection(&This->csReceive);
491 break;
494 tr.value = SInt64ToWide(next_time);
495 SetMovieTime(This->pQTMovie, &tr);
496 MoviesTask(This->pQTMovie,0);
497 QTVisualContextTask(This->vContext);
499 TRACE("In loop at time %ld\n",movie_time);
500 TRACE("In Next time %ld\n",next_time);
502 mStart = movie_time;
503 mStop = next_time;
505 time = (float)movie_time / tr.scale;
506 tStart = time * 10000000;
507 time = (float)next_time / tr.scale;
508 tStop = time * 10000000;
510 /* Deliver Audio */
511 if (This->pAudio_Pin && ((BaseOutputPin*)This->pAudio_Pin)->pin.pConnectedTo && This->aSession)
513 int data_size=0;
514 BYTE* ptr;
515 IMediaSample *sample = NULL;
516 AudioBufferList aData;
517 UInt32 flags;
518 UInt32 frames;
519 WAVEFORMATEX* pvi;
520 float duration;
522 pvi = (WAVEFORMATEX*)This->pAudio_Pin->pmt->pbFormat;
524 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->pAudio_Pin, &sample, NULL, NULL, 0);
526 if (FAILED(hr))
528 ERR("Audio: Unable to get delivery buffer (%x)\n", hr);
529 goto audio_error;
532 hr = IMediaSample_GetPointer(sample, &ptr);
533 if (FAILED(hr))
535 ERR("Audio: Unable to get pointer to buffer (%x)\n", hr);
536 goto audio_error;
539 duration = (float)next_time / tr.scale;
540 time = (float)movie_time / tr.scale;
541 duration -= time;
542 frames = pvi->nSamplesPerSec * duration;
543 TRACE("Need audio for %f seconds (%li frames)\n",duration,frames);
545 data_size = IMediaSample_GetSize(sample);
546 if (data_size < frames * pvi->nBlockAlign)
547 FIXME("Audio buffer is too small\n");
549 aData.mNumberBuffers = 1;
550 aData.mBuffers[0].mNumberChannels = pvi->nChannels;
551 aData.mBuffers[0].mDataByteSize = data_size;
552 aData.mBuffers[0].mData = ptr;
554 err = MovieAudioExtractionFillBuffer(This->aSession, &frames, &aData, &flags);
555 TRACE("Got %i frames\n",(int)frames);
557 IMediaSample_SetActualDataLength(sample, frames * pvi->nBlockAlign);
559 IMediaSample_SetMediaTime(sample, &mStart, &mStop);
560 IMediaSample_SetTime(sample, &tStart, &tStop);
562 hr = OutputQueue_Receive(This->pAudio_Pin->queue, sample);
563 TRACE("Audio Delivered (%x)\n",hr);
565 audio_error:
566 if (sample)
567 IMediaSample_Release(sample);
569 else
570 TRACE("Audio Pin not connected or no Audio\n");
572 /* Deliver Video */
573 if (This->pVideo_Pin && QTVisualContextIsNewImageAvailable(This->vContext,0))
575 err = QTVisualContextCopyImageForTime(This->vContext, NULL, NULL, &pixelBuffer);
576 if (err == noErr)
578 int data_size=0;
579 BYTE* ptr;
580 IMediaSample *sample = NULL;
582 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->pVideo_Pin, &sample, NULL, NULL, 0);
583 if (FAILED(hr))
585 ERR("Video: Unable to get delivery buffer (%x)\n", hr);
586 goto video_error;
589 data_size = IMediaSample_GetSize(sample);
590 if (data_size < This->outputSize)
592 ERR("Sample size is too small %d < %d\n", data_size, This->outputSize)
594 hr = E_FAIL;
595 goto video_error;
598 hr = IMediaSample_GetPointer(sample, &ptr);
599 if (FAILED(hr))
601 ERR("Video: Unable to get pointer to buffer (%x)\n", hr);
602 goto video_error;
605 hr = AccessPixelBufferPixels( pixelBuffer, ptr);
606 if (FAILED(hr))
608 ERR("Failed to access Pixels\n");
609 goto video_error;
612 IMediaSample_SetActualDataLength(sample, This->outputSize);
614 IMediaSample_SetMediaTime(sample, &mStart, &mStop);
615 IMediaSample_SetTime(sample, &tStart, &tStop);
617 hr = OutputQueue_Receive(This->pVideo_Pin->queue, sample);
618 TRACE("Video Delivered (%x)\n",hr);
620 video_error:
621 if (sample)
622 IMediaSample_Release(sample);
623 if (pixelBuffer)
624 CVPixelBufferRelease(pixelBuffer);
627 else
628 TRACE("No video to deliver\n");
630 movie_time = next_time;
631 LeaveCriticalSection(&This->csReceive);
632 } while (hr == S_OK);
634 This->state = State_Stopped;
635 if (This->pAudio_Pin)
636 OutputQueue_EOS(This->pAudio_Pin->queue);
637 if (This->pVideo_Pin)
638 OutputQueue_EOS(This->pVideo_Pin->queue);
640 return hr;
643 static HRESULT WINAPI QT_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
645 HRESULT hr = S_OK;
646 QTSplitter *This = (QTSplitter *)iface;
647 HRESULT hr_any = VFW_E_NOT_CONNECTED;
649 TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
651 EnterCriticalSection(&This->csReceive);
652 This->filter.rtStreamStart = tStart;
654 if (This->pVideo_Pin)
655 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->pVideo_Pin);
656 if (SUCCEEDED(hr))
657 hr_any = hr;
658 if (This->pAudio_Pin)
659 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->pAudio_Pin);
660 if (SUCCEEDED(hr))
661 hr_any = hr;
663 hr = hr_any;
665 SetEvent(This->runEvent);
666 LeaveCriticalSection(&This->csReceive);
668 return hr;
671 static HRESULT WINAPI QT_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
673 QTSplitter *This = (QTSplitter *)iface;
674 TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
676 *pState = This->state;
678 return S_OK;
681 static HRESULT WINAPI QT_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
683 FIXME("(%p)->(%s,%p) stub\n", iface, debugstr_w(Id), ppPin);
684 return E_NOTIMPL;
687 static const IBaseFilterVtbl QT_Vtbl = {
688 QT_QueryInterface,
689 BaseFilterImpl_AddRef,
690 QT_Release,
691 BaseFilterImpl_GetClassID,
692 QT_Stop,
693 QT_Pause,
694 QT_Run,
695 QT_GetState,
696 BaseFilterImpl_SetSyncSource,
697 BaseFilterImpl_GetSyncSource,
698 BaseFilterImpl_EnumPins,
699 QT_FindPin,
700 BaseFilterImpl_QueryFilterInfo,
701 BaseFilterImpl_JoinFilterGraph,
702 BaseFilterImpl_QueryVendorInfo
706 * Input Pin
708 static HRESULT QT_RemoveOutputPins(QTSplitter *This)
710 HRESULT hr;
711 TRACE("(%p)\n", This);
713 if (This->pVideo_Pin)
715 hr = BaseOutputPinImpl_BreakConnect(&This->pVideo_Pin->pin);
716 TRACE("Disconnect: %08x\n", hr);
717 IPin_Release((IPin*)This->pVideo_Pin);
718 This->pVideo_Pin = NULL;
720 if (This->pAudio_Pin)
722 hr = BaseOutputPinImpl_BreakConnect(&This->pAudio_Pin->pin);
723 TRACE("Disconnect: %08x\n", hr);
724 IPin_Release((IPin*)This->pAudio_Pin);
725 This->pAudio_Pin = NULL;
728 BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
729 return S_OK;
732 static ULONG WINAPI QTInPin_Release(IPin *iface)
734 QTInPin *This = (QTInPin*)iface;
735 ULONG refCount = InterlockedDecrement(&This->pin.refCount);
737 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
738 if (!refCount)
740 FreeMediaType(&This->pin.mtCurrent);
741 if (This->pAlloc)
742 IMemAllocator_Release(This->pAlloc);
743 This->pAlloc = NULL;
744 This->pin.lpVtbl = NULL;
745 return 0;
747 else
748 return refCount;
751 static HRESULT QT_Process_Video_Track(QTSplitter* filter, Track trk)
753 AM_MEDIA_TYPE amt;
754 VIDEOINFOHEADER * pvi;
755 PIN_INFO piOutput;
756 HRESULT hr = S_OK;
757 OSErr err;
758 static const WCHAR szwVideoOut[] = {'V','i','d','e','o',0};
759 CFMutableDictionaryRef pixelBufferOptions = NULL;
760 CFMutableDictionaryRef visualContextOptions = NULL;
761 CFNumberRef n = NULL;
762 int t;
763 DWORD outputWidth, outputHeight, outputDepth;
764 Fixed trackWidth, trackHeight;
766 ZeroMemory(&amt, sizeof(amt));
767 amt.formattype = FORMAT_VideoInfo;
768 amt.majortype = MEDIATYPE_Video;
769 amt.subtype = MEDIASUBTYPE_RGB24;
771 GetTrackDimensions(trk, &trackWidth, &trackHeight);
773 outputDepth = 3;
774 outputWidth = Fix2Long(trackWidth);
775 outputHeight = Fix2Long(trackHeight);
776 TRACE("Width %i Height %i\n",outputWidth, outputHeight);
778 amt.cbFormat = sizeof(VIDEOINFOHEADER);
779 amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
780 ZeroMemory(amt.pbFormat, amt.cbFormat);
781 pvi = (VIDEOINFOHEADER *)amt.pbFormat;
782 pvi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
783 pvi->bmiHeader.biWidth = outputWidth;
784 pvi->bmiHeader.biHeight = outputHeight;
785 pvi->bmiHeader.biPlanes = 1;
786 pvi->bmiHeader.biBitCount = 24;
787 pvi->bmiHeader.biCompression = BI_RGB;
788 pvi->bmiHeader.biSizeImage = outputWidth * outputHeight * outputDepth;
790 filter->outputSize = pvi->bmiHeader.biSizeImage;
791 amt.lSampleSize = 0;
793 pixelBufferOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
795 t = k32ARGBPixelFormat;
796 n = CFNumberCreate(NULL, kCFNumberIntType, &t);
797 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, n);
798 CFRelease(n);
800 n = CFNumberCreate(NULL, kCFNumberIntType, &outputWidth);
801 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferWidthKey, n);
802 CFRelease(n);
804 n = CFNumberCreate(NULL, kCFNumberIntType, &outputHeight);
805 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferHeightKey, n);
806 CFRelease(n);
808 t = 16;
809 n = CFNumberCreate(NULL, kCFNumberIntType, &t);
810 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, n);
811 CFRelease(n);
813 visualContextOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
815 CFDictionarySetValue(visualContextOptions, kQTVisualContextPixelBufferAttributesKey, pixelBufferOptions);
817 err = QTPixelBufferContextCreate(NULL, visualContextOptions,&filter->vContext);
818 CFRelease(pixelBufferOptions);
819 CFRelease(visualContextOptions);
820 if (err != noErr)
822 ERR("Failed to create Visual Context\n");
823 return E_FAIL;
826 err = SetMovieVisualContext(filter->pQTMovie, filter->vContext);
827 if (err != noErr)
829 ERR("Failed to set Visual Context\n");
830 return E_FAIL;
833 piOutput.dir = PINDIR_OUTPUT;
834 piOutput.pFilter = (IBaseFilter *)filter;
835 lstrcpyW(piOutput.achName,szwVideoOut);
837 hr = QT_AddPin(filter, &piOutput, &amt, TRUE);
838 if (FAILED(hr))
839 ERR("Failed to add Video Track\n");
840 else
841 TRACE("Video Pin %p\n",filter->pVideo_Pin);
843 return hr;
846 static HRESULT QT_Process_Audio_Track(QTSplitter* filter, Track trk)
848 AM_MEDIA_TYPE amt;
849 WAVEFORMATEX* pvi;
850 PIN_INFO piOutput;
851 HRESULT hr = S_OK;
852 static const WCHAR szwAudioOut[] = {'A','u','d','i','o',0};
853 Media audioMedia;
855 SoundDescriptionHandle aDesc = (SoundDescriptionHandle) NewHandle(sizeof(SoundDescription));
857 audioMedia = GetTrackMedia(trk);
858 GetMediaSampleDescription(audioMedia, 1, (SampleDescriptionHandle)aDesc);
860 ZeroMemory(&amt, sizeof(amt));
861 amt.formattype = FORMAT_WaveFormatEx;
862 amt.majortype = MEDIATYPE_Audio;
863 amt.subtype = MEDIASUBTYPE_PCM;
864 amt.bTemporalCompression = 0;
866 amt.cbFormat = sizeof(WAVEFORMATEX);
867 amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
868 ZeroMemory(amt.pbFormat, amt.cbFormat);
869 pvi = (WAVEFORMATEX*)amt.pbFormat;
871 pvi->cbSize = sizeof(WAVEFORMATEX);
872 pvi->wFormatTag = WAVE_FORMAT_PCM;
873 pvi->nChannels = ((SoundDescription)**aDesc).numChannels;
874 if (pvi->nChannels < 1 || pvi->nChannels > 2)
875 pvi->nChannels = 2;
876 pvi->nSamplesPerSec = (((SoundDescription)**aDesc).sampleRate/65536);
877 if (pvi->nSamplesPerSec < 8000 || pvi->nChannels > 48000)
878 pvi->nSamplesPerSec = 44100;
879 pvi->wBitsPerSample = ((SoundDescription)**aDesc).sampleSize;
880 if (pvi->wBitsPerSample < 8 || pvi->wBitsPerSample > 32)
881 pvi->wBitsPerSample = 16;
882 pvi->nBlockAlign = (pvi->nChannels * pvi->wBitsPerSample) / 8;
883 pvi->nAvgBytesPerSec = pvi->nSamplesPerSec * pvi->nBlockAlign;
885 DisposeHandle((Handle)aDesc);
887 piOutput.dir = PINDIR_OUTPUT;
888 piOutput.pFilter = (IBaseFilter *)filter;
889 lstrcpyW(piOutput.achName,szwAudioOut);
891 hr = QT_AddPin(filter, &piOutput, &amt, FALSE);
892 if (FAILED(hr))
893 ERR("Failed to add Audio Track\n");
894 else
895 TRACE("Audio Pin %p\n",filter->pAudio_Pin);
896 return hr;
899 static HRESULT QT_Process_Movie(QTSplitter* filter)
901 HRESULT hr = S_OK;
902 OSErr err;
903 WineDataRefRecord ptrDataRefRec;
904 Handle dataRef = NULL;
905 Track trk;
906 short id = 0;
907 DWORD tid;
908 HANDLE thread;
910 TRACE("Trying movie connect\n");
912 ptrDataRefRec.pReader = filter->pInputPin.pReader;
913 ptrDataRefRec.streamSubtype = filter->pInputPin.subType;
914 PtrToHand( &ptrDataRefRec, &dataRef, sizeof(WineDataRefRecord));
916 err = NewMovieFromDataRef(&filter->pQTMovie, newMovieActive|newMovieDontInteractWithUser|newMovieDontAutoUpdateClock|newMovieDontAskUnresolvedDataRefs|newMovieAsyncOK, &id, dataRef, 'WINE');
918 DisposeHandle(dataRef);
920 if (err != noErr)
922 FIXME("QuickTime cannot handle media type(%i)\n",err);
923 return VFW_E_TYPE_NOT_ACCEPTED;
926 PrePrerollMovie(filter->pQTMovie, 0, fixed1, NULL, NULL);
927 PrerollMovie(filter->pQTMovie, 0, fixed1);
928 GoToBeginningOfMovie(filter->pQTMovie);
929 SetMovieActive(filter->pQTMovie,TRUE);
931 if (GetMovieLoadState(filter->pQTMovie) < kMovieLoadStateLoaded)
932 MoviesTask(filter->pQTMovie,100);
934 trk = GetMovieIndTrackType(filter->pQTMovie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
935 TRACE("%p is a video track\n",trk);
936 if (trk)
937 hr = QT_Process_Video_Track(filter, trk);
939 if (FAILED(hr))
940 return hr;
942 trk = GetMovieIndTrackType(filter->pQTMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
943 TRACE("%p is a audio track\n",trk);
944 if (trk)
945 hr = QT_Process_Audio_Track(filter, trk);
947 thread = CreateThread(NULL, 0, QTSplitter_thread, filter, 0, &tid);
948 if (thread)
950 TRACE("Created thread 0x%08x\n", tid);
951 CloseHandle(thread);
953 else
954 hr = HRESULT_FROM_WIN32(GetLastError());
956 return hr;
959 static HRESULT WINAPI QTInPin_ReceiveConnection(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
961 HRESULT hr = S_OK;
962 ALLOCATOR_PROPERTIES props;
963 QTInPin *This = (QTInPin*)iface;
965 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
967 EnterCriticalSection(This->pin.pCritSec);
968 This->pReader = NULL;
970 if (This->pin.pConnectedTo)
971 hr = VFW_E_ALREADY_CONNECTED;
972 else if (IPin_QueryAccept(iface, pmt) != S_OK)
973 hr = VFW_E_TYPE_NOT_ACCEPTED;
974 else
976 PIN_DIRECTION pindirReceive;
977 IPin_QueryDirection(pReceivePin, &pindirReceive);
978 if (pindirReceive != PINDIR_OUTPUT)
979 hr = VFW_E_INVALID_DIRECTION;
982 if (FAILED(hr))
984 LeaveCriticalSection(This->pin.pCritSec);
985 return hr;
988 hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
989 if (FAILED(hr))
991 LeaveCriticalSection(This->pin.pCritSec);
992 TRACE("Input source is not an AsyncReader\n");
993 return hr;
996 LeaveCriticalSection(This->pin.pCritSec);
997 EnterCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
998 hr = QT_Process_Movie((QTSplitter *)This->pin.pinInfo.pFilter);
999 if (FAILED(hr))
1001 LeaveCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
1002 TRACE("Unable to process movie\n");
1003 return hr;
1006 This->pAlloc = NULL;
1007 props.cBuffers = 8;
1008 props.cbAlign = 1;
1009 props.cbBuffer = ((QTSplitter *)This->pin.pinInfo.pFilter)->outputSize + props.cbAlign;
1010 props.cbPrefix = 0;
1012 hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1013 if (SUCCEEDED(hr))
1015 CopyMediaType(&This->pin.mtCurrent, pmt);
1016 This->pin.pConnectedTo = pReceivePin;
1017 IPin_AddRef(pReceivePin);
1018 hr = IMemAllocator_Commit(This->pAlloc);
1020 else
1022 QT_RemoveOutputPins((QTSplitter *)This->pin.pinInfo.pFilter);
1023 if (This->pReader)
1024 IAsyncReader_Release(This->pReader);
1025 This->pReader = NULL;
1026 if (This->pAlloc)
1027 IMemAllocator_Release(This->pAlloc);
1028 This->pAlloc = NULL;
1030 TRACE("Size: %i\n", props.cbBuffer);
1031 LeaveCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
1033 return hr;
1036 static HRESULT WINAPI QTInPin_Disconnect(IPin *iface)
1038 HRESULT hr;
1039 QTInPin *This = (QTInPin*)iface;
1040 FILTER_STATE state;
1041 TRACE("()\n");
1043 hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1044 EnterCriticalSection(This->pin.pCritSec);
1045 if (This->pin.pConnectedTo)
1047 QTSplitter *Parser = (QTSplitter *)This->pin.pinInfo.pFilter;
1049 if (SUCCEEDED(hr) && state == State_Stopped)
1051 IMemAllocator_Decommit(This->pAlloc);
1052 IPin_Disconnect(This->pin.pConnectedTo);
1053 This->pin.pConnectedTo = NULL;
1054 hr = QT_RemoveOutputPins(Parser);
1056 else
1057 hr = VFW_E_NOT_STOPPED;
1059 else
1060 hr = S_FALSE;
1061 LeaveCriticalSection(This->pin.pCritSec);
1062 return hr;
1065 static HRESULT WINAPI QTInPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
1067 QTInPin *This = (QTInPin*)iface;
1069 TRACE("(%p)->(%p)\n", This, pmt);
1071 if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
1073 This->subType = pmt->subtype;
1074 return S_OK;
1076 return S_FALSE;
1079 static HRESULT WINAPI QTInPin_EndOfStream(IPin *iface)
1081 QTInPin *pin = (QTInPin*)iface;
1082 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1084 FIXME("Propagate message on %p\n", This);
1085 return S_OK;
1088 static HRESULT WINAPI QTInPin_BeginFlush(IPin *iface)
1090 QTInPin *pin = (QTInPin*)iface;
1091 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1093 FIXME("Propagate message on %p\n", This);
1094 return S_OK;
1097 static HRESULT WINAPI QTInPin_EndFlush(IPin *iface)
1099 QTInPin *pin = (QTInPin*)iface;
1100 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1102 FIXME("Propagate message on %p\n", This);
1103 return S_OK;
1106 static HRESULT WINAPI QTInPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1108 QTInPin *pin = (QTInPin*)iface;
1109 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
1111 BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1112 FIXME("Propagate message on %p\n", This);
1113 return S_OK;
1116 static HRESULT WINAPI QTInPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1118 QTInPin *This = (QTInPin*)iface;
1120 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
1122 *ppv = NULL;
1124 if (IsEqualIID(riid, &IID_IUnknown))
1125 *ppv = iface;
1126 else if (IsEqualIID(riid, &IID_IPin))
1127 *ppv = iface;
1128 else if (IsEqualIID(riid, &IID_IMediaSeeking))
1130 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1133 if (*ppv)
1135 IUnknown_AddRef((IUnknown *)(*ppv));
1136 return S_OK;
1139 FIXME("No interface for %s!\n", debugstr_guid(riid));
1141 return E_NOINTERFACE;
1144 static HRESULT WINAPI QTInPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1146 BasePin *This = (BasePin *)iface;
1148 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
1150 return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
1153 static const IPinVtbl QT_InputPin_Vtbl = {
1154 QTInPin_QueryInterface,
1155 BasePinImpl_AddRef,
1156 QTInPin_Release,
1157 BaseInputPinImpl_Connect,
1158 QTInPin_ReceiveConnection,
1159 QTInPin_Disconnect,
1160 BasePinImpl_ConnectedTo,
1161 BasePinImpl_ConnectionMediaType,
1162 BasePinImpl_QueryPinInfo,
1163 BasePinImpl_QueryDirection,
1164 BasePinImpl_QueryId,
1165 QTInPin_QueryAccept,
1166 QTInPin_EnumMediaTypes,
1167 BasePinImpl_QueryInternalConnections,
1168 QTInPin_EndOfStream,
1169 QTInPin_BeginFlush,
1170 QTInPin_EndFlush,
1171 QTInPin_NewSegment
1175 * Output Pin
1178 static HRESULT WINAPI QTOutPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1180 QTOutPin *This = (QTOutPin *)iface;
1182 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1184 *ppv = NULL;
1186 if (IsEqualIID(riid, &IID_IUnknown))
1187 *ppv = iface;
1188 else if (IsEqualIID(riid, &IID_IPin))
1189 *ppv = iface;
1190 else if (IsEqualIID(riid, &IID_IMediaSeeking))
1191 return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1193 if (*ppv)
1195 IUnknown_AddRef((IUnknown *)(*ppv));
1196 return S_OK;
1198 FIXME("No interface for %s!\n", debugstr_guid(riid));
1199 return E_NOINTERFACE;
1202 static ULONG WINAPI QTOutPin_Release(IPin *iface)
1204 QTOutPin *This = (QTOutPin *)iface;
1205 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
1206 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
1208 if (!refCount)
1210 DeleteMediaType(This->pmt);
1211 FreeMediaType(&This->pin.pin.mtCurrent);
1212 OutputQueue_Destroy(This->queue);
1213 CoTaskMemFree(This);
1214 return 0;
1216 return refCount;
1219 static HRESULT WINAPI QTOutPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
1221 QTOutPin *This = (QTOutPin *)iface;
1223 if (iPosition < 0)
1224 return E_INVALIDARG;
1225 if (iPosition > 0)
1226 return VFW_S_NO_MORE_ITEMS;
1227 CopyMediaType(pmt, This->pmt);
1228 return S_OK;
1231 static HRESULT WINAPI QTOutPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
1233 /* Unused */
1234 return S_OK;
1237 static HRESULT WINAPI QTOutPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc)
1239 HRESULT hr;
1240 QTOutPin *This = (QTOutPin *)iface;
1241 QTSplitter *QTfilter = (QTSplitter*)This->pin.pin.pinInfo.pFilter;
1243 *pAlloc = NULL;
1244 if (QTfilter->pInputPin.pAlloc)
1245 hr = IMemInputPin_NotifyAllocator(pPin, QTfilter->pInputPin.pAlloc, FALSE);
1246 else
1247 hr = VFW_E_NO_ALLOCATOR;
1249 return hr;
1252 static HRESULT WINAPI QTOutPin_BreakConnect(BaseOutputPin *This)
1254 HRESULT hr;
1256 TRACE("(%p)->()\n", This);
1258 EnterCriticalSection(This->pin.pCritSec);
1259 if (!This->pin.pConnectedTo || !This->pMemInputPin)
1260 hr = VFW_E_NOT_CONNECTED;
1261 else
1263 hr = IPin_Disconnect(This->pin.pConnectedTo);
1264 IPin_Disconnect((IPin *)This);
1266 LeaveCriticalSection(This->pin.pCritSec);
1268 return hr;
1271 static const IPinVtbl QT_OutputPin_Vtbl = {
1272 QTOutPin_QueryInterface,
1273 BasePinImpl_AddRef,
1274 QTOutPin_Release,
1275 BaseOutputPinImpl_Connect,
1276 BaseOutputPinImpl_ReceiveConnection,
1277 BaseOutputPinImpl_Disconnect,
1278 BasePinImpl_ConnectedTo,
1279 BasePinImpl_ConnectionMediaType,
1280 BasePinImpl_QueryPinInfo,
1281 BasePinImpl_QueryDirection,
1282 BasePinImpl_QueryId,
1283 BasePinImpl_QueryAccept,
1284 BasePinImpl_EnumMediaTypes,
1285 BasePinImpl_QueryInternalConnections,
1286 BaseOutputPinImpl_EndOfStream,
1287 BaseOutputPinImpl_BeginFlush,
1288 BaseOutputPinImpl_EndFlush,
1289 BasePinImpl_NewSegment
1292 static const BasePinFuncTable output_BaseFuncTable = {
1293 NULL,
1294 BaseOutputPinImpl_AttemptConnection,
1295 BasePinImpl_GetMediaTypeVersion,
1296 QTOutPin_GetMediaType
1299 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
1300 QTOutPin_DecideBufferSize,
1301 QTOutPin_DecideAllocator,
1302 QTOutPin_BreakConnect
1305 static const OutputQueueFuncTable output_OutputQueueFuncTable = {
1306 OutputQueueImpl_ThreadProc
1309 static HRESULT QT_AddPin(QTSplitter *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt, BOOL video)
1311 HRESULT hr;
1312 IPin **target;
1314 if (video)
1315 target = (IPin**)&This->pVideo_Pin;
1316 else
1317 target = (IPin**)&This->pAudio_Pin;
1319 if (*target != NULL)
1321 FIXME("We already have a %s pin\n",(video)?"video":"audio");
1322 return E_FAIL;
1325 hr = BaseOutputPin_Construct(&QT_OutputPin_Vtbl, sizeof(QTOutPin), piOutput, &output_BaseFuncTable, &output_BaseOutputFuncTable, &This->filter.csFilter, (IPin**)target);
1326 if (SUCCEEDED(hr))
1328 QTOutPin *pin = (QTOutPin*)*target;
1329 pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1330 CopyMediaType(pin->pmt, amt);
1331 pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
1333 BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
1335 hr = OutputQueue_Construct((BaseOutputPin*)pin, TRUE, TRUE, 5, FALSE, THREAD_PRIORITY_NORMAL, &output_OutputQueueFuncTable, &pin->queue);
1337 else
1338 ERR("Failed with error %x\n", hr);
1339 return hr;