1 /* 2 * Copyright 2003 Michael G�nnewig 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <stdarg.h> 20 21 #include "windef.h" 22 #include "winbase.h" 23 #include "wingdi.h" 24 #include "winuser.h" 25 #include "winerror.h" 26 #include "vfw.h" 27 28 #include "avifile_private.h" 29 #include "extrachunk.h" 30 31 #include "wine/debug.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(avifile); 34 35 /***********************************************************************/ 36 37 static HRESULT WINAPI ITmpFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj); 38 static ULONG WINAPI ITmpFile_fnAddRef(IAVIFile* iface); 39 static ULONG WINAPI ITmpFile_fnRelease(IAVIFile* iface); 40 static HRESULT WINAPI ITmpFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size); 41 static HRESULT WINAPI ITmpFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam); 42 static HRESULT WINAPI ITmpFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi); 43 static HRESULT WINAPI ITmpFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size); 44 static HRESULT WINAPI ITmpFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size); 45 static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile*iface); 46 static HRESULT WINAPI ITmpFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam); 47 48 static const struct IAVIFileVtbl itmpft = { 49 ITmpFile_fnQueryInterface, 50 ITmpFile_fnAddRef, 51 ITmpFile_fnRelease, 52 ITmpFile_fnInfo, 53 ITmpFile_fnGetStream, 54 ITmpFile_fnCreateStream, 55 ITmpFile_fnWriteData, 56 ITmpFile_fnReadData, 57 ITmpFile_fnEndRecord, 58 ITmpFile_fnDeleteStream 59 }; 60 61 typedef struct _ITmpFileImpl { 62 /* IUnknown stuff */ 63 const IAVIFileVtbl *lpVtbl; 64 LONG ref; 65 66 /* IAVIFile stuff */ 67 AVIFILEINFOW fInfo; 68 PAVISTREAM *ppStreams; 69 } ITmpFileImpl; 70 71 PAVIFILE AVIFILE_CreateAVITempFile(int nStreams, const PAVISTREAM *ppStreams) { 72 ITmpFileImpl *tmpFile; 73 int i; 74 75 tmpFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ITmpFileImpl)); 76 if (tmpFile == NULL) 77 return NULL; 78 79 tmpFile->lpVtbl = &itmpft; 80 tmpFile->ref = 1; 81 memset(&tmpFile->fInfo, 0, sizeof(tmpFile->fInfo)); 82 83 tmpFile->fInfo.dwStreams = nStreams; 84 tmpFile->ppStreams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(PAVISTREAM)); 85 if (tmpFile->ppStreams == NULL) { 86 HeapFree(GetProcessHeap(), 0, tmpFile); 87 return NULL; 88 } 89 90 for (i = 0; i < nStreams; i++) { 91 AVISTREAMINFOW sInfo; 92 93 tmpFile->ppStreams[i] = ppStreams[i]; 94 95 AVIStreamAddRef(ppStreams[i]); 96 AVIStreamInfoW(ppStreams[i], &sInfo, sizeof(sInfo)); 97 if (i == 0) { 98 tmpFile->fInfo.dwScale = sInfo.dwScale; 99 tmpFile->fInfo.dwRate = sInfo.dwRate; 100 if (!sInfo.dwScale || !sInfo.dwRate) { 101 tmpFile->fInfo.dwScale = 1; 102 tmpFile->fInfo.dwRate = 100; 103 } 104 } 105 106 if (tmpFile->fInfo.dwSuggestedBufferSize < sInfo.dwSuggestedBufferSize) 107 tmpFile->fInfo.dwSuggestedBufferSize = sInfo.dwSuggestedBufferSize; 108 109 { 110 register DWORD tmp; 111 112 tmp = MulDiv(AVIStreamSampleToTime(ppStreams[i], sInfo.dwLength), 113 tmpFile->fInfo.dwScale, tmpFile->fInfo.dwRate * 1000); 114 if (tmpFile->fInfo.dwLength < tmp) 115 tmpFile->fInfo.dwLength = tmp; 116 117 tmp = sInfo.rcFrame.right - sInfo.rcFrame.left; 118 if (tmpFile->fInfo.dwWidth < tmp) 119 tmpFile->fInfo.dwWidth = tmp; 120 tmp = sInfo.rcFrame.bottom - sInfo.rcFrame.top; 121 if (tmpFile->fInfo.dwHeight < tmp) 122 tmpFile->fInfo.dwHeight = tmp; 123 } 124 } 125 126 return (PAVIFILE)tmpFile; 127 } 128 129 static HRESULT WINAPI ITmpFile_fnQueryInterface(IAVIFile *iface, REFIID refiid, 130 LPVOID *obj) 131 { 132 ITmpFileImpl *This = (ITmpFileImpl *)iface; 133 134 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj); 135 136 if (IsEqualGUID(&IID_IUnknown, refiid) || 137 IsEqualGUID(&IID_IAVIFile, refiid)) { 138 *obj = iface; 139 IAVIFile_AddRef(iface); 140 141 return S_OK; 142 } 143 144 return OLE_E_ENUM_NOMORE; 145 } 146 147 static ULONG WINAPI ITmpFile_fnAddRef(IAVIFile *iface) 148 { 149 ITmpFileImpl *This = (ITmpFileImpl *)iface; 150 ULONG ref = InterlockedIncrement(&This->ref); 151 152 TRACE("(%p) -> %d\n", iface, ref); 153 154 return ref; 155 } 156 157 static ULONG WINAPI ITmpFile_fnRelease(IAVIFile *iface) 158 { 159 ITmpFileImpl *This = (ITmpFileImpl *)iface; 160 ULONG ref = InterlockedDecrement(&This->ref); 161 162 TRACE("(%p) -> %d\n", iface, ref); 163 164 if (!ref) { 165 unsigned int i; 166 167 for (i = 0; i < This->fInfo.dwStreams; i++) { 168 if (This->ppStreams[i] != NULL) { 169 AVIStreamRelease(This->ppStreams[i]); 170 171 This->ppStreams[i] = NULL; 172 } 173 } 174 175 HeapFree(GetProcessHeap(), 0, This); 176 return 0; 177 } 178 179 return ref; 180 } 181 182 static HRESULT WINAPI ITmpFile_fnInfo(IAVIFile *iface, 183 AVIFILEINFOW *afi, LONG size) 184 { 185 ITmpFileImpl *This = (ITmpFileImpl *)iface; 186 187 TRACE("(%p,%p,%d)\n",iface,afi,size); 188 189 if (afi == NULL) 190 return AVIERR_BADPARAM; 191 if (size < 0) 192 return AVIERR_BADSIZE; 193 194 memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo))); 195 196 if ((DWORD)size < sizeof(This->fInfo)) 197 return AVIERR_BUFFERTOOSMALL; 198 return AVIERR_OK; 199 } 200 201 static HRESULT WINAPI ITmpFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis, 202 DWORD fccType, LONG lParam) 203 { 204 ITmpFileImpl *This = (ITmpFileImpl *)iface; 205 206 ULONG nStream = (ULONG)-1; 207 208 TRACE("(%p,%p,0x%08X,%d)\n", iface, avis, fccType, lParam); 209 210 if (avis == NULL || lParam < 0) 211 return AVIERR_BADPARAM; 212 213 if (fccType != streamtypeANY) { 214 /* search the number of the specified stream */ 215 ULONG i; 216 217 for (i = 0; i < This->fInfo.dwStreams; i++) { 218 AVISTREAMINFOW sInfo; 219 HRESULT hr; 220 221 hr = AVIStreamInfoW(This->ppStreams[i], &sInfo, sizeof(sInfo)); 222 if (FAILED(hr)) 223 return hr; 224 225 if (sInfo.fccType == fccType) { 226 if (lParam == 0) { 227 nStream = i; 228 break; 229 } else 230 lParam--; 231 } 232 } 233 } else 234 nStream = lParam; 235 236 /* Does the requested stream exist ? */ 237 if (nStream < This->fInfo.dwStreams && This->ppStreams[nStream] != NULL) { 238 *avis = This->ppStreams[nStream]; 239 AVIStreamAddRef(*avis); 240 241 return AVIERR_OK; 242 } 243 244 /* Sorry, but the specified stream doesn't exist */ 245 return AVIERR_NODATA; 246 } 247 248 static HRESULT WINAPI ITmpFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis, 249 AVISTREAMINFOW *asi) 250 { 251 TRACE("(%p,%p,%p)\n",iface,avis,asi); 252 253 return AVIERR_UNSUPPORTED; 254 } 255 256 static HRESULT WINAPI ITmpFile_fnWriteData(IAVIFile *iface, DWORD ckid, 257 LPVOID lpData, LONG size) 258 { 259 TRACE("(%p,0x%08X,%p,%d)\n", iface, ckid, lpData, size); 260 261 return AVIERR_UNSUPPORTED; 262 } 263 264 static HRESULT WINAPI ITmpFile_fnReadData(IAVIFile *iface, DWORD ckid, 265 LPVOID lpData, LONG *size) 266 { 267 TRACE("(%p,0x%08X,%p,%p)\n", iface, ckid, lpData, size); 268 269 return AVIERR_UNSUPPORTED; 270 } 271 272 static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile *iface) 273 { 274 TRACE("(%p)\n",iface); 275 276 return AVIERR_OK; 277 } 278 279 static HRESULT WINAPI ITmpFile_fnDeleteStream(IAVIFile *iface, DWORD fccType, 280 LONG lParam) 281 { 282 TRACE("(%p,0x%08X,%d)\n", iface, fccType, lParam); 283 284 return AVIERR_UNSUPPORTED; 285 } 286