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
impl_from_IAVIFile(IAVIFile * iface)45 static inline ITmpFileImpl *impl_from_IAVIFile(IAVIFile *iface)
46 {
47 return CONTAINING_RECORD(iface, ITmpFileImpl, IAVIFile_iface);
48 }
49
ITmpFile_fnQueryInterface(IAVIFile * iface,REFIID refiid,LPVOID * obj)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
ITmpFile_fnAddRef(IAVIFile * iface)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
ITmpFile_fnRelease(IAVIFile * iface)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
ITmpFile_fnInfo(IAVIFile * iface,AVIFILEINFOW * afi,LONG size)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
ITmpFile_fnGetStream(IAVIFile * iface,PAVISTREAM * avis,DWORD fccType,LONG lParam)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
ITmpFile_fnCreateStream(IAVIFile * iface,PAVISTREAM * avis,AVISTREAMINFOW * asi)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
ITmpFile_fnWriteData(IAVIFile * iface,DWORD ckid,LPVOID lpData,LONG size)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
ITmpFile_fnReadData(IAVIFile * iface,DWORD ckid,LPVOID lpData,LONG * size)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
ITmpFile_fnEndRecord(IAVIFile * iface)192 static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile *iface)
193 {
194 TRACE("(%p)\n",iface);
195
196 return AVIERR_OK;
197 }
198
ITmpFile_fnDeleteStream(IAVIFile * iface,DWORD fccType,LONG lParam)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
AVIFILE_CreateAVITempFile(int nStreams,const PAVISTREAM * ppStreams)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