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(quartz
);
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 %lu.\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 %lu.\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 %lu, 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(quartz
))
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 %lu.\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 static HRESULT WINAPI
pin_QueryInterface(IPin
*iface
, REFIID iid
, void **out
)
270 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
273 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
277 if (pin
->ops
->pin_query_interface
&& SUCCEEDED(hr
= pin
->ops
->pin_query_interface(pin
, iid
, out
)))
280 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_IPin
))
284 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
285 return E_NOINTERFACE
;
288 IUnknown_AddRef((IUnknown
*)*out
);
292 static ULONG WINAPI
pin_AddRef(IPin
*iface
)
294 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
295 return IBaseFilter_AddRef(&pin
->filter
->IBaseFilter_iface
);
298 static ULONG WINAPI
pin_Release(IPin
*iface
)
300 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
301 return IBaseFilter_Release(&pin
->filter
->IBaseFilter_iface
);
304 static HRESULT WINAPI
pin_ConnectedTo(IPin
* iface
, IPin
** ppPin
)
306 struct strmbase_pin
*This
= impl_from_IPin(iface
);
309 TRACE("pin %p %s:%s, peer %p.\n", This
, debugstr_w(This
->filter
->name
), debugstr_w(This
->name
), ppPin
);
311 EnterCriticalSection(&This
->filter
->filter_cs
);
321 hr
= VFW_E_NOT_CONNECTED
;
325 LeaveCriticalSection(&This
->filter
->filter_cs
);
330 static HRESULT WINAPI
pin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*pmt
)
332 struct strmbase_pin
*This
= impl_from_IPin(iface
);
335 TRACE("pin %p %s:%s, pmt %p.\n", This
, debugstr_w(This
->filter
->name
), debugstr_w(This
->name
), pmt
);
337 EnterCriticalSection(&This
->filter
->filter_cs
);
341 CopyMediaType(pmt
, &This
->mt
);
342 strmbase_dump_media_type(pmt
);
347 ZeroMemory(pmt
, sizeof(*pmt
));
348 hr
= VFW_E_NOT_CONNECTED
;
351 LeaveCriticalSection(&This
->filter
->filter_cs
);
356 static HRESULT WINAPI
pin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
358 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
360 TRACE("pin %p %s:%s, info %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), info
);
362 info
->dir
= pin
->dir
;
363 IBaseFilter_AddRef(info
->pFilter
= &pin
->filter
->IBaseFilter_iface
);
364 lstrcpyW(info
->achName
, pin
->name
);
369 static HRESULT WINAPI
pin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
371 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
373 TRACE("pin %p %s:%s, dir %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), dir
);
380 static HRESULT WINAPI
pin_QueryId(IPin
*iface
, WCHAR
**id
)
382 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
384 TRACE("pin %p %s:%s, id %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), id
);
386 if (!(*id
= CoTaskMemAlloc((lstrlenW(pin
->id
) + 1) * sizeof(WCHAR
))))
387 return E_OUTOFMEMORY
;
389 lstrcpyW(*id
, pin
->id
);
394 static BOOL
query_accept(struct strmbase_pin
*pin
, const AM_MEDIA_TYPE
*mt
)
396 if (pin
->ops
->pin_query_accept
&& pin
->ops
->pin_query_accept(pin
, mt
) != S_OK
)
401 static HRESULT WINAPI
pin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mt
)
403 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
405 TRACE("pin %p %s:%s, mt %p.\n", pin
, debugstr_w(pin
->filter
->name
), debugstr_w(pin
->name
), mt
);
406 strmbase_dump_media_type(mt
);
408 return query_accept(pin
, mt
) ? S_OK
: S_FALSE
;
411 static HRESULT WINAPI
pin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**enum_media_types
)
413 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
417 TRACE("pin %p %s:%s, enum_media_types %p.\n", pin
, debugstr_w(pin
->filter
->name
),
418 debugstr_w(pin
->name
), enum_media_types
);
420 if (pin
->ops
->pin_get_media_type
)
422 if (FAILED(hr
= pin
->ops
->pin_get_media_type(pin
, 0, &mt
)))
428 return enum_media_types_create(pin
, enum_media_types
);
431 static HRESULT WINAPI
pin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*count
)
433 struct strmbase_pin
*pin
= impl_from_IPin(iface
);
435 TRACE("pin %p %s:%s, pins %p, count %p.\n", pin
, debugstr_w(pin
->filter
->name
),
436 debugstr_w(pin
->name
), pins
, count
);
438 return E_NOTIMPL
; /* to tell caller that all input pins connected to all output pins */
441 /*** OutputPin implementation ***/
443 static inline struct strmbase_source
*impl_source_from_IPin( IPin
*iface
)
445 return CONTAINING_RECORD(iface
, struct strmbase_source
, pin
.IPin_iface
);
448 static BOOL
compare_media_types(const AM_MEDIA_TYPE
*req_mt
, const AM_MEDIA_TYPE
*pin_mt
)
453 if (!IsEqualGUID(&req_mt
->majortype
, &pin_mt
->majortype
)
454 && !IsEqualGUID(&req_mt
->majortype
, &GUID_NULL
))
457 if (!IsEqualGUID(&req_mt
->subtype
, &pin_mt
->subtype
)
458 && !IsEqualGUID(&req_mt
->subtype
, &GUID_NULL
))
461 if (!IsEqualGUID(&req_mt
->formattype
, &pin_mt
->formattype
)
462 && !IsEqualGUID(&req_mt
->formattype
, &GUID_NULL
))
468 static HRESULT WINAPI
source_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
470 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
471 AM_MEDIA_TYPE candidate
, *candidate_ptr
;
472 IEnumMediaTypes
*enummt
;
478 TRACE("pin %p %s:%s, peer %p, mt %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
479 debugstr_w(pin
->pin
.name
), peer
, mt
);
480 strmbase_dump_media_type(mt
);
485 IPin_QueryDirection(peer
, &dir
);
486 if (dir
!= PINDIR_INPUT
)
488 WARN("Attempt to connect to another source pin, returning VFW_E_INVALID_DIRECTION.\n");
489 return VFW_E_INVALID_DIRECTION
;
492 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
496 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
497 WARN("Pin is already connected, returning VFW_E_ALREADY_CONNECTED.\n");
498 return VFW_E_ALREADY_CONNECTED
;
501 if (pin
->pin
.filter
->state
!= State_Stopped
)
503 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
504 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
505 return VFW_E_NOT_STOPPED
;
508 /* We don't check the subtype here. The rationale (as given by the DirectX
509 * documentation) is that the format type is supposed to provide at least
510 * as much information as the subtype. */
511 if (mt
&& !IsEqualGUID(&mt
->majortype
, &GUID_NULL
)
512 && !IsEqualGUID(&mt
->formattype
, &GUID_NULL
))
514 hr
= pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, mt
);
515 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
519 if (SUCCEEDED(IPin_EnumMediaTypes(peer
, &enummt
)))
521 while (IEnumMediaTypes_Next(enummt
, 1, &candidate_ptr
, &count
) == S_OK
)
523 if (compare_media_types(mt
, candidate_ptr
)
524 && pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, candidate_ptr
) == S_OK
)
526 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
527 DeleteMediaType(candidate_ptr
);
528 IEnumMediaTypes_Release(enummt
);
531 DeleteMediaType(candidate_ptr
);
534 IEnumMediaTypes_Release(enummt
);
537 if (pin
->pFuncsTable
->base
.pin_get_media_type
)
539 for (i
= 0; pin
->pFuncsTable
->base
.pin_get_media_type(&pin
->pin
, i
, &candidate
) == S_OK
; ++i
)
541 strmbase_dump_media_type(&candidate
);
542 if (compare_media_types(mt
, &candidate
)
543 && pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, &candidate
) == S_OK
)
545 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
546 FreeMediaType(&candidate
);
549 FreeMediaType(&candidate
);
553 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
555 return VFW_E_NO_ACCEPTABLE_TYPES
;
558 static HRESULT WINAPI
source_ReceiveConnection(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
560 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
562 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin
,
563 debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
), peer
, mt
);
568 static HRESULT WINAPI
source_Disconnect(IPin
*iface
)
571 struct strmbase_source
*This
= impl_source_from_IPin(iface
);
573 TRACE("pin %p %s:%s.\n", This
, debugstr_w(This
->pin
.filter
->name
), debugstr_w(This
->pin
.name
));
575 EnterCriticalSection(&This
->pin
.filter
->filter_cs
);
577 if (This
->pin
.filter
->state
!= State_Stopped
)
579 LeaveCriticalSection(&This
->pin
.filter
->filter_cs
);
580 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
581 return VFW_E_NOT_STOPPED
;
584 if (This
->pFuncsTable
->source_disconnect
)
585 This
->pFuncsTable
->source_disconnect(This
);
587 if (This
->pMemInputPin
)
589 IMemInputPin_Release(This
->pMemInputPin
);
590 This
->pMemInputPin
= NULL
;
593 if (This
->pAllocator
)
595 IMemAllocator_Release(This
->pAllocator
);
596 This
->pAllocator
= NULL
;
601 IPin_Release(This
->pin
.peer
);
602 This
->pin
.peer
= NULL
;
603 FreeMediaType(&This
->pin
.mt
);
604 ZeroMemory(&This
->pin
.mt
, sizeof(This
->pin
.mt
));
610 LeaveCriticalSection(&This
->pin
.filter
->filter_cs
);
615 static HRESULT WINAPI
source_EndOfStream(IPin
*iface
)
617 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
619 WARN("pin %p %s:%s, unexpected call.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
621 /* not supposed to do anything in an output pin */
626 static HRESULT WINAPI
source_BeginFlush(IPin
*iface
)
628 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
630 WARN("pin %p %s:%s, unexpected call.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
632 /* not supposed to do anything in an output pin */
637 static HRESULT WINAPI
source_EndFlush(IPin
*iface
)
639 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
641 WARN("pin %p %s:%s, unexpected call.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
643 /* not supposed to do anything in an output pin */
648 static HRESULT WINAPI
source_NewSegment(IPin
* iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
650 struct strmbase_source
*pin
= impl_source_from_IPin(iface
);
652 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
653 debugstr_w(pin
->pin
.name
), debugstr_time(start
), debugstr_time(stop
), rate
);
658 static const IPinVtbl source_vtbl
=
664 source_ReceiveConnection
,
667 pin_ConnectionMediaType
,
673 pin_QueryInternalConnections
,
680 HRESULT WINAPI
BaseOutputPinImpl_DecideAllocator(struct strmbase_source
*This
,
681 IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
685 hr
= IMemInputPin_GetAllocator(pPin
, pAlloc
);
687 if (hr
== VFW_E_NO_ALLOCATOR
)
688 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
,
689 CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (void **)pAlloc
);
693 ALLOCATOR_PROPERTIES rProps
;
694 ZeroMemory(&rProps
, sizeof(ALLOCATOR_PROPERTIES
));
696 IMemInputPin_GetAllocatorRequirements(pPin
, &rProps
);
697 hr
= This
->pFuncsTable
->pfnDecideBufferSize(This
, *pAlloc
, &rProps
);
701 hr
= IMemInputPin_NotifyAllocator(pPin
, *pAlloc
, FALSE
);
706 /*** The Construct functions ***/
708 /* Function called as a helper to IPin_Connect */
709 /* specific AM_MEDIA_TYPE - it cannot be NULL */
710 HRESULT WINAPI
BaseOutputPinImpl_AttemptConnection(struct strmbase_source
*This
,
711 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
714 IMemAllocator
* pMemAlloc
= NULL
;
716 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
718 if (!query_accept(&This
->pin
, pmt
))
719 return VFW_E_TYPE_NOT_ACCEPTED
;
721 This
->pin
.peer
= pReceivePin
;
722 IPin_AddRef(pReceivePin
);
723 CopyMediaType(&This
->pin
.mt
, pmt
);
725 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->pin
.IPin_iface
, pmt
);
727 /* get the IMemInputPin interface we will use to deliver samples to the
731 This
->pMemInputPin
= NULL
;
732 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (LPVOID
)&This
->pMemInputPin
);
736 hr
= This
->pFuncsTable
->pfnDecideAllocator(This
, This
->pMemInputPin
, &pMemAlloc
);
738 This
->pAllocator
= pMemAlloc
;
740 IMemAllocator_Release(pMemAlloc
);
743 /* break connection if we couldn't get the allocator */
746 if (This
->pMemInputPin
)
747 IMemInputPin_Release(This
->pMemInputPin
);
748 This
->pMemInputPin
= NULL
;
750 IPin_Disconnect(pReceivePin
);
756 IPin_Release(This
->pin
.peer
);
757 This
->pin
.peer
= NULL
;
758 FreeMediaType(&This
->pin
.mt
);
761 TRACE("Returning %#lx.\n", hr
);
765 void strmbase_source_init(struct strmbase_source
*pin
, struct strmbase_filter
*filter
,
766 const WCHAR
*name
, const struct strmbase_source_ops
*func_table
)
768 memset(pin
, 0, sizeof(*pin
));
769 pin
->pin
.IPin_iface
.lpVtbl
= &source_vtbl
;
770 pin
->pin
.filter
= filter
;
771 pin
->pin
.dir
= PINDIR_OUTPUT
;
772 lstrcpyW(pin
->pin
.name
, name
);
773 lstrcpyW(pin
->pin
.id
, name
);
774 pin
->pin
.ops
= &func_table
->base
;
775 pin
->pFuncsTable
= func_table
;
778 void strmbase_source_cleanup(struct strmbase_source
*pin
)
780 FreeMediaType(&pin
->pin
.mt
);
782 IMemAllocator_Release(pin
->pAllocator
);
783 pin
->pAllocator
= NULL
;
786 static struct strmbase_sink
*impl_sink_from_IPin(IPin
*iface
)
788 return CONTAINING_RECORD(iface
, struct strmbase_sink
, pin
.IPin_iface
);
791 static HRESULT WINAPI
sink_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
793 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
795 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin
, debugstr_w(pin
->pin
.name
),
796 debugstr_w(pin
->pin
.filter
->name
), peer
, mt
);
802 static HRESULT WINAPI
sink_ReceiveConnection(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
804 struct strmbase_sink
*This
= impl_sink_from_IPin(iface
);
805 PIN_DIRECTION pindirReceive
;
808 TRACE("pin %p %s:%s, peer %p, mt %p.\n", This
, debugstr_w(This
->pin
.filter
->name
),
809 debugstr_w(This
->pin
.name
), pReceivePin
, pmt
);
810 strmbase_dump_media_type(pmt
);
815 EnterCriticalSection(&This
->pin
.filter
->filter_cs
);
817 if (This
->pin
.filter
->state
!= State_Stopped
)
819 LeaveCriticalSection(&This
->pin
.filter
->filter_cs
);
820 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
821 return VFW_E_NOT_STOPPED
;
825 hr
= VFW_E_ALREADY_CONNECTED
;
827 if (SUCCEEDED(hr
) && !query_accept(&This
->pin
, pmt
))
828 hr
= VFW_E_TYPE_NOT_ACCEPTED
; /* FIXME: shouldn't we just map common errors onto
829 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
833 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
835 if (pindirReceive
!= PINDIR_OUTPUT
)
837 ERR("Can't connect from non-output pin\n");
838 hr
= VFW_E_INVALID_DIRECTION
;
842 if (SUCCEEDED(hr
) && This
->pFuncsTable
->sink_connect
)
843 hr
= This
->pFuncsTable
->sink_connect(This
, pReceivePin
, pmt
);
847 CopyMediaType(&This
->pin
.mt
, pmt
);
848 This
->pin
.peer
= pReceivePin
;
849 IPin_AddRef(pReceivePin
);
852 LeaveCriticalSection(&This
->pin
.filter
->filter_cs
);
857 static HRESULT WINAPI
sink_Disconnect(IPin
*iface
)
859 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
862 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
864 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
866 if (pin
->pin
.filter
->state
!= State_Stopped
)
868 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
869 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
870 return VFW_E_NOT_STOPPED
;
875 if (pin
->pFuncsTable
->sink_disconnect
)
876 pin
->pFuncsTable
->sink_disconnect(pin
);
880 IMemAllocator_Release(pin
->pAllocator
);
881 pin
->pAllocator
= NULL
;
884 IPin_Release(pin
->pin
.peer
);
885 pin
->pin
.peer
= NULL
;
886 FreeMediaType(&pin
->pin
.mt
);
887 memset(&pin
->pin
.mt
, 0, sizeof(AM_MEDIA_TYPE
));
893 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
898 static HRESULT
deliver_endofstream(IPin
* pin
, LPVOID unused
)
900 return IPin_EndOfStream( pin
);
903 static HRESULT WINAPI
sink_EndOfStream(IPin
*iface
)
905 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
908 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
910 if (pin
->pFuncsTable
->sink_eos
)
912 EnterCriticalSection(&pin
->pin
.filter
->stream_cs
);
913 hr
= pin
->pFuncsTable
->sink_eos(pin
);
914 LeaveCriticalSection(&pin
->pin
.filter
->stream_cs
);
918 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
921 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
924 hr
= SendFurther(pin
, deliver_endofstream
, NULL
);
928 static HRESULT
deliver_beginflush(IPin
* pin
, LPVOID unused
)
930 return IPin_BeginFlush( pin
);
933 static HRESULT WINAPI
sink_BeginFlush(IPin
*iface
)
935 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
938 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
940 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
942 pin
->flushing
= TRUE
;
944 if (pin
->pFuncsTable
->sink_begin_flush
)
945 hr
= pin
->pFuncsTable
->sink_begin_flush(pin
);
947 hr
= SendFurther(pin
, deliver_beginflush
, NULL
);
949 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
954 static HRESULT
deliver_endflush(IPin
* pin
, LPVOID unused
)
956 return IPin_EndFlush( pin
);
959 static HRESULT WINAPI
sink_EndFlush(IPin
* iface
)
961 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
964 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
966 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
968 pin
->flushing
= FALSE
;
970 if (pin
->pFuncsTable
->sink_end_flush
)
971 hr
= pin
->pFuncsTable
->sink_end_flush(pin
);
973 hr
= SendFurther(pin
, deliver_endflush
, NULL
);
975 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
980 typedef struct newsegmentargs
982 REFERENCE_TIME tStart
, tStop
;
986 static HRESULT
deliver_newsegment(IPin
*pin
, LPVOID data
)
988 newsegmentargs
*args
= data
;
989 return IPin_NewSegment(pin
, args
->tStart
, args
->tStop
, args
->rate
);
992 static HRESULT WINAPI
sink_NewSegment(IPin
*iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
994 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
997 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
998 debugstr_w(pin
->pin
.name
), debugstr_time(start
), debugstr_time(stop
), rate
);
1000 if (pin
->pFuncsTable
->sink_new_segment
)
1001 return pin
->pFuncsTable
->sink_new_segment(pin
, start
, stop
, rate
);
1003 args
.tStart
= start
;
1007 return SendFurther(pin
, deliver_newsegment
, &args
);
1010 static const IPinVtbl sink_vtbl
=
1016 sink_ReceiveConnection
,
1019 pin_ConnectionMediaType
,
1025 pin_QueryInternalConnections
,
1032 /*** IMemInputPin implementation ***/
1034 static inline struct strmbase_sink
*impl_from_IMemInputPin(IMemInputPin
*iface
)
1036 return CONTAINING_RECORD(iface
, struct strmbase_sink
, IMemInputPin_iface
);
1039 static HRESULT WINAPI
MemInputPin_QueryInterface(IMemInputPin
* iface
, REFIID riid
, LPVOID
* ppv
)
1041 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1043 return IPin_QueryInterface(&This
->pin
.IPin_iface
, riid
, ppv
);
1046 static ULONG WINAPI
MemInputPin_AddRef(IMemInputPin
* iface
)
1048 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1050 return IPin_AddRef(&This
->pin
.IPin_iface
);
1053 static ULONG WINAPI
MemInputPin_Release(IMemInputPin
* iface
)
1055 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1057 return IPin_Release(&This
->pin
.IPin_iface
);
1060 static HRESULT WINAPI
MemInputPin_GetAllocator(IMemInputPin
* iface
, IMemAllocator
** ppAllocator
)
1062 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1064 TRACE("pin %p %s:%s, allocator %p.\n", This
, debugstr_w(This
->pin
.filter
->name
),
1065 debugstr_w(This
->pin
.name
), ppAllocator
);
1067 *ppAllocator
= This
->pAllocator
;
1069 IMemAllocator_AddRef(*ppAllocator
);
1071 return *ppAllocator
? S_OK
: VFW_E_NO_ALLOCATOR
;
1074 static HRESULT WINAPI
MemInputPin_NotifyAllocator(IMemInputPin
* iface
, IMemAllocator
* pAllocator
, BOOL bReadOnly
)
1076 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1078 TRACE("pin %p %s:%s, allocator %p, read_only %d.\n", This
, debugstr_w(This
->pin
.filter
->name
),
1079 debugstr_w(This
->pin
.name
), pAllocator
, bReadOnly
);
1082 FIXME("Read only flag not handled yet!\n");
1084 /* FIXME: Should we release the allocator on disconnection? */
1087 WARN("Null allocator\n");
1091 if (This
->preferred_allocator
&& pAllocator
!= This
->preferred_allocator
)
1094 if (This
->pAllocator
)
1095 IMemAllocator_Release(This
->pAllocator
);
1096 This
->pAllocator
= pAllocator
;
1097 if (This
->pAllocator
)
1098 IMemAllocator_AddRef(This
->pAllocator
);
1103 static HRESULT WINAPI
MemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
1105 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1107 TRACE("pin %p %s:%s, props %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1108 debugstr_w(pin
->pin
.name
), props
);
1110 /* override this method if you have any specific requirements */
1115 static HRESULT WINAPI
MemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
1117 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1118 HRESULT hr
= S_FALSE
;
1120 TRACE("pin %p %s:%s, sample %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1121 debugstr_w(pin
->pin
.name
), sample
);
1123 if (pin
->pFuncsTable
->pfnReceive
)
1125 EnterCriticalSection(&pin
->pin
.filter
->stream_cs
);
1126 hr
= pin
->pFuncsTable
->pfnReceive(pin
, sample
);
1127 LeaveCriticalSection(&pin
->pin
.filter
->stream_cs
);
1132 static HRESULT WINAPI
MemInputPin_ReceiveMultiple(IMemInputPin
* iface
, IMediaSample
** pSamples
, LONG nSamples
, LONG
*nSamplesProcessed
)
1136 for (*nSamplesProcessed
= 0; *nSamplesProcessed
< nSamples
; (*nSamplesProcessed
)++)
1138 hr
= IMemInputPin_Receive(iface
, pSamples
[*nSamplesProcessed
]);
1146 static HRESULT WINAPI
MemInputPin_ReceiveCanBlock(IMemInputPin
* iface
)
1148 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1150 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
1155 static const IMemInputPinVtbl MemInputPin_Vtbl
=
1157 MemInputPin_QueryInterface
,
1159 MemInputPin_Release
,
1160 MemInputPin_GetAllocator
,
1161 MemInputPin_NotifyAllocator
,
1162 MemInputPin_GetAllocatorRequirements
,
1163 MemInputPin_Receive
,
1164 MemInputPin_ReceiveMultiple
,
1165 MemInputPin_ReceiveCanBlock
1168 void strmbase_sink_init(struct strmbase_sink
*pin
, struct strmbase_filter
*filter
,
1169 const WCHAR
*name
, const struct strmbase_sink_ops
*func_table
, IMemAllocator
*allocator
)
1171 memset(pin
, 0, sizeof(*pin
));
1172 pin
->pin
.IPin_iface
.lpVtbl
= &sink_vtbl
;
1173 pin
->pin
.filter
= filter
;
1174 pin
->pin
.dir
= PINDIR_INPUT
;
1175 lstrcpyW(pin
->pin
.name
, name
);
1176 lstrcpyW(pin
->pin
.id
, name
);
1177 pin
->pin
.ops
= &func_table
->base
;
1178 pin
->pFuncsTable
= func_table
;
1179 pin
->pAllocator
= pin
->preferred_allocator
= allocator
;
1180 if (pin
->preferred_allocator
)
1181 IMemAllocator_AddRef(pin
->preferred_allocator
);
1182 pin
->IMemInputPin_iface
.lpVtbl
= &MemInputPin_Vtbl
;
1185 void strmbase_sink_cleanup(struct strmbase_sink
*pin
)
1187 FreeMediaType(&pin
->pin
.mt
);
1188 if (pin
->pAllocator
)
1189 IMemAllocator_Release(pin
->pAllocator
);
1190 pin
->pAllocator
= NULL
;
1191 pin
->pin
.IPin_iface
.lpVtbl
= NULL
;