2 * Generic Implementation of IPin Interface
4 * Copyright 2003 Robert Shearman
5 * Copyright 2010 Aric Stewart, CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "strmbase_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(strmbase
);
26 static const IMemInputPinVtbl MemInputPin_Vtbl
;
28 typedef HRESULT (*SendPinFunc
)( IPin
*to
, LPVOID arg
);
30 struct enum_media_types
32 IEnumMediaTypes IEnumMediaTypes_iface
;
35 unsigned int index
, count
;
36 struct strmbase_pin
*pin
;
39 static const IEnumMediaTypesVtbl enum_media_types_vtbl
;
41 static HRESULT
enum_media_types_create(struct strmbase_pin
*pin
, IEnumMediaTypes
**out
)
43 struct enum_media_types
*object
;
49 if (!(object
= heap_alloc_zero(sizeof(*object
))))
55 object
->IEnumMediaTypes_iface
.lpVtbl
= &enum_media_types_vtbl
;
58 IPin_AddRef(&pin
->IPin_iface
);
60 if (pin
->ops
->pin_get_media_type
)
62 while (pin
->ops
->pin_get_media_type(pin
, object
->count
, &mt
) == S_OK
)
69 TRACE("Created enumerator %p.\n", object
);
70 *out
= &object
->IEnumMediaTypes_iface
;
75 static struct enum_media_types
*impl_from_IEnumMediaTypes(IEnumMediaTypes
*iface
)
77 return CONTAINING_RECORD(iface
, struct enum_media_types
, IEnumMediaTypes_iface
);
80 static HRESULT WINAPI
enum_media_types_QueryInterface(IEnumMediaTypes
*iface
, REFIID iid
, void **out
)
82 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
84 if (IsEqualGUID(iid
, &IID_IUnknown
) || IsEqualGUID(iid
, &IID_IEnumMediaTypes
))
86 IEnumMediaTypes_AddRef(iface
);
91 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
96 static ULONG WINAPI
enum_media_types_AddRef(IEnumMediaTypes
*iface
)
98 struct enum_media_types
*enummt
= impl_from_IEnumMediaTypes(iface
);
99 ULONG refcount
= InterlockedIncrement(&enummt
->refcount
);
100 TRACE("%p increasing refcount to %u.\n", enummt
, refcount
);
104 static ULONG WINAPI
enum_media_types_Release(IEnumMediaTypes
*iface
)
106 struct enum_media_types
*enummt
= impl_from_IEnumMediaTypes(iface
);
107 ULONG refcount
= InterlockedDecrement(&enummt
->refcount
);
109 TRACE("%p decreasing refcount to %u.\n", enummt
, refcount
);
112 IPin_Release(&enummt
->pin
->IPin_iface
);
118 static HRESULT WINAPI
enum_media_types_Next(IEnumMediaTypes
*iface
, ULONG count
,
119 AM_MEDIA_TYPE
**mts
, ULONG
*ret_count
)
121 struct enum_media_types
*enummt
= impl_from_IEnumMediaTypes(iface
);
126 TRACE("enummt %p, count %u, mts %p, ret_count %p.\n", enummt
, count
, mts
, ret_count
);
128 if (!enummt
->pin
->ops
->pin_get_media_type
)
132 return count
? S_FALSE
: S_OK
;
135 for (i
= 0; i
< count
; ++i
)
137 hr
= enummt
->pin
->ops
->pin_get_media_type(enummt
->pin
, enummt
->index
+ i
, &mt
);
140 if ((mts
[i
] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
148 DeleteMediaType(mts
[i
]);
150 return E_OUTOFMEMORY
;
155 if (TRACE_ON(strmbase
))
157 TRACE("Returning media type %u:\n", enummt
->index
+ i
);
158 strmbase_dump_media_type(mts
[i
]);
162 if (count
!= 1 || ret_count
)
165 return i
== count
? S_OK
: S_FALSE
;
168 static HRESULT WINAPI
enum_media_types_Skip(IEnumMediaTypes
*iface
, ULONG count
)
170 struct enum_media_types
*enummt
= impl_from_IEnumMediaTypes(iface
);
172 TRACE("enummt %p, count %u.\n", enummt
, count
);
174 enummt
->index
+= count
;
176 return enummt
->index
> enummt
->count
? S_FALSE
: S_OK
;
179 static HRESULT WINAPI
enum_media_types_Reset(IEnumMediaTypes
*iface
)
181 struct enum_media_types
*enummt
= impl_from_IEnumMediaTypes(iface
);
184 TRACE("enummt %p.\n", enummt
);
187 if (enummt
->pin
->ops
->pin_get_media_type
)
189 while (enummt
->pin
->ops
->pin_get_media_type(enummt
->pin
, enummt
->count
, &mt
) == S_OK
)
201 static HRESULT WINAPI
enum_media_types_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**out
)
203 struct enum_media_types
*enummt
= impl_from_IEnumMediaTypes(iface
);
206 TRACE("enummt %p, out %p.\n", enummt
, out
);
208 if (FAILED(hr
= enum_media_types_create(enummt
->pin
, out
)))
210 return IEnumMediaTypes_Skip(*out
, enummt
->index
);
213 static const IEnumMediaTypesVtbl enum_media_types_vtbl
=
215 enum_media_types_QueryInterface
,
216 enum_media_types_AddRef
,
217 enum_media_types_Release
,
218 enum_media_types_Next
,
219 enum_media_types_Skip
,
220 enum_media_types_Reset
,
221 enum_media_types_Clone
,
224 static inline struct strmbase_pin
*impl_from_IPin(IPin
*iface
)
226 return CONTAINING_RECORD(iface
, struct strmbase_pin
, IPin_iface
);
229 /** Helper function, there are a lot of places where the error code is inherited
230 * The following rules apply:
232 * Return the first received error code (E_NOTIMPL is ignored)
233 * If no errors occur: return the first received non-error-code that isn't S_OK
235 static HRESULT
updatehres( HRESULT original
, HRESULT
new )
237 if (FAILED( original
) || new == E_NOTIMPL
)
240 if (FAILED( new ) || original
== S_OK
)
246 /** Sends a message from a pin further to other, similar pins
247 * fnMiddle is called on each pin found further on the stream.
248 * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source)
250 * If the pin given is an input pin, the message will be sent downstream to other input pins
251 * If the pin given is an output pin, the message will be sent upstream to other output pins
253 static HRESULT
SendFurther(struct strmbase_sink
*sink
, SendPinFunc func
, void *arg
)
255 struct strmbase_pin
*pin
;
259 for (i
= 0; (pin
= sink
->pin
.filter
->ops
->filter_get_pin(sink
->pin
.filter
, i
)); ++i
)
261 if (pin
->dir
== PINDIR_OUTPUT
&& pin
->peer
)
262 hr
= updatehres(hr
, func(pin
->peer
, arg
));
268 HRESULT
strmbase_pin_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*mt
)
270 return VFW_S_NO_MORE_ITEMS
;
273 static HRESULT WINAPI
pin_QueryInterface(IPin
*iface
, REFIID iid
, void **out
)
275 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
278 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
282 if (pin
->ops
->pin_query_interface
&& SUCCEEDED(hr
= pin
->ops
->pin_query_interface(pin
, iid
, out
)))
285 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IPin
))
289 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
290 return E_NOINTERFACE
;
293 IUnknown_AddRef((IUnknown
*)*out
);
297 static ULONG WINAPI
pin_AddRef(IPin
*iface
)
299 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
300 return IBaseFilter_AddRef(&pin
->filter
->IBaseFilter_iface
);
303 static ULONG WINAPI
pin_Release(IPin
*iface
)
305 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
306 return IBaseFilter_Release(&pin
->filter
->IBaseFilter_iface
);
309 static HRESULT WINAPI
pin_ConnectedTo(IPin
* iface
, IPin
** ppPin
)
311 struct strmbase_pin
*This
= impl_from_IPin(iface
);
314 TRACE("pin %p %s:%s, peer %p.\n", This
, debugstr_w(This
->filter
->name
), debugstr_w(This
->name
), ppPin
);
316 EnterCriticalSection(&This
->filter
->csFilter
);
326 hr
= VFW_E_NOT_CONNECTED
;
330 LeaveCriticalSection(&This
->filter
->csFilter
);
335 static HRESULT WINAPI
pin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*pmt
)
337 struct strmbase_pin
*This
= impl_from_IPin(iface
);
340 TRACE("pin %p %s:%s, pmt %p.\n", This
, debugstr_w(This
->filter
->name
), debugstr_w(This
->name
), pmt
);
342 EnterCriticalSection(&This
->filter
->csFilter
);
346 CopyMediaType(pmt
, &This
->mt
);
347 strmbase_dump_media_type(pmt
);
352 ZeroMemory(pmt
, sizeof(*pmt
));
353 hr
= VFW_E_NOT_CONNECTED
;
356 LeaveCriticalSection(&This
->filter
->csFilter
);
361 static HRESULT WINAPI
pin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
363 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
365 TRACE("pin %p %s:%s, info %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), info
);
367 info
->dir
= pin
->dir
;
368 IBaseFilter_AddRef(info
->pFilter
= &pin
->filter
->IBaseFilter_iface
);
369 lstrcpyW(info
->achName
, pin
->name
);
374 static HRESULT WINAPI
pin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
376 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
378 TRACE("pin %p %s:%s, dir %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), dir
);
385 static HRESULT WINAPI
pin_QueryId(IPin
*iface
, WCHAR
**id
)
387 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
389 TRACE("pin %p %s:%s, id %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), id
);
391 if (!(*id
= CoTaskMemAlloc((lstrlenW(pin
->name
) + 1) * sizeof(WCHAR
))))
392 return E_OUTOFMEMORY
;
394 lstrcpyW(*id
, pin
->name
);
399 static BOOL
query_accept(struct strmbase_pin
*pin
, const AM_MEDIA_TYPE
*mt
)
401 if (pin
->ops
->pin_query_accept
&& pin
->ops
->pin_query_accept(pin
, mt
) != S_OK
)
406 static HRESULT WINAPI
pin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mt
)
408 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
410 TRACE("pin %p %s:%s, mt %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), mt
);
411 strmbase_dump_media_type(mt
);
413 return query_accept(pin
, mt
) ? S_OK
: S_FALSE
;
416 static HRESULT WINAPI
pin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**enum_media_types
)
418 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
422 TRACE("pin %p %s:%s, enum_media_types %p.\n", pin
, debugstr_w(pin
->filter
->name
),
423 debugstr_w(pin
->name
), enum_media_types
);
425 if (pin
->ops
->pin_get_media_type
)
427 if (FAILED(hr
= pin
->ops
->pin_get_media_type(pin
, 0, &mt
)))
433 return enum_media_types_create(pin
, enum_media_types
);
436 static HRESULT WINAPI
pin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*count
)
438 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
440 TRACE("pin %p %s:%s, pins %p, count %p.\n", pin
, debugstr_w(pin
->filter
->name
),
441 debugstr_w(pin
->name
), pins
, count
);
443 return E_NOTIMPL
; /* to tell caller that all input pins connected to all output pins */
446 /*** OutputPin implementation ***/
448 static inline struct strmbase_source
*impl_source_from_IPin( IPin
*iface
)
450 return CONTAINING_RECORD(iface
, struct strmbase_source
, pin
.IPin_iface
);
453 static BOOL
compare_media_types(const AM_MEDIA_TYPE
*req_mt
, const AM_MEDIA_TYPE
*pin_mt
)
458 if (!IsEqualGUID(&req_mt
->majortype
, &pin_mt
->majortype
)
459 && !IsEqualGUID(&req_mt
->majortype
, &GUID_NULL
))
462 if (!IsEqualGUID(&req_mt
->subtype
, &pin_mt
->subtype
)
463 && !IsEqualGUID(&req_mt
->subtype
, &GUID_NULL
))
466 if (!IsEqualGUID(&req_mt
->formattype
, &pin_mt
->formattype
)
467 && !IsEqualGUID(&req_mt
->formattype
, &GUID_NULL
))
473 static HRESULT WINAPI
source_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
475 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
476 AM_MEDIA_TYPE candidate
, *candidate_ptr
;
477 IEnumMediaTypes
*enummt
;
483 TRACE("pin %p %s:%s, peer %p, mt %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
484 debugstr_w(pin
->pin
.name
), peer
, mt
);
485 strmbase_dump_media_type(mt
);
490 IPin_QueryDirection(peer
, &dir
);
491 if (dir
!= PINDIR_INPUT
)
493 WARN("Attempt to connect to another source pin, returning VFW_E_INVALID_DIRECTION.\n");
494 return VFW_E_INVALID_DIRECTION
;
497 EnterCriticalSection(&pin
->pin
.filter
->csFilter
);
501 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
502 WARN("Pin is already connected, returning VFW_E_ALREADY_CONNECTED.\n");
503 return VFW_E_ALREADY_CONNECTED
;
506 if (pin
->pin
.filter
->state
!= State_Stopped
)
508 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
509 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
510 return VFW_E_NOT_STOPPED
;
513 /* We don't check the subtype here. The rationale (as given by the DirectX
514 * documentation) is that the format type is supposed to provide at least
515 * as much information as the subtype. */
516 if (mt
&& !IsEqualGUID(&mt
->majortype
, &GUID_NULL
)
517 && !IsEqualGUID(&mt
->formattype
, &GUID_NULL
))
519 hr
= pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, mt
);
520 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
524 if (pin
->pFuncsTable
->base
.pin_get_media_type
)
526 for (i
= 0; pin
->pFuncsTable
->base
.pin_get_media_type(&pin
->pin
, i
, &candidate
) == S_OK
; ++i
)
528 strmbase_dump_media_type(&candidate
);
529 if (compare_media_types(mt
, &candidate
)
530 && pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, &candidate
) == S_OK
)
532 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
533 FreeMediaType(&candidate
);
536 FreeMediaType(&candidate
);
540 if (SUCCEEDED(IPin_EnumMediaTypes(peer
, &enummt
)))
542 while (IEnumMediaTypes_Next(enummt
, 1, &candidate_ptr
, &count
) == S_OK
)
544 if (compare_media_types(mt
, candidate_ptr
)
545 && pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, candidate_ptr
) == S_OK
)
547 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
548 DeleteMediaType(candidate_ptr
);
549 IEnumMediaTypes_Release(enummt
);
552 DeleteMediaType(candidate_ptr
);
555 IEnumMediaTypes_Release(enummt
);
558 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
560 return VFW_E_NO_ACCEPTABLE_TYPES
;
563 static HRESULT WINAPI
source_ReceiveConnection(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
565 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
567 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin
,
568 debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
), peer
, mt
);
573 static HRESULT WINAPI
source_Disconnect(IPin
*iface
)
576 struct strmbase_source
*This
= impl_source_from_IPin(iface
);
578 TRACE("pin %p %s:%s.\n", This
, debugstr_w(This
->pin
.filter
->name
), debugstr_w(This
->pin
.name
));
580 EnterCriticalSection(&This
->pin
.filter
->csFilter
);
582 if (This
->pin
.filter
->state
!= State_Stopped
)
584 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
585 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
586 return VFW_E_NOT_STOPPED
;
589 if (This
->pFuncsTable
->source_disconnect
)
590 This
->pFuncsTable
->source_disconnect(This
);
592 if (This
->pMemInputPin
)
594 IMemInputPin_Release(This
->pMemInputPin
);
595 This
->pMemInputPin
= NULL
;
598 if (This
->pAllocator
)
600 IMemAllocator_Release(This
->pAllocator
);
601 This
->pAllocator
= NULL
;
606 IPin_Release(This
->pin
.peer
);
607 This
->pin
.peer
= NULL
;
608 FreeMediaType(&This
->pin
.mt
);
609 ZeroMemory(&This
->pin
.mt
, sizeof(This
->pin
.mt
));
615 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
620 static HRESULT WINAPI
source_EndOfStream(IPin
*iface
)
622 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
624 WARN("pin %p %s:%s, unexpected call.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
626 /* not supposed to do anything in an output pin */
631 static HRESULT WINAPI
source_BeginFlush(IPin
*iface
)
633 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
635 WARN("pin %p %s:%s, unexpected call.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
637 /* not supposed to do anything in an output pin */
642 static HRESULT WINAPI
source_EndFlush(IPin
*iface
)
644 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
646 WARN("pin %p %s:%s, unexpected call.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
648 /* not supposed to do anything in an output pin */
653 static HRESULT WINAPI
source_NewSegment(IPin
* iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
655 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
657 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
658 debugstr_w(pin
->pin
.name
), debugstr_time(start
), debugstr_time(stop
), rate
);
663 static const IPinVtbl source_vtbl
=
669 source_ReceiveConnection
,
672 pin_ConnectionMediaType
,
678 pin_QueryInternalConnections
,
685 HRESULT WINAPI
BaseOutputPinImpl_GetDeliveryBuffer(struct strmbase_source
*This
,
686 IMediaSample
**ppSample
, REFERENCE_TIME
*tStart
, REFERENCE_TIME
*tStop
, DWORD dwFlags
)
690 TRACE("(%p)->(%p, %p, %p, %x)\n", This
, ppSample
, tStart
, tStop
, dwFlags
);
693 hr
= VFW_E_NOT_CONNECTED
;
696 hr
= IMemAllocator_GetBuffer(This
->pAllocator
, ppSample
, tStart
, tStop
, dwFlags
);
699 hr
= IMediaSample_SetTime(*ppSample
, tStart
, tStop
);
705 /* replaces OutputPin_CommitAllocator */
706 HRESULT WINAPI
BaseOutputPinImpl_Active(struct strmbase_source
*This
)
710 TRACE("(%p)->()\n", This
);
712 EnterCriticalSection(&This
->pin
.filter
->csFilter
);
714 if (!This
->pin
.peer
|| !This
->pMemInputPin
)
715 hr
= VFW_E_NOT_CONNECTED
;
717 hr
= IMemAllocator_Commit(This
->pAllocator
);
719 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
721 TRACE("--> %08x\n", hr
);
725 /* replaces OutputPin_DecommitAllocator */
726 HRESULT WINAPI
BaseOutputPinImpl_Inactive(struct strmbase_source
*This
)
730 TRACE("(%p)->()\n", This
);
732 EnterCriticalSection(&This
->pin
.filter
->csFilter
);
734 if (!This
->pin
.peer
|| !This
->pMemInputPin
)
735 hr
= VFW_E_NOT_CONNECTED
;
737 hr
= IMemAllocator_Decommit(This
->pAllocator
);
739 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
741 TRACE("--> %08x\n", hr
);
745 HRESULT WINAPI
BaseOutputPinImpl_InitAllocator(struct strmbase_source
*This
, IMemAllocator
**pMemAlloc
)
747 return CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (LPVOID
*)pMemAlloc
);
750 HRESULT WINAPI
BaseOutputPinImpl_DecideAllocator(struct strmbase_source
*This
,
751 IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
755 hr
= IMemInputPin_GetAllocator(pPin
, pAlloc
);
757 if (hr
== VFW_E_NO_ALLOCATOR
)
758 /* Input pin provides no allocator, use standard memory allocator */
759 hr
= BaseOutputPinImpl_InitAllocator(This
, pAlloc
);
763 ALLOCATOR_PROPERTIES rProps
;
764 ZeroMemory(&rProps
, sizeof(ALLOCATOR_PROPERTIES
));
766 IMemInputPin_GetAllocatorRequirements(pPin
, &rProps
);
767 hr
= This
->pFuncsTable
->pfnDecideBufferSize(This
, *pAlloc
, &rProps
);
771 hr
= IMemInputPin_NotifyAllocator(pPin
, *pAlloc
, FALSE
);
776 /*** The Construct functions ***/
778 /* Function called as a helper to IPin_Connect */
779 /* specific AM_MEDIA_TYPE - it cannot be NULL */
780 HRESULT WINAPI
BaseOutputPinImpl_AttemptConnection(struct strmbase_source
*This
,
781 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
784 IMemAllocator
* pMemAlloc
= NULL
;
786 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
788 if (!query_accept(&This
->pin
, pmt
))
789 return VFW_E_TYPE_NOT_ACCEPTED
;
791 This
->pin
.peer
= pReceivePin
;
792 IPin_AddRef(pReceivePin
);
793 CopyMediaType(&This
->pin
.mt
, pmt
);
795 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->pin
.IPin_iface
, pmt
);
797 /* get the IMemInputPin interface we will use to deliver samples to the
801 This
->pMemInputPin
= NULL
;
802 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (LPVOID
)&This
->pMemInputPin
);
806 hr
= This
->pFuncsTable
->pfnDecideAllocator(This
, This
->pMemInputPin
, &pMemAlloc
);
808 This
->pAllocator
= pMemAlloc
;
810 IMemAllocator_Release(pMemAlloc
);
813 /* break connection if we couldn't get the allocator */
816 if (This
->pMemInputPin
)
817 IMemInputPin_Release(This
->pMemInputPin
);
818 This
->pMemInputPin
= NULL
;
820 IPin_Disconnect(pReceivePin
);
826 IPin_Release(This
->pin
.peer
);
827 This
->pin
.peer
= NULL
;
828 FreeMediaType(&This
->pin
.mt
);
831 TRACE(" -- %x\n", hr
);
835 void strmbase_source_init(struct strmbase_source
*pin
, struct strmbase_filter
*filter
,
836 const WCHAR
*name
, const struct strmbase_source_ops
*func_table
)
838 memset(pin
, 0, sizeof(*pin
));
839 pin
->pin
.IPin_iface
.lpVtbl
= &source_vtbl
;
840 pin
->pin
.filter
= filter
;
841 pin
->pin
.dir
= PINDIR_OUTPUT
;
842 lstrcpyW(pin
->pin
.name
, name
);
843 pin
->pin
.ops
= &func_table
->base
;
844 pin
->pFuncsTable
= func_table
;
847 void strmbase_source_cleanup(struct strmbase_source
*pin
)
849 FreeMediaType(&pin
->pin
.mt
);
851 IMemAllocator_Release(pin
->pAllocator
);
852 pin
->pAllocator
= NULL
;
855 static struct strmbase_sink
*impl_sink_from_IPin(IPin
*iface
)
857 return CONTAINING_RECORD(iface
, struct strmbase_sink
, pin
.IPin_iface
);
860 static HRESULT WINAPI
sink_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
862 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
864 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin
, debugstr_w(pin
->pin
.name
),
865 debugstr_w(pin
->pin
.filter
->name
), peer
, mt
);
871 static HRESULT WINAPI
sink_ReceiveConnection(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
873 struct strmbase_sink
*This
= impl_sink_from_IPin(iface
);
874 PIN_DIRECTION pindirReceive
;
877 TRACE("pin %p %s:%s, peer %p, mt %p.\n", This
, debugstr_w(This
->pin
.filter
->name
),
878 debugstr_w(This
->pin
.name
), pReceivePin
, pmt
);
879 strmbase_dump_media_type(pmt
);
884 EnterCriticalSection(&This
->pin
.filter
->csFilter
);
886 if (This
->pin
.filter
->state
!= State_Stopped
)
888 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
889 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
890 return VFW_E_NOT_STOPPED
;
894 hr
= VFW_E_ALREADY_CONNECTED
;
896 if (SUCCEEDED(hr
) && !query_accept(&This
->pin
, pmt
))
897 hr
= VFW_E_TYPE_NOT_ACCEPTED
; /* FIXME: shouldn't we just map common errors onto
898 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
902 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
904 if (pindirReceive
!= PINDIR_OUTPUT
)
906 ERR("Can't connect from non-output pin\n");
907 hr
= VFW_E_INVALID_DIRECTION
;
911 if (SUCCEEDED(hr
) && This
->pFuncsTable
->sink_connect
)
912 hr
= This
->pFuncsTable
->sink_connect(This
, pReceivePin
, pmt
);
916 CopyMediaType(&This
->pin
.mt
, pmt
);
917 This
->pin
.peer
= pReceivePin
;
918 IPin_AddRef(pReceivePin
);
921 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
926 static HRESULT WINAPI
sink_Disconnect(IPin
*iface
)
928 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
931 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
933 EnterCriticalSection(&pin
->pin
.filter
->csFilter
);
937 if (pin
->pFuncsTable
->sink_disconnect
)
938 pin
->pFuncsTable
->sink_disconnect(pin
);
942 IMemAllocator_Release(pin
->pAllocator
);
943 pin
->pAllocator
= NULL
;
946 IPin_Release(pin
->pin
.peer
);
947 pin
->pin
.peer
= NULL
;
948 FreeMediaType(&pin
->pin
.mt
);
949 memset(&pin
->pin
.mt
, 0, sizeof(AM_MEDIA_TYPE
));
955 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
960 static HRESULT
deliver_endofstream(IPin
* pin
, LPVOID unused
)
962 return IPin_EndOfStream( pin
);
965 static HRESULT WINAPI
sink_EndOfStream(IPin
*iface
)
967 struct strmbase_sink
*This
= impl_sink_from_IPin(iface
);
970 TRACE("pin %p %s:%s.\n", This
, debugstr_w(This
->pin
.filter
->name
), debugstr_w(This
->pin
.name
));
972 if (This
->pFuncsTable
->sink_eos
)
973 return This
->pFuncsTable
->sink_eos(This
);
975 EnterCriticalSection(&This
->pin
.filter
->csFilter
);
978 LeaveCriticalSection(&This
->pin
.filter
->csFilter
);
981 hr
= SendFurther(This
, deliver_endofstream
, NULL
);
985 static HRESULT
deliver_beginflush(IPin
* pin
, LPVOID unused
)
987 return IPin_BeginFlush( pin
);
990 static HRESULT WINAPI
sink_BeginFlush(IPin
*iface
)
992 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
995 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
997 EnterCriticalSection(&pin
->pin
.filter
->csFilter
);
999 pin
->flushing
= TRUE
;
1001 if (pin
->pFuncsTable
->sink_begin_flush
)
1002 hr
= pin
->pFuncsTable
->sink_begin_flush(pin
);
1004 hr
= SendFurther(pin
, deliver_beginflush
, NULL
);
1006 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
1011 static HRESULT
deliver_endflush(IPin
* pin
, LPVOID unused
)
1013 return IPin_EndFlush( pin
);
1016 static HRESULT WINAPI
sink_EndFlush(IPin
* iface
)
1018 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
1021 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
1023 EnterCriticalSection(&pin
->pin
.filter
->csFilter
);
1025 pin
->flushing
= FALSE
;
1027 if (pin
->pFuncsTable
->sink_end_flush
)
1028 hr
= pin
->pFuncsTable
->sink_end_flush(pin
);
1030 hr
= SendFurther(pin
, deliver_endflush
, NULL
);
1032 LeaveCriticalSection(&pin
->pin
.filter
->csFilter
);
1037 typedef struct newsegmentargs
1039 REFERENCE_TIME tStart
, tStop
;
1043 static HRESULT
deliver_newsegment(IPin
*pin
, LPVOID data
)
1045 newsegmentargs
*args
= data
;
1046 return IPin_NewSegment(pin
, args
->tStart
, args
->tStop
, args
->rate
);
1049 static HRESULT WINAPI
sink_NewSegment(IPin
*iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
1051 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
1052 newsegmentargs args
;
1054 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1055 debugstr_w(pin
->pin
.name
), debugstr_time(start
), debugstr_time(stop
), rate
);
1057 if (pin
->pFuncsTable
->sink_new_segment
)
1058 return pin
->pFuncsTable
->sink_new_segment(pin
, start
, stop
, rate
);
1060 args
.tStart
= start
;
1064 return SendFurther(pin
, deliver_newsegment
, &args
);
1067 static const IPinVtbl sink_vtbl
=
1073 sink_ReceiveConnection
,
1076 pin_ConnectionMediaType
,
1082 pin_QueryInternalConnections
,
1089 /*** IMemInputPin implementation ***/
1091 static inline struct strmbase_sink
*impl_from_IMemInputPin(IMemInputPin
*iface
)
1093 return CONTAINING_RECORD(iface
, struct strmbase_sink
, IMemInputPin_iface
);
1096 static HRESULT WINAPI
MemInputPin_QueryInterface(IMemInputPin
* iface
, REFIID riid
, LPVOID
* ppv
)
1098 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1100 return IPin_QueryInterface(&This
->pin
.IPin_iface
, riid
, ppv
);
1103 static ULONG WINAPI
MemInputPin_AddRef(IMemInputPin
* iface
)
1105 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1107 return IPin_AddRef(&This
->pin
.IPin_iface
);
1110 static ULONG WINAPI
MemInputPin_Release(IMemInputPin
* iface
)
1112 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1114 return IPin_Release(&This
->pin
.IPin_iface
);
1117 static HRESULT WINAPI
MemInputPin_GetAllocator(IMemInputPin
* iface
, IMemAllocator
** ppAllocator
)
1119 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1121 TRACE("pin %p %s:%s, allocator %p.\n", This
, debugstr_w(This
->pin
.filter
->name
),
1122 debugstr_w(This
->pin
.name
), ppAllocator
);
1124 *ppAllocator
= This
->pAllocator
;
1126 IMemAllocator_AddRef(*ppAllocator
);
1128 return *ppAllocator
? S_OK
: VFW_E_NO_ALLOCATOR
;
1131 static HRESULT WINAPI
MemInputPin_NotifyAllocator(IMemInputPin
* iface
, IMemAllocator
* pAllocator
, BOOL bReadOnly
)
1133 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1135 TRACE("pin %p %s:%s, allocator %p, read_only %d.\n", This
, debugstr_w(This
->pin
.filter
->name
),
1136 debugstr_w(This
->pin
.name
), pAllocator
, bReadOnly
);
1139 FIXME("Read only flag not handled yet!\n");
1141 /* FIXME: Should we release the allocator on disconnection? */
1144 WARN("Null allocator\n");
1148 if (This
->preferred_allocator
&& pAllocator
!= This
->preferred_allocator
)
1151 if (This
->pAllocator
)
1152 IMemAllocator_Release(This
->pAllocator
);
1153 This
->pAllocator
= pAllocator
;
1154 if (This
->pAllocator
)
1155 IMemAllocator_AddRef(This
->pAllocator
);
1160 static HRESULT WINAPI
MemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
1162 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1164 TRACE("pin %p %s:%s, props %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1165 debugstr_w(pin
->pin
.name
), props
);
1167 /* override this method if you have any specific requirements */
1172 static HRESULT WINAPI
MemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
1174 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1175 HRESULT hr
= S_FALSE
;
1177 TRACE("pin %p %s:%s, sample %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1178 debugstr_w(pin
->pin
.name
), sample
);
1180 if (pin
->pFuncsTable
->pfnReceive
)
1181 hr
= pin
->pFuncsTable
->pfnReceive(pin
, sample
);
1185 static HRESULT WINAPI
MemInputPin_ReceiveMultiple(IMemInputPin
* iface
, IMediaSample
** pSamples
, LONG nSamples
, LONG
*nSamplesProcessed
)
1189 for (*nSamplesProcessed
= 0; *nSamplesProcessed
< nSamples
; (*nSamplesProcessed
)++)
1191 hr
= IMemInputPin_Receive(iface
, pSamples
[*nSamplesProcessed
]);
1199 static HRESULT WINAPI
MemInputPin_ReceiveCanBlock(IMemInputPin
* iface
)
1201 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1203 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
1208 static const IMemInputPinVtbl MemInputPin_Vtbl
=
1210 MemInputPin_QueryInterface
,
1212 MemInputPin_Release
,
1213 MemInputPin_GetAllocator
,
1214 MemInputPin_NotifyAllocator
,
1215 MemInputPin_GetAllocatorRequirements
,
1216 MemInputPin_Receive
,
1217 MemInputPin_ReceiveMultiple
,
1218 MemInputPin_ReceiveCanBlock
1221 void strmbase_sink_init(struct strmbase_sink
*pin
, struct strmbase_filter
*filter
,
1222 const WCHAR
*name
, const struct strmbase_sink_ops
*func_table
, IMemAllocator
*allocator
)
1224 memset(pin
, 0, sizeof(*pin
));
1225 pin
->pin
.IPin_iface
.lpVtbl
= &sink_vtbl
;
1226 pin
->pin
.filter
= filter
;
1227 pin
->pin
.dir
= PINDIR_INPUT
;
1228 lstrcpyW(pin
->pin
.name
, name
);
1229 pin
->pin
.ops
= &func_table
->base
;
1230 pin
->pFuncsTable
= func_table
;
1231 pin
->pAllocator
= pin
->preferred_allocator
= allocator
;
1232 if (pin
->preferred_allocator
)
1233 IMemAllocator_AddRef(pin
->preferred_allocator
);
1234 pin
->IMemInputPin_iface
.lpVtbl
= &MemInputPin_Vtbl
;
1237 void strmbase_sink_cleanup(struct strmbase_sink
*pin
)
1239 FreeMediaType(&pin
->pin
.mt
);
1240 if (pin
->pAllocator
)
1241 IMemAllocator_Release(pin
->pAllocator
);
1242 pin
->pAllocator
= NULL
;
1243 pin
->pin
.IPin_iface
.lpVtbl
= NULL
;