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"
24 #include "wine/debug.h"
25 #include "wine/unicode.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-1))
38 #define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + 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
;
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
82 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (LPVOID
)&This
->pMemInputPin
);
85 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pMemAlloc
);
87 if (hr
== VFW_E_NO_ALLOCATOR
)
89 /* Input pin provides no allocator, use standard memory allocator */
90 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (LPVOID
*)&pMemAlloc
);
94 hr
= IMemInputPin_NotifyAllocator(This
->pMemInputPin
, pMemAlloc
, FALSE
);
99 hr
= IMemAllocator_SetProperties(pMemAlloc
, &This
->allocProps
, &actual
);
102 IMemAllocator_Release(pMemAlloc
);
104 /* break connection if we couldn't get the allocator */
106 IPin_Disconnect(pReceivePin
);
111 IPin_Release(This
->pin
.pConnectedTo
);
112 This
->pin
.pConnectedTo
= NULL
;
113 FreeMediaType(&This
->pin
.mtCurrent
);
116 TRACE(" -- %x\n", hr
);
120 HRESULT
InputPin_Construct(const PIN_INFO
* pPinInfo
, SAMPLEPROC pSampleProc
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
126 if (pPinInfo
->dir
!= PINDIR_INPUT
)
128 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo
->dir
);
132 pPinImpl
= CoTaskMemAlloc(sizeof(*pPinImpl
));
135 return E_OUTOFMEMORY
;
137 if (SUCCEEDED(InputPin_Init(pPinInfo
, pSampleProc
, pUserData
, pQueryAccept
, pCritSec
, pPinImpl
)))
139 pPinImpl
->pin
.lpVtbl
= &InputPin_Vtbl
;
140 pPinImpl
->lpVtblMemInput
= &MemInputPin_Vtbl
;
142 *ppPin
= (IPin
*)(&pPinImpl
->pin
.lpVtbl
);
148 /* Note that we don't init the vtables here (like C++ constructor) */
149 HRESULT
InputPin_Init(const PIN_INFO
* pPinInfo
, SAMPLEPROC pSampleProc
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, InputPin
* pPinImpl
)
153 /* Common attributes */
154 pPinImpl
->pin
.refCount
= 1;
155 pPinImpl
->pin
.pConnectedTo
= NULL
;
156 pPinImpl
->pin
.fnQueryAccept
= pQueryAccept
;
157 pPinImpl
->pin
.pUserData
= pUserData
;
158 pPinImpl
->pin
.pCritSec
= pCritSec
;
159 Copy_PinInfo(&pPinImpl
->pin
.pinInfo
, pPinInfo
);
160 ZeroMemory(&pPinImpl
->pin
.mtCurrent
, sizeof(AM_MEDIA_TYPE
));
162 /* Input pin attributes */
163 pPinImpl
->fnSampleProc
= pSampleProc
;
164 pPinImpl
->pAllocator
= NULL
;
165 pPinImpl
->tStart
= 0;
172 HRESULT
OutputPin_Init(const PIN_INFO
* pPinInfo
, ALLOCATOR_PROPERTIES
* props
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, OutputPin
* pPinImpl
)
176 /* Common attributes */
177 pPinImpl
->pin
.lpVtbl
= &OutputPin_Vtbl
;
178 pPinImpl
->pin
.refCount
= 1;
179 pPinImpl
->pin
.pConnectedTo
= NULL
;
180 pPinImpl
->pin
.fnQueryAccept
= pQueryAccept
;
181 pPinImpl
->pin
.pUserData
= pUserData
;
182 pPinImpl
->pin
.pCritSec
= pCritSec
;
183 Copy_PinInfo(&pPinImpl
->pin
.pinInfo
, pPinInfo
);
184 ZeroMemory(&pPinImpl
->pin
.mtCurrent
, sizeof(AM_MEDIA_TYPE
));
186 /* Output pin attributes */
187 pPinImpl
->pMemInputPin
= NULL
;
188 pPinImpl
->pConnectSpecific
= OutputPin_ConnectSpecific
;
191 memcpy(&pPinImpl
->allocProps
, props
, sizeof(pPinImpl
->allocProps
));
192 if (pPinImpl
->allocProps
.cbAlign
== 0)
193 pPinImpl
->allocProps
.cbAlign
= 1;
196 ZeroMemory(&pPinImpl
->allocProps
, sizeof(pPinImpl
->allocProps
));
201 HRESULT
OutputPin_Construct(const PIN_INFO
* pPinInfo
, ALLOCATOR_PROPERTIES
*props
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
203 OutputPin
* pPinImpl
;
207 if (pPinInfo
->dir
!= PINDIR_OUTPUT
)
209 ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo
->dir
);
213 pPinImpl
= CoTaskMemAlloc(sizeof(*pPinImpl
));
216 return E_OUTOFMEMORY
;
218 if (SUCCEEDED(OutputPin_Init(pPinInfo
, props
, pUserData
, pQueryAccept
, pCritSec
, pPinImpl
)))
220 pPinImpl
->pin
.lpVtbl
= &OutputPin_Vtbl
;
222 *ppPin
= (IPin
*)(&pPinImpl
->pin
.lpVtbl
);
228 /*** Common pin functions ***/
230 ULONG WINAPI
IPinImpl_AddRef(IPin
* iface
)
232 IPinImpl
*This
= (IPinImpl
*)iface
;
233 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
235 TRACE("(%p)->() AddRef from %d\n", iface
, refCount
- 1);
240 HRESULT WINAPI
IPinImpl_Disconnect(IPin
* iface
)
243 IPinImpl
*This
= (IPinImpl
*)iface
;
247 EnterCriticalSection(This
->pCritSec
);
249 if (This
->pConnectedTo
)
251 IPin_Release(This
->pConnectedTo
);
252 This
->pConnectedTo
= NULL
;
258 LeaveCriticalSection(This
->pCritSec
);
263 HRESULT WINAPI
IPinImpl_ConnectedTo(IPin
* iface
, IPin
** ppPin
)
266 IPinImpl
*This
= (IPinImpl
*)iface
;
268 /* TRACE("(%p)\n", ppPin);*/
270 EnterCriticalSection(This
->pCritSec
);
272 if (This
->pConnectedTo
)
274 *ppPin
= This
->pConnectedTo
;
279 hr
= VFW_E_NOT_CONNECTED
;
281 LeaveCriticalSection(This
->pCritSec
);
286 HRESULT WINAPI
IPinImpl_ConnectionMediaType(IPin
* iface
, AM_MEDIA_TYPE
* pmt
)
289 IPinImpl
*This
= (IPinImpl
*)iface
;
291 TRACE("(%p/%p)->(%p)\n", This
, iface
, pmt
);
293 EnterCriticalSection(This
->pCritSec
);
295 if (This
->pConnectedTo
)
297 CopyMediaType(pmt
, &This
->mtCurrent
);
302 ZeroMemory(pmt
, sizeof(*pmt
));
303 hr
= VFW_E_NOT_CONNECTED
;
306 LeaveCriticalSection(This
->pCritSec
);
311 HRESULT WINAPI
IPinImpl_QueryPinInfo(IPin
* iface
, PIN_INFO
* pInfo
)
313 IPinImpl
*This
= (IPinImpl
*)iface
;
315 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
317 Copy_PinInfo(pInfo
, &This
->pinInfo
);
318 IBaseFilter_AddRef(pInfo
->pFilter
);
323 HRESULT WINAPI
IPinImpl_QueryDirection(IPin
* iface
, PIN_DIRECTION
* pPinDir
)
325 IPinImpl
*This
= (IPinImpl
*)iface
;
327 TRACE("(%p/%p)->(%p)\n", This
, iface
, pPinDir
);
329 *pPinDir
= This
->pinInfo
.dir
;
334 HRESULT WINAPI
IPinImpl_QueryId(IPin
* iface
, LPWSTR
* Id
)
336 IPinImpl
*This
= (IPinImpl
*)iface
;
338 TRACE("(%p/%p)->(%p)\n", This
, iface
, Id
);
340 *Id
= CoTaskMemAlloc((strlenW(This
->pinInfo
.achName
) + 1) * sizeof(WCHAR
));
342 return E_OUTOFMEMORY
;
344 strcpyW(*Id
, This
->pinInfo
.achName
);
349 HRESULT WINAPI
IPinImpl_QueryAccept(IPin
* iface
, const AM_MEDIA_TYPE
* pmt
)
351 IPinImpl
*This
= (IPinImpl
*)iface
;
353 TRACE("(%p/%p)->(%p)\n", This
, iface
, pmt
);
355 return (This
->fnQueryAccept(This
->pUserData
, pmt
) == S_OK
? S_OK
: S_FALSE
);
358 HRESULT WINAPI
IPinImpl_EnumMediaTypes(IPin
* iface
, IEnumMediaTypes
** ppEnum
)
360 IPinImpl
*This
= (IPinImpl
*)iface
;
361 ENUMMEDIADETAILS emd
;
363 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
365 /* override this method to allow enumeration of your types */
367 emd
.pMediaTypes
= NULL
;
369 return IEnumMediaTypesImpl_Construct(&emd
, ppEnum
);
372 HRESULT WINAPI
IPinImpl_QueryInternalConnections(IPin
* iface
, IPin
** apPin
, ULONG
* cPin
)
374 IPinImpl
*This
= (IPinImpl
*)iface
;
376 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, apPin
, cPin
);
378 return E_NOTIMPL
; /* to tell caller that all input pins connected to all output pins */
381 /*** IPin implementation for an input pin ***/
383 HRESULT WINAPI
InputPin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
385 InputPin
*This
= (InputPin
*)iface
;
387 TRACE("(%p)->(%s, %p)\n", iface
, qzdebugstr_guid(riid
), ppv
);
391 if (IsEqualIID(riid
, &IID_IUnknown
))
392 *ppv
= (LPVOID
)iface
;
393 else if (IsEqualIID(riid
, &IID_IPin
))
394 *ppv
= (LPVOID
)iface
;
395 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
396 *ppv
= (LPVOID
)&This
->lpVtblMemInput
;
400 IUnknown_AddRef((IUnknown
*)(*ppv
));
404 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
406 return E_NOINTERFACE
;
409 ULONG WINAPI
InputPin_Release(IPin
* iface
)
411 InputPin
*This
= (InputPin
*)iface
;
412 ULONG refCount
= InterlockedDecrement(&This
->pin
.refCount
);
414 TRACE("(%p)->() Release from %d\n", iface
, refCount
+ 1);
418 FreeMediaType(&This
->pin
.mtCurrent
);
419 if (This
->pAllocator
)
420 IMemAllocator_Release(This
->pAllocator
);
428 HRESULT WINAPI
InputPin_Connect(IPin
* iface
, IPin
* pConnector
, const AM_MEDIA_TYPE
* pmt
)
430 ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector
, pmt
);
436 HRESULT WINAPI
InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
438 InputPin
*This
= (InputPin
*)iface
;
439 PIN_DIRECTION pindirReceive
;
442 TRACE("(%p, %p)\n", pReceivePin
, pmt
);
443 dump_AM_MEDIA_TYPE(pmt
);
445 EnterCriticalSection(This
->pin
.pCritSec
);
447 if (This
->pin
.pConnectedTo
)
448 hr
= VFW_E_ALREADY_CONNECTED
;
450 if (SUCCEEDED(hr
) && This
->pin
.fnQueryAccept(This
->pin
.pUserData
, pmt
) != S_OK
)
451 hr
= VFW_E_TYPE_NOT_ACCEPTED
; /* FIXME: shouldn't we just map common errors onto
452 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
456 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
458 if (pindirReceive
!= PINDIR_OUTPUT
)
460 ERR("Can't connect from non-output pin\n");
461 hr
= VFW_E_INVALID_DIRECTION
;
467 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
468 This
->pin
.pConnectedTo
= pReceivePin
;
469 IPin_AddRef(pReceivePin
);
472 LeaveCriticalSection(This
->pin
.pCritSec
);
477 HRESULT WINAPI
InputPin_EndOfStream(IPin
* iface
)
484 HRESULT WINAPI
InputPin_BeginFlush(IPin
* iface
)
490 HRESULT WINAPI
InputPin_EndFlush(IPin
* iface
)
496 HRESULT WINAPI
InputPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
498 InputPin
*This
= (InputPin
*)iface
;
500 TRACE("(%x%08x, %x%08x, %e)\n", (ULONG
)(tStart
>> 32), (ULONG
)tStart
, (ULONG
)(tStop
>> 32), (ULONG
)tStop
, dRate
);
502 This
->tStart
= tStart
;
509 static const IPinVtbl InputPin_Vtbl
=
511 InputPin_QueryInterface
,
515 InputPin_ReceiveConnection
,
517 IPinImpl_ConnectedTo
,
518 IPinImpl_ConnectionMediaType
,
519 IPinImpl_QueryPinInfo
,
520 IPinImpl_QueryDirection
,
522 IPinImpl_QueryAccept
,
523 IPinImpl_EnumMediaTypes
,
524 IPinImpl_QueryInternalConnections
,
525 InputPin_EndOfStream
,
531 /*** IMemInputPin implementation ***/
533 HRESULT WINAPI
MemInputPin_QueryInterface(IMemInputPin
* iface
, REFIID riid
, LPVOID
* ppv
)
535 InputPin
*This
= impl_from_IMemInputPin(iface
);
537 return IPin_QueryInterface((IPin
*)&This
->pin
, riid
, ppv
);
540 ULONG WINAPI
MemInputPin_AddRef(IMemInputPin
* iface
)
542 InputPin
*This
= impl_from_IMemInputPin(iface
);
544 return IPin_AddRef((IPin
*)&This
->pin
);
547 ULONG WINAPI
MemInputPin_Release(IMemInputPin
* iface
)
549 InputPin
*This
= impl_from_IMemInputPin(iface
);
551 return IPin_Release((IPin
*)&This
->pin
);
554 HRESULT WINAPI
MemInputPin_GetAllocator(IMemInputPin
* iface
, IMemAllocator
** ppAllocator
)
556 InputPin
*This
= impl_from_IMemInputPin(iface
);
558 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppAllocator
);
560 *ppAllocator
= This
->pAllocator
;
562 IMemAllocator_AddRef(*ppAllocator
);
564 return *ppAllocator
? S_OK
: VFW_E_NO_ALLOCATOR
;
567 HRESULT WINAPI
MemInputPin_NotifyAllocator(IMemInputPin
* iface
, IMemAllocator
* pAllocator
, BOOL bReadOnly
)
569 InputPin
*This
= impl_from_IMemInputPin(iface
);
571 TRACE("(%p/%p)->(%p, %d)\n", This
, iface
, pAllocator
, bReadOnly
);
573 if (This
->pAllocator
)
574 IMemAllocator_Release(This
->pAllocator
);
575 This
->pAllocator
= pAllocator
;
576 if (This
->pAllocator
)
577 IMemAllocator_AddRef(This
->pAllocator
);
582 HRESULT WINAPI
MemInputPin_GetAllocatorRequirements(IMemInputPin
* iface
, ALLOCATOR_PROPERTIES
* pProps
)
584 InputPin
*This
= impl_from_IMemInputPin(iface
);
586 TRACE("(%p/%p)->(%p)\n", This
, iface
, pProps
);
588 /* override this method if you have any specific requirements */
593 HRESULT WINAPI
MemInputPin_Receive(IMemInputPin
* iface
, IMediaSample
* pSample
)
595 InputPin
*This
= impl_from_IMemInputPin(iface
);
597 /* this trace commented out for performance reasons */
598 /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
600 return This
->fnSampleProc(This
->pin
.pUserData
, pSample
);
603 HRESULT WINAPI
MemInputPin_ReceiveMultiple(IMemInputPin
* iface
, IMediaSample
** pSamples
, long nSamples
, long *nSamplesProcessed
)
606 InputPin
*This
= impl_from_IMemInputPin(iface
);
608 TRACE("(%p/%p)->(%p, %ld, %p)\n", This
, iface
, pSamples
, nSamples
, nSamplesProcessed
);
610 for (*nSamplesProcessed
= 0; *nSamplesProcessed
< nSamples
; (*nSamplesProcessed
)++)
612 hr
= IMemInputPin_Receive(iface
, pSamples
[*nSamplesProcessed
]);
620 HRESULT WINAPI
MemInputPin_ReceiveCanBlock(IMemInputPin
* iface
)
622 InputPin
*This
= impl_from_IMemInputPin(iface
);
624 FIXME("(%p/%p)->()\n", This
, iface
);
626 /* FIXME: we should check whether any output pins will block */
631 static const IMemInputPinVtbl MemInputPin_Vtbl
=
633 MemInputPin_QueryInterface
,
636 MemInputPin_GetAllocator
,
637 MemInputPin_NotifyAllocator
,
638 MemInputPin_GetAllocatorRequirements
,
640 MemInputPin_ReceiveMultiple
,
641 MemInputPin_ReceiveCanBlock
644 HRESULT WINAPI
OutputPin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
646 OutputPin
*This
= (OutputPin
*)iface
;
648 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
652 if (IsEqualIID(riid
, &IID_IUnknown
))
653 *ppv
= (LPVOID
)iface
;
654 else if (IsEqualIID(riid
, &IID_IPin
))
655 *ppv
= (LPVOID
)iface
;
659 IUnknown_AddRef((IUnknown
*)(*ppv
));
663 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
665 return E_NOINTERFACE
;
668 ULONG WINAPI
OutputPin_Release(IPin
* iface
)
670 OutputPin
*This
= (OutputPin
*)iface
;
671 ULONG refCount
= InterlockedDecrement(&This
->pin
.refCount
);
673 TRACE("(%p)->() Release from %d\n", iface
, refCount
+ 1);
677 FreeMediaType(&This
->pin
.mtCurrent
);
684 HRESULT WINAPI
OutputPin_Connect(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
687 OutputPin
*This
= (OutputPin
*)iface
;
689 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
690 dump_AM_MEDIA_TYPE(pmt
);
692 /* If we try to connect to ourself, we will definitely deadlock.
693 * There are other cases where we could deadlock too, but this
694 * catches the obvious case */
695 assert(pReceivePin
!= iface
);
697 EnterCriticalSection(This
->pin
.pCritSec
);
699 /* if we have been a specific type to connect with, then we can either connect
700 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
701 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
))
702 hr
= This
->pConnectSpecific(iface
, pReceivePin
, pmt
);
705 /* negotiate media type */
707 IEnumMediaTypes
* pEnumCandidates
;
708 AM_MEDIA_TYPE
* pmtCandidate
; /* Candidate media type */
710 if (SUCCEEDED(hr
= IPin_EnumMediaTypes(iface
, &pEnumCandidates
)))
712 hr
= VFW_E_NO_ACCEPTABLE_TYPES
; /* Assume the worst, but set to S_OK if connected successfully */
714 /* try this filter's media types first */
715 while (S_OK
== IEnumMediaTypes_Next(pEnumCandidates
, 1, &pmtCandidate
, NULL
))
717 if (( !pmt
|| CompareMediaTypes(pmt
, pmtCandidate
, TRUE
) ) &&
718 (This
->pConnectSpecific(iface
, pReceivePin
, pmtCandidate
) == S_OK
))
721 CoTaskMemFree(pmtCandidate
);
724 CoTaskMemFree(pmtCandidate
);
726 IEnumMediaTypes_Release(pEnumCandidates
);
729 /* then try receiver filter's media types */
730 if (hr
!= S_OK
&& SUCCEEDED(hr
= IPin_EnumMediaTypes(pReceivePin
, &pEnumCandidates
))) /* if we haven't already connected successfully */
732 hr
= VFW_E_NO_ACCEPTABLE_TYPES
; /* Assume the worst, but set to S_OK if connected successfully */
734 while (S_OK
== IEnumMediaTypes_Next(pEnumCandidates
, 1, &pmtCandidate
, NULL
))
736 if (( !pmt
|| CompareMediaTypes(pmt
, pmtCandidate
, TRUE
) ) &&
737 (This
->pConnectSpecific(iface
, pReceivePin
, pmtCandidate
) == S_OK
))
740 CoTaskMemFree(pmtCandidate
);
743 CoTaskMemFree(pmtCandidate
);
745 IEnumMediaTypes_Release(pEnumCandidates
);
747 } /* if negotiate media type */
749 LeaveCriticalSection(This
->pin
.pCritSec
);
751 TRACE(" -- %x\n", hr
);
755 HRESULT WINAPI
OutputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
757 ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin
, pmt
);
762 HRESULT WINAPI
OutputPin_Disconnect(IPin
* iface
)
765 OutputPin
*This
= (OutputPin
*)iface
;
769 EnterCriticalSection(This
->pin
.pCritSec
);
771 if (This
->pMemInputPin
)
773 IMemInputPin_Release(This
->pMemInputPin
);
774 This
->pMemInputPin
= NULL
;
776 if (This
->pin
.pConnectedTo
)
778 IPin_Release(This
->pin
.pConnectedTo
);
779 This
->pin
.pConnectedTo
= NULL
;
785 LeaveCriticalSection(This
->pin
.pCritSec
);
790 HRESULT WINAPI
OutputPin_EndOfStream(IPin
* iface
)
794 /* not supposed to do anything in an output pin */
799 HRESULT WINAPI
OutputPin_BeginFlush(IPin
* iface
)
801 TRACE("(%p)->()\n", iface
);
803 /* not supposed to do anything in an output pin */
808 HRESULT WINAPI
OutputPin_EndFlush(IPin
* iface
)
810 TRACE("(%p)->()\n", iface
);
812 /* not supposed to do anything in an output pin */
817 HRESULT WINAPI
OutputPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
819 TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface
, (ULONG
)(tStart
>> 32), (ULONG
)tStart
, (ULONG
)(tStop
>> 32), (ULONG
)tStop
, dRate
);
821 /* not supposed to do anything in an output pin */
826 static const IPinVtbl OutputPin_Vtbl
=
828 OutputPin_QueryInterface
,
832 OutputPin_ReceiveConnection
,
833 OutputPin_Disconnect
,
834 IPinImpl_ConnectedTo
,
835 IPinImpl_ConnectionMediaType
,
836 IPinImpl_QueryPinInfo
,
837 IPinImpl_QueryDirection
,
839 IPinImpl_QueryAccept
,
840 IPinImpl_EnumMediaTypes
,
841 IPinImpl_QueryInternalConnections
,
842 OutputPin_EndOfStream
,
843 OutputPin_BeginFlush
,
848 HRESULT
OutputPin_GetDeliveryBuffer(OutputPin
* This
, IMediaSample
** ppSample
, REFERENCE_TIME
* tStart
, REFERENCE_TIME
* tStop
, DWORD dwFlags
)
852 TRACE("(%p, %p, %p, %x)\n", ppSample
, tStart
, tStop
, dwFlags
);
854 EnterCriticalSection(This
->pin
.pCritSec
);
856 if (!This
->pin
.pConnectedTo
)
857 hr
= VFW_E_NOT_CONNECTED
;
860 IMemAllocator
* pAlloc
= NULL
;
862 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pAlloc
);
865 hr
= IMemAllocator_GetBuffer(pAlloc
, ppSample
, tStart
, tStop
, dwFlags
);
868 hr
= IMediaSample_SetTime(*ppSample
, tStart
, tStop
);
871 IMemAllocator_Release(pAlloc
);
874 LeaveCriticalSection(This
->pin
.pCritSec
);
879 HRESULT
OutputPin_SendSample(OutputPin
* This
, IMediaSample
* pSample
)
882 IMemInputPin
* pMemConnected
= NULL
;
884 EnterCriticalSection(This
->pin
.pCritSec
);
886 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
887 hr
= VFW_E_NOT_CONNECTED
;
890 /* we don't have the lock held when using This->pMemInputPin,
891 * so we need to AddRef it to stop it being deleted while we are
893 pMemConnected
= This
->pMemInputPin
;
894 IMemInputPin_AddRef(pMemConnected
);
897 LeaveCriticalSection(This
->pin
.pCritSec
);
901 /* NOTE: if we are in a critical section when Receive is called
902 * then it causes some problems (most notably with the native Video
903 * Renderer) if we are re-entered for whatever reason */
904 hr
= IMemInputPin_Receive(pMemConnected
, pSample
);
905 IMemInputPin_Release(pMemConnected
);
911 HRESULT
OutputPin_DeliverNewSegment(OutputPin
* This
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
915 EnterCriticalSection(This
->pin
.pCritSec
);
917 if (!This
->pin
.pConnectedTo
)
918 hr
= VFW_E_NOT_CONNECTED
;
920 hr
= IPin_NewSegment(This
->pin
.pConnectedTo
, tStart
, tStop
, dRate
);
922 LeaveCriticalSection(This
->pin
.pCritSec
);
927 HRESULT
OutputPin_CommitAllocator(OutputPin
* This
)
931 TRACE("(%p)->()\n", This
);
933 EnterCriticalSection(This
->pin
.pCritSec
);
935 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
936 hr
= VFW_E_NOT_CONNECTED
;
939 IMemAllocator
* pAlloc
= NULL
;
941 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pAlloc
);
944 hr
= IMemAllocator_Commit(pAlloc
);
947 IMemAllocator_Release(pAlloc
);
950 LeaveCriticalSection(This
->pin
.pCritSec
);
955 HRESULT
OutputPin_DeliverDisconnect(OutputPin
* This
)
959 TRACE("(%p)->()\n", This
);
961 EnterCriticalSection(This
->pin
.pCritSec
);
963 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
964 hr
= VFW_E_NOT_CONNECTED
;
967 IMemAllocator
* pAlloc
= NULL
;
969 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pAlloc
);
972 hr
= IMemAllocator_Decommit(pAlloc
);
975 IMemAllocator_Release(pAlloc
);
978 hr
= IPin_Disconnect(This
->pin
.pConnectedTo
);
981 LeaveCriticalSection(This
->pin
.pCritSec
);
987 HRESULT
PullPin_Construct(const PIN_INFO
* pPinInfo
, SAMPLEPROC pSampleProc
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
993 if (pPinInfo
->dir
!= PINDIR_INPUT
)
995 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo
->dir
);
999 pPinImpl
= CoTaskMemAlloc(sizeof(*pPinImpl
));
1002 return E_OUTOFMEMORY
;
1004 if (SUCCEEDED(PullPin_Init(pPinInfo
, pSampleProc
, pUserData
, pQueryAccept
, pCritSec
, pPinImpl
)))
1006 pPinImpl
->pin
.lpVtbl
= &PullPin_Vtbl
;
1008 *ppPin
= (IPin
*)(&pPinImpl
->pin
.lpVtbl
);
1014 HRESULT
PullPin_Init(const PIN_INFO
* pPinInfo
, SAMPLEPROC pSampleProc
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, PullPin
* pPinImpl
)
1016 /* Common attributes */
1017 pPinImpl
->pin
.refCount
= 1;
1018 pPinImpl
->pin
.pConnectedTo
= NULL
;
1019 pPinImpl
->pin
.fnQueryAccept
= pQueryAccept
;
1020 pPinImpl
->pin
.pUserData
= pUserData
;
1021 pPinImpl
->pin
.pCritSec
= pCritSec
;
1022 Copy_PinInfo(&pPinImpl
->pin
.pinInfo
, pPinInfo
);
1023 ZeroMemory(&pPinImpl
->pin
.mtCurrent
, sizeof(AM_MEDIA_TYPE
));
1025 /* Input pin attributes */
1026 pPinImpl
->fnSampleProc
= pSampleProc
;
1027 pPinImpl
->fnPreConnect
= NULL
;
1028 pPinImpl
->pAlloc
= NULL
;
1029 pPinImpl
->pReader
= NULL
;
1030 pPinImpl
->hThread
= NULL
;
1031 pPinImpl
->hEventStateChanged
= CreateEventW(NULL
, FALSE
, TRUE
, NULL
);
1033 pPinImpl
->rtStart
= 0;
1034 pPinImpl
->rtStop
= ((LONGLONG
)0x7fffffff << 32) | 0xffffffff;
1039 HRESULT WINAPI
PullPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
1041 PIN_DIRECTION pindirReceive
;
1043 PullPin
*This
= (PullPin
*)iface
;
1045 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
1046 dump_AM_MEDIA_TYPE(pmt
);
1048 EnterCriticalSection(This
->pin
.pCritSec
);
1050 if (This
->pin
.pConnectedTo
)
1051 hr
= VFW_E_ALREADY_CONNECTED
;
1053 if (SUCCEEDED(hr
) && (This
->pin
.fnQueryAccept(This
->pin
.pUserData
, pmt
) != S_OK
))
1054 hr
= VFW_E_TYPE_NOT_ACCEPTED
; /* FIXME: shouldn't we just map common errors onto
1055 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1059 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
1061 if (pindirReceive
!= PINDIR_OUTPUT
)
1063 ERR("Can't connect from non-output pin\n");
1064 hr
= VFW_E_INVALID_DIRECTION
;
1070 hr
= IPin_QueryInterface(pReceivePin
, &IID_IAsyncReader
, (LPVOID
*)&This
->pReader
);
1075 ALLOCATOR_PROPERTIES props
;
1077 props
.cbBuffer
= 64 * 1024; /* 64k bytes */
1080 hr
= IAsyncReader_RequestAllocator(This
->pReader
, NULL
, &props
, &This
->pAlloc
);
1083 if (SUCCEEDED(hr
) && This
->fnPreConnect
)
1085 hr
= This
->fnPreConnect(iface
, pReceivePin
);
1090 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
1091 This
->pin
.pConnectedTo
= pReceivePin
;
1092 IPin_AddRef(pReceivePin
);
1095 LeaveCriticalSection(This
->pin
.pCritSec
);
1099 HRESULT WINAPI
PullPin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
1101 PullPin
*This
= (PullPin
*)iface
;
1103 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
1107 if (IsEqualIID(riid
, &IID_IUnknown
))
1108 *ppv
= (LPVOID
)iface
;
1109 else if (IsEqualIID(riid
, &IID_IPin
))
1110 *ppv
= (LPVOID
)iface
;
1114 IUnknown_AddRef((IUnknown
*)(*ppv
));
1118 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
1120 return E_NOINTERFACE
;
1123 ULONG WINAPI
PullPin_Release(IPin
* iface
)
1125 PullPin
*This
= (PullPin
*)iface
;
1126 ULONG refCount
= InterlockedDecrement(&This
->pin
.refCount
);
1128 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
1133 PullPin_StopProcessing(This
);
1135 IMemAllocator_Release(This
->pAlloc
);
1137 IAsyncReader_Release(This
->pReader
);
1138 CloseHandle(This
->hEventStateChanged
);
1139 CoTaskMemFree(This
);
1145 static DWORD WINAPI
PullPin_Thread_Main(LPVOID pv
)
1148 SleepEx(INFINITE
, TRUE
);
1151 static void CALLBACK
PullPin_Thread_Process(ULONG_PTR iface
)
1153 PullPin
*This
= (PullPin
*)iface
;
1156 REFERENCE_TIME rtCurrent
;
1157 ALLOCATOR_PROPERTIES allocProps
;
1159 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
1161 SetEvent(This
->hEventStateChanged
);
1163 hr
= IMemAllocator_GetProperties(This
->pAlloc
, &allocProps
);
1165 rtCurrent
= MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This
->rtStart
), allocProps
.cbAlign
));
1169 while (rtCurrent
< This
->rtStop
&& hr
== S_OK
)
1171 /* FIXME: to improve performance by quite a bit this should be changed
1172 * so that one sample is processed while one sample is fetched. However,
1173 * it is harder to debug so for the moment it will stay as it is */
1174 IMediaSample
* pSample
= NULL
;
1175 REFERENCE_TIME rtSampleStop
;
1178 TRACE("Process sample\n");
1180 hr
= IMemAllocator_GetBuffer(This
->pAlloc
, &pSample
, NULL
, NULL
, 0);
1184 rtSampleStop
= rtCurrent
+ MEDIATIME_FROM_BYTES(IMediaSample_GetSize(pSample
));
1185 if (rtSampleStop
> This
->rtStop
)
1186 rtSampleStop
= MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This
->rtStop
), allocProps
.cbAlign
));
1187 hr
= IMediaSample_SetTime(pSample
, &rtCurrent
, &rtSampleStop
);
1188 rtCurrent
= rtSampleStop
;
1192 hr
= IAsyncReader_Request(This
->pReader
, pSample
, (ULONG_PTR
)0);
1195 hr
= IAsyncReader_WaitForNext(This
->pReader
, 10000, &pSample
, &dwUser
);
1198 hr
= This
->fnSampleProc(This
->pin
.pUserData
, pSample
);
1200 ERR("Processing error: %x\n", hr
);
1203 IMediaSample_Release(pSample
);
1211 static void CALLBACK
PullPin_Thread_Stop(ULONG_PTR iface
)
1213 PullPin
*This
= (PullPin
*)iface
;
1215 TRACE("(%p/%p)->()\n", This
, (LPVOID
)iface
);
1217 EnterCriticalSection(This
->pin
.pCritSec
);
1221 CloseHandle(This
->hThread
);
1222 This
->hThread
= NULL
;
1223 if (FAILED(hr
= IMemAllocator_Decommit(This
->pAlloc
)))
1224 ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr
);
1226 LeaveCriticalSection(This
->pin
.pCritSec
);
1228 SetEvent(This
->hEventStateChanged
);
1233 HRESULT
PullPin_InitProcessing(PullPin
* This
)
1237 TRACE("(%p)->()\n", This
);
1239 assert(!This
->hThread
);
1241 /* if we are connected */
1244 EnterCriticalSection(This
->pin
.pCritSec
);
1247 assert(!This
->hThread
);
1249 This
->hThread
= CreateThread(NULL
, 0, PullPin_Thread_Main
, NULL
, 0, &dwThreadId
);
1251 hr
= HRESULT_FROM_WIN32(GetLastError());
1254 hr
= IMemAllocator_Commit(This
->pAlloc
);
1256 LeaveCriticalSection(This
->pin
.pCritSec
);
1259 TRACE(" -- %x\n", hr
);
1264 HRESULT
PullPin_StartProcessing(PullPin
* This
)
1266 /* if we are connected */
1267 TRACE("(%p)->()\n", This
);
1270 assert(This
->hThread
);
1272 ResetEvent(This
->hEventStateChanged
);
1274 if (!QueueUserAPC(PullPin_Thread_Process
, This
->hThread
, (ULONG_PTR
)This
))
1275 return HRESULT_FROM_WIN32(GetLastError());
1281 HRESULT
PullPin_PauseProcessing(PullPin
* This
)
1283 /* make the processing function exit its loop */
1289 HRESULT
PullPin_StopProcessing(PullPin
* This
)
1291 /* if we are connected */
1294 assert(This
->hThread
);
1296 ResetEvent(This
->hEventStateChanged
);
1298 PullPin_PauseProcessing(This
);
1300 if (!QueueUserAPC(PullPin_Thread_Stop
, This
->hThread
, (ULONG_PTR
)This
))
1301 return HRESULT_FROM_WIN32(GetLastError());
1307 HRESULT
PullPin_WaitForStateChange(PullPin
* This
, DWORD dwMilliseconds
)
1309 if (WaitForSingleObject(This
->hEventStateChanged
, dwMilliseconds
) == WAIT_TIMEOUT
)
1314 HRESULT
PullPin_Seek(PullPin
* This
, REFERENCE_TIME rtStart
, REFERENCE_TIME rtStop
)
1316 FIXME("(%p)->(%x%08x, %x%08x)\n", This
, (LONG
)(rtStart
>> 32), (LONG
)rtStart
, (LONG
)(rtStop
>> 32), (LONG
)rtStop
);
1318 PullPin_BeginFlush((IPin
*)This
);
1319 /* FIXME: need critical section? */
1320 This
->rtStart
= rtStart
;
1321 This
->rtStop
= rtStop
;
1322 PullPin_EndFlush((IPin
*)This
);
1327 HRESULT WINAPI
PullPin_EndOfStream(IPin
* iface
)
1329 FIXME("(%p)->()\n", iface
);
1333 HRESULT WINAPI
PullPin_BeginFlush(IPin
* iface
)
1335 FIXME("(%p)->()\n", iface
);
1339 HRESULT WINAPI
PullPin_EndFlush(IPin
* iface
)
1341 FIXME("(%p)->()\n", iface
);
1345 HRESULT WINAPI
PullPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
1347 FIXME("(%p)->(%s, %s, %g)\n", iface
, wine_dbgstr_longlong(tStart
), wine_dbgstr_longlong(tStop
), dRate
);
1351 static const IPinVtbl PullPin_Vtbl
=
1353 PullPin_QueryInterface
,
1357 PullPin_ReceiveConnection
,
1358 IPinImpl_Disconnect
,
1359 IPinImpl_ConnectedTo
,
1360 IPinImpl_ConnectionMediaType
,
1361 IPinImpl_QueryPinInfo
,
1362 IPinImpl_QueryDirection
,
1364 IPinImpl_QueryAccept
,
1365 IPinImpl_EnumMediaTypes
,
1366 IPinImpl_QueryInternalConnections
,
1367 PullPin_EndOfStream
,