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 typedef struct _ITmpFileImpl { 38 IAVIFile IAVIFile_iface; 39 LONG ref; 40 41 AVIFILEINFOW fInfo; 42 PAVISTREAM *ppStreams; 43 } ITmpFileImpl; 44 45 static inline ITmpFileImpl *impl_from_IAVIFile(IAVIFile *iface) 46 { 47 return CONTAINING_RECORD(iface, ITmpFileImpl, IAVIFile_iface); 48 } 49 50 static HRESULT WINAPI ITmpFile_fnQueryInterface(IAVIFile *iface, REFIID refiid, 51 LPVOID *obj) 52 { 53 ITmpFileImpl *This = impl_from_IAVIFile(iface); 54 55 TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj); 56 57 if (IsEqualGUID(&IID_IUnknown, refiid) || 58 IsEqualGUID(&IID_IAVIFile, refiid)) { 59 *obj = iface; 60 IAVIFile_AddRef(iface); 61 62 return S_OK; 63 } 64 65 return OLE_E_ENUM_NOMORE; 66 } 67 68 static ULONG WINAPI ITmpFile_fnAddRef(IAVIFile *iface) 69 { 70 ITmpFileImpl *This = impl_from_IAVIFile(iface); 71 ULONG ref = InterlockedIncrement(&This->ref); 72 73 TRACE("(%p) -> %d\n", iface, ref); 74 75 return ref; 76 } 77 78 static ULONG WINAPI ITmpFile_fnRelease(IAVIFile *iface) 79 { 80 ITmpFileImpl *This = impl_from_IAVIFile(iface); 81 ULONG ref = InterlockedDecrement(&This->ref); 82 83 TRACE("(%p) -> %d\n", iface, ref); 84 85 if (!ref) { 86 unsigned int i; 87 88 for (i = 0; i < This->fInfo.dwStreams; i++) { 89 if (This->ppStreams[i] != NULL) { 90 AVIStreamRelease(This->ppStreams[i]); 91 92 This->ppStreams[i] = NULL; 93 } 94 } 95 96 HeapFree(GetProcessHeap(), 0, This); 97 } 98 99 return ref; 100 } 101 102 static HRESULT WINAPI ITmpFile_fnInfo(IAVIFile *iface, 103 AVIFILEINFOW *afi, LONG size) 104 { 105 ITmpFileImpl *This = impl_from_IAVIFile(iface); 106 107 TRACE("(%p,%p,%d)\n",iface,afi,size); 108 109 if (afi == NULL) 110 return AVIERR_BADPARAM; 111 if (size < 0) 112 return AVIERR_BADSIZE; 113 114 memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo))); 115 116 if ((DWORD)size < sizeof(This->fInfo)) 117 return AVIERR_BUFFERTOOSMALL; 118 return AVIERR_OK; 119 } 120 121 static HRESULT WINAPI ITmpFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis, 122 DWORD fccType, LONG lParam) 123 { 124 ITmpFileImpl *This = impl_from_IAVIFile(iface); 125 126 ULONG nStream = (ULONG)-1; 127 128 TRACE("(%p,%p,0x%08X,%d)\n", iface, avis, fccType, lParam); 129 130 if (avis == NULL || lParam < 0) 131 return AVIERR_BADPARAM; 132 133 if (fccType != streamtypeANY) { 134 /* search the number of the specified stream */ 135 ULONG i; 136 137 for (i = 0; i < This->fInfo.dwStreams; i++) { 138 AVISTREAMINFOW sInfo; 139 HRESULT hr; 140 141 hr = AVIStreamInfoW(This->ppStreams[i], &sInfo, sizeof(sInfo)); 142 if (FAILED(hr)) 143 return hr; 144 145 if (sInfo.fccType == fccType) { 146 if (lParam == 0) { 147 nStream = i; 148 break; 149 } else 150 lParam--; 151 } 152 } 153 } else 154 nStream = lParam; 155 156 /* Does the requested stream exist ? */ 157 if (nStream < This->fInfo.dwStreams && This->ppStreams[nStream] != NULL) { 158 *avis = This->ppStreams[nStream]; 159 AVIStreamAddRef(*avis); 160 161 return AVIERR_OK; 162 } 163 164 /* Sorry, but the specified stream doesn't exist */ 165 return AVIERR_NODATA; 166 } 167 168 static HRESULT WINAPI ITmpFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis, 169 AVISTREAMINFOW *asi) 170 { 171 TRACE("(%p,%p,%p)\n",iface,avis,asi); 172 173 return AVIERR_UNSUPPORTED; 174 } 175 176 static HRESULT WINAPI ITmpFile_fnWriteData(IAVIFile *iface, DWORD ckid, 177 LPVOID lpData, LONG size) 178 { 179 TRACE("(%p,0x%08X,%p,%d)\n", iface, ckid, lpData, size); 180 181 return AVIERR_UNSUPPORTED; 182 } 183 184 static HRESULT WINAPI ITmpFile_fnReadData(IAVIFile *iface, DWORD ckid, 185 LPVOID lpData, LONG *size) 186 { 187 TRACE("(%p,0x%08X,%p,%p)\n", iface, ckid, lpData, size); 188 189 return AVIERR_UNSUPPORTED; 190 } 191 192 static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile *iface) 193 { 194 TRACE("(%p)\n",iface); 195 196 return AVIERR_OK; 197 } 198 199 static HRESULT WINAPI ITmpFile_fnDeleteStream(IAVIFile *iface, DWORD fccType, 200 LONG lParam) 201 { 202 TRACE("(%p,0x%08X,%d)\n", iface, fccType, lParam); 203 204 return AVIERR_UNSUPPORTED; 205 } 206 207 static const struct IAVIFileVtbl itmpft = { 208 ITmpFile_fnQueryInterface, 209 ITmpFile_fnAddRef, 210 ITmpFile_fnRelease, 211 ITmpFile_fnInfo, 212 ITmpFile_fnGetStream, 213 ITmpFile_fnCreateStream, 214 ITmpFile_fnWriteData, 215 ITmpFile_fnReadData, 216 ITmpFile_fnEndRecord, 217 ITmpFile_fnDeleteStream 218 }; 219 220 PAVIFILE AVIFILE_CreateAVITempFile(int nStreams, const PAVISTREAM *ppStreams) 221 { 222 ITmpFileImpl *tmpFile; 223 int i; 224 225 tmpFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ITmpFileImpl)); 226 if (tmpFile == NULL) 227 return NULL; 228 229 tmpFile->IAVIFile_iface.lpVtbl = &itmpft; 230 tmpFile->ref = 1; 231 memset(&tmpFile->fInfo, 0, sizeof(tmpFile->fInfo)); 232 233 tmpFile->fInfo.dwStreams = nStreams; 234 tmpFile->ppStreams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(PAVISTREAM)); 235 if (tmpFile->ppStreams == NULL) { 236 HeapFree(GetProcessHeap(), 0, tmpFile); 237 return NULL; 238 } 239 240 for (i = 0; i < nStreams; i++) { 241 AVISTREAMINFOW sInfo; 242 243 tmpFile->ppStreams[i] = ppStreams[i]; 244 245 AVIStreamAddRef(ppStreams[i]); 246 AVIStreamInfoW(ppStreams[i], &sInfo, sizeof(sInfo)); 247 if (i == 0) { 248 tmpFile->fInfo.dwScale = sInfo.dwScale; 249 tmpFile->fInfo.dwRate = sInfo.dwRate; 250 if (!sInfo.dwScale || !sInfo.dwRate) { 251 tmpFile->fInfo.dwScale = 1; 252 tmpFile->fInfo.dwRate = 100; 253 } 254 } 255 256 if (tmpFile->fInfo.dwSuggestedBufferSize < sInfo.dwSuggestedBufferSize) 257 tmpFile->fInfo.dwSuggestedBufferSize = sInfo.dwSuggestedBufferSize; 258 259 { 260 DWORD tmp; 261 262 tmp = MulDiv(AVIStreamSampleToTime(ppStreams[i], sInfo.dwLength), 263 tmpFile->fInfo.dwScale, tmpFile->fInfo.dwRate * 1000); 264 if (tmpFile->fInfo.dwLength < tmp) 265 tmpFile->fInfo.dwLength = tmp; 266 267 tmp = sInfo.rcFrame.right - sInfo.rcFrame.left; 268 if (tmpFile->fInfo.dwWidth < tmp) 269 tmpFile->fInfo.dwWidth = tmp; 270 tmp = sInfo.rcFrame.bottom - sInfo.rcFrame.top; 271 if (tmpFile->fInfo.dwHeight < tmp) 272 tmpFile->fInfo.dwHeight = tmp; 273 } 274 } 275 276 return &tmpFile->IAVIFile_iface; 277 } 278