2 * QuickTime splitter + decoder
4 * Copyright 2011 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
26 #define LoadResource __carbon_LoadResource
27 #define CompareString __carbon_CompareString
28 #define GetCurrentThread __carbon_GetCurrentThread
29 #define GetCurrentProcess __carbon_GetCurrentProcess
30 #define AnimatePalette __carbon_AnimatePalette
31 #define EqualRgn __carbon_EqualRgn
32 #define FillRgn __carbon_FillRgn
33 #define FrameRgn __carbon_FrameRgn
34 #define GetPixel __carbon_GetPixel
35 #define InvertRgn __carbon_InvertRgn
36 #define LineTo __carbon_LineTo
37 #define OffsetRgn __carbon_OffsetRgn
38 #define PaintRgn __carbon_PaintRgn
39 #define Polygon __carbon_Polygon
40 #define ResizePalette __carbon_ResizePalette
41 #define SetRectRgn __carbon_SetRectRgn
43 #define CheckMenuItem __carbon_CheckMenuItem
44 #define DeleteMenu __carbon_DeleteMenu
45 #define DrawMenuBar __carbon_DrawMenuBar
46 #define EnableMenuItem __carbon_EnableMenuItem
47 #define EqualRect __carbon_EqualRect
48 #define FillRect __carbon_FillRect
49 #define FrameRect __carbon_FrameRect
50 #define GetCursor __carbon_GetCursor
51 #define GetMenu __carbon_GetMenu
52 #define InvertRect __carbon_InvertRect
53 #define IsWindowVisible __carbon_IsWindowVisible
54 #define MoveWindow __carbon_MoveWindow
55 #define OffsetRect __carbon_OffsetRect
56 #define PtInRect __carbon_PtInRect
57 #define SetCursor __carbon_SetCursor
58 #define SetRect __carbon_SetRect
59 #define ShowCursor __carbon_ShowCursor
60 #define ShowWindow __carbon_ShowWindow
61 #define UnionRect __carbon_UnionRect
63 #include <QuickTime/Movies.h>
64 #include <QuickTime/QuickTimeComponents.h>
68 #undef GetCurrentThread
71 #undef GetCurrentProcess
94 #undef IsWindowVisible
107 #undef STDMETHODCALLTYPE
113 #define NONAMELESSSTRUCT
114 #define NONAMELESSUNION
125 #include "wine/unicode.h"
126 #include "wine/debug.h"
127 #include "wine/strmbase.h"
129 #include "qtprivate.h"
131 WINE_DEFAULT_DEBUG_CHANNEL(qtsplitter);
132 extern CLSID CLSID_QTSplitter;
134 typedef struct QTOutPin {
141 typedef struct QTInPin {
145 IAsyncReader *pReader;
146 IMemAllocator *pAlloc;
149 typedef struct QTSplitter {
153 QTOutPin *pVideo_Pin;
155 ALLOCATOR_PROPERTIES props;
158 QTVisualContextRef vContext;
164 static const IPinVtbl QT_OutputPin_Vtbl;
165 static const IPinVtbl QT_InputPin_Vtbl;
166 static const IBaseFilterVtbl QT_Vtbl;
168 static HRESULT QT_AddPin(QTSplitter *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt);
169 static HRESULT QT_RemoveOutputPins(QTSplitter *This);
175 static IPin* WINAPI QT_GetPin(BaseFilter *iface, int pos)
177 QTSplitter *This = (QTSplitter *)iface;
178 TRACE("Asking for pos %x\n", pos);
180 if (pos > 2 || pos < 0)
185 IPin_AddRef((IPin*)&This->pInputPin);
186 return (IPin*)&This->pInputPin;
188 if (This->pVideo_Pin)
189 IPin_AddRef((IPin*)This->pVideo_Pin);
190 return (IPin*)This->pVideo_Pin;
191 case 2: /* TODO: Audio */
198 static LONG WINAPI QT_GetPinCount(BaseFilter *iface)
200 QTSplitter *This = (QTSplitter *)iface;
202 if (This->pVideo_Pin) c++;
206 static const BaseFilterFuncTable BaseFuncTable = {
211 IUnknown * CALLBACK QTSplitter_create(IUnknown *punkout, HRESULT *phr)
213 IUnknown *obj = NULL;
216 static const WCHAR wcsInputPinName[] = {'I','n','p','u','t',' ','P','i','n',0};
220 RegisterWineDataHandler();
222 This = CoTaskMemAlloc(sizeof(*This));
223 obj = (IUnknown*)This;
226 *phr = E_OUTOFMEMORY;
230 BaseFilter_Init(&This->filter, &QT_Vtbl, &CLSID_QTSplitter, (DWORD_PTR)(__FILE__ ": QTSplitter.csFilter"), &BaseFuncTable);
232 This->pVideo_Pin = NULL;
233 This->state = State_Stopped;
235 piInput = &This->pInputPin.pin.pinInfo;
236 piInput->dir = PINDIR_INPUT;
237 piInput->pFilter = (IBaseFilter *)This;
238 lstrcpynW(piInput->achName, wcsInputPinName, sizeof(piInput->achName) / sizeof(piInput->achName[0]));
239 This->pInputPin.pin.lpVtbl = &QT_InputPin_Vtbl;
240 This->pInputPin.pin.refCount = 1;
241 This->pInputPin.pin.pConnectedTo = NULL;
242 This->pInputPin.pin.pCritSec = &This->filter.csFilter;
243 ZeroMemory(&This->pInputPin.pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
248 static void QT_Destroy(QTSplitter *This)
250 IPin *connected = NULL;
253 TRACE("Destroying\n");
255 /* Don't need to clean up output pins, disconnecting input pin will do that */
256 IPin_ConnectedTo((IPin *)&This->pInputPin, &connected);
259 IPin_Disconnect(connected);
260 IPin_Release(connected);
262 pinref = IPin_Release((IPin *)&This->pInputPin);
265 ERR("pinref should be null, is %u, destroying anyway\n", pinref);
266 assert((LONG)pinref > 0);
269 pinref = IPin_Release((IPin *)&This->pInputPin);
273 DisposeMovie(This->pQTMovie);
275 QTVisualContextRelease(This->vContext);
281 static HRESULT WINAPI QT_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID *ppv)
283 QTSplitter *This = (QTSplitter *)iface;
284 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
288 if (IsEqualIID(riid, &IID_IUnknown))
290 else if (IsEqualIID(riid, &IID_IPersist))
292 else if (IsEqualIID(riid, &IID_IMediaFilter))
294 else if (IsEqualIID(riid, &IID_IBaseFilter))
299 IUnknown_AddRef((IUnknown *)(*ppv));
303 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
304 FIXME("No interface for %s!\n", debugstr_guid(riid));
306 return E_NOINTERFACE;
309 static ULONG WINAPI QT_Release(IBaseFilter *iface)
311 QTSplitter *This = (QTSplitter *)iface;
312 ULONG refCount = BaseFilterImpl_Release(iface);
314 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
322 static HRESULT WINAPI QT_Stop(IBaseFilter *iface)
324 QTSplitter *This = (QTSplitter *)iface;
328 IAsyncReader_BeginFlush(This->pInputPin.pReader);
329 IAsyncReader_EndFlush(This->pInputPin.pReader);
334 static HRESULT WINAPI QT_Pause(IBaseFilter *iface)
342 static DWORD WINAPI QTSplitter_thread_reader(LPVOID data)
344 QTSplitter *This = (QTSplitter *)data;
346 TimeValue movie_time=0, next_time;
347 CVPixelBufferRef pixelBuffer = NULL;
351 This->state = State_Running;
352 GetMovieTime(This->pQTMovie, &tr);
356 LONGLONG tStart=0, tStop=0;
359 MoviesTask(This->pQTMovie,0);
360 QTVisualContextTask(This->vContext);
361 GetMovieNextInterestingTime(This->pQTMovie, nextTimeStep, 0, NULL, movie_time, 1, &next_time, NULL);
365 TRACE("No next time\n");
369 tr.value = SInt64ToWide(next_time);
370 SetMovieTime(This->pQTMovie, &tr);
371 MoviesTask(This->pQTMovie,0);
372 QTVisualContextTask(This->vContext);
374 TRACE("In loop at time %ld\n",movie_time);
375 TRACE("In Next time %ld\n",next_time);
377 time = (float)movie_time / tr.scale;
378 tStart = time * 10000000;
379 time = (float)next_time / tr.scale;
380 tStop = time * 10000000;
383 if (QTVisualContextIsNewImageAvailable(This->vContext,0))
385 err = QTVisualContextCopyImageForTime(This->vContext, NULL, NULL, &pixelBuffer);
390 IMediaSample *sample = NULL;
392 hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->pVideo_Pin, &sample, NULL, NULL, 0);
395 ERR("Video: Unable to get delivery buffer (%x)\n", hr);
399 data_size = IMediaSample_GetSize(sample);
400 if (data_size < This->outputSize)
402 ERR("Sample size is too small %d < %d\n", data_size, This->outputSize)
408 hr = IMediaSample_GetPointer(sample, &ptr);
411 ERR("Video: Unable to get pointer to buffer (%x)\n", hr);
415 hr = AccessPixelBufferPixels( pixelBuffer, ptr);
418 ERR("Failed to access Pixels\n");
422 IMediaSample_SetActualDataLength(sample, This->outputSize);
424 IMediaSample_SetMediaTime(sample, &tStart, &tStop);
426 IMediaSample_SetTime(sample, &tStart, &tStop);
428 IMediaSample_SetTime(sample, NULL, NULL);
430 hr = OutputQueue_Receive(This->pVideo_Pin->queue, sample);
431 TRACE("Video Delivered (%x)\n",hr);
435 IMediaSample_Release(sample);
437 CVPixelBufferRelease(pixelBuffer);
441 movie_time = next_time;
442 } while (hr == S_OK);
444 This->state = State_Stopped;
445 OutputQueue_EOS(This->pVideo_Pin->queue);
450 static HRESULT WINAPI QT_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
453 QTSplitter *This = (QTSplitter *)iface;
454 HRESULT hr_any = VFW_E_NOT_CONNECTED;
457 TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
459 EnterCriticalSection(&This->filter.csFilter);
460 This->filter.rtStreamStart = tStart;
462 if (This->pVideo_Pin)
463 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->pVideo_Pin);
468 LeaveCriticalSection(&This->filter.csFilter);
470 CreateThread(NULL, 0, QTSplitter_thread_reader, This, 0, &tid);
471 TRACE("Created thread 0x%08x\n",tid);
476 static HRESULT WINAPI QT_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
478 QTSplitter *This = (QTSplitter *)iface;
479 TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
481 *pState = This->state;
486 static HRESULT WINAPI QT_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
488 FIXME("(%p)->(%s,%p) stub\n", iface, debugstr_w(Id), ppPin);
492 static const IBaseFilterVtbl QT_Vtbl = {
494 BaseFilterImpl_AddRef,
496 BaseFilterImpl_GetClassID,
501 BaseFilterImpl_SetSyncSource,
502 BaseFilterImpl_GetSyncSource,
503 BaseFilterImpl_EnumPins,
505 BaseFilterImpl_QueryFilterInfo,
506 BaseFilterImpl_JoinFilterGraph,
507 BaseFilterImpl_QueryVendorInfo
513 static HRESULT QT_RemoveOutputPins(QTSplitter *This)
516 TRACE("(%p)\n", This);
518 if (This->pVideo_Pin)
520 hr = BaseOutputPinImpl_BreakConnect(&This->pVideo_Pin->pin);
521 TRACE("Disconnect: %08x\n", hr);
522 IPin_Release((IPin*)This->pVideo_Pin);
523 This->pVideo_Pin = NULL;
526 BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
530 static ULONG WINAPI QTInPin_Release(IPin *iface)
532 QTInPin *This = (QTInPin*)iface;
533 ULONG refCount = InterlockedDecrement(&This->pin.refCount);
535 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
538 FreeMediaType(&This->pin.mtCurrent);
540 IMemAllocator_Release(This->pAlloc);
542 This->pin.lpVtbl = NULL;
549 static HRESULT QT_Process_Video_Track(QTSplitter* filter, Track trk)
552 VIDEOINFOHEADER * pvi;
556 static const WCHAR szwVideoOut[] = {'V','i','d','e','o',0};
557 CFMutableDictionaryRef pixelBufferOptions = NULL;
558 CFMutableDictionaryRef visualContextOptions = NULL;
559 CFNumberRef n = NULL;
561 DWORD outputWidth, outputHeight, outputDepth;
562 Fixed trackWidth, trackHeight;
564 ZeroMemory(&amt, sizeof(amt));
565 amt.formattype = FORMAT_VideoInfo;
566 amt.majortype = MEDIATYPE_Video;
567 amt.subtype = MEDIASUBTYPE_RGB24;
569 GetTrackDimensions(trk, &trackWidth, &trackHeight);
572 outputWidth = Fix2Long(trackWidth);
573 outputHeight = Fix2Long(trackHeight);
574 TRACE("Width %i Height %i\n",outputWidth, outputHeight);
576 amt.cbFormat = sizeof(VIDEOINFOHEADER);
577 amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
578 ZeroMemory(amt.pbFormat, amt.cbFormat);
579 pvi = (VIDEOINFOHEADER *)amt.pbFormat;
580 pvi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
581 pvi->bmiHeader.biWidth = outputWidth;
582 pvi->bmiHeader.biHeight = -outputHeight;
583 pvi->bmiHeader.biPlanes = 1;
584 pvi->bmiHeader.biBitCount = 24;
585 pvi->bmiHeader.biCompression = BI_RGB;
587 filter->outputSize = outputWidth * outputHeight * outputDepth;
590 pixelBufferOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
592 t = k32ARGBPixelFormat;
593 n = CFNumberCreate(NULL, kCFNumberIntType, &t);
594 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, n);
597 n = CFNumberCreate(NULL, kCFNumberIntType, &outputWidth);
598 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferWidthKey, n);
601 n = CFNumberCreate(NULL, kCFNumberIntType, &outputHeight);
602 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferHeightKey, n);
606 n = CFNumberCreate(NULL, kCFNumberIntType, &t);
607 CFDictionaryAddValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, n);
610 visualContextOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
612 CFDictionarySetValue(visualContextOptions, kQTVisualContextPixelBufferAttributesKey, pixelBufferOptions);
614 err = QTPixelBufferContextCreate(NULL, visualContextOptions,&filter->vContext);
615 CFRelease(pixelBufferOptions);
616 CFRelease(visualContextOptions);
619 ERR("Failed to create Visual Context\n");
623 err = SetMovieVisualContext(filter->pQTMovie, filter->vContext);
626 ERR("Failed to set Visual Context\n");
630 piOutput.dir = PINDIR_OUTPUT;
631 piOutput.pFilter = (IBaseFilter *)filter;
632 lstrcpyW(piOutput.achName,szwVideoOut);
634 hr = QT_AddPin(filter, &piOutput, &amt);
636 ERR("Failed to add Video Track\n");
638 TRACE("Video Pin %p\n",filter->pVideo_Pin);
643 static HRESULT QT_Process_Movie(QTSplitter* filter)
647 WineDataRefRecord ptrDataRefRec;
648 Handle dataRef = NULL;
652 TRACE("Trying movie connect\n");
654 ptrDataRefRec.pReader = filter->pInputPin.pReader;
655 ptrDataRefRec.streamSubtype = filter->pInputPin.subType;
656 PtrToHand( &ptrDataRefRec, &dataRef, sizeof(WineDataRefRecord));
658 err = NewMovieFromDataRef(&filter->pQTMovie, newMovieActive|newMovieDontInteractWithUser|newMovieDontAutoUpdateClock|newMovieDontAskUnresolvedDataRefs|newMovieIdleImportOK, &id, dataRef, 'WINE');
662 FIXME("Quicktime cannot handle media type(%i)\n",err);
663 return VFW_E_TYPE_NOT_ACCEPTED;
666 PrePrerollMovie(filter->pQTMovie, 0, fixed1, NULL, NULL);
667 PrerollMovie(filter->pQTMovie, 0, fixed1);
668 GoToBeginningOfMovie(filter->pQTMovie);
669 SetMovieActive(filter->pQTMovie,TRUE);
671 if (GetMovieLoadState(filter->pQTMovie) < kMovieLoadStateLoaded)
672 MoviesTask(filter->pQTMovie,100);
674 trk = GetMovieIndTrackType(filter->pQTMovie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
675 TRACE("%p is a video track\n",trk);
677 hr = QT_Process_Video_Track(filter, trk);
685 static HRESULT WINAPI QTInPin_ReceiveConnection(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
688 ALLOCATOR_PROPERTIES props;
689 QTInPin *This = (QTInPin*)iface;
691 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
693 EnterCriticalSection(This->pin.pCritSec);
694 This->pReader = NULL;
696 if (This->pin.pConnectedTo)
697 hr = VFW_E_ALREADY_CONNECTED;
698 else if (IPin_QueryAccept(iface, pmt) != S_OK)
699 hr = VFW_E_TYPE_NOT_ACCEPTED;
702 PIN_DIRECTION pindirReceive;
703 IPin_QueryDirection(pReceivePin, &pindirReceive);
704 if (pindirReceive != PINDIR_OUTPUT)
705 hr = VFW_E_INVALID_DIRECTION;
710 LeaveCriticalSection(This->pin.pCritSec);
714 hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
717 LeaveCriticalSection(This->pin.pCritSec);
718 TRACE("Input source is not an AsyncReader\n");
722 LeaveCriticalSection(This->pin.pCritSec);
723 EnterCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
724 hr = QT_Process_Movie((QTSplitter *)This->pin.pinInfo.pFilter);
727 LeaveCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
728 TRACE("Unable to process movie\n");
735 props.cbBuffer = ((QTSplitter *)This->pin.pinInfo.pFilter)->outputSize + props.cbAlign;
738 hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
741 CopyMediaType(&This->pin.mtCurrent, pmt);
742 This->pin.pConnectedTo = pReceivePin;
743 IPin_AddRef(pReceivePin);
744 hr = IMemAllocator_Commit(This->pAlloc);
748 QT_RemoveOutputPins((QTSplitter *)This->pin.pinInfo.pFilter);
750 IAsyncReader_Release(This->pReader);
751 This->pReader = NULL;
753 IMemAllocator_Release(This->pAlloc);
756 TRACE("Size: %i\n", props.cbBuffer);
757 LeaveCriticalSection(&((QTSplitter *)This->pin.pinInfo.pFilter)->filter.csFilter);
762 static HRESULT WINAPI QTInPin_Disconnect(IPin *iface)
765 QTInPin *This = (QTInPin*)iface;
769 hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
770 EnterCriticalSection(This->pin.pCritSec);
771 if (This->pin.pConnectedTo)
773 QTSplitter *Parser = (QTSplitter *)This->pin.pinInfo.pFilter;
775 if (SUCCEEDED(hr) && state == State_Stopped)
777 IMemAllocator_Decommit(This->pAlloc);
778 IPin_Disconnect(This->pin.pConnectedTo);
779 This->pin.pConnectedTo = NULL;
780 hr = QT_RemoveOutputPins(Parser);
783 hr = VFW_E_NOT_STOPPED;
787 LeaveCriticalSection(This->pin.pCritSec);
791 static HRESULT WINAPI QTInPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
793 QTInPin *This = (QTInPin*)iface;
795 TRACE("(%p)->(%p)\n", This, pmt);
797 if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
799 This->subType = pmt->subtype;
805 static HRESULT WINAPI QTInPin_EndOfStream(IPin *iface)
807 QTInPin *pin = (QTInPin*)iface;
808 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
810 FIXME("Propagate message on %p\n", This);
814 static HRESULT WINAPI QTInPin_BeginFlush(IPin *iface)
816 QTInPin *pin = (QTInPin*)iface;
817 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
819 FIXME("Propagate message on %p\n", This);
823 static HRESULT WINAPI QTInPin_EndFlush(IPin *iface)
825 QTInPin *pin = (QTInPin*)iface;
826 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
828 FIXME("Propagate message on %p\n", This);
832 static HRESULT WINAPI QTInPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
834 QTInPin *pin = (QTInPin*)iface;
835 QTSplitter *This = (QTSplitter*)pin->pin.pinInfo.pFilter;
837 BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
838 FIXME("Propagate message on %p\n", This);
842 static HRESULT WINAPI QTInPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
844 QTInPin *This = (QTInPin*)iface;
846 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
850 if (IsEqualIID(riid, &IID_IUnknown))
852 else if (IsEqualIID(riid, &IID_IPin))
854 else if (IsEqualIID(riid, &IID_IMediaSeeking))
856 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
861 IUnknown_AddRef((IUnknown *)(*ppv));
865 FIXME("No interface for %s!\n", debugstr_guid(riid));
867 return E_NOINTERFACE;
870 static HRESULT WINAPI QTInPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
872 BasePin *This = (BasePin *)iface;
874 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
876 return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
879 static const IPinVtbl QT_InputPin_Vtbl = {
880 QTInPin_QueryInterface,
883 BaseInputPinImpl_Connect,
884 QTInPin_ReceiveConnection,
886 BasePinImpl_ConnectedTo,
887 BasePinImpl_ConnectionMediaType,
888 BasePinImpl_QueryPinInfo,
889 BasePinImpl_QueryDirection,
892 QTInPin_EnumMediaTypes,
893 BasePinImpl_QueryInternalConnections,
904 static HRESULT WINAPI QTOutPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
906 QTOutPin *This = (QTOutPin *)iface;
908 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
912 if (IsEqualIID(riid, &IID_IUnknown))
914 else if (IsEqualIID(riid, &IID_IPin))
916 else if (IsEqualIID(riid, &IID_IMediaSeeking))
917 return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
921 IUnknown_AddRef((IUnknown *)(*ppv));
924 FIXME("No interface for %s!\n", debugstr_guid(riid));
925 return E_NOINTERFACE;
928 static ULONG WINAPI QTOutPin_Release(IPin *iface)
930 QTOutPin *This = (QTOutPin *)iface;
931 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
932 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
936 DeleteMediaType(This->pmt);
937 FreeMediaType(&This->pin.pin.mtCurrent);
938 OutputQueue_Destroy(This->queue);
945 static HRESULT WINAPI QTOutPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
947 QTOutPin *This = (QTOutPin *)iface;
952 return VFW_S_NO_MORE_ITEMS;
953 CopyMediaType(pmt, This->pmt);
957 static HRESULT WINAPI QTOutPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
963 static HRESULT WINAPI QTOutPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc)
966 QTOutPin *This = (QTOutPin *)iface;
967 QTSplitter *QTfilter = (QTSplitter*)This->pin.pin.pinInfo.pFilter;
970 if (QTfilter->pInputPin.pAlloc)
971 hr = IMemInputPin_NotifyAllocator(pPin, QTfilter->pInputPin.pAlloc, FALSE);
973 hr = VFW_E_NO_ALLOCATOR;
978 static HRESULT WINAPI QTOutPin_BreakConnect(BaseOutputPin *This)
982 TRACE("(%p)->()\n", This);
984 EnterCriticalSection(This->pin.pCritSec);
985 if (!This->pin.pConnectedTo || !This->pMemInputPin)
986 hr = VFW_E_NOT_CONNECTED;
989 hr = IPin_Disconnect(This->pin.pConnectedTo);
990 IPin_Disconnect((IPin *)This);
992 LeaveCriticalSection(This->pin.pCritSec);
997 static const IPinVtbl QT_OutputPin_Vtbl = {
998 QTOutPin_QueryInterface,
1001 BaseOutputPinImpl_Connect,
1002 BaseOutputPinImpl_ReceiveConnection,
1003 BaseOutputPinImpl_Disconnect,
1004 BasePinImpl_ConnectedTo,
1005 BasePinImpl_ConnectionMediaType,
1006 BasePinImpl_QueryPinInfo,
1007 BasePinImpl_QueryDirection,
1008 BasePinImpl_QueryId,
1009 BasePinImpl_QueryAccept,
1010 BasePinImpl_EnumMediaTypes,
1011 BasePinImpl_QueryInternalConnections,
1012 BaseOutputPinImpl_EndOfStream,
1013 BaseOutputPinImpl_BeginFlush,
1014 BaseOutputPinImpl_EndFlush,
1015 BasePinImpl_NewSegment
1018 static const BasePinFuncTable output_BaseFuncTable = {
1020 BaseOutputPinImpl_AttemptConnection,
1021 BasePinImpl_GetMediaTypeVersion,
1022 QTOutPin_GetMediaType
1025 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
1026 QTOutPin_DecideBufferSize,
1027 QTOutPin_DecideAllocator,
1028 QTOutPin_BreakConnect
1031 static const OutputQueueFuncTable output_OutputQueueFuncTable = {
1032 OutputQueueImpl_ThreadProc
1035 static HRESULT QT_AddPin(QTSplitter *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt)
1040 target = (IPin**)&This->pVideo_Pin;
1042 if (*target != NULL)
1044 ERR("We we already have a video pin\n");
1048 hr = BaseOutputPin_Construct(&QT_OutputPin_Vtbl, sizeof(QTOutPin), piOutput, &output_BaseFuncTable, &output_BaseOutputFuncTable, &This->filter.csFilter, (IPin**)target);
1051 QTOutPin *pin = (QTOutPin*)*target;
1052 pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1053 CopyMediaType(pin->pmt, amt);
1054 pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
1056 BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
1058 hr = OutputQueue_Construct((BaseOutputPin*)pin, TRUE, TRUE, 5, FALSE, THREAD_PRIORITY_NORMAL, &output_OutputQueueFuncTable, &pin->queue);
1061 ERR("Failed with error %x\n", hr);