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 /* Function called as a helper to IPin_Connect */
155 /* specific AM_MEDIA_TYPE - it cannot be NULL */
156 /* NOTE: not part of standard interface */
157 static HRESULT
OutputPin_ConnectSpecific(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
159 OutputPin
*This
= (OutputPin
*)iface
;
161 IMemAllocator
* pMemAlloc
= NULL
;
162 ALLOCATOR_PROPERTIES actual
; /* FIXME: should we put the actual props back in to This? */
164 TRACE("(%p, %p)\n", pReceivePin
, pmt
);
165 dump_AM_MEDIA_TYPE(pmt
);
167 /* FIXME: call queryacceptproc */
169 This
->pin
.pConnectedTo
= pReceivePin
;
170 IPin_AddRef(pReceivePin
);
171 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
173 hr
= IPin_ReceiveConnection(pReceivePin
, iface
, pmt
);
175 /* get the IMemInputPin interface we will use to deliver samples to the
179 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (LPVOID
)&This
->pMemInputPin
);
182 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pMemAlloc
);
184 if (hr
== VFW_E_NO_ALLOCATOR
)
186 /* Input pin provides no allocator, use standard memory allocator */
187 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (LPVOID
*)&pMemAlloc
);
191 hr
= IMemInputPin_NotifyAllocator(This
->pMemInputPin
, pMemAlloc
, FALSE
);
196 hr
= IMemAllocator_SetProperties(pMemAlloc
, &This
->allocProps
, &actual
);
199 IMemAllocator_Release(pMemAlloc
);
201 /* break connection if we couldn't get the allocator */
203 IPin_Disconnect(pReceivePin
);
208 IPin_Release(This
->pin
.pConnectedTo
);
209 This
->pin
.pConnectedTo
= NULL
;
210 DeleteMediaType(&This
->pin
.mtCurrent
);
213 TRACE(" -- %x\n", hr
);
217 HRESULT
OutputPin_Init(const PIN_INFO
* pPinInfo
, const ALLOCATOR_PROPERTIES
* props
,
218 LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
,
219 LPCRITICAL_SECTION pCritSec
, OutputPin
* pPinImpl
)
223 /* Common attributes */
224 pPinImpl
->pin
.refCount
= 1;
225 pPinImpl
->pin
.pConnectedTo
= NULL
;
226 pPinImpl
->pin
.fnQueryAccept
= pQueryAccept
;
227 pPinImpl
->pin
.pUserData
= pUserData
;
228 pPinImpl
->pin
.pCritSec
= pCritSec
;
229 Copy_PinInfo(&pPinImpl
->pin
.pinInfo
, pPinInfo
);
231 /* Output pin attributes */
232 pPinImpl
->pMemInputPin
= NULL
;
233 pPinImpl
->pConnectSpecific
= OutputPin_ConnectSpecific
;
236 pPinImpl
->allocProps
= *props
;
237 if (pPinImpl
->allocProps
.cbAlign
== 0)
238 pPinImpl
->allocProps
.cbAlign
= 1;
241 ZeroMemory(&pPinImpl
->allocProps
, sizeof(pPinImpl
->allocProps
));
246 HRESULT WINAPI
OutputPin_Connect(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
249 OutputPin
*This
= (OutputPin
*)iface
;
251 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
252 dump_AM_MEDIA_TYPE(pmt
);
254 /* If we try to connect to ourself, we will definitely deadlock.
255 * There are other cases where we could deadlock too, but this
256 * catches the obvious case */
257 assert(pReceivePin
!= iface
);
259 EnterCriticalSection(This
->pin
.pCritSec
);
261 /* if we have been a specific type to connect with, then we can either connect
262 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
263 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
))
264 hr
= This
->pConnectSpecific(iface
, pReceivePin
, pmt
);
267 /* negotiate media type */
269 IEnumMediaTypes
* pEnumCandidates
;
270 AM_MEDIA_TYPE
* pmtCandidate
; /* Candidate media type */
272 if (SUCCEEDED(hr
= IPin_EnumMediaTypes(iface
, &pEnumCandidates
)))
274 hr
= VFW_E_NO_ACCEPTABLE_TYPES
; /* Assume the worst, but set to S_OK if connected successfully */
276 /* try this filter's media types first */
277 while (S_OK
== IEnumMediaTypes_Next(pEnumCandidates
, 1, &pmtCandidate
, NULL
))
279 if (( !pmt
|| CompareMediaTypes(pmt
, pmtCandidate
, TRUE
) ) &&
280 (This
->pConnectSpecific(iface
, pReceivePin
, pmtCandidate
) == S_OK
))
284 DeleteMediaType(pmtCandidate
);
287 DeleteMediaType(pmtCandidate
);
289 IEnumMediaTypes_Release(pEnumCandidates
);
292 /* then try receiver filter's media types */
293 if (hr
!= S_OK
&& SUCCEEDED(hr
= IPin_EnumMediaTypes(pReceivePin
, &pEnumCandidates
))) /* if we haven't already connected successfully */
295 hr
= VFW_E_NO_ACCEPTABLE_TYPES
; /* Assume the worst, but set to S_OK if connected successfully */
297 while (S_OK
== IEnumMediaTypes_Next(pEnumCandidates
, 1, &pmtCandidate
, NULL
))
299 if (( !pmt
|| CompareMediaTypes(pmt
, pmtCandidate
, TRUE
) ) &&
300 (This
->pConnectSpecific(iface
, pReceivePin
, pmtCandidate
) == S_OK
))
303 DeleteMediaType(pmtCandidate
);
306 DeleteMediaType(pmtCandidate
);
308 IEnumMediaTypes_Release(pEnumCandidates
);
310 } /* if negotiate media type */
312 LeaveCriticalSection(This
->pin
.pCritSec
);
314 TRACE(" -- %x\n", hr
);
318 HRESULT WINAPI
OutputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
320 ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin
, pmt
);
325 HRESULT WINAPI
OutputPin_Disconnect(IPin
* iface
)
328 OutputPin
*This
= (OutputPin
*)iface
;
332 EnterCriticalSection(This
->pin
.pCritSec
);
334 if (This
->pMemInputPin
)
336 IMemInputPin_Release(This
->pMemInputPin
);
337 This
->pMemInputPin
= NULL
;
339 if (This
->pin
.pConnectedTo
)
341 IPin_Release(This
->pin
.pConnectedTo
);
342 This
->pin
.pConnectedTo
= NULL
;
348 LeaveCriticalSection(This
->pin
.pCritSec
);
353 HRESULT
OutputPin_GetDeliveryBuffer(OutputPin
* This
, IMediaSample
** ppSample
, REFERENCE_TIME
* tStart
, REFERENCE_TIME
* tStop
, DWORD dwFlags
)
357 TRACE("(%p, %p, %p, %x)\n", ppSample
, tStart
, tStop
, dwFlags
);
359 EnterCriticalSection(This
->pin
.pCritSec
);
361 if (!This
->pin
.pConnectedTo
)
362 hr
= VFW_E_NOT_CONNECTED
;
365 IMemAllocator
* pAlloc
= NULL
;
367 hr
= IMemInputPin_GetAllocator(This
->pMemInputPin
, &pAlloc
);
370 hr
= IMemAllocator_GetBuffer(pAlloc
, ppSample
, tStart
, tStop
, dwFlags
);
373 hr
= IMediaSample_SetTime(*ppSample
, tStart
, tStop
);
376 IMemAllocator_Release(pAlloc
);
379 LeaveCriticalSection(This
->pin
.pCritSec
);
384 HRESULT
OutputPin_SendSample(OutputPin
* This
, IMediaSample
* pSample
)
387 IMemInputPin
* pMemConnected
= NULL
;
389 EnterCriticalSection(This
->pin
.pCritSec
);
391 if (!This
->pin
.pConnectedTo
|| !This
->pMemInputPin
)
392 hr
= VFW_E_NOT_CONNECTED
;
395 /* we don't have the lock held when using This->pMemInputPin,
396 * so we need to AddRef it to stop it being deleted while we are
398 pMemConnected
= This
->pMemInputPin
;
399 IMemInputPin_AddRef(pMemConnected
);
402 LeaveCriticalSection(This
->pin
.pCritSec
);
406 /* NOTE: if we are in a critical section when Receive is called
407 * then it causes some problems (most notably with the native Video
408 * Renderer) if we are re-entered for whatever reason */
409 hr
= IMemInputPin_Receive(pMemConnected
, pSample
);
410 IMemInputPin_Release(pMemConnected
);