| /* DirectShow Sample Grabber object (QEDIT.DLL) |
| * |
| * Copyright 2009 Paul Chitescu |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <assert.h> |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "ole2.h" |
| |
| #include "qedit_private.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(qedit); |
| |
| static WCHAR const vendor_name[] = { 'W', 'i', 'n', 'e', 0 }; |
| |
| /* Sample Grabber filter implementation */ |
| typedef struct _SG_Impl { |
| const IBaseFilterVtbl* IBaseFilter_Vtbl; |
| const ISampleGrabberVtbl* ISampleGrabber_Vtbl; |
| /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */ |
| LONG refCount; |
| FILTER_INFO info; |
| FILTER_STATE state; |
| IMemAllocator *allocator; |
| IReferenceClock *refClock; |
| } SG_Impl; |
| |
| /* Get the SampleGrabber implementation This pointer from various interface pointers */ |
| static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface) |
| { |
| return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IBaseFilter_Vtbl)); |
| } |
| |
| static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface) |
| { |
| return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, ISampleGrabber_Vtbl)); |
| } |
| |
| |
| /* Cleanup at end of life */ |
| static void SampleGrabber_cleanup(SG_Impl *This) |
| { |
| TRACE("(%p)\n", This); |
| if (This->info.pGraph) |
| WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph); |
| if (This->allocator) |
| IMemAllocator_Release(This->allocator); |
| if (This->refClock) |
| IReferenceClock_Release(This->refClock); |
| } |
| |
| /* Common helper AddRef called from all interfaces */ |
| static ULONG SampleGrabber_addref(SG_Impl *This) |
| { |
| ULONG refCount = InterlockedIncrement(&This->refCount); |
| TRACE("(%p) new ref = %u\n", This, refCount); |
| return refCount; |
| } |
| |
| /* Common helper Release called from all interfaces */ |
| static ULONG SampleGrabber_release(SG_Impl *This) |
| { |
| ULONG refCount = InterlockedDecrement(&This->refCount); |
| TRACE("(%p) new ref = %u\n", This, refCount); |
| if (refCount == 0) |
| { |
| SampleGrabber_cleanup(This); |
| CoTaskMemFree(This); |
| return 0; |
| } |
| return refCount; |
| } |
| |
| /* Common helper QueryInterface called from all interfaces */ |
| static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject) |
| { |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); |
| |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IPersist) || |
| IsEqualIID(riid, &IID_IMediaFilter) || |
| IsEqualIID(riid, &IID_IBaseFilter)) { |
| SampleGrabber_addref(This); |
| *ppvObject = &(This->IBaseFilter_Vtbl); |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, &IID_ISampleGrabber)) { |
| SampleGrabber_addref(This); |
| *ppvObject = &(This->ISampleGrabber_Vtbl); |
| return S_OK; |
| } |
| else if (IsEqualIID(riid, &IID_IMemInputPin)) |
| FIXME("IMemInputPin not implemented\n"); |
| else if (IsEqualIID(riid, &IID_IMediaPosition)) |
| FIXME("IMediaPosition not implemented\n"); |
| else if (IsEqualIID(riid, &IID_IMediaSeeking)) |
| FIXME("IMediaSeeking not implemented\n"); |
| else if (IsEqualIID(riid, &IID_IQualityControl)) |
| FIXME("IQualityControl not implemented\n"); |
| *ppvObject = NULL; |
| WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject); |
| return E_NOINTERFACE; |
| } |
| |
| |
| /* SampleGrabber implementation of IBaseFilter interface */ |
| |
| /* IUnknown */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppvObject) |
| { |
| return SampleGrabber_query(impl_from_IBaseFilter(iface), riid, ppvObject); |
| } |
| |
| /* IUnknown */ |
| static ULONG WINAPI |
| SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface) |
| { |
| return SampleGrabber_addref(impl_from_IBaseFilter(iface)); |
| } |
| |
| /* IUnknown */ |
| static ULONG WINAPI |
| SampleGrabber_IBaseFilter_Release(IBaseFilter *iface) |
| { |
| return SampleGrabber_release(impl_from_IBaseFilter(iface)); |
| } |
| |
| /* IPersist */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID) |
| { |
| TRACE("(%p)\n", pClassID); |
| if (!pClassID) |
| return E_POINTER; |
| *pClassID = CLSID_SampleGrabber; |
| return S_OK; |
| } |
| |
| /* IMediaFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)\n", This); |
| This->state = State_Stopped; |
| return S_OK; |
| } |
| |
| /* IMediaFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)\n", This); |
| This->state = State_Paused; |
| return S_OK; |
| } |
| |
| /* IMediaFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)\n", This); |
| This->state = State_Running; |
| return S_OK; |
| } |
| |
| /* IMediaFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)->(%u, %p)\n", This, msTout, state); |
| if (!state) |
| return E_POINTER; |
| *state = This->state; |
| return S_OK; |
| } |
| |
| /* IMediaFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)->(%p)\n", This, clock); |
| if (clock != This->refClock) |
| { |
| if (clock) |
| IReferenceClock_AddRef(clock); |
| if (This->refClock) |
| IReferenceClock_Release(This->refClock); |
| This->refClock = clock; |
| } |
| return S_OK; |
| } |
| |
| /* IMediaFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)->(%p)\n", This, clock); |
| if (!clock) |
| return E_POINTER; |
| if (This->refClock) |
| IReferenceClock_AddRef(This->refClock); |
| *clock = This->refClock; |
| return S_OK; |
| } |
| |
| /* IBaseFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| FIXME("(%p)->(%p): stub\n", This, pins); |
| if (!pins) |
| return E_POINTER; |
| return E_OUTOFMEMORY; |
| } |
| |
| /* IBaseFilter */ |
| 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); |
| if (!id || !pin) |
| return E_POINTER; |
| *pin = NULL; |
| return VFW_E_NOT_FOUND; |
| } |
| |
| /* IBaseFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)->(%p)\n", This, info); |
| if (!info) |
| return E_POINTER; |
| if (This->info.pGraph) |
| IFilterGraph_AddRef(This->info.pGraph); |
| *info = This->info; |
| return S_OK; |
| } |
| |
| /* IBaseFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name) |
| { |
| SG_Impl *This = impl_from_IBaseFilter(iface); |
| TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name)); |
| This->info.pGraph = graph; |
| if (name) |
| lstrcpynW(This->info.achName,name,MAX_FILTER_NAME); |
| return S_OK; |
| } |
| |
| /* IBaseFilter */ |
| static HRESULT WINAPI |
| SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor) |
| { |
| TRACE("(%p)\n", vendor); |
| if (!vendor) |
| return E_POINTER; |
| *vendor = CoTaskMemAlloc(sizeof(vendor_name)); |
| CopyMemory(*vendor, vendor_name, sizeof(vendor_name)); |
| return S_OK; |
| } |
| |
| |
| /* SampleGrabber implementation of ISampleGrabber interface */ |
| |
| /* IUnknown */ |
| static HRESULT WINAPI |
| SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppvObject) |
| { |
| return SampleGrabber_query(impl_from_ISampleGrabber(iface), riid, ppvObject); |
| } |
| |
| /* IUnknown */ |
| static ULONG WINAPI |
| SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface) |
| { |
| return SampleGrabber_addref(impl_from_ISampleGrabber(iface)); |
| } |
| |
| /* IUnknown */ |
| static ULONG WINAPI |
| SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface) |
| { |
| return SampleGrabber_release(impl_from_ISampleGrabber(iface)); |
| } |
| |
| /* ISampleGrabber */ |
| 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; |
| } |
| |
| /* ISampleGrabber */ |
| 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); |
| if (!type) |
| return E_POINTER; |
| return E_NOTIMPL; |
| } |
| |
| /* ISampleGrabber */ |
| 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); |
| if (!type) |
| return E_POINTER; |
| return E_NOTIMPL; |
| } |
| |
| /* ISampleGrabber */ |
| static HRESULT WINAPI |
| SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm) |
| { |
| TRACE("(%u)\n", bufferEm); |
| if (bufferEm) { |
| FIXME("buffering not implemented\n"); |
| return E_NOTIMPL; |
| } |
| return S_OK; |
| } |
| |
| /* ISampleGrabber */ |
| static HRESULT WINAPI |
| SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer) |
| { |
| FIXME("(%p, %p): stub\n", bufSize, buffer); |
| if (!bufSize) |
| return E_POINTER; |
| return E_INVALIDARG; |
| } |
| |
| /* ISampleGrabber */ |
| static HRESULT WINAPI |
| SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample) |
| { |
| /* MS doesn't implement it either, noone should call it */ |
| WARN("(%p): not implemented\n", sample); |
| return E_NOTIMPL; |
| } |
| |
| /* ISampleGrabber */ |
| 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); |
| return E_NOTIMPL; |
| } |
| |
| |
| /* SampleGrabber vtables and constructor */ |
| |
| static const IBaseFilterVtbl IBaseFilter_VTable = |
| { |
| SampleGrabber_IBaseFilter_QueryInterface, |
| SampleGrabber_IBaseFilter_AddRef, |
| SampleGrabber_IBaseFilter_Release, |
| SampleGrabber_IBaseFilter_GetClassID, |
| SampleGrabber_IBaseFilter_Stop, |
| SampleGrabber_IBaseFilter_Pause, |
| SampleGrabber_IBaseFilter_Run, |
| SampleGrabber_IBaseFilter_GetState, |
| SampleGrabber_IBaseFilter_SetSyncSource, |
| SampleGrabber_IBaseFilter_GetSyncSource, |
| SampleGrabber_IBaseFilter_EnumPins, |
| SampleGrabber_IBaseFilter_FindPin, |
| SampleGrabber_IBaseFilter_QueryFilterInfo, |
| SampleGrabber_IBaseFilter_JoinFilterGraph, |
| SampleGrabber_IBaseFilter_QueryVendorInfo, |
| }; |
| |
| static const ISampleGrabberVtbl ISampleGrabber_VTable = |
| { |
| SampleGrabber_ISampleGrabber_QueryInterface, |
| SampleGrabber_ISampleGrabber_AddRef, |
| SampleGrabber_ISampleGrabber_Release, |
| SampleGrabber_ISampleGrabber_SetOneShot, |
| SampleGrabber_ISampleGrabber_SetMediaType, |
| SampleGrabber_ISampleGrabber_GetConnectedMediaType, |
| SampleGrabber_ISampleGrabber_SetBufferSamples, |
| SampleGrabber_ISampleGrabber_GetCurrentBuffer, |
| SampleGrabber_ISampleGrabber_GetCurrentSample, |
| SampleGrabber_ISampleGrabber_SetCallback, |
| }; |
| |
| HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv) |
| { |
| SG_Impl* obj = NULL; |
| |
| TRACE("(%p,%p)\n", ppv, pUnkOuter); |
| |
| if (pUnkOuter) |
| return CLASS_E_NOAGGREGATION; |
| |
| obj = CoTaskMemAlloc(sizeof(SG_Impl)); |
| if (NULL == obj) { |
| *ppv = NULL; |
| return E_OUTOFMEMORY; |
| } |
| ZeroMemory(obj, sizeof(SG_Impl)); |
| |
| obj->refCount = 1; |
| obj->IBaseFilter_Vtbl = &IBaseFilter_VTable; |
| obj->ISampleGrabber_Vtbl = &ISampleGrabber_VTable; |
| obj->info.achName[0] = 0; |
| obj->info.pGraph = NULL; |
| obj->state = State_Stopped; |
| obj->allocator = NULL; |
| obj->refClock = NULL; |
| *ppv = obj; |
| |
| return S_OK; |
| } |