wrc: Use ARRAY_SIZE instead of open coding it.
[wine.git] / libs / strmbase / pin.c
blob03330837477b4650359c5032504318f072398ce9
1 /*
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;
33 LONG refcount;
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;
44 AM_MEDIA_TYPE mt;
46 if (!out)
47 return E_POINTER;
49 if (!(object = heap_alloc_zero(sizeof(*object))))
51 *out = NULL;
52 return E_OUTOFMEMORY;
55 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
56 object->refcount = 1;
57 object->pin = pin;
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)
64 FreeMediaType(&mt);
65 ++object->count;
69 TRACE("Created enumerator %p.\n", object);
70 *out = &object->IEnumMediaTypes_iface;
72 return S_OK;
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);
87 *out = iface;
88 return S_OK;
91 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
92 *out = NULL;
93 return E_NOINTERFACE;
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);
101 return 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);
110 if (!refcount)
112 IPin_Release(&enummt->pin->IPin_iface);
113 heap_free(enummt);
115 return refcount;
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);
122 AM_MEDIA_TYPE mt;
123 unsigned int i;
124 HRESULT hr;
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)
130 if (ret_count)
131 *ret_count = 0;
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);
138 if (hr == S_OK)
140 if ((mts[i] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
141 *mts[i] = mt;
142 else
143 hr = E_OUTOFMEMORY;
145 if (FAILED(hr))
147 while (i--)
148 DeleteMediaType(mts[i]);
149 *ret_count = 0;
150 return E_OUTOFMEMORY;
152 else if (hr != S_OK)
153 break;
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)
163 *ret_count = i;
164 enummt->index += i;
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);
182 AM_MEDIA_TYPE mt;
184 TRACE("enummt %p.\n", enummt);
186 enummt->count = 0;
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)
191 FreeMediaType(&mt);
192 ++enummt->count;
196 enummt->index = 0;
198 return S_OK;
201 static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
203 struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
204 HRESULT hr;
206 TRACE("enummt %p, out %p.\n", enummt, out);
208 if (FAILED(hr = enum_media_types_create(enummt->pin, out)))
209 return hr;
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)
238 return original;
240 if (FAILED( new ) || original == S_OK)
241 return new;
243 return original;
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;
256 HRESULT hr = S_OK;
257 unsigned int i;
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));
265 return hr;
268 static HRESULT WINAPI pin_QueryInterface(IPin *iface, REFIID iid, void **out)
270 struct strmbase_pin *pin = impl_from_IPin(iface);
271 HRESULT hr;
273 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
275 *out = NULL;
277 if (pin->ops->pin_query_interface && SUCCEEDED(hr = pin->ops->pin_query_interface(pin, iid, out)))
278 return hr;
280 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IPin))
281 *out = iface;
282 else
284 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
285 return E_NOINTERFACE;
288 IUnknown_AddRef((IUnknown *)*out);
289 return S_OK;
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);
307 HRESULT hr;
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);
313 if (This->peer)
315 *ppPin = This->peer;
316 IPin_AddRef(*ppPin);
317 hr = S_OK;
319 else
321 hr = VFW_E_NOT_CONNECTED;
322 *ppPin = NULL;
325 LeaveCriticalSection(&This->filter->filter_cs);
327 return hr;
330 static HRESULT WINAPI pin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
332 struct strmbase_pin *This = impl_from_IPin(iface);
333 HRESULT hr;
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);
339 if (This->peer)
341 CopyMediaType(pmt, &This->mt);
342 strmbase_dump_media_type(pmt);
343 hr = S_OK;
345 else
347 ZeroMemory(pmt, sizeof(*pmt));
348 hr = VFW_E_NOT_CONNECTED;
351 LeaveCriticalSection(&This->filter->filter_cs);
353 return hr;
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);
366 return S_OK;
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);
375 *dir = pin->dir;
377 return S_OK;
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);
391 return S_OK;
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)
397 return FALSE;
398 return TRUE;
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);
414 AM_MEDIA_TYPE mt;
415 HRESULT hr;
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)))
423 return hr;
424 if (hr == S_OK)
425 FreeMediaType(&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)
450 if (!req_mt)
451 return TRUE;
453 if (!IsEqualGUID(&req_mt->majortype, &pin_mt->majortype)
454 && !IsEqualGUID(&req_mt->majortype, &GUID_NULL))
455 return FALSE;
457 if (!IsEqualGUID(&req_mt->subtype, &pin_mt->subtype)
458 && !IsEqualGUID(&req_mt->subtype, &GUID_NULL))
459 return FALSE;
461 if (!IsEqualGUID(&req_mt->formattype, &pin_mt->formattype)
462 && !IsEqualGUID(&req_mt->formattype, &GUID_NULL))
463 return FALSE;
465 return TRUE;
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;
473 PIN_DIRECTION dir;
474 unsigned int i;
475 ULONG count;
476 HRESULT hr;
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);
482 if (!peer)
483 return E_POINTER;
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);
494 if (pin->pin.peer)
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);
516 return hr;
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);
529 return S_OK;
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);
547 return S_OK;
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);
565 return E_UNEXPECTED;
568 static HRESULT WINAPI source_Disconnect(IPin *iface)
570 HRESULT hr;
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;
599 if (This->pin.peer)
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));
605 hr = S_OK;
607 else
608 hr = S_FALSE;
610 LeaveCriticalSection(&This->pin.filter->filter_cs);
612 return hr;
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 */
623 return E_UNEXPECTED;
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 */
634 return E_UNEXPECTED;
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 */
645 return E_UNEXPECTED;
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);
655 return S_OK;
658 static const IPinVtbl source_vtbl =
660 pin_QueryInterface,
661 pin_AddRef,
662 pin_Release,
663 source_Connect,
664 source_ReceiveConnection,
665 source_Disconnect,
666 pin_ConnectedTo,
667 pin_ConnectionMediaType,
668 pin_QueryPinInfo,
669 pin_QueryDirection,
670 pin_QueryId,
671 pin_QueryAccept,
672 pin_EnumMediaTypes,
673 pin_QueryInternalConnections,
674 source_EndOfStream,
675 source_BeginFlush,
676 source_EndFlush,
677 source_NewSegment,
680 HRESULT WINAPI BaseOutputPinImpl_DecideAllocator(struct strmbase_source *This,
681 IMemInputPin *pPin, IMemAllocator **pAlloc)
683 HRESULT hr;
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);
691 if (SUCCEEDED(hr))
693 ALLOCATOR_PROPERTIES rProps;
694 ZeroMemory(&rProps, sizeof(ALLOCATOR_PROPERTIES));
696 IMemInputPin_GetAllocatorRequirements(pPin, &rProps);
697 hr = This->pFuncsTable->pfnDecideBufferSize(This, *pAlloc, &rProps);
700 if (SUCCEEDED(hr))
701 hr = IMemInputPin_NotifyAllocator(pPin, *pAlloc, FALSE);
703 return hr;
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)
713 HRESULT hr;
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
728 * connected pin */
729 if (SUCCEEDED(hr))
731 This->pMemInputPin = NULL;
732 hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
734 if (SUCCEEDED(hr))
736 hr = This->pFuncsTable->pfnDecideAllocator(This, This->pMemInputPin, &pMemAlloc);
737 if (SUCCEEDED(hr))
738 This->pAllocator = pMemAlloc;
739 else if (pMemAlloc)
740 IMemAllocator_Release(pMemAlloc);
743 /* break connection if we couldn't get the allocator */
744 if (FAILED(hr))
746 if (This->pMemInputPin)
747 IMemInputPin_Release(This->pMemInputPin);
748 This->pMemInputPin = NULL;
750 IPin_Disconnect(pReceivePin);
754 if (FAILED(hr))
756 IPin_Release(This->pin.peer);
757 This->pin.peer = NULL;
758 FreeMediaType(&This->pin.mt);
761 TRACE("Returning %#lx.\n", hr);
762 return 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);
781 if (pin->pAllocator)
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);
798 return E_UNEXPECTED;
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;
806 HRESULT hr = S_OK;
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);
812 if (!pmt)
813 return E_POINTER;
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;
824 if (This->pin.peer)
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? */
831 if (SUCCEEDED(hr))
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);
845 if (SUCCEEDED(hr))
847 CopyMediaType(&This->pin.mt, pmt);
848 This->pin.peer = pReceivePin;
849 IPin_AddRef(pReceivePin);
852 LeaveCriticalSection(&This->pin.filter->filter_cs);
854 return hr;
857 static HRESULT WINAPI sink_Disconnect(IPin *iface)
859 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
860 HRESULT hr;
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;
873 if (pin->pin.peer)
875 if (pin->pFuncsTable->sink_disconnect)
876 pin->pFuncsTable->sink_disconnect(pin);
878 if (pin->pAllocator)
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));
888 hr = S_OK;
890 else
891 hr = S_FALSE;
893 LeaveCriticalSection(&pin->pin.filter->filter_cs);
895 return hr;
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);
906 HRESULT hr = S_OK;
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);
915 return hr;
918 EnterCriticalSection(&pin->pin.filter->filter_cs);
919 if (pin->flushing)
920 hr = S_FALSE;
921 LeaveCriticalSection(&pin->pin.filter->filter_cs);
923 if (hr == S_OK)
924 hr = SendFurther(pin, deliver_endofstream, NULL);
925 return hr;
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);
936 HRESULT hr;
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);
946 else
947 hr = SendFurther(pin, deliver_beginflush, NULL);
949 LeaveCriticalSection(&pin->pin.filter->filter_cs);
951 return hr;
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);
962 HRESULT hr;
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);
972 else
973 hr = SendFurther(pin, deliver_endflush, NULL);
975 LeaveCriticalSection(&pin->pin.filter->filter_cs);
977 return hr;
980 typedef struct newsegmentargs
982 REFERENCE_TIME tStart, tStop;
983 double rate;
984 } newsegmentargs;
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);
995 newsegmentargs args;
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;
1004 args.tStop = stop;
1005 args.rate = rate;
1007 return SendFurther(pin, deliver_newsegment, &args);
1010 static const IPinVtbl sink_vtbl =
1012 pin_QueryInterface,
1013 pin_AddRef,
1014 pin_Release,
1015 sink_Connect,
1016 sink_ReceiveConnection,
1017 sink_Disconnect,
1018 pin_ConnectedTo,
1019 pin_ConnectionMediaType,
1020 pin_QueryPinInfo,
1021 pin_QueryDirection,
1022 pin_QueryId,
1023 pin_QueryAccept,
1024 pin_EnumMediaTypes,
1025 pin_QueryInternalConnections,
1026 sink_EndOfStream,
1027 sink_BeginFlush,
1028 sink_EndFlush,
1029 sink_NewSegment,
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;
1068 if (*ppAllocator)
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);
1081 if (bReadOnly)
1082 FIXME("Read only flag not handled yet!\n");
1084 /* FIXME: Should we release the allocator on disconnection? */
1085 if (!pAllocator)
1087 WARN("Null allocator\n");
1088 return E_POINTER;
1091 if (This->preferred_allocator && pAllocator != This->preferred_allocator)
1092 return E_FAIL;
1094 if (This->pAllocator)
1095 IMemAllocator_Release(This->pAllocator);
1096 This->pAllocator = pAllocator;
1097 if (This->pAllocator)
1098 IMemAllocator_AddRef(This->pAllocator);
1100 return S_OK;
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 */
1112 return E_NOTIMPL;
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);
1129 return hr;
1132 static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed)
1134 HRESULT hr = S_OK;
1136 for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
1138 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
1139 if (hr != S_OK)
1140 break;
1143 return hr;
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));
1152 return S_OK;
1155 static const IMemInputPinVtbl MemInputPin_Vtbl =
1157 MemInputPin_QueryInterface,
1158 MemInputPin_AddRef,
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;