From 746a02797754b82e52b387b067073036442bdb4a Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 2 Mar 2010 11:28:12 +0000 Subject: [PATCH] [QEDIT] sync qedit to wine 1.1.39 svn path=/trunk/; revision=45752 --- reactos/dll/directx/qedit/samplegrabber.c | 982 +++++++++++++++++++++- 1 file changed, 970 insertions(+), 12 deletions(-) diff --git a/reactos/dll/directx/qedit/samplegrabber.c b/reactos/dll/directx/qedit/samplegrabber.c index 4e80f24f4d5..b4912eb63de 100644 --- a/reactos/dll/directx/qedit/samplegrabber.c +++ b/reactos/dll/directx/qedit/samplegrabber.c @@ -33,19 +33,353 @@ WINE_DEFAULT_DEBUG_CHANNEL(qedit); static WCHAR const vendor_name[] = { 'W', 'i', 'n', 'e', 0 }; +static WCHAR const pin_in_name[] = { 'I', 'n', 0 }; +static WCHAR const pin_out_name[] = { 'O', 'u', 't', 0 }; + +IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount); +IEnumMediaTypes *mediaenum_create(AM_MEDIA_TYPE *mtype); + +/* Fixed pins enumerator, holds filter referenced */ +typedef struct _PE_Impl { + IEnumPins pe; + IBaseFilter *filter; + LONG refCount; + ULONG numPins; + ULONG index; + IPin *pins[0]; +} PE_Impl; + + +/* IEnumPins interface implementation */ + +/* IUnknown */ +static ULONG WINAPI +Fixed_IEnumPins_AddRef(IEnumPins *iface) +{ + PE_Impl *This = (PE_Impl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + TRACE("(%p) new ref = %u\n", This, refCount); + return refCount; +} + +/* IUnknown */ +static ULONG WINAPI +Fixed_IEnumPins_Release(IEnumPins *iface) +{ + PE_Impl *This = (PE_Impl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + TRACE("(%p) new ref = %u\n", This, refCount); + if (refCount == 0) + { + IBaseFilter_Release(This->filter); + CoTaskMemFree(This); + return 0; + } + return refCount; +} + +/* IUnknown */ +static HRESULT WINAPI +Fixed_IEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppvObject) +{ + PE_Impl *This = (PE_Impl *)iface; + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IEnumPins)) { + Fixed_IEnumPins_AddRef(iface); + *ppvObject = &(This->pins); + return S_OK; + } + *ppvObject = NULL; + WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject); + return E_NOINTERFACE; +} + +/* IEnumPins */ +static HRESULT WINAPI +Fixed_IEnumPins_Next(IEnumPins *iface, ULONG nPins, IPin **pins, ULONG *fetched) +{ + PE_Impl *This = (PE_Impl *)iface; + ULONG count = 0; + TRACE("(%p)->(%u, %p, %p) index = %u\n", This, nPins, pins, fetched, This->index); + if (!nPins) + return E_INVALIDARG; + if (!pins || ((nPins != 1) && !fetched)) + return E_POINTER; + while ((count < nPins) && (This->index < This->numPins)) { + IPin *pin = This->pins[This->index++]; + IPin_AddRef(pin); + pins[count++] = pin; + } + if (fetched) + *fetched = count; + return (count == nPins) ? S_OK : S_FALSE; +} + +/* IEnumPins */ +static HRESULT WINAPI +Fixed_IEnumPins_Skip(IEnumPins *iface, ULONG nPins) +{ + PE_Impl *This = (PE_Impl *)iface; + TRACE("(%p)->(%u) index = %u\n", This, nPins, This->index); + nPins += This->index; + if (nPins >= This->numPins) { + This->index = This->numPins; + return S_FALSE; + } + This->index = nPins; + return S_OK; +} + +/* IEnumPins */ +static HRESULT WINAPI +Fixed_IEnumPins_Reset(IEnumPins *iface) +{ + PE_Impl *This = (PE_Impl *)iface; + TRACE("(%p)->() index = %u\n", This, This->index); + This->index = 0; + return S_OK; +} + +/* IEnumPins */ +static HRESULT WINAPI +Fixed_IEnumPins_Clone(IEnumPins *iface, IEnumPins **pins) +{ + PE_Impl *This = (PE_Impl *)iface; + TRACE("(%p)->(%p) index = %u\n", This, pins, This->index); + if (!pins) + return E_POINTER; + *pins = pinsenum_create(This->filter, This->pins, This->numPins); + if (!*pins) + return E_OUTOFMEMORY; + ((PE_Impl *)*pins)->index = This->index; + return S_OK; +} + + +/* Virtual tables and constructor */ + +static const IEnumPinsVtbl IEnumPins_VTable = +{ + Fixed_IEnumPins_QueryInterface, + Fixed_IEnumPins_AddRef, + Fixed_IEnumPins_Release, + Fixed_IEnumPins_Next, + Fixed_IEnumPins_Skip, + Fixed_IEnumPins_Reset, + Fixed_IEnumPins_Clone, +}; + +IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount) +{ + ULONG len = sizeof(PE_Impl) + (pinCount * sizeof(IPin *)); + PE_Impl *obj = CoTaskMemAlloc(len); + if (obj) { + ULONG i; + ZeroMemory(obj, len); + obj->pe.lpVtbl = &IEnumPins_VTable; + obj->refCount = 1; + obj->filter = filter; + obj->numPins = pinCount; + obj->index = 0; + for (i=0; ipins[i] = pins[i]; + IBaseFilter_AddRef(filter); + } + return &obj->pe; +} + + +/* Single media type enumerator */ +typedef struct _ME_Impl { + IEnumMediaTypes me; + LONG refCount; + BOOL past; + AM_MEDIA_TYPE mtype; +} ME_Impl; + + +/* IEnumMediaTypes interface implementation */ + +/* IUnknown */ +static ULONG WINAPI +Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface) +{ + ME_Impl *This = (ME_Impl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + TRACE("(%p) new ref = %u\n", This, refCount); + return refCount; +} + +/* IUnknown */ +static ULONG WINAPI +Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface) +{ + ME_Impl *This = (ME_Impl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + TRACE("(%p) new ref = %u\n", This, refCount); + if (refCount == 0) + { + if (This->mtype.pbFormat) + CoTaskMemFree(This->mtype.pbFormat); + CoTaskMemFree(This); + return 0; + } + return refCount; +} + +/* IUnknown */ +static HRESULT WINAPI +Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, void **ppvObject) +{ + ME_Impl *This = (ME_Impl *)iface; + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IEnumMediaTypes)) { + Single_IEnumMediaTypes_AddRef(iface); + *ppvObject = &(This->me); + return S_OK; + } + *ppvObject = NULL; + WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject); + return E_NOINTERFACE; +} + +/* IEnumMediaTypes */ +static HRESULT WINAPI +Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes, AM_MEDIA_TYPE **types, ULONG *fetched) +{ + ME_Impl *This = (ME_Impl *)iface; + ULONG count = 0; + TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched); + if (!nTypes) + return E_INVALIDARG; + if (!types || ((nTypes != 1) && !fetched)) + return E_POINTER; + if (!This->past) { + AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + *mtype = This->mtype; + if (mtype->cbFormat) { + mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat); + CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat); + } + *types = mtype; + This->past = TRUE; + count = 1; + } + if (fetched) + *fetched = count; + return (count == nTypes) ? S_OK : S_FALSE; +} + +/* IEnumMediaTypes */ +static HRESULT WINAPI +Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes) +{ + ME_Impl *This = (ME_Impl *)iface; + TRACE("(%p)->(%u)\n", This, nTypes); + if (nTypes) + This->past = TRUE; + return This->past ? S_FALSE : S_OK; +} + +/* IEnumMediaTypes */ +static HRESULT WINAPI +Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface) +{ + ME_Impl *This = (ME_Impl *)iface; + TRACE("(%p)->()\n", This); + This->past = FALSE; + return S_OK; +} + +/* IEnumMediaTypes */ +static HRESULT WINAPI +Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me) +{ + ME_Impl *This = (ME_Impl *)iface; + TRACE("(%p)->(%p)\n", This, me); + if (!me) + return E_POINTER; + *me = mediaenum_create(&This->mtype); + if (!*me) + return E_OUTOFMEMORY; + ((ME_Impl *)*me)->past = This->past; + return S_OK; +} + + +/* Virtual tables and constructor */ + +static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable = +{ + Single_IEnumMediaTypes_QueryInterface, + Single_IEnumMediaTypes_AddRef, + Single_IEnumMediaTypes_Release, + Single_IEnumMediaTypes_Next, + Single_IEnumMediaTypes_Skip, + Single_IEnumMediaTypes_Reset, + Single_IEnumMediaTypes_Clone, +}; + +IEnumMediaTypes *mediaenum_create(AM_MEDIA_TYPE *mtype) +{ + ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl)); + if (obj) { + ZeroMemory(obj, sizeof(ME_Impl)); + obj->me.lpVtbl = &IEnumMediaTypes_VTable; + obj->refCount = 1; + obj->past = FALSE; + obj->mtype = *mtype; + obj->mtype.pUnk = NULL; + if (mtype->cbFormat) { + obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat); + CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat); + } + else + obj->mtype.pbFormat = NULL; + } + return &obj->me; +} + + +/* Sample Grabber pin implementation */ +typedef struct _SG_Pin { + const IPinVtbl* lpVtbl; + PIN_DIRECTION dir; + WCHAR const *name; + struct _SG_Impl *sg; + IPin *pair; +} SG_Pin; /* Sample Grabber filter implementation */ typedef struct _SG_Impl { const IBaseFilterVtbl* IBaseFilter_Vtbl; const ISampleGrabberVtbl* ISampleGrabber_Vtbl; + const IMemInputPinVtbl* IMemInputPin_Vtbl; /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */ LONG refCount; FILTER_INFO info; FILTER_STATE state; + AM_MEDIA_TYPE mtype; + SG_Pin pin_in; + SG_Pin pin_out; IMemAllocator *allocator; IReferenceClock *refClock; + IMemInputPin *memOutput; + ISampleGrabberCB *grabberIface; + LONG grabberMethod; + LONG oneShot; } SG_Impl; +enum { + OneShot_None, + OneShot_Wait, + OneShot_Past, +}; + /* Get the SampleGrabber implementation This pointer from various interface pointers */ static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface) { @@ -57,6 +391,11 @@ static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface) return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, ISampleGrabber_Vtbl)); } +static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface) +{ + return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IMemInputPin_Vtbl)); +} + /* Cleanup at end of life */ static void SampleGrabber_cleanup(SG_Impl *This) @@ -68,6 +407,12 @@ static void SampleGrabber_cleanup(SG_Impl *This) IMemAllocator_Release(This->allocator); if (This->refClock) IReferenceClock_Release(This->refClock); + if (This->memOutput) + IMemInputPin_Release(This->memOutput); + if (This->grabberIface) + ISampleGrabberCB_Release(This->grabberIface); + if (This->mtype.pbFormat) + CoTaskMemFree(This->mtype.pbFormat); } /* Common helper AddRef called from all interfaces */ @@ -110,8 +455,11 @@ static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject) *ppvObject = &(This->ISampleGrabber_Vtbl); return S_OK; } - else if (IsEqualIID(riid, &IID_IMemInputPin)) - FIXME("IMemInputPin not implemented\n"); + else if (IsEqualIID(riid, &IID_IMemInputPin)) { + SampleGrabber_addref(This); + *ppvObject = &(This->IMemInputPin_Vtbl); + return S_OK; + } else if (IsEqualIID(riid, &IID_IMediaPosition)) FIXME("IMediaPosition not implemented\n"); else if (IsEqualIID(riid, &IID_IMediaSeeking)) @@ -123,6 +471,45 @@ static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject) return E_NOINTERFACE; } +/* Helper that calls installed sample callbacks */ +static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample) +{ + double time = 0.0; + REFERENCE_TIME tStart, tEnd; + if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd))) + time = 1e-7 * tStart; + switch (This->grabberMethod) { + case 0: + { + ULONG ref = IMediaSample_AddRef(sample); + ISampleGrabberCB_SampleCB(This->grabberIface, time, sample); + ref = IMediaSample_Release(sample) + 1 - ref; + if (ref) + { + ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref); + /* ugly as hell but some apps are sooo buggy */ + while (ref--) + IMediaSample_Release(sample); + } + } + break; + case 1: + { + BYTE *data = 0; + long size = IMediaSample_GetActualDataLength(sample); + if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data) + ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size); + } + break; + case -1: + break; + default: + FIXME("unsupported method %ld\n", (long int)This->grabberMethod); + /* do not bother us again */ + This->grabberMethod = -1; + } +} + /* SampleGrabber implementation of IBaseFilter interface */ @@ -236,10 +623,14 @@ static HRESULT WINAPI SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins) { SG_Impl *This = impl_from_IBaseFilter(iface); - FIXME("(%p)->(%p): stub\n", This, pins); + IPin *pin[2]; + TRACE("(%p)->(%p)\n", This, pins); if (!pins) return E_POINTER; - return E_OUTOFMEMORY; + pin[0] = (IPin*)&This->pin_in.lpVtbl; + pin[1] = (IPin*)&This->pin_out.lpVtbl; + *pins = pinsenum_create(iface, pin, 2); + return *pins ? S_OK : E_OUTOFMEMORY; } /* IBaseFilter */ @@ -247,9 +638,21 @@ static HRESULT WINAPI SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin) { SG_Impl *This = impl_from_IBaseFilter(iface); - FIXME("(%p)->(%s, %p): stub\n", This, debugstr_w(id), pin); + TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin); if (!id || !pin) return E_POINTER; + if (!lstrcmpiW(id,pin_in_name)) + { + SampleGrabber_addref(This); + *pin = (IPin*)&(This->pin_in.lpVtbl); + return S_OK; + } + else if (!lstrcmpiW(id,pin_out_name)) + { + SampleGrabber_addref(This); + *pin = (IPin*)&(This->pin_out.lpVtbl); + return S_OK; + } *pin = NULL; return VFW_E_NOT_FOUND; } @@ -277,6 +680,7 @@ SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *grap This->info.pGraph = graph; if (name) lstrcpynW(This->info.achName,name,MAX_FILTER_NAME); + This->oneShot = OneShot_None; return S_OK; } @@ -321,8 +725,9 @@ static HRESULT WINAPI SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot) { SG_Impl *This = impl_from_ISampleGrabber(iface); - FIXME("(%p)->(%u): stub\n", This, oneShot); - return E_NOTIMPL; + TRACE("(%p)->(%u)\n", This, oneShot); + This->oneShot = oneShot ? OneShot_Wait : OneShot_None; + return S_OK; } /* ISampleGrabber */ @@ -330,10 +735,24 @@ static HRESULT WINAPI SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type) { SG_Impl *This = impl_from_ISampleGrabber(iface); - FIXME("(%p)->(%p): stub\n", This, type); + TRACE("(%p)->(%p)\n", This, type); if (!type) return E_POINTER; - return E_NOTIMPL; + TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n", + debugstr_guid(&type->majortype), debugstr_guid(&type->subtype), + type->lSampleSize, + debugstr_guid(&type->formattype), type->cbFormat); + if (This->mtype.pbFormat) + CoTaskMemFree(This->mtype.pbFormat); + This->mtype = *type; + This->mtype.pUnk = NULL; + if (type->cbFormat) { + This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat); + CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat); + } + else + This->mtype.pbFormat = NULL; + return S_OK; } /* ISampleGrabber */ @@ -341,10 +760,17 @@ static HRESULT WINAPI SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type) { SG_Impl *This = impl_from_ISampleGrabber(iface); - FIXME("(%p)->(%p): stub\n", This, type); + TRACE("(%p)->(%p)\n", This, type); if (!type) return E_POINTER; - return E_NOTIMPL; + if (!This->pin_in.pair) + return VFW_E_NOT_CONNECTED; + *type = This->mtype; + if (type->cbFormat) { + type->pbFormat = CoTaskMemAlloc(type->cbFormat); + CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat); + } + return S_OK; } /* ISampleGrabber */ @@ -383,10 +809,467 @@ static HRESULT WINAPI SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod) { SG_Impl *This = impl_from_ISampleGrabber(iface); - FIXME("(%p)->(%p, %u): stub\n", This, cb, whichMethod); + TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod); + if (This->grabberIface) + ISampleGrabberCB_Release(This->grabberIface); + This->grabberIface = cb; + This->grabberMethod = whichMethod; + if (cb) + ISampleGrabberCB_AddRef(cb); + return S_OK; +} + + +/* SampleGrabber implementation of IMemInputPin interface */ + +/* IUnknown */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppvObject) +{ + return SampleGrabber_query(impl_from_IMemInputPin(iface), riid, ppvObject); +} + +/* IUnknown */ +static ULONG WINAPI +SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface) +{ + return SampleGrabber_addref(impl_from_IMemInputPin(iface)); +} + +/* IUnknown */ +static ULONG WINAPI +SampleGrabber_IMemInputPin_Release(IMemInputPin *iface) +{ + return SampleGrabber_release(impl_from_IMemInputPin(iface)); +} + +/* IMemInputPin */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator) +{ + SG_Impl *This = impl_from_IMemInputPin(iface); + TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator); + if (!allocator) + return E_POINTER; + *allocator = This->allocator; + if (!*allocator) + return VFW_E_NO_ALLOCATOR; + IMemAllocator_AddRef(*allocator); + return S_OK; +} + +/* IMemInputPin */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly) +{ + SG_Impl *This = impl_from_IMemInputPin(iface); + TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator); + if (This->allocator == allocator) + return S_OK; + if (This->allocator) + IMemAllocator_Release(This->allocator); + This->allocator = allocator; + if (allocator) + IMemAllocator_AddRef(allocator); + return S_OK; +} + +/* IMemInputPin */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props) +{ + SG_Impl *This = impl_from_IMemInputPin(iface); + FIXME("(%p)->(%p): semi-stub\n", This, props); + if (!props) + return E_POINTER; + return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL; +} + +/* IMemInputPin */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample) +{ + SG_Impl *This = impl_from_IMemInputPin(iface); + HRESULT hr; + TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface); + if (!sample) + return E_POINTER; + if ((This->state != State_Running) || (This->oneShot == OneShot_Past)) + return S_FALSE; + if (This->grabberIface) + SampleGrabber_callback(This, sample); + hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK; + if (This->oneShot == OneShot_Wait) { + This->oneShot = OneShot_Past; + hr = S_FALSE; + if (This->pin_out.pair) + IPin_EndOfStream(This->pin_out.pair); + } + return hr; +} + +/* IMemInputPin */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed) +{ + SG_Impl *This = impl_from_IMemInputPin(iface); + TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface); + if (!samples || !nProcessed) + return E_POINTER; + if ((This->state != State_Running) || (This->oneShot == OneShot_Past)) + return S_FALSE; + if (This->grabberIface) { + LONG idx; + for (idx = 0; idx < nSamples; idx++) + SampleGrabber_callback(This, samples[idx]); + } + return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK; +} + +/* IMemInputPin */ +static HRESULT WINAPI +SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface) +{ + SG_Impl *This = impl_from_IMemInputPin(iface); + TRACE("(%p)\n", This); + return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK; +} + + +/* SampleGrabber member pin implementation */ + +/* IUnknown */ +static ULONG WINAPI +SampleGrabber_IPin_AddRef(IPin *iface) +{ + return SampleGrabber_addref(((SG_Pin *)iface)->sg); +} + +/* IUnknown */ +static ULONG WINAPI +SampleGrabber_IPin_Release(IPin *iface) +{ + return SampleGrabber_release(((SG_Pin *)iface)->sg); +} + +/* IUnknown */ +static HRESULT WINAPI +SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppvObject) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IPin)) { + SampleGrabber_addref(This->sg); + *ppvObject = This; + return S_OK; + } + else if (IsEqualIID(riid, &IID_IMemInputPin)) { + SampleGrabber_addref(This->sg); + *ppvObject = &(This->sg->IMemInputPin_Vtbl); + return S_OK; + } + *ppvObject = NULL; + WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject); + return E_NOINTERFACE; +} + +/* IPin - input pin */ +static HRESULT WINAPI +SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype) +{ + WARN("(%p, %p): unexpected\n", receiver, mtype); + return E_UNEXPECTED; +} + +/* IPin - output pin */ +static HRESULT WINAPI +SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type) +{ + SG_Pin *This = (SG_Pin *)iface; + HRESULT hr; + TRACE("(%p)->(%p, %p)\n", This, receiver, type); + if (!receiver) + return E_POINTER; + if (This->pair) + return VFW_E_ALREADY_CONNECTED; + if (This->sg->state != State_Stopped) + return VFW_E_NOT_STOPPED; + if (type) { + TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n", + debugstr_guid(&type->majortype), debugstr_guid(&type->subtype), + type->lSampleSize, + debugstr_guid(&type->formattype), type->cbFormat); + if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) && + !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype)) + return VFW_E_TYPE_NOT_ACCEPTED; + if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) && + !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype)) + return VFW_E_TYPE_NOT_ACCEPTED; + if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) && + !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) && + !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype)) + return VFW_E_TYPE_NOT_ACCEPTED; + } + else + type = &This->sg->mtype; + hr = IPin_ReceiveConnection(receiver,(IPin*)&This->lpVtbl,type); + if (FAILED(hr)) + return hr; + This->pair = receiver; + if (This->sg->memOutput) { + IMemInputPin_Release(This->sg->memOutput); + This->sg->memOutput = NULL; + } + IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput)); + TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput); + return S_OK; +} + +/* IPin - input pin */ +static HRESULT WINAPI +SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p, %p)\n", This, connector, type); + if (!connector) + return E_POINTER; + if (This->pair) + return VFW_E_ALREADY_CONNECTED; + if (This->sg->state != State_Stopped) + return VFW_E_NOT_STOPPED; + if (type) { + TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n", + debugstr_guid(&type->majortype), debugstr_guid(&type->subtype), + type->lSampleSize, + debugstr_guid(&type->formattype), type->cbFormat); + if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) && + !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype)) + return VFW_E_TYPE_NOT_ACCEPTED; + if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) && + !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype)) + return VFW_E_TYPE_NOT_ACCEPTED; + if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) && + !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) && + !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype)) + return VFW_E_TYPE_NOT_ACCEPTED; + if (This->sg->mtype.pbFormat) + CoTaskMemFree(This->sg->mtype.pbFormat); + This->sg->mtype = *type; + This->sg->mtype.pUnk = NULL; + if (type->cbFormat) { + This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat); + CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat); + } + else + This->sg->mtype.pbFormat = NULL; + } + This->pair = connector; + TRACE("(%p) Accepted IPin %p\n", This, connector); + return S_OK; +} + +/* IPin - output pin */ +static HRESULT WINAPI +SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype) +{ + WARN("(%p, %p): unexpected\n", connector, mtype); + return E_UNEXPECTED; +} + +/* IPin - input pin */ +static HRESULT WINAPI +SampleGrabber_In_IPin_Disconnect(IPin *iface) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->() pair = %p\n", This, This->pair); + if (This->sg->state != State_Stopped) + return VFW_E_NOT_STOPPED; + if (This->pair) { + This->pair = NULL; + return S_OK; + } + return S_FALSE; +} + +/* IPin - output pin */ +static HRESULT WINAPI +SampleGrabber_Out_IPin_Disconnect(IPin *iface) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->() pair = %p\n", This, This->pair); + if (This->sg->state != State_Stopped) + return VFW_E_NOT_STOPPED; + if (This->pair) { + This->pair = NULL; + if (This->sg->memOutput) { + IMemInputPin_Release(This->sg->memOutput); + This->sg->memOutput = NULL; + } + return S_OK; + } + return S_FALSE; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair); + if (!pin) + return E_POINTER; + *pin = This->pair; + if (*pin) { + IPin_AddRef(*pin); + return S_OK; + } + return VFW_E_NOT_CONNECTED; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p)\n", This, mtype); + if (!mtype) + return E_POINTER; + if (!This->pair) + return VFW_E_NOT_CONNECTED; + *mtype = This->sg->mtype; + if (mtype->cbFormat) { + mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat); + CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat); + } + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p)\n", This, info); + if (!info) + return E_POINTER; + SampleGrabber_addref(This->sg); + info->pFilter = (IBaseFilter *)This->sg; + info->dir = This->dir; + lstrcpynW(info->achName,This->name,MAX_PIN_NAME); + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p)\n", This, dir); + if (!dir) + return E_POINTER; + *dir = This->dir; + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id) +{ + SG_Pin *This = (SG_Pin *)iface; + int len; + TRACE("(%p)->(%p)\n", This, id); + if (!id) + return E_POINTER; + len = sizeof(WCHAR)*(1+lstrlenW(This->name)); + *id = CoTaskMemAlloc(len); + CopyMemory(*id, This->name, len); + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype) +{ + TRACE("(%p)\n", mtype); + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p)\n", This, mtypes); + if (!mtypes) + return E_POINTER; + *mtypes = mediaenum_create(&This->sg->mtype); + return *mtypes ? S_OK : E_OUTOFMEMORY; +} + +/* IPin - input pin */ +static HRESULT WINAPI +SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins) +{ + SG_Pin *This = (SG_Pin *)iface; + TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0)); + if (!nPins) + return E_POINTER; + if (*nPins) { + if (!pins) + return E_POINTER; + IPin_AddRef((IPin*)&This->sg->pin_out.lpVtbl); + *pins = (IPin*)&This->sg->pin_out.lpVtbl; + *nPins = 1; + return S_OK; + } + *nPins = 1; + return S_FALSE; +} + +/* IPin - output pin */ +static HRESULT WINAPI +SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins) +{ + WARN("(%p, %p): unexpected\n", pins, nPins); + if (nPins) + *nPins = 0; return E_NOTIMPL; } +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_EndOfStream(IPin *iface) +{ + FIXME(": stub\n"); + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_BeginFlush(IPin *iface) +{ + FIXME(": stub\n"); + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_EndFlush(IPin *iface) +{ + FIXME(": stub\n"); + return S_OK; +} + +/* IPin */ +static HRESULT WINAPI +SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate) +{ + FIXME(": stub\n"); + return S_OK; +} + /* SampleGrabber vtables and constructor */ @@ -423,6 +1306,63 @@ static const ISampleGrabberVtbl ISampleGrabber_VTable = SampleGrabber_ISampleGrabber_SetCallback, }; +static const IMemInputPinVtbl IMemInputPin_VTable = +{ + SampleGrabber_IMemInputPin_QueryInterface, + SampleGrabber_IMemInputPin_AddRef, + SampleGrabber_IMemInputPin_Release, + SampleGrabber_IMemInputPin_GetAllocator, + SampleGrabber_IMemInputPin_NotifyAllocator, + SampleGrabber_IMemInputPin_GetAllocatorRequirements, + SampleGrabber_IMemInputPin_Receive, + SampleGrabber_IMemInputPin_ReceiveMultiple, + SampleGrabber_IMemInputPin_ReceiveCanBlock, +}; + +static const IPinVtbl IPin_In_VTable = +{ + SampleGrabber_IPin_QueryInterface, + SampleGrabber_IPin_AddRef, + SampleGrabber_IPin_Release, + SampleGrabber_In_IPin_Connect, + SampleGrabber_In_IPin_ReceiveConnection, + SampleGrabber_In_IPin_Disconnect, + SampleGrabber_IPin_ConnectedTo, + SampleGrabber_IPin_ConnectionMediaType, + SampleGrabber_IPin_QueryPinInfo, + SampleGrabber_IPin_QueryDirection, + SampleGrabber_IPin_QueryId, + SampleGrabber_IPin_QueryAccept, + SampleGrabber_IPin_EnumMediaTypes, + SampleGrabber_In_IPin_QueryInternalConnections, + SampleGrabber_IPin_EndOfStream, + SampleGrabber_IPin_BeginFlush, + SampleGrabber_IPin_EndFlush, + SampleGrabber_IPin_NewSegment, +}; + +static const IPinVtbl IPin_Out_VTable = +{ + SampleGrabber_IPin_QueryInterface, + SampleGrabber_IPin_AddRef, + SampleGrabber_IPin_Release, + SampleGrabber_Out_IPin_Connect, + SampleGrabber_Out_IPin_ReceiveConnection, + SampleGrabber_Out_IPin_Disconnect, + SampleGrabber_IPin_ConnectedTo, + SampleGrabber_IPin_ConnectionMediaType, + SampleGrabber_IPin_QueryPinInfo, + SampleGrabber_IPin_QueryDirection, + SampleGrabber_IPin_QueryId, + SampleGrabber_IPin_QueryAccept, + SampleGrabber_IPin_EnumMediaTypes, + SampleGrabber_Out_IPin_QueryInternalConnections, + SampleGrabber_IPin_EndOfStream, + SampleGrabber_IPin_BeginFlush, + SampleGrabber_IPin_EndFlush, + SampleGrabber_IPin_NewSegment, +}; + HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv) { SG_Impl* obj = NULL; @@ -442,11 +1382,29 @@ HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv) obj->refCount = 1; obj->IBaseFilter_Vtbl = &IBaseFilter_VTable; obj->ISampleGrabber_Vtbl = &ISampleGrabber_VTable; + obj->IMemInputPin_Vtbl = &IMemInputPin_VTable; + obj->pin_in.lpVtbl = &IPin_In_VTable; + obj->pin_in.dir = PINDIR_INPUT; + obj->pin_in.name = pin_in_name; + obj->pin_in.sg = obj; + obj->pin_in.pair = NULL; + obj->pin_out.lpVtbl = &IPin_Out_VTable; + obj->pin_out.dir = PINDIR_OUTPUT; + obj->pin_out.name = pin_out_name; + obj->pin_out.sg = obj; + obj->pin_out.pair = NULL; obj->info.achName[0] = 0; obj->info.pGraph = NULL; obj->state = State_Stopped; + obj->mtype.majortype = GUID_NULL; + obj->mtype.subtype = MEDIASUBTYPE_None; + obj->mtype.formattype = FORMAT_None; obj->allocator = NULL; obj->refClock = NULL; + obj->memOutput = NULL; + obj->grabberIface = NULL; + obj->grabberMethod = -1; + obj->oneShot = OneShot_None; *ppv = obj; return S_OK;