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 %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(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 %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 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
->name
) + 1) * sizeof(WCHAR
))))
387 return E_OUTOFMEMORY
;
389 lstrcpyW(*id
, pin
->name
);
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 (pin
->pFuncsTable
->base
.pin_get_media_type
)
521 for (i
= 0; pin
->pFuncsTable
->base
.pin_get_media_type(&pin
->pin
, i
, &candidate
) == S_OK
; ++i
)
523 strmbase_dump_media_type(&candidate
);
524 if (compare_media_types(mt
, &candidate
)
525 && pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, &candidate
) == S_OK
)
527 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
528 FreeMediaType(&candidate
);
531 FreeMediaType(&candidate
);
535 if (SUCCEEDED(IPin_EnumMediaTypes(peer
, &enummt
)))
537 while (IEnumMediaTypes_Next(enummt
, 1, &candidate_ptr
, &count
) == S_OK
)
539 if (compare_media_types(mt
, candidate_ptr
)
540 && pin
->pFuncsTable
->pfnAttemptConnection(pin
, peer
, candidate_ptr
) == S_OK
)
542 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
543 DeleteMediaType(candidate_ptr
);
544 IEnumMediaTypes_Release(enummt
);
547 DeleteMediaType(candidate_ptr
);
550 IEnumMediaTypes_Release(enummt
);
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_GetDeliveryBuffer(struct strmbase_source
*This
,
681 IMediaSample
**ppSample
, REFERENCE_TIME
*tStart
, REFERENCE_TIME
*tStop
, DWORD dwFlags
)
685 TRACE("(%p)->(%p, %p, %p, %x)\n", This
, ppSample
, tStart
, tStop
, dwFlags
);
688 hr
= VFW_E_NOT_CONNECTED
;
691 hr
= IMemAllocator_GetBuffer(This
->pAllocator
, ppSample
, tStart
, tStop
, dwFlags
);
694 hr
= IMediaSample_SetTime(*ppSample
, tStart
, tStop
);
700 HRESULT WINAPI
BaseOutputPinImpl_InitAllocator(struct strmbase_source
*This
, IMemAllocator
**pMemAlloc
)
702 return CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (LPVOID
*)pMemAlloc
);
705 HRESULT WINAPI
BaseOutputPinImpl_DecideAllocator(struct strmbase_source
*This
,
706 IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
710 hr
= IMemInputPin_GetAllocator(pPin
, pAlloc
);
712 if (hr
== VFW_E_NO_ALLOCATOR
)
713 /* Input pin provides no allocator, use standard memory allocator */
714 hr
= BaseOutputPinImpl_InitAllocator(This
, pAlloc
);
718 ALLOCATOR_PROPERTIES rProps
;
719 ZeroMemory(&rProps
, sizeof(ALLOCATOR_PROPERTIES
));
721 IMemInputPin_GetAllocatorRequirements(pPin
, &rProps
);
722 hr
= This
->pFuncsTable
->pfnDecideBufferSize(This
, *pAlloc
, &rProps
);
726 hr
= IMemInputPin_NotifyAllocator(pPin
, *pAlloc
, FALSE
);
731 /*** The Construct functions ***/
733 /* Function called as a helper to IPin_Connect */
734 /* specific AM_MEDIA_TYPE - it cannot be NULL */
735 HRESULT WINAPI
BaseOutputPinImpl_AttemptConnection(struct strmbase_source
*This
,
736 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
739 IMemAllocator
* pMemAlloc
= NULL
;
741 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
743 if (!query_accept(&This
->pin
, pmt
))
744 return VFW_E_TYPE_NOT_ACCEPTED
;
746 This
->pin
.peer
= pReceivePin
;
747 IPin_AddRef(pReceivePin
);
748 CopyMediaType(&This
->pin
.mt
, pmt
);
750 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->pin
.IPin_iface
, pmt
);
752 /* get the IMemInputPin interface we will use to deliver samples to the
756 This
->pMemInputPin
= NULL
;
757 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (LPVOID
)&This
->pMemInputPin
);
761 hr
= This
->pFuncsTable
->pfnDecideAllocator(This
, This
->pMemInputPin
, &pMemAlloc
);
763 This
->pAllocator
= pMemAlloc
;
765 IMemAllocator_Release(pMemAlloc
);
768 /* break connection if we couldn't get the allocator */
771 if (This
->pMemInputPin
)
772 IMemInputPin_Release(This
->pMemInputPin
);
773 This
->pMemInputPin
= NULL
;
775 IPin_Disconnect(pReceivePin
);
781 IPin_Release(This
->pin
.peer
);
782 This
->pin
.peer
= NULL
;
783 FreeMediaType(&This
->pin
.mt
);
786 TRACE(" -- %x\n", hr
);
790 void strmbase_source_init(struct strmbase_source
*pin
, struct strmbase_filter
*filter
,
791 const WCHAR
*name
, const struct strmbase_source_ops
*func_table
)
793 memset(pin
, 0, sizeof(*pin
));
794 pin
->pin
.IPin_iface
.lpVtbl
= &source_vtbl
;
795 pin
->pin
.filter
= filter
;
796 pin
->pin
.dir
= PINDIR_OUTPUT
;
797 lstrcpyW(pin
->pin
.name
, name
);
798 pin
->pin
.ops
= &func_table
->base
;
799 pin
->pFuncsTable
= func_table
;
802 void strmbase_source_cleanup(struct strmbase_source
*pin
)
804 FreeMediaType(&pin
->pin
.mt
);
806 IMemAllocator_Release(pin
->pAllocator
);
807 pin
->pAllocator
= NULL
;
810 static struct strmbase_sink
*impl_sink_from_IPin(IPin
*iface
)
812 return CONTAINING_RECORD(iface
, struct strmbase_sink
, pin
.IPin_iface
);
815 static HRESULT WINAPI
sink_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
817 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
819 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin
, debugstr_w(pin
->pin
.name
),
820 debugstr_w(pin
->pin
.filter
->name
), peer
, mt
);
826 static HRESULT WINAPI
sink_ReceiveConnection(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
828 struct strmbase_sink
*This
= impl_sink_from_IPin(iface
);
829 PIN_DIRECTION pindirReceive
;
832 TRACE("pin %p %s:%s, peer %p, mt %p.\n", This
, debugstr_w(This
->pin
.filter
->name
),
833 debugstr_w(This
->pin
.name
), pReceivePin
, pmt
);
834 strmbase_dump_media_type(pmt
);
839 EnterCriticalSection(&This
->pin
.filter
->filter_cs
);
841 if (This
->pin
.filter
->state
!= State_Stopped
)
843 LeaveCriticalSection(&This
->pin
.filter
->filter_cs
);
844 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
845 return VFW_E_NOT_STOPPED
;
849 hr
= VFW_E_ALREADY_CONNECTED
;
851 if (SUCCEEDED(hr
) && !query_accept(&This
->pin
, pmt
))
852 hr
= VFW_E_TYPE_NOT_ACCEPTED
; /* FIXME: shouldn't we just map common errors onto
853 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
857 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
859 if (pindirReceive
!= PINDIR_OUTPUT
)
861 ERR("Can't connect from non-output pin\n");
862 hr
= VFW_E_INVALID_DIRECTION
;
866 if (SUCCEEDED(hr
) && This
->pFuncsTable
->sink_connect
)
867 hr
= This
->pFuncsTable
->sink_connect(This
, pReceivePin
, pmt
);
871 CopyMediaType(&This
->pin
.mt
, pmt
);
872 This
->pin
.peer
= pReceivePin
;
873 IPin_AddRef(pReceivePin
);
876 LeaveCriticalSection(&This
->pin
.filter
->filter_cs
);
881 static HRESULT WINAPI
sink_Disconnect(IPin
*iface
)
883 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
886 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
888 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
890 if (pin
->pin
.filter
->state
!= State_Stopped
)
892 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
893 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
894 return VFW_E_NOT_STOPPED
;
899 if (pin
->pFuncsTable
->sink_disconnect
)
900 pin
->pFuncsTable
->sink_disconnect(pin
);
904 IMemAllocator_Release(pin
->pAllocator
);
905 pin
->pAllocator
= NULL
;
908 IPin_Release(pin
->pin
.peer
);
909 pin
->pin
.peer
= NULL
;
910 FreeMediaType(&pin
->pin
.mt
);
911 memset(&pin
->pin
.mt
, 0, sizeof(AM_MEDIA_TYPE
));
917 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
922 static HRESULT
deliver_endofstream(IPin
* pin
, LPVOID unused
)
924 return IPin_EndOfStream( pin
);
927 static HRESULT WINAPI
sink_EndOfStream(IPin
*iface
)
929 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
932 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
934 if (pin
->pFuncsTable
->sink_eos
)
936 EnterCriticalSection(&pin
->pin
.filter
->stream_cs
);
937 hr
= pin
->pFuncsTable
->sink_eos(pin
);
938 LeaveCriticalSection(&pin
->pin
.filter
->stream_cs
);
942 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
945 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
948 hr
= SendFurther(pin
, deliver_endofstream
, NULL
);
952 static HRESULT
deliver_beginflush(IPin
* pin
, LPVOID unused
)
954 return IPin_BeginFlush( pin
);
957 static HRESULT WINAPI
sink_BeginFlush(IPin
*iface
)
959 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
962 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
964 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
966 pin
->flushing
= TRUE
;
968 if (pin
->pFuncsTable
->sink_begin_flush
)
969 hr
= pin
->pFuncsTable
->sink_begin_flush(pin
);
971 hr
= SendFurther(pin
, deliver_beginflush
, NULL
);
973 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
978 static HRESULT
deliver_endflush(IPin
* pin
, LPVOID unused
)
980 return IPin_EndFlush( pin
);
983 static HRESULT WINAPI
sink_EndFlush(IPin
* iface
)
985 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
988 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
990 EnterCriticalSection(&pin
->pin
.filter
->filter_cs
);
992 pin
->flushing
= FALSE
;
994 if (pin
->pFuncsTable
->sink_end_flush
)
995 hr
= pin
->pFuncsTable
->sink_end_flush(pin
);
997 hr
= SendFurther(pin
, deliver_endflush
, NULL
);
999 LeaveCriticalSection(&pin
->pin
.filter
->filter_cs
);
1004 typedef struct newsegmentargs
1006 REFERENCE_TIME tStart
, tStop
;
1010 static HRESULT
deliver_newsegment(IPin
*pin
, LPVOID data
)
1012 newsegmentargs
*args
= data
;
1013 return IPin_NewSegment(pin
, args
->tStart
, args
->tStop
, args
->rate
);
1016 static HRESULT WINAPI
sink_NewSegment(IPin
*iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
1018 struct strmbase_sink
*pin
= impl_sink_from_IPin(iface
);
1019 newsegmentargs args
;
1021 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1022 debugstr_w(pin
->pin
.name
), debugstr_time(start
), debugstr_time(stop
), rate
);
1024 if (pin
->pFuncsTable
->sink_new_segment
)
1025 return pin
->pFuncsTable
->sink_new_segment(pin
, start
, stop
, rate
);
1027 args
.tStart
= start
;
1031 return SendFurther(pin
, deliver_newsegment
, &args
);
1034 static const IPinVtbl sink_vtbl
=
1040 sink_ReceiveConnection
,
1043 pin_ConnectionMediaType
,
1049 pin_QueryInternalConnections
,
1056 /*** IMemInputPin implementation ***/
1058 static inline struct strmbase_sink
*impl_from_IMemInputPin(IMemInputPin
*iface
)
1060 return CONTAINING_RECORD(iface
, struct strmbase_sink
, IMemInputPin_iface
);
1063 static HRESULT WINAPI
MemInputPin_QueryInterface(IMemInputPin
* iface
, REFIID riid
, LPVOID
* ppv
)
1065 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1067 return IPin_QueryInterface(&This
->pin
.IPin_iface
, riid
, ppv
);
1070 static ULONG WINAPI
MemInputPin_AddRef(IMemInputPin
* iface
)
1072 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1074 return IPin_AddRef(&This
->pin
.IPin_iface
);
1077 static ULONG WINAPI
MemInputPin_Release(IMemInputPin
* iface
)
1079 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1081 return IPin_Release(&This
->pin
.IPin_iface
);
1084 static HRESULT WINAPI
MemInputPin_GetAllocator(IMemInputPin
* iface
, IMemAllocator
** ppAllocator
)
1086 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1088 TRACE("pin %p %s:%s, allocator %p.\n", This
, debugstr_w(This
->pin
.filter
->name
),
1089 debugstr_w(This
->pin
.name
), ppAllocator
);
1091 *ppAllocator
= This
->pAllocator
;
1093 IMemAllocator_AddRef(*ppAllocator
);
1095 return *ppAllocator
? S_OK
: VFW_E_NO_ALLOCATOR
;
1098 static HRESULT WINAPI
MemInputPin_NotifyAllocator(IMemInputPin
* iface
, IMemAllocator
* pAllocator
, BOOL bReadOnly
)
1100 struct strmbase_sink
*This
= impl_from_IMemInputPin(iface
);
1102 TRACE("pin %p %s:%s, allocator %p, read_only %d.\n", This
, debugstr_w(This
->pin
.filter
->name
),
1103 debugstr_w(This
->pin
.name
), pAllocator
, bReadOnly
);
1106 FIXME("Read only flag not handled yet!\n");
1108 /* FIXME: Should we release the allocator on disconnection? */
1111 WARN("Null allocator\n");
1115 if (This
->preferred_allocator
&& pAllocator
!= This
->preferred_allocator
)
1118 if (This
->pAllocator
)
1119 IMemAllocator_Release(This
->pAllocator
);
1120 This
->pAllocator
= pAllocator
;
1121 if (This
->pAllocator
)
1122 IMemAllocator_AddRef(This
->pAllocator
);
1127 static HRESULT WINAPI
MemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
1129 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1131 TRACE("pin %p %s:%s, props %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1132 debugstr_w(pin
->pin
.name
), props
);
1134 /* override this method if you have any specific requirements */
1139 static HRESULT WINAPI
MemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
1141 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1142 HRESULT hr
= S_FALSE
;
1144 TRACE("pin %p %s:%s, sample %p.\n", pin
, debugstr_w(pin
->pin
.filter
->name
),
1145 debugstr_w(pin
->pin
.name
), sample
);
1147 if (pin
->pFuncsTable
->pfnReceive
)
1149 EnterCriticalSection(&pin
->pin
.filter
->stream_cs
);
1150 hr
= pin
->pFuncsTable
->pfnReceive(pin
, sample
);
1151 LeaveCriticalSection(&pin
->pin
.filter
->stream_cs
);
1156 static HRESULT WINAPI
MemInputPin_ReceiveMultiple(IMemInputPin
* iface
, IMediaSample
** pSamples
, LONG nSamples
, LONG
*nSamplesProcessed
)
1160 for (*nSamplesProcessed
= 0; *nSamplesProcessed
< nSamples
; (*nSamplesProcessed
)++)
1162 hr
= IMemInputPin_Receive(iface
, pSamples
[*nSamplesProcessed
]);
1170 static HRESULT WINAPI
MemInputPin_ReceiveCanBlock(IMemInputPin
* iface
)
1172 struct strmbase_sink
*pin
= impl_from_IMemInputPin(iface
);
1174 TRACE("pin %p %s:%s.\n", pin
, debugstr_w(pin
->pin
.filter
->name
), debugstr_w(pin
->pin
.name
));
1179 static const IMemInputPinVtbl MemInputPin_Vtbl
=
1181 MemInputPin_QueryInterface
,
1183 MemInputPin_Release
,
1184 MemInputPin_GetAllocator
,
1185 MemInputPin_NotifyAllocator
,
1186 MemInputPin_GetAllocatorRequirements
,
1187 MemInputPin_Receive
,
1188 MemInputPin_ReceiveMultiple
,
1189 MemInputPin_ReceiveCanBlock
1192 void strmbase_sink_init(struct strmbase_sink
*pin
, struct strmbase_filter
*filter
,
1193 const WCHAR
*name
, const struct strmbase_sink_ops
*func_table
, IMemAllocator
*allocator
)
1195 memset(pin
, 0, sizeof(*pin
));
1196 pin
->pin
.IPin_iface
.lpVtbl
= &sink_vtbl
;
1197 pin
->pin
.filter
= filter
;
1198 pin
->pin
.dir
= PINDIR_INPUT
;
1199 lstrcpyW(pin
->pin
.name
, name
);
1200 pin
->pin
.ops
= &func_table
->base
;
1201 pin
->pFuncsTable
= func_table
;
1202 pin
->pAllocator
= pin
->preferred_allocator
= allocator
;
1203 if (pin
->preferred_allocator
)
1204 IMemAllocator_AddRef(pin
->preferred_allocator
);
1205 pin
->IMemInputPin_iface
.lpVtbl
= &MemInputPin_Vtbl
;
1208 void strmbase_sink_cleanup(struct strmbase_sink
*pin
)
1210 FreeMediaType(&pin
->pin
.mt
);
1211 if (pin
->pAllocator
)
1212 IMemAllocator_Release(pin
->pAllocator
);
1213 pin
->pAllocator
= NULL
;
1214 pin
->pin
.IPin_iface
.lpVtbl
= NULL
;