|  | /* | 
|  | * Copyright 2003 Michael Günnewig | 
|  | * | 
|  | * 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 <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winerror.h" | 
|  | #include "vfw.h" | 
|  |  | 
|  | #include "avifile_private.h" | 
|  | #include "extrachunk.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(avifile); | 
|  |  | 
|  | /***********************************************************************/ | 
|  |  | 
|  | typedef struct _ITmpFileImpl { | 
|  | IAVIFile     IAVIFile_iface; | 
|  | LONG         ref; | 
|  |  | 
|  | AVIFILEINFOW  fInfo; | 
|  | PAVISTREAM   *ppStreams; | 
|  | } ITmpFileImpl; | 
|  |  | 
|  | static inline ITmpFileImpl *impl_from_IAVIFile(IAVIFile *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, ITmpFileImpl, IAVIFile_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnQueryInterface(IAVIFile *iface, REFIID refiid, | 
|  | LPVOID *obj) | 
|  | { | 
|  | ITmpFileImpl *This = impl_from_IAVIFile(iface); | 
|  |  | 
|  | TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj); | 
|  |  | 
|  | if (IsEqualGUID(&IID_IUnknown, refiid) || | 
|  | IsEqualGUID(&IID_IAVIFile, refiid)) { | 
|  | *obj = iface; | 
|  | IAVIFile_AddRef(iface); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | return OLE_E_ENUM_NOMORE; | 
|  | } | 
|  |  | 
|  | static ULONG   WINAPI ITmpFile_fnAddRef(IAVIFile *iface) | 
|  | { | 
|  | ITmpFileImpl *This = impl_from_IAVIFile(iface); | 
|  | ULONG ref = InterlockedIncrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p) -> %d\n", iface, ref); | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | static ULONG   WINAPI ITmpFile_fnRelease(IAVIFile *iface) | 
|  | { | 
|  | ITmpFileImpl *This = impl_from_IAVIFile(iface); | 
|  | ULONG ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p) -> %d\n", iface, ref); | 
|  |  | 
|  | if (!ref) { | 
|  | unsigned int i; | 
|  |  | 
|  | for (i = 0; i < This->fInfo.dwStreams; i++) { | 
|  | if (This->ppStreams[i] != NULL) { | 
|  | AVIStreamRelease(This->ppStreams[i]); | 
|  |  | 
|  | This->ppStreams[i] = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnInfo(IAVIFile *iface, | 
|  | AVIFILEINFOW *afi, LONG size) | 
|  | { | 
|  | ITmpFileImpl *This = impl_from_IAVIFile(iface); | 
|  |  | 
|  | TRACE("(%p,%p,%d)\n",iface,afi,size); | 
|  |  | 
|  | if (afi == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  | if (size < 0) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo))); | 
|  |  | 
|  | if ((DWORD)size < sizeof(This->fInfo)) | 
|  | return AVIERR_BUFFERTOOSMALL; | 
|  | return AVIERR_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis, | 
|  | DWORD fccType, LONG lParam) | 
|  | { | 
|  | ITmpFileImpl *This = impl_from_IAVIFile(iface); | 
|  |  | 
|  | ULONG nStream = (ULONG)-1; | 
|  |  | 
|  | TRACE("(%p,%p,0x%08X,%d)\n", iface, avis, fccType, lParam); | 
|  |  | 
|  | if (avis == NULL || lParam < 0) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | if (fccType != streamtypeANY) { | 
|  | /* search the number of the specified stream */ | 
|  | ULONG i; | 
|  |  | 
|  | for (i = 0; i < This->fInfo.dwStreams; i++) { | 
|  | AVISTREAMINFOW sInfo; | 
|  | HRESULT        hr; | 
|  |  | 
|  | hr = AVIStreamInfoW(This->ppStreams[i], &sInfo, sizeof(sInfo)); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | if (sInfo.fccType == fccType) { | 
|  | if (lParam == 0) { | 
|  | nStream = i; | 
|  | break; | 
|  | } else | 
|  | lParam--; | 
|  | } | 
|  | } | 
|  | } else | 
|  | nStream = lParam; | 
|  |  | 
|  | /* Does the requested stream exist ? */ | 
|  | if (nStream < This->fInfo.dwStreams && This->ppStreams[nStream] != NULL) { | 
|  | *avis = This->ppStreams[nStream]; | 
|  | AVIStreamAddRef(*avis); | 
|  |  | 
|  | return AVIERR_OK; | 
|  | } | 
|  |  | 
|  | /* Sorry, but the specified stream doesn't exist */ | 
|  | return AVIERR_NODATA; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis, | 
|  | AVISTREAMINFOW *asi) | 
|  | { | 
|  | TRACE("(%p,%p,%p)\n",iface,avis,asi); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnWriteData(IAVIFile *iface, DWORD ckid, | 
|  | LPVOID lpData, LONG size) | 
|  | { | 
|  | TRACE("(%p,0x%08X,%p,%d)\n", iface, ckid, lpData, size); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnReadData(IAVIFile *iface, DWORD ckid, | 
|  | LPVOID lpData, LONG *size) | 
|  | { | 
|  | TRACE("(%p,0x%08X,%p,%p)\n", iface, ckid, lpData, size); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile *iface) | 
|  | { | 
|  | TRACE("(%p)\n",iface); | 
|  |  | 
|  | return AVIERR_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITmpFile_fnDeleteStream(IAVIFile *iface, DWORD fccType, | 
|  | LONG lParam) | 
|  | { | 
|  | TRACE("(%p,0x%08X,%d)\n", iface, fccType, lParam); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | static const struct IAVIFileVtbl itmpft = { | 
|  | ITmpFile_fnQueryInterface, | 
|  | ITmpFile_fnAddRef, | 
|  | ITmpFile_fnRelease, | 
|  | ITmpFile_fnInfo, | 
|  | ITmpFile_fnGetStream, | 
|  | ITmpFile_fnCreateStream, | 
|  | ITmpFile_fnWriteData, | 
|  | ITmpFile_fnReadData, | 
|  | ITmpFile_fnEndRecord, | 
|  | ITmpFile_fnDeleteStream | 
|  | }; | 
|  |  | 
|  | PAVIFILE AVIFILE_CreateAVITempFile(int nStreams, const PAVISTREAM *ppStreams) | 
|  | { | 
|  | ITmpFileImpl *tmpFile; | 
|  | int           i; | 
|  |  | 
|  | tmpFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ITmpFileImpl)); | 
|  | if (tmpFile == NULL) | 
|  | return NULL; | 
|  |  | 
|  | tmpFile->IAVIFile_iface.lpVtbl = &itmpft; | 
|  | tmpFile->ref    = 1; | 
|  | memset(&tmpFile->fInfo, 0, sizeof(tmpFile->fInfo)); | 
|  |  | 
|  | tmpFile->fInfo.dwStreams = nStreams; | 
|  | tmpFile->ppStreams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(PAVISTREAM)); | 
|  | if (tmpFile->ppStreams == NULL) { | 
|  | HeapFree(GetProcessHeap(), 0, tmpFile); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < nStreams; i++) { | 
|  | AVISTREAMINFOW sInfo; | 
|  |  | 
|  | tmpFile->ppStreams[i] = ppStreams[i]; | 
|  |  | 
|  | AVIStreamAddRef(ppStreams[i]); | 
|  | AVIStreamInfoW(ppStreams[i], &sInfo, sizeof(sInfo)); | 
|  | if (i == 0) { | 
|  | tmpFile->fInfo.dwScale = sInfo.dwScale; | 
|  | tmpFile->fInfo.dwRate  = sInfo.dwRate; | 
|  | if (!sInfo.dwScale || !sInfo.dwRate) { | 
|  | tmpFile->fInfo.dwScale = 1; | 
|  | tmpFile->fInfo.dwRate  = 100; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (tmpFile->fInfo.dwSuggestedBufferSize < sInfo.dwSuggestedBufferSize) | 
|  | tmpFile->fInfo.dwSuggestedBufferSize = sInfo.dwSuggestedBufferSize; | 
|  |  | 
|  | { | 
|  | register DWORD tmp; | 
|  |  | 
|  | tmp = MulDiv(AVIStreamSampleToTime(ppStreams[i], sInfo.dwLength), | 
|  | tmpFile->fInfo.dwScale, tmpFile->fInfo.dwRate * 1000); | 
|  | if (tmpFile->fInfo.dwLength < tmp) | 
|  | tmpFile->fInfo.dwLength = tmp; | 
|  |  | 
|  | tmp = sInfo.rcFrame.right - sInfo.rcFrame.left; | 
|  | if (tmpFile->fInfo.dwWidth < tmp) | 
|  | tmpFile->fInfo.dwWidth = tmp; | 
|  | tmp = sInfo.rcFrame.bottom - sInfo.rcFrame.top; | 
|  | if (tmpFile->fInfo.dwHeight < tmp) | 
|  | tmpFile->fInfo.dwHeight = tmp; | 
|  | } | 
|  | } | 
|  |  | 
|  | return (PAVIFILE)tmpFile; | 
|  | } |