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
32 #include "qcap_main.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(qcap
);
43 #define ALIGNDOWN(value,boundary) ((value) & ~(boundary-1))
44 #define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + boundary)
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 HRESULT WINAPI
IPinImpl_ConnectedTo(IPin
* iface
, IPin
** ppPin
)
60 IPinImpl
*This
= (IPinImpl
*)iface
;
62 /* TRACE("(%p)\n", ppPin);*/
64 EnterCriticalSection(This
->pCritSec
);
66 if (This
->pConnectedTo
)
68 *ppPin
= This
->pConnectedTo
;
73 hr
= VFW_E_NOT_CONNECTED
;
75 LeaveCriticalSection(This
->pCritSec
);
80 HRESULT WINAPI
IPinImpl_ConnectionMediaType(IPin
* iface
, AM_MEDIA_TYPE
* pmt
)
83 IPinImpl
*This
= (IPinImpl
*)iface
;
85 TRACE("(%p/%p)->(%p)\n", This
, iface
, pmt
);
87 EnterCriticalSection(This
->pCritSec
);
89 if (This
->pConnectedTo
)
91 CopyMediaType(pmt
, &This
->mtCurrent
);
96 ZeroMemory(pmt
, sizeof(*pmt
));
97 hr
= VFW_E_NOT_CONNECTED
;
100 LeaveCriticalSection(This
->pCritSec
);
105 HRESULT WINAPI
IPinImpl_QueryPinInfo(IPin
* iface
, PIN_INFO
* pInfo
)
107 IPinImpl
*This
= (IPinImpl
*)iface
;
109 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
111 Copy_PinInfo(pInfo
, &This
->pinInfo
);
112 IBaseFilter_AddRef(pInfo
->pFilter
);
117 HRESULT WINAPI
IPinImpl_QueryDirection(IPin
* iface
, PIN_DIRECTION
* pPinDir
)
119 IPinImpl
*This
= (IPinImpl
*)iface
;
121 TRACE("(%p/%p)->(%p)\n", This
, iface
, pPinDir
);
123 *pPinDir
= This
->pinInfo
.dir
;
128 HRESULT WINAPI
IPinImpl_QueryId(IPin
* iface
, LPWSTR
* Id
)
130 IPinImpl
*This
= (IPinImpl
*)iface
;
132 TRACE("(%p/%p)->(%p)\n", This
, iface
, Id
);
134 *Id
= CoTaskMemAlloc((strlenW(This
->pinInfo
.achName
) + 1) * sizeof(WCHAR
));
136 return E_OUTOFMEMORY
;
138 strcpyW(*Id
, This
->pinInfo
.achName
);
143 HRESULT WINAPI
IPinImpl_QueryAccept(IPin
* iface
, const AM_MEDIA_TYPE
* pmt
)
145 IPinImpl
*This
= (IPinImpl
*)iface
;
147 TRACE("(%p/%p)->(%p)\n", This
, iface
, pmt
);
149 if (!This
->fnQueryAccept
) return S_OK
;
151 return (This
->fnQueryAccept(This
->pUserData
, pmt
) == S_OK
? S_OK
: S_FALSE
);
154 HRESULT WINAPI
IPinImpl_QueryInternalConnections(IPin
* iface
, IPin
** apPin
, ULONG
* cPin
)
156 IPinImpl
*This
= (IPinImpl
*)iface
;
158 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, apPin
, cPin
);
160 return E_NOTIMPL
; /* to tell caller that all input pins connected to all output pins */
163 /* Function called as a helper to IPin_Connect */
164 /* specific AM_MEDIA_TYPE - it cannot be NULL */
165 /* NOTE: not part of standard interface */
166 static HRESULT
OutputPin_ConnectSpecific(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
168 OutputPin
*This
= (OutputPin
*)iface
;
170 IMemAllocator
* pMemAlloc
= NULL
;
171 ALLOCATOR_PROPERTIES actual
; /* FIXME: should we put the actual props back in to This? */
173 TRACE("(%p, %p)\n", pReceivePin
, pmt
);
174 dump_AM_MEDIA_TYPE(pmt
);
176 /* FIXME: call queryacceptproc */
178 This
->pin
.pConnectedTo
= pReceivePin
;
179 IPin_AddRef(pReceivePin
);
180 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
182 hr
= IPin_ReceiveConnection(pReceivePin
, iface
, pmt
);
184 /* get the IMemInputPin interface we will use to deliver samples to the
188 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (LPVOID
)&This
->pMemInputPin
);
191 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pMemAlloc
);
193 if (hr
== VFW_E_NO_ALLOCATOR
)
195 /* Input pin provides no allocator, use standard memory allocator */
196 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (LPVOID
*)&pMemAlloc
);
200 hr
= IMemInputPin_NotifyAllocator(This
->pMemInputPin
, pMemAlloc
, FALSE
);
205 hr
= IMemAllocator_SetProperties(pMemAlloc
, &This
->allocProps
, &actual
);
208 IMemAllocator_Release(pMemAlloc
);
210 /* break connection if we couldn't get the allocator */
212 IPin_Disconnect(pReceivePin
);
217 IPin_Release(This
->pin
.pConnectedTo
);
218 This
->pin
.pConnectedTo
= NULL
;
219 DeleteMediaType(&This
->pin
.mtCurrent
);
222 TRACE(" -- %x\n", hr
);
226 HRESULT
OutputPin_Init(const PIN_INFO
* pPinInfo
, const ALLOCATOR_PROPERTIES
* props
,
227 LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
,
228 LPCRITICAL_SECTION pCritSec
, OutputPin
* pPinImpl
)
232 /* Common attributes */
233 pPinImpl
->pin
.refCount
= 1;
234 pPinImpl
->pin
.pConnectedTo
= NULL
;
235 pPinImpl
->pin
.fnQueryAccept
= pQueryAccept
;
236 pPinImpl
->pin
.pUserData
= pUserData
;
237 pPinImpl
->pin
.pCritSec
= pCritSec
;
238 Copy_PinInfo(&pPinImpl
->pin
.pinInfo
, pPinInfo
);
240 /* Output pin attributes */
241 pPinImpl
->pMemInputPin
= NULL
;
242 pPinImpl
->pConnectSpecific
= OutputPin_ConnectSpecific
;
245 memcpy(&pPinImpl
->allocProps
, props
, sizeof(pPinImpl
->allocProps
));
246 if (pPinImpl
->allocProps
.cbAlign
== 0)
247 pPinImpl
->allocProps
.cbAlign
= 1;
250 ZeroMemory(&pPinImpl
->allocProps
, sizeof(pPinImpl
->allocProps
));
255 HRESULT WINAPI
OutputPin_Connect(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
258 OutputPin
*This
= (OutputPin
*)iface
;
260 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
261 dump_AM_MEDIA_TYPE(pmt
);
263 /* If we try to connect to ourself, we will definitely deadlock.
264 * There are other cases where we could deadlock too, but this
265 * catches the obvious case */
266 assert(pReceivePin
!= iface
);
268 EnterCriticalSection(This
->pin
.pCritSec
);
270 /* if we have been a specific type to connect with, then we can either connect
271 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
272 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
))
273 hr
= This
->pConnectSpecific(iface
, pReceivePin
, pmt
);
276 /* negotiate media type */
278 IEnumMediaTypes
* pEnumCandidates
;
279 AM_MEDIA_TYPE
* pmtCandidate
; /* Candidate media type */
281 if (SUCCEEDED(hr
= IPin_EnumMediaTypes(iface
, &pEnumCandidates
)))
283 hr
= VFW_E_NO_ACCEPTABLE_TYPES
; /* Assume the worst, but set to S_OK if connected successfully */
285 /* try this filter's media types first */
286 while (S_OK
== IEnumMediaTypes_Next(pEnumCandidates
, 1, &pmtCandidate
, NULL
))
288 if (( !pmt
|| CompareMediaTypes(pmt
, pmtCandidate
, TRUE
) ) &&
289 (This
->pConnectSpecific(iface
, pReceivePin
, pmtCandidate
) == S_OK
))
293 DeleteMediaType(pmtCandidate
);
296 DeleteMediaType(pmtCandidate
);
298 IEnumMediaTypes_Release(pEnumCandidates
);
301 /* then try receiver filter's media types */
302 if (hr
!= S_OK
&& SUCCEEDED(hr
= IPin_EnumMediaTypes(pReceivePin
, &pEnumCandidates
))) /* if we haven't already connected successfully */
304 hr
= VFW_E_NO_ACCEPTABLE_TYPES
; /* Assume the worst, but set to S_OK if connected successfully */
306 while (S_OK
== IEnumMediaTypes_Next(pEnumCandidates
, 1, &pmtCandidate
, NULL
))
308 if (( !pmt
|| CompareMediaTypes(pmt
, pmtCandidate
, TRUE
) ) &&
309 (This
->pConnectSpecific(iface
, pReceivePin
, pmtCandidate
) == S_OK
))
312 DeleteMediaType(pmtCandidate
);
315 DeleteMediaType(pmtCandidate
);
317 IEnumMediaTypes_Release(pEnumCandidates
);
319 } /* if negotiate media type */
321 LeaveCriticalSection(This
->pin
.pCritSec
);
323 TRACE(" -- %x\n", hr
);
327 HRESULT WINAPI
OutputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
329 ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin
, pmt
);
334 HRESULT WINAPI
OutputPin_Disconnect(IPin
* iface
)
337 OutputPin
*This
= (OutputPin
*)iface
;
341 EnterCriticalSection(This
->pin
.pCritSec
);
343 if (This
->pMemInputPin
)
345 IMemInputPin_Release(This
->pMemInputPin
);
346 This
->pMemInputPin
= NULL
;
348 if (This
->pin
.pConnectedTo
)
350 IPin_Release(This
->pin
.pConnectedTo
);
351 This
->pin
.pConnectedTo
= NULL
;
357 LeaveCriticalSection(This
->pin
.pCritSec
);
362 HRESULT
OutputPin_GetDeliveryBuffer(OutputPin
* This
, IMediaSample
** ppSample
, REFERENCE_TIME
* tStart
, REFERENCE_TIME
* tStop
, DWORD dwFlags
)
366 TRACE("(%p, %p, %p, %x)\n", ppSample
, tStart
, tStop
, dwFlags
);
368 EnterCriticalSection(This
->pin
.pCritSec
);
370 if (!This
->pin
.pConnectedTo
)
371 hr
= VFW_E_NOT_CONNECTED
;
374 IMemAllocator
* pAlloc
= NULL
;
376 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pAlloc
);
379 hr
= IMemAllocator_GetBuffer(pAlloc
, ppSample
, tStart
, tStop
, dwFlags
);
382 hr
= IMediaSample_SetTime(*ppSample
, tStart
, tStop
);
385 IMemAllocator_Release(pAlloc
);
388 LeaveCriticalSection(This
->pin
.pCritSec
);
393 HRESULT
OutputPin_SendSample(OutputPin
* This
, IMediaSample
* pSample
)
396 IMemInputPin
* pMemConnected
= NULL
;
398 EnterCriticalSection(This
->pin
.pCritSec
);
400 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
401 hr
= VFW_E_NOT_CONNECTED
;
404 /* we don't have the lock held when using This->pMemInputPin,
405 * so we need to AddRef it to stop it being deleted while we are
407 pMemConnected
= This
->pMemInputPin
;
408 IMemInputPin_AddRef(pMemConnected
);
411 LeaveCriticalSection(This
->pin
.pCritSec
);
415 /* NOTE: if we are in a critical section when Receive is called
416 * then it causes some problems (most notably with the native Video
417 * Renderer) if we are re-entered for whatever reason */
418 hr
= IMemInputPin_Receive(pMemConnected
, pSample
);
419 IMemInputPin_Release(pMemConnected
);