push 97f44e0adb27fff75ba63d8fb97c65db9edfbe82
[wine/hacks.git] / dlls / quartz / pin.c
blob08ddcefcd6d19e3f101ccd1ca5ea6c784f3f30b5
1 /*
2 * Generic Implementation of IPin Interface
4 * Copyright 2003 Robert Shearman
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 "quartz_private.h"
22 #include "pin.h"
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26 #include "uuids.h"
27 #include "vfwmsgs.h"
28 #include <assert.h>
30 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
32 static const IPinVtbl InputPin_Vtbl;
33 static const IPinVtbl OutputPin_Vtbl;
34 static const IMemInputPinVtbl MemInputPin_Vtbl;
35 static const IPinVtbl PullPin_Vtbl;
37 #define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary))
38 #define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary)))
40 static inline InputPin *impl_from_IMemInputPin( IMemInputPin *iface )
42 return (InputPin *)((char*)iface - FIELD_OFFSET(InputPin, lpVtblMemInput));
46 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
48 /* Tempting to just do a memcpy, but the name field is
49 128 characters long! We will probably never exceed 10
50 most of the time, so we are better off copying
51 each field manually */
52 strcpyW(pDest->achName, pSrc->achName);
53 pDest->dir = pSrc->dir;
54 pDest->pFilter = pSrc->pFilter;
57 /* Function called as a helper to IPin_Connect */
58 /* specific AM_MEDIA_TYPE - it cannot be NULL */
59 /* NOTE: not part of standard interface */
60 static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
62 OutputPin *This = (OutputPin *)iface;
63 HRESULT hr;
64 IMemAllocator * pMemAlloc = NULL;
65 ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */
67 TRACE("(%p, %p)\n", pReceivePin, pmt);
68 dump_AM_MEDIA_TYPE(pmt);
70 /* FIXME: call queryacceptproc */
72 This->pin.pConnectedTo = pReceivePin;
73 IPin_AddRef(pReceivePin);
74 CopyMediaType(&This->pin.mtCurrent, pmt);
76 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
78 /* get the IMemInputPin interface we will use to deliver samples to the
79 * connected pin */
80 if (SUCCEEDED(hr))
82 This->pMemInputPin = NULL;
83 hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
85 if (SUCCEEDED(hr))
87 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
89 if (hr == VFW_E_NO_ALLOCATOR)
91 /* Input pin provides no allocator, use standard memory allocator */
92 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
94 if (SUCCEEDED(hr))
96 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, FALSE);
100 if (SUCCEEDED(hr))
101 hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
103 if (pMemAlloc)
104 IMemAllocator_Release(pMemAlloc);
107 /* break connection if we couldn't get the allocator */
108 if (FAILED(hr))
110 if (This->pMemInputPin)
111 IMemInputPin_Release(This->pMemInputPin);
112 This->pMemInputPin = NULL;
114 IPin_Disconnect(pReceivePin);
118 if (FAILED(hr))
120 IPin_Release(This->pin.pConnectedTo);
121 This->pin.pConnectedTo = NULL;
122 FreeMediaType(&This->pin.mtCurrent);
125 TRACE(" -- %x\n", hr);
126 return hr;
129 HRESULT InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
131 InputPin * pPinImpl;
133 *ppPin = NULL;
135 if (pPinInfo->dir != PINDIR_INPUT)
137 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
138 return E_INVALIDARG;
141 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
143 if (!pPinImpl)
144 return E_OUTOFMEMORY;
146 if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
148 pPinImpl->pin.lpVtbl = &InputPin_Vtbl;
149 pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
151 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
152 return S_OK;
155 CoTaskMemFree(pPinImpl);
156 return E_FAIL;
159 /* Note that we don't init the vtables here (like C++ constructor) */
160 HRESULT InputPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, InputPin * pPinImpl)
162 TRACE("\n");
164 /* Common attributes */
165 pPinImpl->pin.refCount = 1;
166 pPinImpl->pin.pConnectedTo = NULL;
167 pPinImpl->pin.fnQueryAccept = pQueryAccept;
168 pPinImpl->pin.pUserData = pUserData;
169 pPinImpl->pin.pCritSec = pCritSec;
170 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
171 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
173 /* Input pin attributes */
174 pPinImpl->fnSampleProc = pSampleProc;
175 pPinImpl->pAllocator = NULL;
176 pPinImpl->tStart = 0;
177 pPinImpl->tStop = 0;
178 pPinImpl->dRate = 0;
180 return S_OK;
183 HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData,
184 QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
186 TRACE("\n");
188 /* Common attributes */
189 pPinImpl->pin.lpVtbl = &OutputPin_Vtbl;
190 pPinImpl->pin.refCount = 1;
191 pPinImpl->pin.pConnectedTo = NULL;
192 pPinImpl->pin.fnQueryAccept = pQueryAccept;
193 pPinImpl->pin.pUserData = pUserData;
194 pPinImpl->pin.pCritSec = pCritSec;
195 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
196 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
198 /* Output pin attributes */
199 pPinImpl->pMemInputPin = NULL;
200 pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
201 if (props)
203 memcpy(&pPinImpl->allocProps, props, sizeof(pPinImpl->allocProps));
204 if (pPinImpl->allocProps.cbAlign == 0)
205 pPinImpl->allocProps.cbAlign = 1;
207 else
208 ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
210 return S_OK;
213 HRESULT OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
215 OutputPin * pPinImpl;
217 *ppPin = NULL;
219 if (pPinInfo->dir != PINDIR_OUTPUT)
221 ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
222 return E_INVALIDARG;
225 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
227 if (!pPinImpl)
228 return E_OUTOFMEMORY;
230 if (SUCCEEDED(OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
232 pPinImpl->pin.lpVtbl = &OutputPin_Vtbl;
234 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
235 return S_OK;
238 CoTaskMemFree(pPinImpl);
239 return E_FAIL;
242 /*** Common pin functions ***/
244 ULONG WINAPI IPinImpl_AddRef(IPin * iface)
246 IPinImpl *This = (IPinImpl *)iface;
247 ULONG refCount = InterlockedIncrement(&This->refCount);
249 TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
251 return refCount;
254 HRESULT WINAPI IPinImpl_Disconnect(IPin * iface)
256 HRESULT hr;
257 IPinImpl *This = (IPinImpl *)iface;
259 TRACE("()\n");
261 EnterCriticalSection(This->pCritSec);
263 if (This->pConnectedTo)
265 IPin_Release(This->pConnectedTo);
266 This->pConnectedTo = NULL;
267 hr = S_OK;
269 else
270 hr = S_FALSE;
272 LeaveCriticalSection(This->pCritSec);
274 return hr;
277 HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
279 HRESULT hr;
280 IPinImpl *This = (IPinImpl *)iface;
282 /* TRACE("(%p)\n", ppPin);*/
284 EnterCriticalSection(This->pCritSec);
286 if (This->pConnectedTo)
288 *ppPin = This->pConnectedTo;
289 IPin_AddRef(*ppPin);
290 hr = S_OK;
292 else
293 hr = VFW_E_NOT_CONNECTED;
295 LeaveCriticalSection(This->pCritSec);
297 return hr;
300 HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
302 HRESULT hr;
303 IPinImpl *This = (IPinImpl *)iface;
305 TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
307 EnterCriticalSection(This->pCritSec);
309 if (This->pConnectedTo)
311 CopyMediaType(pmt, &This->mtCurrent);
312 hr = S_OK;
314 else
316 ZeroMemory(pmt, sizeof(*pmt));
317 hr = VFW_E_NOT_CONNECTED;
320 LeaveCriticalSection(This->pCritSec);
322 return hr;
325 HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
327 IPinImpl *This = (IPinImpl *)iface;
329 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
331 Copy_PinInfo(pInfo, &This->pinInfo);
332 IBaseFilter_AddRef(pInfo->pFilter);
334 return S_OK;
337 HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
339 IPinImpl *This = (IPinImpl *)iface;
341 TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
343 *pPinDir = This->pinInfo.dir;
345 return S_OK;
348 HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
350 IPinImpl *This = (IPinImpl *)iface;
352 TRACE("(%p/%p)->(%p)\n", This, iface, Id);
354 *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
355 if (!*Id)
356 return E_OUTOFMEMORY;
358 strcpyW(*Id, This->pinInfo.achName);
360 return S_OK;
363 HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
365 IPinImpl *This = (IPinImpl *)iface;
367 TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
369 return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
372 HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
374 IPinImpl *This = (IPinImpl *)iface;
375 ENUMMEDIADETAILS emd;
377 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
379 /* override this method to allow enumeration of your types */
380 emd.cMediaTypes = 0;
381 emd.pMediaTypes = NULL;
383 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
386 HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
388 IPinImpl *This = (IPinImpl *)iface;
390 TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
392 return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
395 /*** IPin implementation for an input pin ***/
397 HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
399 InputPin *This = (InputPin *)iface;
401 TRACE("(%p)->(%s, %p)\n", iface, qzdebugstr_guid(riid), ppv);
403 *ppv = NULL;
405 if (IsEqualIID(riid, &IID_IUnknown))
406 *ppv = (LPVOID)iface;
407 else if (IsEqualIID(riid, &IID_IPin))
408 *ppv = (LPVOID)iface;
409 else if (IsEqualIID(riid, &IID_IMemInputPin))
410 *ppv = (LPVOID)&This->lpVtblMemInput;
412 if (*ppv)
414 IUnknown_AddRef((IUnknown *)(*ppv));
415 return S_OK;
418 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
420 return E_NOINTERFACE;
423 ULONG WINAPI InputPin_Release(IPin * iface)
425 InputPin *This = (InputPin *)iface;
426 ULONG refCount = InterlockedDecrement(&This->pin.refCount);
428 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
430 if (!refCount)
432 FreeMediaType(&This->pin.mtCurrent);
433 if (This->pAllocator)
434 IMemAllocator_Release(This->pAllocator);
435 CoTaskMemFree(This);
436 return 0;
438 else
439 return refCount;
442 HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
444 ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt);
446 return E_UNEXPECTED;
450 HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
452 InputPin *This = (InputPin *)iface;
453 PIN_DIRECTION pindirReceive;
454 HRESULT hr = S_OK;
456 TRACE("(%p, %p)\n", pReceivePin, pmt);
457 dump_AM_MEDIA_TYPE(pmt);
459 EnterCriticalSection(This->pin.pCritSec);
461 if (This->pin.pConnectedTo)
462 hr = VFW_E_ALREADY_CONNECTED;
464 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
465 hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
466 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
468 if (SUCCEEDED(hr))
470 IPin_QueryDirection(pReceivePin, &pindirReceive);
472 if (pindirReceive != PINDIR_OUTPUT)
474 ERR("Can't connect from non-output pin\n");
475 hr = VFW_E_INVALID_DIRECTION;
479 if (SUCCEEDED(hr))
481 CopyMediaType(&This->pin.mtCurrent, pmt);
482 This->pin.pConnectedTo = pReceivePin;
483 IPin_AddRef(pReceivePin);
486 LeaveCriticalSection(This->pin.pCritSec);
488 return hr;
491 HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
493 TRACE("()\n");
495 return S_OK;
498 HRESULT WINAPI InputPin_BeginFlush(IPin * iface)
500 FIXME("()\n");
501 return E_NOTIMPL;
504 HRESULT WINAPI InputPin_EndFlush(IPin * iface)
506 FIXME("()\n");
507 return E_NOTIMPL;
510 HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
512 InputPin *This = (InputPin *)iface;
514 TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
516 This->tStart = tStart;
517 This->tStop = tStop;
518 This->dRate = dRate;
520 return S_OK;
523 static const IPinVtbl InputPin_Vtbl =
525 InputPin_QueryInterface,
526 IPinImpl_AddRef,
527 InputPin_Release,
528 InputPin_Connect,
529 InputPin_ReceiveConnection,
530 IPinImpl_Disconnect,
531 IPinImpl_ConnectedTo,
532 IPinImpl_ConnectionMediaType,
533 IPinImpl_QueryPinInfo,
534 IPinImpl_QueryDirection,
535 IPinImpl_QueryId,
536 IPinImpl_QueryAccept,
537 IPinImpl_EnumMediaTypes,
538 IPinImpl_QueryInternalConnections,
539 InputPin_EndOfStream,
540 InputPin_BeginFlush,
541 InputPin_EndFlush,
542 InputPin_NewSegment
545 /*** IMemInputPin implementation ***/
547 HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
549 InputPin *This = impl_from_IMemInputPin(iface);
551 return IPin_QueryInterface((IPin *)&This->pin, riid, ppv);
554 ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
556 InputPin *This = impl_from_IMemInputPin(iface);
558 return IPin_AddRef((IPin *)&This->pin);
561 ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
563 InputPin *This = impl_from_IMemInputPin(iface);
565 return IPin_Release((IPin *)&This->pin);
568 HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
570 InputPin *This = impl_from_IMemInputPin(iface);
572 TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator);
574 *ppAllocator = This->pAllocator;
575 if (*ppAllocator)
576 IMemAllocator_AddRef(*ppAllocator);
578 return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
581 HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
583 InputPin *This = impl_from_IMemInputPin(iface);
585 TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly);
587 if (This->pAllocator)
588 IMemAllocator_Release(This->pAllocator);
589 This->pAllocator = pAllocator;
590 if (This->pAllocator)
591 IMemAllocator_AddRef(This->pAllocator);
593 return S_OK;
596 HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps)
598 InputPin *This = impl_from_IMemInputPin(iface);
600 TRACE("(%p/%p)->(%p)\n", This, iface, pProps);
602 /* override this method if you have any specific requirements */
604 return E_NOTIMPL;
607 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
609 InputPin *This = impl_from_IMemInputPin(iface);
611 /* this trace commented out for performance reasons */
612 /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
614 return This->fnSampleProc(This->pin.pUserData, pSample);
617 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
619 HRESULT hr = S_OK;
620 InputPin *This = impl_from_IMemInputPin(iface);
622 TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
624 for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
626 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
627 if (hr != S_OK)
628 break;
631 return hr;
634 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
636 InputPin *This = impl_from_IMemInputPin(iface);
638 FIXME("(%p/%p)->()\n", This, iface);
640 /* FIXME: we should check whether any output pins will block */
642 return S_OK;
645 static const IMemInputPinVtbl MemInputPin_Vtbl =
647 MemInputPin_QueryInterface,
648 MemInputPin_AddRef,
649 MemInputPin_Release,
650 MemInputPin_GetAllocator,
651 MemInputPin_NotifyAllocator,
652 MemInputPin_GetAllocatorRequirements,
653 MemInputPin_Receive,
654 MemInputPin_ReceiveMultiple,
655 MemInputPin_ReceiveCanBlock
658 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
660 OutputPin *This = (OutputPin *)iface;
662 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
664 *ppv = NULL;
666 if (IsEqualIID(riid, &IID_IUnknown))
667 *ppv = (LPVOID)iface;
668 else if (IsEqualIID(riid, &IID_IPin))
669 *ppv = (LPVOID)iface;
671 if (*ppv)
673 IUnknown_AddRef((IUnknown *)(*ppv));
674 return S_OK;
677 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
679 return E_NOINTERFACE;
682 ULONG WINAPI OutputPin_Release(IPin * iface)
684 OutputPin *This = (OutputPin *)iface;
685 ULONG refCount = InterlockedDecrement(&This->pin.refCount);
687 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
689 if (!refCount)
691 FreeMediaType(&This->pin.mtCurrent);
692 CoTaskMemFree(This);
693 return 0;
695 return refCount;
698 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
700 HRESULT hr;
701 OutputPin *This = (OutputPin *)iface;
703 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
704 dump_AM_MEDIA_TYPE(pmt);
706 /* If we try to connect to ourself, we will definitely deadlock.
707 * There are other cases where we could deadlock too, but this
708 * catches the obvious case */
709 assert(pReceivePin != iface);
711 EnterCriticalSection(This->pin.pCritSec);
713 /* if we have been a specific type to connect with, then we can either connect
714 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
715 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
716 hr = This->pConnectSpecific(iface, pReceivePin, pmt);
717 else
719 /* negotiate media type */
721 IEnumMediaTypes * pEnumCandidates;
722 AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
724 if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
726 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
728 /* try this filter's media types first */
729 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
731 if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
732 (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
734 hr = S_OK;
735 CoTaskMemFree(pmtCandidate);
736 break;
738 CoTaskMemFree(pmtCandidate);
740 IEnumMediaTypes_Release(pEnumCandidates);
743 /* then try receiver filter's media types */
744 if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
746 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
748 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
750 if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
751 (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
753 hr = S_OK;
754 CoTaskMemFree(pmtCandidate);
755 break;
757 CoTaskMemFree(pmtCandidate);
758 } /* while */
759 IEnumMediaTypes_Release(pEnumCandidates);
760 } /* if not found */
761 } /* if negotiate media type */
762 } /* if succeeded */
763 LeaveCriticalSection(This->pin.pCritSec);
765 TRACE(" -- %x\n", hr);
766 return hr;
769 HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
771 ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
773 return E_UNEXPECTED;
776 HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
778 HRESULT hr;
779 OutputPin *This = (OutputPin *)iface;
781 TRACE("()\n");
783 EnterCriticalSection(This->pin.pCritSec);
785 if (This->pMemInputPin)
787 IMemInputPin_Release(This->pMemInputPin);
788 This->pMemInputPin = NULL;
790 if (This->pin.pConnectedTo)
792 IPin_Release(This->pin.pConnectedTo);
793 This->pin.pConnectedTo = NULL;
794 hr = S_OK;
796 else
797 hr = S_FALSE;
799 LeaveCriticalSection(This->pin.pCritSec);
801 return hr;
804 HRESULT WINAPI OutputPin_EndOfStream(IPin * iface)
806 TRACE("()\n");
808 /* not supposed to do anything in an output pin */
810 return E_UNEXPECTED;
813 HRESULT WINAPI OutputPin_BeginFlush(IPin * iface)
815 TRACE("(%p)->()\n", iface);
817 /* not supposed to do anything in an output pin */
819 return E_UNEXPECTED;
822 HRESULT WINAPI OutputPin_EndFlush(IPin * iface)
824 TRACE("(%p)->()\n", iface);
826 /* not supposed to do anything in an output pin */
828 return E_UNEXPECTED;
831 HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
833 TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
835 /* not supposed to do anything in an output pin */
837 return E_UNEXPECTED;
840 static const IPinVtbl OutputPin_Vtbl =
842 OutputPin_QueryInterface,
843 IPinImpl_AddRef,
844 OutputPin_Release,
845 OutputPin_Connect,
846 OutputPin_ReceiveConnection,
847 OutputPin_Disconnect,
848 IPinImpl_ConnectedTo,
849 IPinImpl_ConnectionMediaType,
850 IPinImpl_QueryPinInfo,
851 IPinImpl_QueryDirection,
852 IPinImpl_QueryId,
853 IPinImpl_QueryAccept,
854 IPinImpl_EnumMediaTypes,
855 IPinImpl_QueryInternalConnections,
856 OutputPin_EndOfStream,
857 OutputPin_BeginFlush,
858 OutputPin_EndFlush,
859 OutputPin_NewSegment
862 HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags)
864 HRESULT hr;
866 TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags);
868 EnterCriticalSection(This->pin.pCritSec);
870 if (!This->pin.pConnectedTo)
871 hr = VFW_E_NOT_CONNECTED;
872 else
874 IMemAllocator * pAlloc = NULL;
876 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
878 if (SUCCEEDED(hr))
879 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags);
881 if (SUCCEEDED(hr))
882 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
884 if (pAlloc)
885 IMemAllocator_Release(pAlloc);
888 LeaveCriticalSection(This->pin.pCritSec);
890 return hr;
893 HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
895 HRESULT hr = S_OK;
896 IMemInputPin * pMemConnected = NULL;
897 PIN_INFO pinInfo;
899 EnterCriticalSection(This->pin.pCritSec);
901 if (!This->pin.pConnectedTo || !This->pMemInputPin)
902 hr = VFW_E_NOT_CONNECTED;
903 else
905 /* we don't have the lock held when using This->pMemInputPin,
906 * so we need to AddRef it to stop it being deleted while we are
907 * using it. Same with its filter. */
908 pMemConnected = This->pMemInputPin;
909 IMemInputPin_AddRef(pMemConnected);
910 hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo);
913 LeaveCriticalSection(This->pin.pCritSec);
915 if (SUCCEEDED(hr))
917 /* NOTE: if we are in a critical section when Receive is called
918 * then it causes some problems (most notably with the native Video
919 * Renderer) if we are re-entered for whatever reason */
920 hr = IMemInputPin_Receive(pMemConnected, pSample);
922 /* If the filter's destroyed, tell upstream to stop sending data */
923 if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr))
924 hr = S_FALSE;
926 if (pMemConnected)
927 IMemInputPin_Release(pMemConnected);
929 return hr;
932 HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
934 HRESULT hr;
936 EnterCriticalSection(This->pin.pCritSec);
938 if (!This->pin.pConnectedTo)
939 hr = VFW_E_NOT_CONNECTED;
940 else
941 hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
943 LeaveCriticalSection(This->pin.pCritSec);
945 return hr;
948 HRESULT OutputPin_CommitAllocator(OutputPin * This)
950 HRESULT hr;
952 TRACE("(%p)->()\n", This);
954 EnterCriticalSection(This->pin.pCritSec);
956 if (!This->pin.pConnectedTo || !This->pMemInputPin)
957 hr = VFW_E_NOT_CONNECTED;
958 else
960 IMemAllocator * pAlloc = NULL;
962 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
964 if (SUCCEEDED(hr))
965 hr = IMemAllocator_Commit(pAlloc);
967 if (pAlloc)
968 IMemAllocator_Release(pAlloc);
971 LeaveCriticalSection(This->pin.pCritSec);
973 return hr;
976 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
978 HRESULT hr;
980 TRACE("(%p)->()\n", This);
982 EnterCriticalSection(This->pin.pCritSec);
984 if (!This->pin.pConnectedTo || !This->pMemInputPin)
985 hr = VFW_E_NOT_CONNECTED;
986 else
988 IMemAllocator * pAlloc = NULL;
990 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
992 if (SUCCEEDED(hr))
993 hr = IMemAllocator_Decommit(pAlloc);
995 if (pAlloc)
996 IMemAllocator_Release(pAlloc);
998 if (SUCCEEDED(hr))
999 hr = IPin_Disconnect(This->pin.pConnectedTo);
1002 LeaveCriticalSection(This->pin.pCritSec);
1004 return hr;
1008 HRESULT PullPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
1010 PullPin * pPinImpl;
1012 *ppPin = NULL;
1014 if (pPinInfo->dir != PINDIR_INPUT)
1016 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1017 return E_INVALIDARG;
1020 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1022 if (!pPinImpl)
1023 return E_OUTOFMEMORY;
1025 if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
1027 pPinImpl->pin.lpVtbl = &PullPin_Vtbl;
1029 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1030 return S_OK;
1033 CoTaskMemFree(pPinImpl);
1034 return E_FAIL;
1037 HRESULT PullPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1039 /* Common attributes */
1040 pPinImpl->pin.refCount = 1;
1041 pPinImpl->pin.pConnectedTo = NULL;
1042 pPinImpl->pin.fnQueryAccept = pQueryAccept;
1043 pPinImpl->pin.pUserData = pUserData;
1044 pPinImpl->pin.pCritSec = pCritSec;
1045 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1046 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1048 /* Input pin attributes */
1049 pPinImpl->fnSampleProc = pSampleProc;
1050 pPinImpl->fnPreConnect = NULL;
1051 pPinImpl->pAlloc = NULL;
1052 pPinImpl->pReader = NULL;
1053 pPinImpl->hThread = NULL;
1054 pPinImpl->hEventStateChanged = CreateEventW(NULL, FALSE, TRUE, NULL);
1056 pPinImpl->rtStart = 0;
1057 pPinImpl->rtCurrent = 0;
1058 pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1060 return S_OK;
1063 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1065 PIN_DIRECTION pindirReceive;
1066 HRESULT hr = S_OK;
1067 PullPin *This = (PullPin *)iface;
1069 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1070 dump_AM_MEDIA_TYPE(pmt);
1072 EnterCriticalSection(This->pin.pCritSec);
1074 if (This->pin.pConnectedTo)
1075 hr = VFW_E_ALREADY_CONNECTED;
1077 if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1078 hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
1079 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1081 if (SUCCEEDED(hr))
1083 IPin_QueryDirection(pReceivePin, &pindirReceive);
1085 if (pindirReceive != PINDIR_OUTPUT)
1087 ERR("Can't connect from non-output pin\n");
1088 hr = VFW_E_INVALID_DIRECTION;
1092 This->pReader = NULL;
1093 This->pAlloc = NULL;
1094 if (SUCCEEDED(hr))
1096 hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1099 if (SUCCEEDED(hr))
1101 ALLOCATOR_PROPERTIES props;
1102 props.cBuffers = 3;
1103 props.cbBuffer = 64 * 1024; /* 64k bytes */
1104 props.cbAlign = 1;
1105 props.cbPrefix = 0;
1106 hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1109 if (SUCCEEDED(hr) && This->fnPreConnect)
1111 hr = This->fnPreConnect(iface, pReceivePin);
1114 if (SUCCEEDED(hr))
1116 CopyMediaType(&This->pin.mtCurrent, pmt);
1117 This->pin.pConnectedTo = pReceivePin;
1118 IPin_AddRef(pReceivePin);
1120 else
1122 if (This->pReader)
1123 IAsyncReader_Release(This->pReader);
1124 This->pReader = NULL;
1125 if (This->pAlloc)
1126 IMemAllocator_Release(This->pAlloc);
1127 This->pAlloc = NULL;
1130 LeaveCriticalSection(This->pin.pCritSec);
1131 return hr;
1134 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1136 PullPin *This = (PullPin *)iface;
1138 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1140 *ppv = NULL;
1142 if (IsEqualIID(riid, &IID_IUnknown))
1143 *ppv = (LPVOID)iface;
1144 else if (IsEqualIID(riid, &IID_IPin))
1145 *ppv = (LPVOID)iface;
1147 if (*ppv)
1149 IUnknown_AddRef((IUnknown *)(*ppv));
1150 return S_OK;
1153 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1155 return E_NOINTERFACE;
1158 ULONG WINAPI PullPin_Release(IPin * iface)
1160 PullPin *This = (PullPin *)iface;
1161 ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1163 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1165 if (!refCount)
1167 if(This->pAlloc)
1168 IMemAllocator_Release(This->pAlloc);
1169 if(This->pReader)
1170 IAsyncReader_Release(This->pReader);
1171 CloseHandle(This->hEventStateChanged);
1172 CoTaskMemFree(This);
1173 return 0;
1175 return refCount;
1178 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1180 for (;;)
1181 SleepEx(INFINITE, TRUE);
1184 static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
1186 PullPin *This = (PullPin *)iface;
1187 HRESULT hr;
1189 ALLOCATOR_PROPERTIES allocProps;
1191 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1193 SetEvent(This->hEventStateChanged);
1195 hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1197 if (This->rtCurrent < This->rtStart)
1198 This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), allocProps.cbAlign));
1200 TRACE("Start\n");
1202 while (This->rtCurrent < This->rtStop && hr == S_OK)
1204 /* FIXME: to improve performance by quite a bit this should be changed
1205 * so that one sample is processed while one sample is fetched. However,
1206 * it is harder to debug so for the moment it will stay as it is */
1207 IMediaSample * pSample = NULL;
1208 REFERENCE_TIME rtSampleStart;
1209 REFERENCE_TIME rtSampleStop;
1210 DWORD_PTR dwUser;
1212 TRACE("Process sample\n");
1214 hr = IMemAllocator_GetBuffer(This->pAlloc, &pSample, NULL, NULL, 0);
1216 if (SUCCEEDED(hr))
1218 rtSampleStart = This->rtCurrent;
1219 rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(pSample));
1220 if (rtSampleStop > This->rtStop)
1221 rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This->rtStop), allocProps.cbAlign));
1222 hr = IMediaSample_SetTime(pSample, &rtSampleStart, &rtSampleStop);
1223 This->rtCurrent = rtSampleStop;
1226 if (SUCCEEDED(hr))
1227 hr = IAsyncReader_Request(This->pReader, pSample, (ULONG_PTR)0);
1229 if (SUCCEEDED(hr))
1230 hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1232 if (SUCCEEDED(hr))
1234 rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(IMediaSample_GetActualDataLength(pSample));
1235 if (rtSampleStop > This->rtStop)
1236 rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This->rtStop), allocProps.cbAlign));
1237 hr = IMediaSample_SetTime(pSample, &rtSampleStart, &rtSampleStop);
1240 if (SUCCEEDED(hr))
1241 hr = This->fnSampleProc(This->pin.pUserData, pSample);
1242 else
1243 ERR("Processing error: %x\n", hr);
1245 if (pSample)
1246 IMediaSample_Release(pSample);
1249 CoUninitialize();
1251 TRACE("End\n");
1254 static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)
1256 PullPin *This = (PullPin *)iface;
1258 TRACE("(%p/%p)->()\n", This, (LPVOID)iface);
1260 EnterCriticalSection(This->pin.pCritSec);
1262 HRESULT hr;
1264 CloseHandle(This->hThread);
1265 This->hThread = NULL;
1266 if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1267 ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1269 LeaveCriticalSection(This->pin.pCritSec);
1271 SetEvent(This->hEventStateChanged);
1273 IBaseFilter_Release(This->pin.pinInfo.pFilter);
1275 ExitThread(0);
1278 HRESULT PullPin_InitProcessing(PullPin * This)
1280 HRESULT hr = S_OK;
1282 TRACE("(%p)->()\n", This);
1284 assert(!This->hThread);
1286 /* if we are connected */
1287 if (This->pAlloc)
1289 EnterCriticalSection(This->pin.pCritSec);
1291 DWORD dwThreadId;
1292 assert(!This->hThread);
1294 /* AddRef the filter to make sure it and it's pins will be around
1295 * as long as the thread */
1296 IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1298 This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, NULL, 0, &dwThreadId);
1299 if (!This->hThread)
1301 hr = HRESULT_FROM_WIN32(GetLastError());
1302 IBaseFilter_Release(This->pin.pinInfo.pFilter);
1305 if (SUCCEEDED(hr))
1306 hr = IMemAllocator_Commit(This->pAlloc);
1308 LeaveCriticalSection(This->pin.pCritSec);
1311 TRACE(" -- %x\n", hr);
1313 return hr;
1316 HRESULT PullPin_StartProcessing(PullPin * This)
1318 /* if we are connected */
1319 TRACE("(%p)->()\n", This);
1320 if(This->pAlloc)
1322 assert(This->hThread);
1324 ResetEvent(This->hEventStateChanged);
1326 if (!QueueUserAPC(PullPin_Thread_Process, This->hThread, (ULONG_PTR)This))
1327 return HRESULT_FROM_WIN32(GetLastError());
1330 return S_OK;
1333 HRESULT PullPin_PauseProcessing(PullPin * This)
1335 /* make the processing function exit its loop */
1336 This->rtStop = 0;
1338 return S_OK;
1341 HRESULT PullPin_StopProcessing(PullPin * This)
1343 /* if we are connected */
1344 if (This->pAlloc)
1346 assert(This->hThread);
1348 ResetEvent(This->hEventStateChanged);
1350 PullPin_PauseProcessing(This);
1352 if (!QueueUserAPC(PullPin_Thread_Stop, This->hThread, (ULONG_PTR)This))
1353 return HRESULT_FROM_WIN32(GetLastError());
1356 return S_OK;
1359 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1361 if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1362 return S_FALSE;
1363 return S_OK;
1366 HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
1368 FIXME("(%p)->(%x%08x, %x%08x)\n", This, (LONG)(rtStart >> 32), (LONG)rtStart, (LONG)(rtStop >> 32), (LONG)rtStop);
1370 PullPin_BeginFlush((IPin *)This);
1371 /* FIXME: need critical section? */
1372 This->rtStart = rtStart;
1373 This->rtStop = rtStop;
1374 PullPin_EndFlush((IPin *)This);
1376 return S_OK;
1379 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1381 FIXME("(%p)->()\n", iface);
1382 return E_NOTIMPL;
1385 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1387 FIXME("(%p)->()\n", iface);
1388 return E_NOTIMPL;
1391 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1393 FIXME("(%p)->()\n", iface);
1394 return E_NOTIMPL;
1397 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1399 FIXME("(%p)->(%s, %s, %g)\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1400 return E_NOTIMPL;
1403 static const IPinVtbl PullPin_Vtbl =
1405 PullPin_QueryInterface,
1406 IPinImpl_AddRef,
1407 PullPin_Release,
1408 OutputPin_Connect,
1409 PullPin_ReceiveConnection,
1410 IPinImpl_Disconnect,
1411 IPinImpl_ConnectedTo,
1412 IPinImpl_ConnectionMediaType,
1413 IPinImpl_QueryPinInfo,
1414 IPinImpl_QueryDirection,
1415 IPinImpl_QueryId,
1416 IPinImpl_QueryAccept,
1417 IPinImpl_EnumMediaTypes,
1418 IPinImpl_QueryInternalConnections,
1419 PullPin_EndOfStream,
1420 PullPin_BeginFlush,
1421 PullPin_EndFlush,
1422 PullPin_NewSegment