From 5f3ab5aa2b49a5d98f915a8de9d03c5c994a074c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 21 Jul 2008 20:51:38 -0700 Subject: [PATCH] quartz: Add support for the file writer filter --- dlls/quartz/Makefile.in | 1 + dlls/quartz/filewriter.c | 966 ++++++++++++++++++++++++++++++++++++++++++ dlls/quartz/main.c | 3 +- dlls/quartz/quartz_private.h | 1 + dlls/quartz/regsvr.c | 20 +- 5 files changed, 989 insertions(+), 2 deletions(-) create mode 100644 dlls/quartz/filewriter.c diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 205c6a7..4753769 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -18,6 +18,7 @@ C_SRCS = \ enumpins.c \ enumregfilters.c \ filesource.c \ + filewriter.c \ filtergraph.c \ filtermapper.c \ main.c \ diff --git a/dlls/quartz/filewriter.c b/dlls/quartz/filewriter.c new file mode 100644 index 0000000..b830d17 --- /dev/null +++ b/dlls/quartz/filewriter.c @@ -0,0 +1,966 @@ +/* + * File Writer + * + * Copyright 2004 Christian Costa + * Copyright 2008 Maarten Lankhorst + * + * 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 "config.h" + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "quartz_private.h" +#include "control_private.h" +#include "pin.h" + +#include "uuids.h" +#include "vfwmsgs.h" +#include "amvideo.h" +#include "windef.h" +#include "winbase.h" +#include "dshow.h" +#include "evcode.h" +#include "strmif.h" +#include "ddraw.h" +#include "assert.h" + +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(quartz); + +static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; + +static const IBaseFilterVtbl FileWriter_Vtbl; +static const IUnknownVtbl IInner_VTable; +static const IPinVtbl FileWriter_InputPin_Vtbl; +static const IFileSinkFilter2Vtbl FileWriter_Sink_Vtbl; +static const IStreamVtbl FileWriter_Stream_Vtbl; + +typedef struct FileWriterImpl +{ + const IBaseFilterVtbl *lpVtbl; + const IUnknownVtbl *IInner_vtbl; + const IFileSinkFilter2Vtbl *sink2_vtbl; + const IStreamVtbl *stream_vtbl; + + LONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + REFERENCE_TIME rtStreamStart; + IReferenceClock * pClock; + FILTER_INFO filterInfo; + + InputPin *pInputPin; + IUnknown *pUnkOuter; + BOOL bUnkOuterValid; + BOOL bAggregatable; + MediaSeekingImpl mediaSeeking; + + DWORD mode; + WCHAR *filename; + HANDLE file; + AM_MEDIA_TYPE amt; + LONGLONG lastpos; +} FileWriterImpl; + +static HRESULT FileWriter_Sample(LPVOID iface, IMediaSample * pSample) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + HRESULT hr = S_OK; + LONGLONG tStart = 0, tStop = 0; + IStream *stream = (IStream *)&This->stream_vtbl; + LARGE_INTEGER move; + BYTE *ptr = NULL; + + TRACE("%p %p\n", iface, pSample); + + EnterCriticalSection(&This->csFilter); + if (This->pInputPin->flushing || This->pInputPin->end_of_stream) + { + hr = S_FALSE; + goto out; + } + + if (This->state == State_Stopped) + { + hr = VFW_E_WRONG_STATE; + goto out; + } + + if (!This->file) + { + ERR("Not backed by a file\n"); + hr = E_UNEXPECTED; + goto out; + } + + hr = IMediaSample_GetTime(pSample, &tStart, &tStop); + if (hr) + goto out; + + move.QuadPart = tStart; + + /* Looks like most of the time it's sequential, optimize by only conditionally seek and cache the last value */ + if (tStart != This->lastpos) + { + TRACE("LastPos: %x%08x, tStart: %x%08x\n", (DWORD)(This->lastpos >> 32), (DWORD)This->lastpos, (DWORD)(tStart >> 32), (DWORD)tStart); + hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL); + if (hr) + goto out; + } + + IMediaSample_GetPointer(pSample, &ptr); + + hr = IStream_Write(stream, ptr, tStop - tStart, NULL); + This->lastpos = tStop; + +out: + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +/* FileWriter can connect to all pins with MEDIATYPE_Stream, + * even to a file source, although that won't make any sense + */ +static HRESULT FileWriter_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream)) + return S_FALSE; + else + return S_OK; +} + +static inline FileWriterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) +{ + return (FileWriterImpl *)((char*)iface - FIELD_OFFSET(FileWriterImpl, mediaSeeking.lpVtbl)); +} + +static HRESULT WINAPI FileWriterImpl_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) +{ + FileWriterImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); +} + +static ULONG WINAPI FileWriterImpl_Seeking_AddRef(IMediaSeeking * iface) +{ + FileWriterImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_AddRef((IUnknown *)This); +} + +static ULONG WINAPI FileWriterImpl_Seeking_Release(IMediaSeeking * iface) +{ + FileWriterImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_Release((IUnknown *)This); +} + +static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl = +{ + FileWriterImpl_Seeking_QueryInterface, + FileWriterImpl_Seeking_AddRef, + FileWriterImpl_Seeking_Release, + MediaSeekingImpl_GetCapabilities, + MediaSeekingImpl_CheckCapabilities, + MediaSeekingImpl_IsFormatSupported, + MediaSeekingImpl_QueryPreferredFormat, + MediaSeekingImpl_GetTimeFormat, + MediaSeekingImpl_IsUsingTimeFormat, + MediaSeekingImpl_SetTimeFormat, + MediaSeekingImpl_GetDuration, + MediaSeekingImpl_GetStopPosition, + MediaSeekingImpl_GetCurrentPosition, + MediaSeekingImpl_ConvertTimeFormat, + MediaSeekingImpl_SetPositions, + MediaSeekingImpl_GetPositions, + MediaSeekingImpl_GetAvailable, + MediaSeekingImpl_SetRate, + MediaSeekingImpl_GetRate, + MediaSeekingImpl_GetPreroll +}; + +static HRESULT FileWriterImpl_Change(IBaseFilter *iface) +{ + TRACE("(%p)\n", iface); + return S_OK; +} + +HRESULT FileWriter_create(IUnknown * pUnkOuter, LPVOID * ppv) +{ + HRESULT hr; + PIN_INFO piInput; + FileWriterImpl * pFileWriter; + + TRACE("(%p, %p)\n", pUnkOuter, ppv); + + *ppv = NULL; + + pFileWriter = CoTaskMemAlloc(sizeof(FileWriterImpl)); + pFileWriter->pUnkOuter = pUnkOuter; + pFileWriter->bUnkOuterValid = FALSE; + pFileWriter->bAggregatable = FALSE; + pFileWriter->IInner_vtbl = &IInner_VTable; + + /* This should really be an ipin vtbl, but that would be more work */ + pFileWriter->stream_vtbl = &FileWriter_Stream_Vtbl; + + pFileWriter->lpVtbl = &FileWriter_Vtbl; + pFileWriter->sink2_vtbl = &FileWriter_Sink_Vtbl; + pFileWriter->refCount = 1; + InitializeCriticalSection(&pFileWriter->csFilter); + pFileWriter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileWriterImpl.csFilter"); + pFileWriter->state = State_Stopped; + pFileWriter->pClock = NULL; + pFileWriter->mode = 0; + pFileWriter->filename = NULL; + pFileWriter->file = INVALID_HANDLE_VALUE; + ZeroMemory(&pFileWriter->amt, sizeof(pFileWriter->amt)); + ZeroMemory(&pFileWriter->filterInfo, sizeof(FILTER_INFO)); + + /* construct input pin */ + piInput.dir = PINDIR_INPUT; + piInput.pFilter = (IBaseFilter *)pFileWriter; + lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); + + hr = InputPin_Construct(&FileWriter_InputPin_Vtbl, &piInput, FileWriter_Sample, (LPVOID)pFileWriter, FileWriter_QueryAccept, NULL, &pFileWriter->csFilter, NULL, (IPin **)&pFileWriter->pInputPin); + + if (SUCCEEDED(hr)) + { + MediaSeekingImpl_Init((IBaseFilter*)pFileWriter, FileWriterImpl_Change, FileWriterImpl_Change, FileWriterImpl_Change, &pFileWriter->mediaSeeking, &pFileWriter->csFilter); + pFileWriter->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl; + + *ppv = (LPVOID)pFileWriter; + } + else + { + pFileWriter->csFilter.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&pFileWriter->csFilter); + CoTaskMemFree(pFileWriter); + } + + return hr; +} + +static HRESULT WINAPI FileWriterInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS_MULTI(FileWriterImpl, IInner_vtbl, iface); + TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); + + if (This->bAggregatable) + This->bUnkOuterValid = TRUE; + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = (LPVOID)&(This->IInner_vtbl); + else if (IsEqualIID(riid, &IID_IPersist)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IMediaFilter)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IBaseFilter)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IMediaSeeking)) + *ppv = &This->mediaSeeking; + else if (IsEqualIID(riid, &IID_IFileSinkFilter) + || IsEqualIID(riid, &IID_IFileSinkFilter2)) + *ppv = &This->sink2_vtbl; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + if (IsEqualIID(riid, &IID_IPersistStream)) + FIXME("No interface for IPersistStream!\n"); + else if (!IsEqualIID(riid, &IID_IPin)) + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI FileWriterInner_AddRef(IUnknown * iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, IInner_vtbl, iface); + ULONG refCount = InterlockedIncrement(&This->refCount); + + TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); + + return refCount; +} + +static ULONG WINAPI FileWriterInner_Release(IUnknown * iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, IInner_vtbl, iface); + ULONG refCount = InterlockedDecrement(&This->refCount); + + TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1); + + if (!refCount) + { + IPin *pConnectedTo; + + if (This->pClock) + IReferenceClock_Release(This->pClock); + + if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo))) + { + IPin_Disconnect(pConnectedTo); + IPin_Release(pConnectedTo); + } + IPin_Disconnect((IPin *)This->pInputPin); + IPin_Release((IPin *)This->pInputPin); + + This->lpVtbl = NULL; + + This->csFilter.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->csFilter); + + TRACE("Destroying File Writer\n"); + CoTaskMemFree(This); + return 0; + } + else + return refCount; +} + +static const IUnknownVtbl IInner_VTable = +{ + FileWriterInner_QueryInterface, + FileWriterInner_AddRef, + FileWriterInner_Release +}; + +static HRESULT WINAPI FileWriter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + if (This->bAggregatable) + This->bUnkOuterValid = TRUE; + + if (This->pUnkOuter) + { + if (This->bAggregatable) + return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + HRESULT hr; + + IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); + hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); + IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); + This->bAggregatable = TRUE; + return hr; + } + + *ppv = NULL; + return E_NOINTERFACE; + } + + return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); +} + +static ULONG WINAPI FileWriter_AddRef(IBaseFilter * iface) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + if (This->pUnkOuter && This->bUnkOuterValid) + return IUnknown_AddRef(This->pUnkOuter); + return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); +} + +static ULONG WINAPI FileWriter_Release(IBaseFilter * iface) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + if (This->pUnkOuter && This->bUnkOuterValid) + return IUnknown_Release(This->pUnkOuter); + return IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); +} + +/** IPersist methods **/ + +static HRESULT WINAPI FileWriter_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pClsid); + + *pClsid = CLSID_FileWriter; + + return S_OK; +} + +/** IMediaFilter methods **/ + +static HRESULT WINAPI FileWriter_Stop(IBaseFilter * iface) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + FIXME("(%p/%p)->() stub\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Stopped; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_Pause(IBaseFilter * iface) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + FIXME("(%p/%p)->() stub\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + if (This->state == State_Stopped) + { + This->lastpos = -1; + This->pInputPin->end_of_stream = 0; + } + This->state = State_Paused; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + FIXME("(%p/%p)->() stub\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + if (This->state == State_Stopped) + { + This->lastpos = -1; + This->pInputPin->end_of_stream = 0; + } + This->rtStreamStart = tStart; + This->state = State_Running; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState); + + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pClock); + + EnterCriticalSection(&This->csFilter); + { + if (This->pClock) + IReferenceClock_Release(This->pClock); + This->pClock = pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); + + EnterCriticalSection(&This->csFilter); + { + *ppClock = This->pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +/** IBaseFilter implementation **/ + +static HRESULT FileWriter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + /* Our pins are static, not changing so setting static tick count is ok */ + *lastsynctick = 0; + + if (pos >= 1) + return S_FALSE; + + *pin = (IPin *)This->pInputPin; + IPin_AddRef(*pin); + return S_OK; +} + +static HRESULT WINAPI FileWriter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + return IEnumPinsImpl_Construct(ppEnum, FileWriter_GetPin, iface); +} + +static HRESULT WINAPI FileWriter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin); + + FIXME("FileWriter::FindPin(...)\n"); + + /* FIXME: critical section */ + + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pInfo); + + strcpyW(pInfo->achName, This->filterInfo.achName); + pInfo->pGraph = This->filterInfo.pGraph; + + if (pInfo->pGraph) + IFilterGraph_AddRef(pInfo->pGraph); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + + TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName)); + + EnterCriticalSection(&This->csFilter); + { + if (pName) + strcpyW(This->filterInfo.achName, pName); + else + *This->filterInfo.achName = '\0'; + This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */ + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + FileWriterImpl *This = (FileWriterImpl *)iface; + TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo); + return E_NOTIMPL; +} + +static const IBaseFilterVtbl FileWriter_Vtbl = +{ + FileWriter_QueryInterface, + FileWriter_AddRef, + FileWriter_Release, + FileWriter_GetClassID, + FileWriter_Stop, + FileWriter_Pause, + FileWriter_Run, + FileWriter_GetState, + FileWriter_SetSyncSource, + FileWriter_GetSyncSource, + FileWriter_EnumPins, + FileWriter_FindPin, + FileWriter_QueryFilterInfo, + FileWriter_JoinFilterGraph, + FileWriter_QueryVendorInfo +}; + +static HRESULT WINAPI FileWriterImpl_Sink_QueryInterface(IFileSinkFilter2 *iface, REFIID riid, void **ppv) +{ + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + + return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); +} + +static ULONG WINAPI FileWriterImpl_Sink_AddRef(IFileSinkFilter2* iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + + return IUnknown_AddRef((IUnknown *)This); +} + +static ULONG WINAPI FileWriterImpl_Sink_Release(IFileSinkFilter2* iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + + return IUnknown_Release((IUnknown *)This); +} + +static HRESULT WINAPI FileWriterImpl_Sink_SetFileName(IFileSinkFilter2* iface, const WCHAR *filename, const AM_MEDIA_TYPE *pmt) +{ + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + HRESULT hr; + + EnterCriticalSection(&This->csFilter); + CoTaskMemFree(This->filename); + FreeMediaType(&This->amt); + if (pmt) + CopyMediaType(&This->amt, pmt); + else + This->amt.majortype = GUID_NULL; + This->filename = CoTaskMemAlloc(sizeof(WCHAR) * (lstrlenW(filename) + 1)); + lstrcpyW(This->filename, filename); + + This->file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, + (This->mode & AM_FILE_OVERWRITE) ? CREATE_ALWAYS : OPEN_ALWAYS, 0, NULL); + if (This->file == INVALID_HANDLE_VALUE) + hr = HRESULT_FROM_WIN32(GetLastError()); + else + hr = S_OK; + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI FileWriterImpl_Sink_GetCurFile(IFileSinkFilter2* iface, WCHAR **filename, AM_MEDIA_TYPE *pmt) +{ + HRESULT hr; + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + + EnterCriticalSection(&This->csFilter); + if (This->filename) + { + *filename = CoTaskMemAlloc(sizeof(WCHAR) * (lstrlenW(This->filename) + 1)); + lstrcpyW(*filename, This->filename); + if (pmt) + CopyMediaType(&This->amt, pmt); + hr = S_OK; + } + else + hr = E_FAIL; + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI FileWriterImpl_Sink_SetMode(IFileSinkFilter2* iface, DWORD mode) +{ + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + + EnterCriticalSection(&This->csFilter); + This->mode = mode; + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI FileWriterImpl_Sink_GetMode(IFileSinkFilter2* iface, DWORD *mode) +{ + ICOM_THIS_MULTI(FileWriterImpl, sink2_vtbl, iface); + + EnterCriticalSection(&This->csFilter); + *mode = This->mode; + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static const IFileSinkFilter2Vtbl FileWriter_Sink_Vtbl = +{ + FileWriterImpl_Sink_QueryInterface, + FileWriterImpl_Sink_AddRef, + FileWriterImpl_Sink_Release, + FileWriterImpl_Sink_SetFileName, + FileWriterImpl_Sink_GetCurFile, + FileWriterImpl_Sink_SetMode, + FileWriterImpl_Sink_GetMode +}; + +static HRESULT WINAPI FileWriter_InputPin_QueryInterface(IPin *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IStream)) + { + InputPin* This = (InputPin*)iface; + FileWriterImpl *pFileWriter = (FileWriterImpl *)This->pin.pinInfo.pFilter; + + *ppv = &pFileWriter->stream_vtbl; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; + } + else + return InputPin_QueryInterface(iface, riid, ppv); +} + +static HRESULT WINAPI FileWriter_InputPin_EndOfStream(IPin *iface) +{ + InputPin* This = (InputPin*)iface; + IMediaEventSink* pEventSink; + IFilterGraph *graph; + HRESULT hr = S_OK; + + TRACE("(%p/%p)->()\n", This, iface); + + InputPin_EndOfStream(iface); + graph = ((FileWriterImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph; + if (graph) + { + hr = IFilterGraph_QueryInterface(((FileWriterImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink); + if (SUCCEEDED(hr)) + { + hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0); + IMediaEventSink_Release(pEventSink); + } + } + + return hr; +} + +static const IPinVtbl FileWriter_InputPin_Vtbl = +{ + FileWriter_InputPin_QueryInterface, + IPinImpl_AddRef, + InputPin_Release, + InputPin_Connect, + InputPin_ReceiveConnection, + IPinImpl_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + FileWriter_InputPin_EndOfStream, + InputPin_BeginFlush, + InputPin_EndFlush, + InputPin_NewSegment +}; + +static HRESULT WINAPI FileWriter_Stream_QueryInterface(IStream *iface, REFIID riid, void **ppv) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + return IUnknown_QueryInterface((IUnknown *)This->pInputPin, riid, ppv); +} + +static ULONG WINAPI FileWriter_Stream_AddRef(IStream *iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + return IUnknown_AddRef((IUnknown *)This->pInputPin); +} + +static ULONG WINAPI FileWriter_Stream_Release(IStream *iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + return IUnknown_Release((IUnknown *)This->pInputPin); +} + +static HRESULT WINAPI FileWriter_Stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *cbread) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + HRESULT hr = S_OK; + + TRACE("(%p/%p)->(%p, %u, %p)\n", iface, This, pv, cb, cbread); + + EnterCriticalSection(&This->csFilter); + if (This->file == INVALID_HANDLE_VALUE) + { + hr = E_UNEXPECTED; + goto out; + } + if (!ReadFile(This->file, pv, cb, cbread, NULL)) + hr = HRESULT_FROM_WIN32(GetLastError()); + +out: + LeaveCriticalSection(&This->csFilter); + TRACE("%08x\n", hr); + return hr; +} + +static HRESULT WINAPI FileWriter_Stream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *cbwritten) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + HRESULT hr = S_OK; + + TRACE("(%p/%p)->(%p, %u, %p)\n", iface, This, pv, cb, cbwritten); + + EnterCriticalSection(&This->csFilter); + if (This->file == INVALID_HANDLE_VALUE) + { + hr = E_UNEXPECTED; + goto out; + } + if (!WriteFile(This->file, pv, cb, cbwritten, NULL)) + hr = HRESULT_FROM_WIN32(GetLastError()); + +out: + LeaveCriticalSection(&This->csFilter); + TRACE("%08x\n", hr); + return hr; +} + +static HRESULT WINAPI FileWriter_Stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + HRESULT hr = S_OK; + BOOL success; + + TRACE("(%p/%p)->(%s, %u, %s)\n", iface, This, wine_dbgstr_longlong(move.QuadPart), origin, + newpos ? wine_dbgstr_longlong(newpos->QuadPart) : NULL); + + EnterCriticalSection(&This->csFilter); + if (This->file == INVALID_HANDLE_VALUE) + { + hr = E_UNEXPECTED; + goto out; + } + + if (origin == STREAM_SEEK_SET) + success = SetFilePointerEx(This->file, move, (LARGE_INTEGER *)newpos, FILE_BEGIN); + else if (origin == STREAM_SEEK_CUR) + success = SetFilePointerEx(This->file, move, (LARGE_INTEGER *)newpos, FILE_CURRENT); + else if (origin == STREAM_SEEK_END) + success = SetFilePointerEx(This->file, move, (LARGE_INTEGER *)newpos, FILE_END); + else + { + hr = E_INVALIDARG; + goto out; + } + if (!success) + hr = HRESULT_FROM_WIN32(GetLastError()); + +out: + LeaveCriticalSection(&This->csFilter); + TRACE("%08x\n", hr); + return hr; +} + +/* Rest of the methods aren't used by the avi writer in windows, which is pretty much the only one using this filter */ + +static HRESULT WINAPI FileWriter_Stream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_CopyTo(IStream *iface, IStream *to, ULARGE_INTEGER cb, ULARGE_INTEGER *read, ULARGE_INTEGER *written) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_Commit(IStream *iface, DWORD flags) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_Revert(IStream *iface) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_LockRegion(IStream *iface, ULARGE_INTEGER ofs, ULARGE_INTEGER cb, DWORD locktype) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_UnlockRegion(IStream *iface, ULARGE_INTEGER ofs, ULARGE_INTEGER cb, DWORD locktype) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_Stat(IStream *iface, STATSTG *obj, DWORD flags) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileWriter_Stream_Clone(IStream *iface, IStream **to) +{ + ICOM_THIS_MULTI(FileWriterImpl, stream_vtbl, iface); + + FIXME("(%p/%p)->(..) stub\n", iface, This); + *to = NULL; + return E_NOTIMPL; +} + +static const IStreamVtbl FileWriter_Stream_Vtbl = +{ + FileWriter_Stream_QueryInterface, + FileWriter_Stream_AddRef, + FileWriter_Stream_Release, + FileWriter_Stream_Read, + FileWriter_Stream_Write, + FileWriter_Stream_Seek, + FileWriter_Stream_SetSize, + FileWriter_Stream_CopyTo, + FileWriter_Stream_Commit, + FileWriter_Stream_Revert, + FileWriter_Stream_LockRegion, + FileWriter_Stream_UnlockRegion, + FileWriter_Stream_Stat, + FileWriter_Stream_Clone +}; diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index 4d16973..a86c90b 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -78,7 +78,8 @@ static const struct object_creation_info object_creation[] = { &CLSID_AVIDec, AVIDec_create }, { &CLSID_SystemClock, QUARTZ_CreateSystemClock }, { &CLSID_ACMWrapper, ACMWrapper_create }, - { &CLSID_WAVEParser, WAVEParser_create } + { &CLSID_WAVEParser, WAVEParser_create }, + { &CLSID_FileWriter, FileWriter_create } }; static HRESULT WINAPI diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index 665abd6..674829a 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -60,6 +60,7 @@ HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj); +HRESULT FileWriter_create(IUnknown *pUnkOuter, LPVOID *ppObj); HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum); diff --git a/dlls/quartz/regsvr.c b/dlls/quartz/regsvr.c index 6ff4d42..f52a024 100644 --- a/dlls/quartz/regsvr.c +++ b/dlls/quartz/regsvr.c @@ -898,7 +898,13 @@ static struct regsvr_coclass const coclass_list[] = { "quartz.dll", "Both" }, - { NULL } /* list terminator */ + { &CLSID_FileWriter, + "File writer", + NULL, + "quartz.dll", + "Both" + }, + { NULL } /* list terminator */ }; /*********************************************************************** @@ -1227,6 +1233,18 @@ static struct regsvr_filter const filter_list[] = { { 0xFFFFFFFF }, } }, + { &CLSID_FileWriter, + &CLSID_LegacyAmFilterCategory, + {'F','i','l','e',' ','W','r','i','t','e','r',0}, + 0x200000, + { { 0, + { { &MEDIATYPE_Stream, &MEDIASUBTYPE_NULL }, + { NULL } + }, + }, + { 0xFFFFFFFF }, + } + }, { NULL } /* list terminator */ }; -- 1.5.4.1