diff --git a/dlls/qedit/Makefile.in b/dlls/qedit/Makefile.in index c4dc37895eb..b6f9e8ee661 100644 --- a/dlls/qedit/Makefile.in +++ b/dlls/qedit/Makefile.in @@ -8,7 +8,8 @@ IMPORTS = strmiids uuid oleaut32 ole32 advapi32 kernel32 C_SRCS = \ main.c \ mediadet.c \ - regsvr.c + regsvr.c \ + samplegrabber.c @MAKE_DLL_RULES@ diff --git a/dlls/qedit/main.c b/dlls/qedit/main.c index df00137647b..ede377fb579 100644 --- a/dlls/qedit/main.c +++ b/dlls/qedit/main.c @@ -53,6 +53,7 @@ struct object_creation_info static const struct object_creation_info object_creation[] = { { &CLSID_MediaDet, MediaDet_create }, + { &CLSID_SampleGrabber, SampleGrabber_create }, }; static HRESULT WINAPI diff --git a/dlls/qedit/qedit_private.h b/dlls/qedit/qedit_private.h index 7af54ce93ae..842ae0f0899 100644 --- a/dlls/qedit/qedit_private.h +++ b/dlls/qedit/qedit_private.h @@ -36,5 +36,6 @@ #include "qedit.h" HRESULT MediaDet_create(IUnknown *pUnkOuter, LPVOID *ppObj); +HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppObj); #endif /* __QEDIT_PRIVATE_INCLUDED__ */ diff --git a/dlls/qedit/regsvr.c b/dlls/qedit/regsvr.c index 9ff18528523..d70c8222ee8 100644 --- a/dlls/qedit/regsvr.c +++ b/dlls/qedit/regsvr.c @@ -294,6 +294,12 @@ static struct regsvr_coclass const coclass_list[] = { "qedit.dll", "Both" }, + { &CLSID_SampleGrabber, + "Sample Grabber", + NULL, + "qedit.dll", + "Both" + }, { NULL } /* list terminator */ }; diff --git a/dlls/qedit/samplegrabber.c b/dlls/qedit/samplegrabber.c new file mode 100644 index 00000000000..4e80f24f4d5 --- /dev/null +++ b/dlls/qedit/samplegrabber.c @@ -0,0 +1,453 @@ +/* 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 +#include + +#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; +}