amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / strmbase / pin.c
blobe5017c2ff9821a786e095110827d1808fef5d8f0
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(strmbase);
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(strmbase))
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 HRESULT strmbase_pin_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
270 return VFW_S_NO_MORE_ITEMS;
273 static HRESULT WINAPI pin_QueryInterface(IPin *iface, REFIID iid, void **out)
275 struct strmbase_pin *pin = impl_from_IPin(iface);
276 HRESULT hr;
278 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
280 *out = NULL;
282 if (pin->ops->pin_query_interface && SUCCEEDED(hr = pin->ops->pin_query_interface(pin, iid, out)))
283 return hr;
285 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IPin))
286 *out = iface;
287 else
289 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
290 return E_NOINTERFACE;
293 IUnknown_AddRef((IUnknown *)*out);
294 return S_OK;
297 static ULONG WINAPI pin_AddRef(IPin *iface)
299 struct strmbase_pin *pin = impl_from_IPin(iface);
300 return IBaseFilter_AddRef(&pin->filter->IBaseFilter_iface);
303 static ULONG WINAPI pin_Release(IPin *iface)
305 struct strmbase_pin *pin = impl_from_IPin(iface);
306 return IBaseFilter_Release(&pin->filter->IBaseFilter_iface);
309 static HRESULT WINAPI pin_ConnectedTo(IPin * iface, IPin ** ppPin)
311 struct strmbase_pin *This = impl_from_IPin(iface);
312 HRESULT hr;
314 TRACE("pin %p %s:%s, peer %p.\n", This, debugstr_w(This->filter->name), debugstr_w(This->name), ppPin);
316 EnterCriticalSection(&This->filter->csFilter);
318 if (This->peer)
320 *ppPin = This->peer;
321 IPin_AddRef(*ppPin);
322 hr = S_OK;
324 else
326 hr = VFW_E_NOT_CONNECTED;
327 *ppPin = NULL;
330 LeaveCriticalSection(&This->filter->csFilter);
332 return hr;
335 static HRESULT WINAPI pin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
337 struct strmbase_pin *This = impl_from_IPin(iface);
338 HRESULT hr;
340 TRACE("pin %p %s:%s, pmt %p.\n", This, debugstr_w(This->filter->name), debugstr_w(This->name), pmt);
342 EnterCriticalSection(&This->filter->csFilter);
344 if (This->peer)
346 CopyMediaType(pmt, &This->mt);
347 strmbase_dump_media_type(pmt);
348 hr = S_OK;
350 else
352 ZeroMemory(pmt, sizeof(*pmt));
353 hr = VFW_E_NOT_CONNECTED;
356 LeaveCriticalSection(&This->filter->csFilter);
358 return hr;
361 static HRESULT WINAPI pin_QueryPinInfo(IPin *iface, PIN_INFO *info)
363 struct strmbase_pin *pin = impl_from_IPin(iface);
365 TRACE("pin %p %s:%s, info %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), info);
367 info->dir = pin->dir;
368 IBaseFilter_AddRef(info->pFilter = &pin->filter->IBaseFilter_iface);
369 lstrcpyW(info->achName, pin->name);
371 return S_OK;
374 static HRESULT WINAPI pin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
376 struct strmbase_pin *pin = impl_from_IPin(iface);
378 TRACE("pin %p %s:%s, dir %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), dir);
380 *dir = pin->dir;
382 return S_OK;
385 static HRESULT WINAPI pin_QueryId(IPin *iface, WCHAR **id)
387 struct strmbase_pin *pin = impl_from_IPin(iface);
389 TRACE("pin %p %s:%s, id %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), id);
391 if (!(*id = CoTaskMemAlloc((lstrlenW(pin->name) + 1) * sizeof(WCHAR))))
392 return E_OUTOFMEMORY;
394 lstrcpyW(*id, pin->name);
396 return S_OK;
399 static BOOL query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
401 if (pin->ops->pin_query_accept && pin->ops->pin_query_accept(pin, mt) != S_OK)
402 return FALSE;
403 return TRUE;
406 static HRESULT WINAPI pin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
408 struct strmbase_pin *pin = impl_from_IPin(iface);
410 TRACE("pin %p %s:%s, mt %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), mt);
411 strmbase_dump_media_type(mt);
413 return query_accept(pin, mt) ? S_OK : S_FALSE;
416 static HRESULT WINAPI pin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
418 struct strmbase_pin *pin = impl_from_IPin(iface);
419 AM_MEDIA_TYPE mt;
420 HRESULT hr;
422 TRACE("pin %p %s:%s, enum_media_types %p.\n", pin, debugstr_w(pin->filter->name),
423 debugstr_w(pin->name), enum_media_types);
425 if (pin->ops->pin_get_media_type)
427 if (FAILED(hr = pin->ops->pin_get_media_type(pin, 0, &mt)))
428 return hr;
429 if (hr == S_OK)
430 FreeMediaType(&mt);
433 return enum_media_types_create(pin, enum_media_types);
436 static HRESULT WINAPI pin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
438 struct strmbase_pin *pin = impl_from_IPin(iface);
440 TRACE("pin %p %s:%s, pins %p, count %p.\n", pin, debugstr_w(pin->filter->name),
441 debugstr_w(pin->name), pins, count);
443 return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
446 /*** OutputPin implementation ***/
448 static inline struct strmbase_source *impl_source_from_IPin( IPin *iface )
450 return CONTAINING_RECORD(iface, struct strmbase_source, pin.IPin_iface);
453 static BOOL compare_media_types(const AM_MEDIA_TYPE *req_mt, const AM_MEDIA_TYPE *pin_mt)
455 if (!req_mt)
456 return TRUE;
458 if (!IsEqualGUID(&req_mt->majortype, &pin_mt->majortype)
459 && !IsEqualGUID(&req_mt->majortype, &GUID_NULL))
460 return FALSE;
462 if (!IsEqualGUID(&req_mt->subtype, &pin_mt->subtype)
463 && !IsEqualGUID(&req_mt->subtype, &GUID_NULL))
464 return FALSE;
466 if (!IsEqualGUID(&req_mt->formattype, &pin_mt->formattype)
467 && !IsEqualGUID(&req_mt->formattype, &GUID_NULL))
468 return FALSE;
470 return TRUE;
473 static HRESULT WINAPI source_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
475 struct strmbase_source *pin = impl_source_from_IPin(iface);
476 AM_MEDIA_TYPE candidate, *candidate_ptr;
477 IEnumMediaTypes *enummt;
478 PIN_DIRECTION dir;
479 unsigned int i;
480 ULONG count;
481 HRESULT hr;
483 TRACE("pin %p %s:%s, peer %p, mt %p.\n", pin, debugstr_w(pin->pin.filter->name),
484 debugstr_w(pin->pin.name), peer, mt);
485 strmbase_dump_media_type(mt);
487 if (!peer)
488 return E_POINTER;
490 IPin_QueryDirection(peer, &dir);
491 if (dir != PINDIR_INPUT)
493 WARN("Attempt to connect to another source pin, returning VFW_E_INVALID_DIRECTION.\n");
494 return VFW_E_INVALID_DIRECTION;
497 EnterCriticalSection(&pin->pin.filter->csFilter);
499 if (pin->pin.peer)
501 LeaveCriticalSection(&pin->pin.filter->csFilter);
502 WARN("Pin is already connected, returning VFW_E_ALREADY_CONNECTED.\n");
503 return VFW_E_ALREADY_CONNECTED;
506 if (pin->pin.filter->state != State_Stopped)
508 LeaveCriticalSection(&pin->pin.filter->csFilter);
509 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
510 return VFW_E_NOT_STOPPED;
513 /* We don't check the subtype here. The rationale (as given by the DirectX
514 * documentation) is that the format type is supposed to provide at least
515 * as much information as the subtype. */
516 if (mt && !IsEqualGUID(&mt->majortype, &GUID_NULL)
517 && !IsEqualGUID(&mt->formattype, &GUID_NULL))
519 hr = pin->pFuncsTable->pfnAttemptConnection(pin, peer, mt);
520 LeaveCriticalSection(&pin->pin.filter->csFilter);
521 return hr;
524 if (pin->pFuncsTable->base.pin_get_media_type)
526 for (i = 0; pin->pFuncsTable->base.pin_get_media_type(&pin->pin, i, &candidate) == S_OK; ++i)
528 strmbase_dump_media_type(&candidate);
529 if (compare_media_types(mt, &candidate)
530 && pin->pFuncsTable->pfnAttemptConnection(pin, peer, &candidate) == S_OK)
532 LeaveCriticalSection(&pin->pin.filter->csFilter);
533 FreeMediaType(&candidate);
534 return S_OK;
536 FreeMediaType(&candidate);
540 if (SUCCEEDED(IPin_EnumMediaTypes(peer, &enummt)))
542 while (IEnumMediaTypes_Next(enummt, 1, &candidate_ptr, &count) == S_OK)
544 if (compare_media_types(mt, candidate_ptr)
545 && pin->pFuncsTable->pfnAttemptConnection(pin, peer, candidate_ptr) == S_OK)
547 LeaveCriticalSection(&pin->pin.filter->csFilter);
548 DeleteMediaType(candidate_ptr);
549 IEnumMediaTypes_Release(enummt);
550 return S_OK;
552 DeleteMediaType(candidate_ptr);
555 IEnumMediaTypes_Release(enummt);
558 LeaveCriticalSection(&pin->pin.filter->csFilter);
560 return VFW_E_NO_ACCEPTABLE_TYPES;
563 static HRESULT WINAPI source_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
565 struct strmbase_source *pin = impl_source_from_IPin(iface);
567 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin,
568 debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name), peer, mt);
570 return E_UNEXPECTED;
573 static HRESULT WINAPI source_Disconnect(IPin *iface)
575 HRESULT hr;
576 struct strmbase_source *This = impl_source_from_IPin(iface);
578 TRACE("pin %p %s:%s.\n", This, debugstr_w(This->pin.filter->name), debugstr_w(This->pin.name));
580 EnterCriticalSection(&This->pin.filter->csFilter);
582 if (This->pin.filter->state != State_Stopped)
584 LeaveCriticalSection(&This->pin.filter->csFilter);
585 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
586 return VFW_E_NOT_STOPPED;
589 if (This->pFuncsTable->source_disconnect)
590 This->pFuncsTable->source_disconnect(This);
592 if (This->pMemInputPin)
594 IMemInputPin_Release(This->pMemInputPin);
595 This->pMemInputPin = NULL;
598 if (This->pAllocator)
600 IMemAllocator_Release(This->pAllocator);
601 This->pAllocator = NULL;
604 if (This->pin.peer)
606 IPin_Release(This->pin.peer);
607 This->pin.peer = NULL;
608 FreeMediaType(&This->pin.mt);
609 ZeroMemory(&This->pin.mt, sizeof(This->pin.mt));
610 hr = S_OK;
612 else
613 hr = S_FALSE;
615 LeaveCriticalSection(&This->pin.filter->csFilter);
617 return hr;
620 static HRESULT WINAPI source_EndOfStream(IPin *iface)
622 struct strmbase_source *pin = impl_source_from_IPin(iface);
624 WARN("pin %p %s:%s, unexpected call.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
626 /* not supposed to do anything in an output pin */
628 return E_UNEXPECTED;
631 static HRESULT WINAPI source_BeginFlush(IPin *iface)
633 struct strmbase_source *pin = impl_source_from_IPin(iface);
635 WARN("pin %p %s:%s, unexpected call.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
637 /* not supposed to do anything in an output pin */
639 return E_UNEXPECTED;
642 static HRESULT WINAPI source_EndFlush(IPin *iface)
644 struct strmbase_source *pin = impl_source_from_IPin(iface);
646 WARN("pin %p %s:%s, unexpected call.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
648 /* not supposed to do anything in an output pin */
650 return E_UNEXPECTED;
653 static HRESULT WINAPI source_NewSegment(IPin * iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
655 struct strmbase_source *pin = impl_source_from_IPin(iface);
657 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin, debugstr_w(pin->pin.filter->name),
658 debugstr_w(pin->pin.name), debugstr_time(start), debugstr_time(stop), rate);
660 return S_OK;
663 static const IPinVtbl source_vtbl =
665 pin_QueryInterface,
666 pin_AddRef,
667 pin_Release,
668 source_Connect,
669 source_ReceiveConnection,
670 source_Disconnect,
671 pin_ConnectedTo,
672 pin_ConnectionMediaType,
673 pin_QueryPinInfo,
674 pin_QueryDirection,
675 pin_QueryId,
676 pin_QueryAccept,
677 pin_EnumMediaTypes,
678 pin_QueryInternalConnections,
679 source_EndOfStream,
680 source_BeginFlush,
681 source_EndFlush,
682 source_NewSegment,
685 HRESULT WINAPI BaseOutputPinImpl_GetDeliveryBuffer(struct strmbase_source *This,
686 IMediaSample **ppSample, REFERENCE_TIME *tStart, REFERENCE_TIME *tStop, DWORD dwFlags)
688 HRESULT hr;
690 TRACE("(%p)->(%p, %p, %p, %x)\n", This, ppSample, tStart, tStop, dwFlags);
692 if (!This->pin.peer)
693 hr = VFW_E_NOT_CONNECTED;
694 else
696 hr = IMemAllocator_GetBuffer(This->pAllocator, ppSample, tStart, tStop, dwFlags);
698 if (SUCCEEDED(hr))
699 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
702 return hr;
705 /* replaces OutputPin_CommitAllocator */
706 HRESULT WINAPI BaseOutputPinImpl_Active(struct strmbase_source *This)
708 HRESULT hr;
710 TRACE("(%p)->()\n", This);
712 EnterCriticalSection(&This->pin.filter->csFilter);
714 if (!This->pin.peer || !This->pMemInputPin)
715 hr = VFW_E_NOT_CONNECTED;
716 else
717 hr = IMemAllocator_Commit(This->pAllocator);
719 LeaveCriticalSection(&This->pin.filter->csFilter);
721 TRACE("--> %08x\n", hr);
722 return hr;
725 /* replaces OutputPin_DecommitAllocator */
726 HRESULT WINAPI BaseOutputPinImpl_Inactive(struct strmbase_source *This)
728 HRESULT hr;
730 TRACE("(%p)->()\n", This);
732 EnterCriticalSection(&This->pin.filter->csFilter);
734 if (!This->pin.peer || !This->pMemInputPin)
735 hr = VFW_E_NOT_CONNECTED;
736 else
737 hr = IMemAllocator_Decommit(This->pAllocator);
739 LeaveCriticalSection(&This->pin.filter->csFilter);
741 TRACE("--> %08x\n", hr);
742 return hr;
745 HRESULT WINAPI BaseOutputPinImpl_InitAllocator(struct strmbase_source *This, IMemAllocator **pMemAlloc)
747 return CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)pMemAlloc);
750 HRESULT WINAPI BaseOutputPinImpl_DecideAllocator(struct strmbase_source *This,
751 IMemInputPin *pPin, IMemAllocator **pAlloc)
753 HRESULT hr;
755 hr = IMemInputPin_GetAllocator(pPin, pAlloc);
757 if (hr == VFW_E_NO_ALLOCATOR)
758 /* Input pin provides no allocator, use standard memory allocator */
759 hr = BaseOutputPinImpl_InitAllocator(This, pAlloc);
761 if (SUCCEEDED(hr))
763 ALLOCATOR_PROPERTIES rProps;
764 ZeroMemory(&rProps, sizeof(ALLOCATOR_PROPERTIES));
766 IMemInputPin_GetAllocatorRequirements(pPin, &rProps);
767 hr = This->pFuncsTable->pfnDecideBufferSize(This, *pAlloc, &rProps);
770 if (SUCCEEDED(hr))
771 hr = IMemInputPin_NotifyAllocator(pPin, *pAlloc, FALSE);
773 return hr;
776 /*** The Construct functions ***/
778 /* Function called as a helper to IPin_Connect */
779 /* specific AM_MEDIA_TYPE - it cannot be NULL */
780 HRESULT WINAPI BaseOutputPinImpl_AttemptConnection(struct strmbase_source *This,
781 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
783 HRESULT hr;
784 IMemAllocator * pMemAlloc = NULL;
786 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
788 if (!query_accept(&This->pin, pmt))
789 return VFW_E_TYPE_NOT_ACCEPTED;
791 This->pin.peer = pReceivePin;
792 IPin_AddRef(pReceivePin);
793 CopyMediaType(&This->pin.mt, pmt);
795 hr = IPin_ReceiveConnection(pReceivePin, &This->pin.IPin_iface, pmt);
797 /* get the IMemInputPin interface we will use to deliver samples to the
798 * connected pin */
799 if (SUCCEEDED(hr))
801 This->pMemInputPin = NULL;
802 hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
804 if (SUCCEEDED(hr))
806 hr = This->pFuncsTable->pfnDecideAllocator(This, This->pMemInputPin, &pMemAlloc);
807 if (SUCCEEDED(hr))
808 This->pAllocator = pMemAlloc;
809 else if (pMemAlloc)
810 IMemAllocator_Release(pMemAlloc);
813 /* break connection if we couldn't get the allocator */
814 if (FAILED(hr))
816 if (This->pMemInputPin)
817 IMemInputPin_Release(This->pMemInputPin);
818 This->pMemInputPin = NULL;
820 IPin_Disconnect(pReceivePin);
824 if (FAILED(hr))
826 IPin_Release(This->pin.peer);
827 This->pin.peer = NULL;
828 FreeMediaType(&This->pin.mt);
831 TRACE(" -- %x\n", hr);
832 return hr;
835 void strmbase_source_init(struct strmbase_source *pin, struct strmbase_filter *filter,
836 const WCHAR *name, const struct strmbase_source_ops *func_table)
838 memset(pin, 0, sizeof(*pin));
839 pin->pin.IPin_iface.lpVtbl = &source_vtbl;
840 pin->pin.filter = filter;
841 pin->pin.dir = PINDIR_OUTPUT;
842 lstrcpyW(pin->pin.name, name);
843 pin->pin.ops = &func_table->base;
844 pin->pFuncsTable = func_table;
847 void strmbase_source_cleanup(struct strmbase_source *pin)
849 FreeMediaType(&pin->pin.mt);
850 if (pin->pAllocator)
851 IMemAllocator_Release(pin->pAllocator);
852 pin->pAllocator = NULL;
855 static struct strmbase_sink *impl_sink_from_IPin(IPin *iface)
857 return CONTAINING_RECORD(iface, struct strmbase_sink, pin.IPin_iface);
860 static HRESULT WINAPI sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
862 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
864 WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin, debugstr_w(pin->pin.name),
865 debugstr_w(pin->pin.filter->name), peer, mt);
867 return E_UNEXPECTED;
871 static HRESULT WINAPI sink_ReceiveConnection(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
873 struct strmbase_sink *This = impl_sink_from_IPin(iface);
874 PIN_DIRECTION pindirReceive;
875 HRESULT hr = S_OK;
877 TRACE("pin %p %s:%s, peer %p, mt %p.\n", This, debugstr_w(This->pin.filter->name),
878 debugstr_w(This->pin.name), pReceivePin, pmt);
879 strmbase_dump_media_type(pmt);
881 if (!pmt)
882 return E_POINTER;
884 EnterCriticalSection(&This->pin.filter->csFilter);
886 if (This->pin.filter->state != State_Stopped)
888 LeaveCriticalSection(&This->pin.filter->csFilter);
889 WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
890 return VFW_E_NOT_STOPPED;
893 if (This->pin.peer)
894 hr = VFW_E_ALREADY_CONNECTED;
896 if (SUCCEEDED(hr) && !query_accept(&This->pin, pmt))
897 hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
898 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
900 if (SUCCEEDED(hr))
902 IPin_QueryDirection(pReceivePin, &pindirReceive);
904 if (pindirReceive != PINDIR_OUTPUT)
906 ERR("Can't connect from non-output pin\n");
907 hr = VFW_E_INVALID_DIRECTION;
911 if (SUCCEEDED(hr) && This->pFuncsTable->sink_connect)
912 hr = This->pFuncsTable->sink_connect(This, pReceivePin, pmt);
914 if (SUCCEEDED(hr))
916 CopyMediaType(&This->pin.mt, pmt);
917 This->pin.peer = pReceivePin;
918 IPin_AddRef(pReceivePin);
921 LeaveCriticalSection(&This->pin.filter->csFilter);
923 return hr;
926 static HRESULT WINAPI sink_Disconnect(IPin *iface)
928 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
929 HRESULT hr;
931 TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
933 EnterCriticalSection(&pin->pin.filter->csFilter);
935 if (pin->pin.peer)
937 if (pin->pFuncsTable->sink_disconnect)
938 pin->pFuncsTable->sink_disconnect(pin);
940 if (pin->pAllocator)
942 IMemAllocator_Release(pin->pAllocator);
943 pin->pAllocator = NULL;
946 IPin_Release(pin->pin.peer);
947 pin->pin.peer = NULL;
948 FreeMediaType(&pin->pin.mt);
949 memset(&pin->pin.mt, 0, sizeof(AM_MEDIA_TYPE));
950 hr = S_OK;
952 else
953 hr = S_FALSE;
955 LeaveCriticalSection(&pin->pin.filter->csFilter);
957 return hr;
960 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
962 return IPin_EndOfStream( pin );
965 static HRESULT WINAPI sink_EndOfStream(IPin *iface)
967 struct strmbase_sink *This = impl_sink_from_IPin(iface);
968 HRESULT hr = S_OK;
970 TRACE("pin %p %s:%s.\n", This, debugstr_w(This->pin.filter->name), debugstr_w(This->pin.name));
972 if (This->pFuncsTable->sink_eos)
973 return This->pFuncsTable->sink_eos(This);
975 EnterCriticalSection(&This->pin.filter->csFilter);
976 if (This->flushing)
977 hr = S_FALSE;
978 LeaveCriticalSection(&This->pin.filter->csFilter);
980 if (hr == S_OK)
981 hr = SendFurther(This, deliver_endofstream, NULL);
982 return hr;
985 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
987 return IPin_BeginFlush( pin );
990 static HRESULT WINAPI sink_BeginFlush(IPin *iface)
992 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
993 HRESULT hr;
995 TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
997 EnterCriticalSection(&pin->pin.filter->csFilter);
999 pin->flushing = TRUE;
1001 if (pin->pFuncsTable->sink_begin_flush)
1002 hr = pin->pFuncsTable->sink_begin_flush(pin);
1003 else
1004 hr = SendFurther(pin, deliver_beginflush, NULL);
1006 LeaveCriticalSection(&pin->pin.filter->csFilter);
1008 return hr;
1011 static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
1013 return IPin_EndFlush( pin );
1016 static HRESULT WINAPI sink_EndFlush(IPin * iface)
1018 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
1019 HRESULT hr;
1021 TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
1023 EnterCriticalSection(&pin->pin.filter->csFilter);
1025 pin->flushing = FALSE;
1027 if (pin->pFuncsTable->sink_end_flush)
1028 hr = pin->pFuncsTable->sink_end_flush(pin);
1029 else
1030 hr = SendFurther(pin, deliver_endflush, NULL);
1032 LeaveCriticalSection(&pin->pin.filter->csFilter);
1034 return hr;
1037 typedef struct newsegmentargs
1039 REFERENCE_TIME tStart, tStop;
1040 double rate;
1041 } newsegmentargs;
1043 static HRESULT deliver_newsegment(IPin *pin, LPVOID data)
1045 newsegmentargs *args = data;
1046 return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate);
1049 static HRESULT WINAPI sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1051 struct strmbase_sink *pin = impl_sink_from_IPin(iface);
1052 newsegmentargs args;
1054 TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin, debugstr_w(pin->pin.filter->name),
1055 debugstr_w(pin->pin.name), debugstr_time(start), debugstr_time(stop), rate);
1057 if (pin->pFuncsTable->sink_new_segment)
1058 return pin->pFuncsTable->sink_new_segment(pin, start, stop, rate);
1060 args.tStart = start;
1061 args.tStop = stop;
1062 args.rate = rate;
1064 return SendFurther(pin, deliver_newsegment, &args);
1067 static const IPinVtbl sink_vtbl =
1069 pin_QueryInterface,
1070 pin_AddRef,
1071 pin_Release,
1072 sink_Connect,
1073 sink_ReceiveConnection,
1074 sink_Disconnect,
1075 pin_ConnectedTo,
1076 pin_ConnectionMediaType,
1077 pin_QueryPinInfo,
1078 pin_QueryDirection,
1079 pin_QueryId,
1080 pin_QueryAccept,
1081 pin_EnumMediaTypes,
1082 pin_QueryInternalConnections,
1083 sink_EndOfStream,
1084 sink_BeginFlush,
1085 sink_EndFlush,
1086 sink_NewSegment,
1089 /*** IMemInputPin implementation ***/
1091 static inline struct strmbase_sink *impl_from_IMemInputPin(IMemInputPin *iface)
1093 return CONTAINING_RECORD(iface, struct strmbase_sink, IMemInputPin_iface);
1096 static HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
1098 struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1100 return IPin_QueryInterface(&This->pin.IPin_iface, riid, ppv);
1103 static ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
1105 struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1107 return IPin_AddRef(&This->pin.IPin_iface);
1110 static ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
1112 struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1114 return IPin_Release(&This->pin.IPin_iface);
1117 static HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
1119 struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1121 TRACE("pin %p %s:%s, allocator %p.\n", This, debugstr_w(This->pin.filter->name),
1122 debugstr_w(This->pin.name), ppAllocator);
1124 *ppAllocator = This->pAllocator;
1125 if (*ppAllocator)
1126 IMemAllocator_AddRef(*ppAllocator);
1128 return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
1131 static HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
1133 struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1135 TRACE("pin %p %s:%s, allocator %p, read_only %d.\n", This, debugstr_w(This->pin.filter->name),
1136 debugstr_w(This->pin.name), pAllocator, bReadOnly);
1138 if (bReadOnly)
1139 FIXME("Read only flag not handled yet!\n");
1141 /* FIXME: Should we release the allocator on disconnection? */
1142 if (!pAllocator)
1144 WARN("Null allocator\n");
1145 return E_POINTER;
1148 if (This->preferred_allocator && pAllocator != This->preferred_allocator)
1149 return E_FAIL;
1151 if (This->pAllocator)
1152 IMemAllocator_Release(This->pAllocator);
1153 This->pAllocator = pAllocator;
1154 if (This->pAllocator)
1155 IMemAllocator_AddRef(This->pAllocator);
1157 return S_OK;
1160 static HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1162 struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
1164 TRACE("pin %p %s:%s, props %p.\n", pin, debugstr_w(pin->pin.filter->name),
1165 debugstr_w(pin->pin.name), props);
1167 /* override this method if you have any specific requirements */
1169 return E_NOTIMPL;
1172 static HRESULT WINAPI MemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
1174 struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
1175 HRESULT hr = S_FALSE;
1177 TRACE("pin %p %s:%s, sample %p.\n", pin, debugstr_w(pin->pin.filter->name),
1178 debugstr_w(pin->pin.name), sample);
1180 if (pin->pFuncsTable->pfnReceive)
1181 hr = pin->pFuncsTable->pfnReceive(pin, sample);
1182 return hr;
1185 static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed)
1187 HRESULT hr = S_OK;
1189 for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
1191 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
1192 if (hr != S_OK)
1193 break;
1196 return hr;
1199 static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
1201 struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
1203 TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
1205 return S_OK;
1208 static const IMemInputPinVtbl MemInputPin_Vtbl =
1210 MemInputPin_QueryInterface,
1211 MemInputPin_AddRef,
1212 MemInputPin_Release,
1213 MemInputPin_GetAllocator,
1214 MemInputPin_NotifyAllocator,
1215 MemInputPin_GetAllocatorRequirements,
1216 MemInputPin_Receive,
1217 MemInputPin_ReceiveMultiple,
1218 MemInputPin_ReceiveCanBlock
1221 void strmbase_sink_init(struct strmbase_sink *pin, struct strmbase_filter *filter,
1222 const WCHAR *name, const struct strmbase_sink_ops *func_table, IMemAllocator *allocator)
1224 memset(pin, 0, sizeof(*pin));
1225 pin->pin.IPin_iface.lpVtbl = &sink_vtbl;
1226 pin->pin.filter = filter;
1227 pin->pin.dir = PINDIR_INPUT;
1228 lstrcpyW(pin->pin.name, name);
1229 pin->pin.ops = &func_table->base;
1230 pin->pFuncsTable = func_table;
1231 pin->pAllocator = pin->preferred_allocator = allocator;
1232 if (pin->preferred_allocator)
1233 IMemAllocator_AddRef(pin->preferred_allocator);
1234 pin->IMemInputPin_iface.lpVtbl = &MemInputPin_Vtbl;
1237 void strmbase_sink_cleanup(struct strmbase_sink *pin)
1239 FreeMediaType(&pin->pin.mt);
1240 if (pin->pAllocator)
1241 IMemAllocator_Release(pin->pAllocator);
1242 pin->pAllocator = NULL;
1243 pin->pin.IPin_iface.lpVtbl = NULL;