hidclass.sys: Return STATUS_INVALID_USER_BUFFER if buffer_len is 0.
[wine.git] / dlls / strmbase / pin.c
blobefce0155a9eaaeb270575fdc1861cda5e2772435
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 %u.\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 %u.\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 %u, 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 %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);
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->name) + 1) * sizeof(WCHAR))))
387 return E_OUTOFMEMORY;
389 lstrcpyW(*id, pin->name);
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 (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);
529 return S_OK;
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);
545 return S_OK;
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);
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_GetDeliveryBuffer(struct strmbase_source *This,
681 IMediaSample **ppSample, REFERENCE_TIME *tStart, REFERENCE_TIME *tStop, DWORD dwFlags)
683 HRESULT hr;
685 TRACE("(%p)->(%p, %p, %p, %x)\n", This, ppSample, tStart, tStop, dwFlags);
687 if (!This->pin.peer)
688 hr = VFW_E_NOT_CONNECTED;
689 else
691 hr = IMemAllocator_GetBuffer(This->pAllocator, ppSample, tStart, tStop, dwFlags);
693 if (SUCCEEDED(hr))
694 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
697 return hr;
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)
708 HRESULT hr;
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);
716 if (SUCCEEDED(hr))
718 ALLOCATOR_PROPERTIES rProps;
719 ZeroMemory(&rProps, sizeof(ALLOCATOR_PROPERTIES));
721 IMemInputPin_GetAllocatorRequirements(pPin, &rProps);
722 hr = This->pFuncsTable->pfnDecideBufferSize(This, *pAlloc, &rProps);
725 if (SUCCEEDED(hr))
726 hr = IMemInputPin_NotifyAllocator(pPin, *pAlloc, FALSE);
728 return hr;
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)
738 HRESULT hr;
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
753 * connected pin */
754 if (SUCCEEDED(hr))
756 This->pMemInputPin = NULL;
757 hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
759 if (SUCCEEDED(hr))
761 hr = This->pFuncsTable->pfnDecideAllocator(This, This->pMemInputPin, &pMemAlloc);
762 if (SUCCEEDED(hr))
763 This->pAllocator = pMemAlloc;
764 else if (pMemAlloc)
765 IMemAllocator_Release(pMemAlloc);
768 /* break connection if we couldn't get the allocator */
769 if (FAILED(hr))
771 if (This->pMemInputPin)
772 IMemInputPin_Release(This->pMemInputPin);
773 This->pMemInputPin = NULL;
775 IPin_Disconnect(pReceivePin);
779 if (FAILED(hr))
781 IPin_Release(This->pin.peer);
782 This->pin.peer = NULL;
783 FreeMediaType(&This->pin.mt);
786 TRACE(" -- %x\n", hr);
787 return 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);
805 if (pin->pAllocator)
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);
822 return E_UNEXPECTED;
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;
830 HRESULT hr = S_OK;
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);
836 if (!pmt)
837 return E_POINTER;
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;
848 if (This->pin.peer)
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? */
855 if (SUCCEEDED(hr))
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);
869 if (SUCCEEDED(hr))
871 CopyMediaType(&This->pin.mt, pmt);
872 This->pin.peer = pReceivePin;
873 IPin_AddRef(pReceivePin);
876 LeaveCriticalSection(&This->pin.filter->filter_cs);
878 return hr;
881 static HRESULT WINAPI sink_Disconnect(IPin *iface)
883 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
884 HRESULT hr;
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;
897 if (pin->pin.peer)
899 if (pin->pFuncsTable->sink_disconnect)
900 pin->pFuncsTable->sink_disconnect(pin);
902 if (pin->pAllocator)
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));
912 hr = S_OK;
914 else
915 hr = S_FALSE;
917 LeaveCriticalSection(&pin->pin.filter->filter_cs);
919 return hr;
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);
930 HRESULT hr = S_OK;
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);
939 return hr;
942 EnterCriticalSection(&pin->pin.filter->filter_cs);
943 if (pin->flushing)
944 hr = S_FALSE;
945 LeaveCriticalSection(&pin->pin.filter->filter_cs);
947 if (hr == S_OK)
948 hr = SendFurther(pin, deliver_endofstream, NULL);
949 return hr;
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);
960 HRESULT hr;
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);
970 else
971 hr = SendFurther(pin, deliver_beginflush, NULL);
973 LeaveCriticalSection(&pin->pin.filter->filter_cs);
975 return hr;
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);
986 HRESULT hr;
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);
996 else
997 hr = SendFurther(pin, deliver_endflush, NULL);
999 LeaveCriticalSection(&pin->pin.filter->filter_cs);
1001 return hr;
1004 typedef struct newsegmentargs
1006 REFERENCE_TIME tStart, tStop;
1007 double rate;
1008 } newsegmentargs;
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;
1028 args.tStop = stop;
1029 args.rate = rate;
1031 return SendFurther(pin, deliver_newsegment, &args);
1034 static const IPinVtbl sink_vtbl =
1036 pin_QueryInterface,
1037 pin_AddRef,
1038 pin_Release,
1039 sink_Connect,
1040 sink_ReceiveConnection,
1041 sink_Disconnect,
1042 pin_ConnectedTo,
1043 pin_ConnectionMediaType,
1044 pin_QueryPinInfo,
1045 pin_QueryDirection,
1046 pin_QueryId,
1047 pin_QueryAccept,
1048 pin_EnumMediaTypes,
1049 pin_QueryInternalConnections,
1050 sink_EndOfStream,
1051 sink_BeginFlush,
1052 sink_EndFlush,
1053 sink_NewSegment,
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;
1092 if (*ppAllocator)
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);
1105 if (bReadOnly)
1106 FIXME("Read only flag not handled yet!\n");
1108 /* FIXME: Should we release the allocator on disconnection? */
1109 if (!pAllocator)
1111 WARN("Null allocator\n");
1112 return E_POINTER;
1115 if (This->preferred_allocator && pAllocator != This->preferred_allocator)
1116 return E_FAIL;
1118 if (This->pAllocator)
1119 IMemAllocator_Release(This->pAllocator);
1120 This->pAllocator = pAllocator;
1121 if (This->pAllocator)
1122 IMemAllocator_AddRef(This->pAllocator);
1124 return S_OK;
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 */
1136 return E_NOTIMPL;
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);
1153 return hr;
1156 static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed)
1158 HRESULT hr = S_OK;
1160 for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
1162 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
1163 if (hr != S_OK)
1164 break;
1167 return hr;
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));
1176 return S_OK;
1179 static const IMemInputPinVtbl MemInputPin_Vtbl =
1181 MemInputPin_QueryInterface,
1182 MemInputPin_AddRef,
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;