1 /*
2 * Copyright 1999 Marcus Meissner
3 * Copyright 2002-2003 Michael Günnewig
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <stdarg.h>
21
22 #define COBJMACROS
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31
32 #include "ole2.h"
33 #include "shellapi.h"
34 #include "shlobj.h"
35 #include "vfw.h"
36 #include "msacm.h"
37
38 #include "avifile_private.h"
39
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
43
44
45 /***********************************************************************
46 * for AVIBuildFilterW -- uses fixed size table
47 */
48 #define MAX_FILTERS 30 /* 30 => 7kB */
49
50 typedef struct _AVIFilter {
51 WCHAR szClsid[40];
52 WCHAR szExtensions[MAX_FILTERS * 7];
53 } AVIFilter;
54
55 /***********************************************************************
56 * for AVISaveOptions
57 */
58 static struct {
59 UINT uFlags;
60 INT nStreams;
61 PAVISTREAM *ppavis;
62 LPAVICOMPRESSOPTIONS *ppOptions;
63 INT nCurrent;
64 } SaveOpts;
65
66 /***********************************************************************
67 * copied from dlls/ole32/compobj.c
68 */
AVIFILE_CLSIDFromString(LPCSTR idstr,LPCLSID id)69 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
70 {
71 BYTE const *s;
72 BYTE *p;
73 INT i;
74 BYTE table[256];
75
76 if (!idstr) {
77 memset(id, 0, sizeof(CLSID));
78 return S_OK;
79 }
80
81 /* validate the CLSID string */
82 if (lstrlenA(idstr) != 38)
83 return CO_E_CLASSSTRING;
84
85 s = (BYTE const*)idstr;
86 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
87 (s[24]!='-') || (s[37]!='}'))
88 return CO_E_CLASSSTRING;
89
90 for (i = 1; i < 37; i++) {
91 if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
92 continue;
93 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
94 ((s[i] >= 'a') && (s[i] <= 'f')) ||
95 ((s[i] >= 'A') && (s[i] <= 'F')))
96 )
97 return CO_E_CLASSSTRING;
98 }
99
100 TRACE("%s -> %p\n", s, id);
101
102 /* quick lookup table */
103 memset(table, 0, 256);
104
105 for (i = 0; i < 10; i++)
106 table['0' + i] = i;
107
108 for (i = 0; i < 6; i++) {
109 table['A' + i] = i+10;
110 table['a' + i] = i+10;
111 }
112
113 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
114 p = (BYTE *) id;
115
116 s++; /* skip leading brace */
117 for (i = 0; i < 4; i++) {
118 p[3 - i] = table[*s]<<4 | table[*(s+1)];
119 s += 2;
120 }
121 p += 4;
122 s++; /* skip - */
123
124 for (i = 0; i < 2; i++) {
125 p[1-i] = table[*s]<<4 | table[*(s+1)];
126 s += 2;
127 }
128 p += 2;
129 s++; /* skip - */
130
131 for (i = 0; i < 2; i++) {
132 p[1-i] = table[*s]<<4 | table[*(s+1)];
133 s += 2;
134 }
135 p += 2;
136 s++; /* skip - */
137
138 /* these are just sequential bytes */
139 for (i = 0; i < 2; i++) {
140 *p++ = table[*s]<<4 | table[*(s+1)];
141 s += 2;
142 }
143 s++; /* skip - */
144
145 for (i = 0; i < 6; i++) {
146 *p++ = table[*s]<<4 | table[*(s+1)];
147 s += 2;
148 }
149
150 return S_OK;
151 }
152
AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile,LPCLSID lpclsid)153 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
154 {
155 CHAR szRegKey[25];
156 CHAR szValue[100];
157 LPWSTR szExt = wcsrchr(szFile, '.');
158 LONG len = ARRAY_SIZE(szValue);
159
160 if (szExt == NULL)
161 return FALSE;
162
163 szExt++;
164
165 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
166 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
167 return FALSE;
168
169 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
170 }
171
172 /***********************************************************************
173 * AVIFileInit (AVIFIL32.@)
174 */
AVIFileInit(void)175 void WINAPI AVIFileInit(void) {
176 OleInitialize(NULL);
177 }
178
179 /***********************************************************************
180 * AVIFileExit (AVIFIL32.@)
181 */
AVIFileExit(void)182 void WINAPI AVIFileExit(void) {
183 /* need to free ole32.dll if we are the last exit call */
184 /* OleUninitialize() */
185 FIXME("(): stub!\n");
186 }
187
188 /***********************************************************************
189 * AVIFileOpen (AVIFIL32.@)
190 * AVIFileOpenA (AVIFIL32.@)
191 */
AVIFileOpenA(PAVIFILE * ppfile,LPCSTR szFile,UINT uMode,LPCLSID lpHandler)192 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
193 LPCLSID lpHandler)
194 {
195 LPWSTR wszFile = NULL;
196 HRESULT hr;
197 int len;
198
199 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
200 debugstr_guid(lpHandler));
201
202 /* check parameters */
203 if (ppfile == NULL || szFile == NULL)
204 return AVIERR_BADPARAM;
205
206 /* convert ASCII string to Unicode and call unicode function */
207 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
208 if (len <= 0)
209 return AVIERR_BADPARAM;
210
211 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
212 if (wszFile == NULL)
213 return AVIERR_MEMORY;
214
215 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
216
217 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
218
219 HeapFree(GetProcessHeap(), 0, wszFile);
220
221 return hr;
222 }
223
224 /***********************************************************************
225 * AVIFileOpenW (AVIFIL32.@)
226 */
AVIFileOpenW(PAVIFILE * ppfile,LPCWSTR szFile,UINT uMode,LPCLSID lpHandler)227 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
228 LPCLSID lpHandler)
229 {
230 IPersistFile *ppersist = NULL;
231 CLSID clsidHandler;
232 HRESULT hr;
233
234 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
235 debugstr_guid(lpHandler));
236
237 /* check parameters */
238 if (ppfile == NULL || szFile == NULL)
239 return AVIERR_BADPARAM;
240
241 *ppfile = NULL;
242
243 /* if no handler then try guessing it by extension */
244 if (lpHandler == NULL) {
245 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
246 clsidHandler = CLSID_AVIFile;
247 } else
248 clsidHandler = *lpHandler;
249
250 /* create instance of handler */
251 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile);
252 if (FAILED(hr) || *ppfile == NULL)
253 return hr;
254
255 /* ask for IPersistFile interface for loading/creating the file */
256 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
257 if (FAILED(hr) || ppersist == NULL) {
258 IAVIFile_Release(*ppfile);
259 *ppfile = NULL;
260 return hr;
261 }
262
263 hr = IPersistFile_Load(ppersist, szFile, uMode);
264 IPersistFile_Release(ppersist);
265 if (FAILED(hr)) {
266 IAVIFile_Release(*ppfile);
267 *ppfile = NULL;
268 }
269
270 return hr;
271 }
272
273 /***********************************************************************
274 * AVIFileAddRef (AVIFIL32.@)
275 */
AVIFileAddRef(PAVIFILE pfile)276 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
277 {
278 TRACE("(%p)\n", pfile);
279
280 if (pfile == NULL) {
281 ERR(": bad handle passed!\n");
282 return 0;
283 }
284
285 return IAVIFile_AddRef(pfile);
286 }
287
288 /***********************************************************************
289 * AVIFileRelease (AVIFIL32.@)
290 */
AVIFileRelease(PAVIFILE pfile)291 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
292 {
293 TRACE("(%p)\n", pfile);
294
295 if (pfile == NULL) {
296 ERR(": bad handle passed!\n");
297 return 0;
298 }
299
300 return IAVIFile_Release(pfile);
301 }
302
303 /***********************************************************************
304 * AVIFileInfo (AVIFIL32.@)
305 * AVIFileInfoA (AVIFIL32.@)
306 */
AVIFileInfoA(PAVIFILE pfile,LPAVIFILEINFOA afi,LONG size)307 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
308 {
309 AVIFILEINFOW afiw;
310 HRESULT hres;
311
312 TRACE("(%p,%p,%d)\n", pfile, afi, size);
313
314 if (pfile == NULL)
315 return AVIERR_BADHANDLE;
316 if ((DWORD)size < sizeof(AVIFILEINFOA))
317 return AVIERR_BADSIZE;
318
319 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
320
321 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
322 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
323 sizeof(afi->szFileType), NULL, NULL);
324 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
325
326 return hres;
327 }
328
329 /***********************************************************************
330 * AVIFileInfoW (AVIFIL32.@)
331 */
AVIFileInfoW(PAVIFILE pfile,LPAVIFILEINFOW afiw,LONG size)332 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
333 {
334 TRACE("(%p,%p,%d)\n", pfile, afiw, size);
335
336 if (pfile == NULL)
337 return AVIERR_BADHANDLE;
338
339 return IAVIFile_Info(pfile, afiw, size);
340 }
341
342 /***********************************************************************
343 * AVIFileGetStream (AVIFIL32.@)
344 */
AVIFileGetStream(PAVIFILE pfile,PAVISTREAM * avis,DWORD fccType,LONG lParam)345 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
346 DWORD fccType, LONG lParam)
347 {
348 TRACE("(%p,%p,'%4.4s',%d)\n", pfile, avis, (char*)&fccType, lParam);
349
350 if (pfile == NULL)
351 return AVIERR_BADHANDLE;
352
353 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
354 }
355
356 /***********************************************************************
357 * AVIFileCreateStream (AVIFIL32.@)
358 * AVIFileCreateStreamA (AVIFIL32.@)
359 */
AVIFileCreateStreamA(PAVIFILE pfile,PAVISTREAM * ppavi,LPAVISTREAMINFOA psi)360 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
361 LPAVISTREAMINFOA psi)
362 {
363 AVISTREAMINFOW psiw;
364
365 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
366
367 if (pfile == NULL)
368 return AVIERR_BADHANDLE;
369
370 /* Only the szName at the end is different */
371 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
372 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
373 ARRAY_SIZE(psiw.szName));
374
375 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
376 }
377
378 /***********************************************************************
379 * AVIFileCreateStreamW (AVIFIL32.@)
380 */
AVIFileCreateStreamW(PAVIFILE pfile,PAVISTREAM * avis,LPAVISTREAMINFOW asi)381 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
382 LPAVISTREAMINFOW asi)
383 {
384 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
385
386 if (pfile == NULL)
387 return AVIERR_BADHANDLE;
388
389 return IAVIFile_CreateStream(pfile, avis, asi);
390 }
391
392 /***********************************************************************
393 * AVIFileWriteData (AVIFIL32.@)
394 */
AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)395 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
396 {
397 TRACE("(%p,'%4.4s',%p,%d)\n", pfile, (char*)&fcc, lp, size);
398
399 if (pfile == NULL)
400 return AVIERR_BADHANDLE;
401
402 return IAVIFile_WriteData(pfile, fcc, lp, size);
403 }
404
405 /***********************************************************************
406 * AVIFileReadData (AVIFIL32.@)
407 */
AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)408 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
409 {
410 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
411
412 if (pfile == NULL)
413 return AVIERR_BADHANDLE;
414
415 return IAVIFile_ReadData(pfile, fcc, lp, size);
416 }
417
418 /***********************************************************************
419 * AVIFileEndRecord (AVIFIL32.@)
420 */
AVIFileEndRecord(PAVIFILE pfile)421 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
422 {
423 TRACE("(%p)\n", pfile);
424
425 if (pfile == NULL)
426 return AVIERR_BADHANDLE;
427
428 return IAVIFile_EndRecord(pfile);
429 }
430
431 /***********************************************************************
432 * AVIStreamAddRef (AVIFIL32.@)
433 */
AVIStreamAddRef(PAVISTREAM pstream)434 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
435 {
436 TRACE("(%p)\n", pstream);
437
438 if (pstream == NULL) {
439 ERR(": bad handle passed!\n");
440 return 0;
441 }
442
443 return IAVIStream_AddRef(pstream);
444 }
445
446 /***********************************************************************
447 * AVIStreamRelease (AVIFIL32.@)
448 */
AVIStreamRelease(PAVISTREAM pstream)449 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
450 {
451 TRACE("(%p)\n", pstream);
452
453 if (pstream == NULL) {
454 ERR(": bad handle passed!\n");
455 return 0;
456 }
457
458 return IAVIStream_Release(pstream);
459 }
460
461 /***********************************************************************
462 * AVIStreamCreate (AVIFIL32.@)
463 */
AVIStreamCreate(PAVISTREAM * ppavi,LONG lParam1,LONG lParam2,LPCLSID pclsidHandler)464 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
465 LPCLSID pclsidHandler)
466 {
467 HRESULT hr;
468
469 TRACE("(%p,0x%08X,0x%08X,%s)\n", ppavi, lParam1, lParam2,
470 debugstr_guid(pclsidHandler));
471
472 if (ppavi == NULL)
473 return AVIERR_BADPARAM;
474
475 *ppavi = NULL;
476 if (pclsidHandler == NULL)
477 return AVIERR_UNSUPPORTED;
478
479 hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi);
480 if (FAILED(hr) || *ppavi == NULL)
481 return hr;
482
483 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
484 if (FAILED(hr)) {
485 IAVIStream_Release(*ppavi);
486 *ppavi = NULL;
487 }
488
489 return hr;
490 }
491
492 /***********************************************************************
493 * AVIStreamInfo (AVIFIL32.@)
494 * AVIStreamInfoA (AVIFIL32.@)
495 */
AVIStreamInfoA(PAVISTREAM pstream,LPAVISTREAMINFOA asi,LONG size)496 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
497 LONG size)
498 {
499 AVISTREAMINFOW asiw;
500 HRESULT hres;
501
502 TRACE("(%p,%p,%d)\n", pstream, asi, size);
503
504 if (pstream == NULL)
505 return AVIERR_BADHANDLE;
506 if ((DWORD)size < sizeof(AVISTREAMINFOA))
507 return AVIERR_BADSIZE;
508
509 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
510
511 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
512 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
513 sizeof(asi->szName), NULL, NULL);
514 asi->szName[sizeof(asi->szName) - 1] = 0;
515
516 return hres;
517 }
518
519 /***********************************************************************
520 * AVIStreamInfoW (AVIFIL32.@)
521 */
AVIStreamInfoW(PAVISTREAM pstream,LPAVISTREAMINFOW asi,LONG size)522 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
523 LONG size)
524 {
525 TRACE("(%p,%p,%d)\n", pstream, asi, size);
526
527 if (pstream == NULL)
528 return AVIERR_BADHANDLE;
529
530 return IAVIStream_Info(pstream, asi, size);
531 }
532
533 /***********************************************************************
534 * AVIStreamFindSample (AVIFIL32.@)
535 */
AVIStreamFindSample(PAVISTREAM pstream,LONG pos,LONG flags)536 LONG WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, LONG flags)
537 {
538 TRACE("(%p,%d,0x%X)\n", pstream, pos, flags);
539
540 if (pstream == NULL)
541 return -1;
542
543 return IAVIStream_FindSample(pstream, pos, flags);
544 }
545
546 /***********************************************************************
547 * AVIStreamReadFormat (AVIFIL32.@)
548 */
AVIStreamReadFormat(PAVISTREAM pstream,LONG pos,LPVOID format,LPLONG formatsize)549 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
550 LPVOID format, LPLONG formatsize)
551 {
552 TRACE("(%p,%d,%p,%p)\n", pstream, pos, format, formatsize);
553
554 if (pstream == NULL)
555 return AVIERR_BADHANDLE;
556
557 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
558 }
559
560 /***********************************************************************
561 * AVIStreamSetFormat (AVIFIL32.@)
562 */
AVIStreamSetFormat(PAVISTREAM pstream,LONG pos,LPVOID format,LONG formatsize)563 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
564 LPVOID format, LONG formatsize)
565 {
566 TRACE("(%p,%d,%p,%d)\n", pstream, pos, format, formatsize);
567
568 if (pstream == NULL)
569 return AVIERR_BADHANDLE;
570
571 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
572 }
573
574 /***********************************************************************
575 * AVIStreamRead (AVIFIL32.@)
576 */
AVIStreamRead(PAVISTREAM pstream,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LPLONG bytesread,LPLONG samplesread)577 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
578 LPVOID buffer, LONG buffersize,
579 LPLONG bytesread, LPLONG samplesread)
580 {
581 TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", pstream, start, samples, buffer,
582 buffersize, bytesread, samplesread);
583
584 if (pstream == NULL)
585 return AVIERR_BADHANDLE;
586
587 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
588 bytesread, samplesread);
589 }
590
591 /***********************************************************************
592 * AVIStreamWrite (AVIFIL32.@)
593 */
AVIStreamWrite(PAVISTREAM pstream,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LPLONG sampwritten,LPLONG byteswritten)594 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
595 LPVOID buffer, LONG buffersize, DWORD flags,
596 LPLONG sampwritten, LPLONG byteswritten)
597 {
598 TRACE("(%p,%d,%d,%p,%d,0x%X,%p,%p)\n", pstream, start, samples, buffer,
599 buffersize, flags, sampwritten, byteswritten);
600
601 if (pstream == NULL)
602 return AVIERR_BADHANDLE;
603
604 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
605 flags, sampwritten, byteswritten);
606 }
607
608 /***********************************************************************
609 * AVIStreamReadData (AVIFIL32.@)
610 */
AVIStreamReadData(PAVISTREAM pstream,DWORD fcc,LPVOID lp,LPLONG lpread)611 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
612 LPLONG lpread)
613 {
614 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
615
616 if (pstream == NULL)
617 return AVIERR_BADHANDLE;
618
619 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
620 }
621
622 /***********************************************************************
623 * AVIStreamWriteData (AVIFIL32.@)
624 */
AVIStreamWriteData(PAVISTREAM pstream,DWORD fcc,LPVOID lp,LONG size)625 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
626 LONG size)
627 {
628 TRACE("(%p,'%4.4s',%p,%d)\n", pstream, (char*)&fcc, lp, size);
629
630 if (pstream == NULL)
631 return AVIERR_BADHANDLE;
632
633 return IAVIStream_WriteData(pstream, fcc, lp, size);
634 }
635
636 /***********************************************************************
637 * AVIStreamGetFrameOpen (AVIFIL32.@)
638 */
AVIStreamGetFrameOpen(PAVISTREAM pstream,LPBITMAPINFOHEADER lpbiWanted)639 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
640 LPBITMAPINFOHEADER lpbiWanted)
641 {
642 PGETFRAME pg = NULL;
643
644 TRACE("(%p,%p)\n", pstream, lpbiWanted);
645
646 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
647 pg == NULL) {
648 pg = AVIFILE_CreateGetFrame(pstream);
649 if (pg == NULL)
650 return NULL;
651 }
652
653 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
654 IGetFrame_Release(pg);
655 return NULL;
656 }
657
658 return pg;
659 }
660
661 /***********************************************************************
662 * AVIStreamGetFrame (AVIFIL32.@)
663 */
AVIStreamGetFrame(PGETFRAME pg,LONG pos)664 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
665 {
666 TRACE("(%p,%d)\n", pg, pos);
667
668 if (pg == NULL)
669 return NULL;
670
671 return IGetFrame_GetFrame(pg, pos);
672 }
673
674 /***********************************************************************
675 * AVIStreamGetFrameClose (AVIFIL32.@)
676 */
AVIStreamGetFrameClose(PGETFRAME pg)677 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
678 {
679 TRACE("(%p)\n", pg);
680
681 if (pg != NULL)
682 return IGetFrame_Release(pg);
683 return 0;
684 }
685
686 /***********************************************************************
687 * AVIMakeCompressedStream (AVIFIL32.@)
688 */
AVIMakeCompressedStream(PAVISTREAM * ppsCompressed,PAVISTREAM psSource,LPAVICOMPRESSOPTIONS aco,LPCLSID pclsidHandler)689 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
690 PAVISTREAM psSource,
691 LPAVICOMPRESSOPTIONS aco,
692 LPCLSID pclsidHandler)
693 {
694 AVISTREAMINFOW asiw;
695 CHAR szRegKey[25];
696 CHAR szValue[100];
697 CLSID clsidHandler;
698 HRESULT hr;
699 LONG size = sizeof(szValue);
700
701 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
702 debugstr_guid(pclsidHandler));
703
704 if (ppsCompressed == NULL)
705 return AVIERR_BADPARAM;
706 if (psSource == NULL)
707 return AVIERR_BADHANDLE;
708
709 *ppsCompressed = NULL;
710
711 /* if no handler given get default ones based on streamtype */
712 if (pclsidHandler == NULL) {
713 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
714 if (FAILED(hr))
715 return hr;
716
717 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
718 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
719 return AVIERR_UNSUPPORTED;
720 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
721 return AVIERR_UNSUPPORTED;
722 } else
723 clsidHandler = *pclsidHandler;
724
725 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed);
726 if (FAILED(hr) || *ppsCompressed == NULL)
727 return hr;
728
729 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
730 if (FAILED(hr)) {
731 IAVIStream_Release(*ppsCompressed);
732 *ppsCompressed = NULL;
733 }
734
735 return hr;
736 }
737
738 /***********************************************************************
739 * AVIMakeFileFromStreams (AVIFIL32.@)
740 */
AVIMakeFileFromStreams(PAVIFILE * ppfile,int nStreams,PAVISTREAM * ppStreams)741 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
742 PAVISTREAM *ppStreams)
743 {
744 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
745
746 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
747 return AVIERR_BADPARAM;
748
749 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
750 if (*ppfile == NULL)
751 return AVIERR_MEMORY;
752
753 return AVIERR_OK;
754 }
755
756 /***********************************************************************
757 * AVIStreamOpenFromFile (AVIFIL32.@)
758 * AVIStreamOpenFromFileA (AVIFIL32.@)
759 */
AVIStreamOpenFromFileA(PAVISTREAM * ppavi,LPCSTR szFile,DWORD fccType,LONG lParam,UINT mode,LPCLSID pclsidHandler)760 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
761 DWORD fccType, LONG lParam,
762 UINT mode, LPCLSID pclsidHandler)
763 {
764 PAVIFILE pfile = NULL;
765 HRESULT hr;
766
767 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_a(szFile),
768 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
769
770 if (ppavi == NULL || szFile == NULL)
771 return AVIERR_BADPARAM;
772
773 *ppavi = NULL;
774
775 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
776 if (FAILED(hr) || pfile == NULL)
777 return hr;
778
779 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
780 IAVIFile_Release(pfile);
781
782 return hr;
783 }
784
785 /***********************************************************************
786 * AVIStreamOpenFromFileW (AVIFIL32.@)
787 */
AVIStreamOpenFromFileW(PAVISTREAM * ppavi,LPCWSTR szFile,DWORD fccType,LONG lParam,UINT mode,LPCLSID pclsidHandler)788 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
789 DWORD fccType, LONG lParam,
790 UINT mode, LPCLSID pclsidHandler)
791 {
792 PAVIFILE pfile = NULL;
793 HRESULT hr;
794
795 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_w(szFile),
796 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
797
798 if (ppavi == NULL || szFile == NULL)
799 return AVIERR_BADPARAM;
800
801 *ppavi = NULL;
802
803 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
804 if (FAILED(hr) || pfile == NULL)
805 return hr;
806
807 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
808 IAVIFile_Release(pfile);
809
810 return hr;
811 }
812
813 /***********************************************************************
814 * AVIStreamBeginStreaming (AVIFIL32.@)
815 */
AVIStreamBeginStreaming(PAVISTREAM pavi,LONG lStart,LONG lEnd,LONG lRate)816 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
817 {
818 IAVIStreaming* pstream = NULL;
819 HRESULT hr;
820
821 TRACE("(%p,%d,%d,%d)\n", pavi, lStart, lEnd, lRate);
822
823 if (pavi == NULL)
824 return AVIERR_BADHANDLE;
825
826 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
827 if (SUCCEEDED(hr) && pstream != NULL) {
828 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
829 IAVIStreaming_Release(pstream);
830 } else
831 hr = AVIERR_OK;
832
833 return hr;
834 }
835
836 /***********************************************************************
837 * AVIStreamEndStreaming (AVIFIL32.@)
838 */
AVIStreamEndStreaming(PAVISTREAM pavi)839 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
840 {
841 IAVIStreaming* pstream = NULL;
842 HRESULT hr;
843
844 TRACE("(%p)\n", pavi);
845
846 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
847 if (SUCCEEDED(hr) && pstream != NULL) {
848 IAVIStreaming_End(pstream);
849 IAVIStreaming_Release(pstream);
850 }
851
852 return AVIERR_OK;
853 }
854
855 /***********************************************************************
856 * AVIStreamStart (AVIFIL32.@)
857 */
AVIStreamStart(PAVISTREAM pstream)858 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
859 {
860 AVISTREAMINFOW asiw;
861
862 TRACE("(%p)\n", pstream);
863
864 if (pstream == NULL)
865 return 0;
866
867 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
868 return 0;
869
870 return asiw.dwStart;
871 }
872
873 /***********************************************************************
874 * AVIStreamLength (AVIFIL32.@)
875 */
AVIStreamLength(PAVISTREAM pstream)876 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
877 {
878 AVISTREAMINFOW asiw;
879
880 TRACE("(%p)\n", pstream);
881
882 if (pstream == NULL)
883 return 0;
884
885 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
886 return 0;
887
888 return asiw.dwLength;
889 }
890
891 /***********************************************************************
892 * AVIStreamSampleToTime (AVIFIL32.@)
893 */
AVIStreamSampleToTime(PAVISTREAM pstream,LONG lSample)894 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
895 {
896 AVISTREAMINFOW asiw;
897 LONG time;
898
899 TRACE("(%p,%d)\n", pstream, lSample);
900
901 if (pstream == NULL)
902 return -1;
903
904 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
905 return -1;
906 if (asiw.dwRate == 0)
907 return -1;
908
909 /* limit to stream bounds */
910 if (lSample < asiw.dwStart)
911 lSample = asiw.dwStart;
912 if (lSample > asiw.dwStart + asiw.dwLength)
913 lSample = asiw.dwStart + asiw.dwLength;
914
915 if (asiw.dwRate / asiw.dwScale < 1000)
916 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
917 else
918 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
919
920 TRACE(" -> %d\n",time);
921 return time;
922 }
923
924 /***********************************************************************
925 * AVIStreamTimeToSample (AVIFIL32.@)
926 */
AVIStreamTimeToSample(PAVISTREAM pstream,LONG lTime)927 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
928 {
929 AVISTREAMINFOW asiw;
930 ULONG sample;
931
932 TRACE("(%p,%d)\n", pstream, lTime);
933
934 if (pstream == NULL || lTime < 0)
935 return -1;
936
937 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
938 return -1;
939 if (asiw.dwScale == 0)
940 return -1;
941
942 if (asiw.dwRate / asiw.dwScale < 1000)
943 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
944 else
945 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
946
947 /* limit to stream bounds */
948 if (sample < asiw.dwStart)
949 sample = asiw.dwStart;
950 if (sample > asiw.dwStart + asiw.dwLength)
951 sample = asiw.dwStart + asiw.dwLength;
952
953 TRACE(" -> %d\n", sample);
954 return sample;
955 }
956
957 /***********************************************************************
958 * AVIBuildFilter (AVIFIL32.@)
959 * AVIBuildFilterA (AVIFIL32.@)
960 */
AVIBuildFilterA(LPSTR szFilter,LONG cbFilter,BOOL fSaving)961 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
962 {
963 LPWSTR wszFilter;
964 HRESULT hr;
965
966 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving);
967
968 /* check parameters */
969 if (szFilter == NULL)
970 return AVIERR_BADPARAM;
971 if (cbFilter < 2)
972 return AVIERR_BADSIZE;
973
974 szFilter[0] = 0;
975 szFilter[1] = 0;
976
977 wszFilter = HeapAlloc(GetProcessHeap(), 0, cbFilter * sizeof(WCHAR));
978 if (wszFilter == NULL)
979 return AVIERR_MEMORY;
980
981 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
982 if (SUCCEEDED(hr)) {
983 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
984 szFilter, cbFilter, NULL, NULL);
985 }
986
987 HeapFree(GetProcessHeap(), 0, wszFilter);
988
989 return hr;
990 }
991
992 /***********************************************************************
993 * AVIBuildFilterW (AVIFIL32.@)
994 */
AVIBuildFilterW(LPWSTR szFilter,LONG cbFilter,BOOL fSaving)995 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
996 {
997 static const WCHAR all_files[] = { '*','.','*',0,0 };
998 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
999 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1000 static const WCHAR szAVIFileExtensions[] =
1001 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1002
1003 AVIFilter *lp;
1004 WCHAR szAllFiles[40];
1005 WCHAR szFileExt[10];
1006 WCHAR szValue[128];
1007 HKEY hKey;
1008 DWORD n, i;
1009 LONG size;
1010 DWORD count = 0;
1011
1012 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving);
1013
1014 /* check parameters */
1015 if (szFilter == NULL)
1016 return AVIERR_BADPARAM;
1017 if (cbFilter < 2)
1018 return AVIERR_BADSIZE;
1019
1020 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_FILTERS * sizeof(AVIFilter));
1021 if (lp == NULL)
1022 return AVIERR_MEMORY;
1023
1024 /*
1025 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1026 * extensions and CLSIDs
1027 * 2. iterate over collected CLSIDs and copy its description and its
1028 * extensions to szFilter if it fits
1029 *
1030 * First filter is named "All multimedia files" and its filter is a
1031 * collection of all possible extensions except "*.*".
1032 */
1033 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != ERROR_SUCCESS) {
1034 HeapFree(GetProcessHeap(), 0, lp);
1035 return AVIERR_ERROR;
1036 }
1037 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, ARRAY_SIZE(szFileExt)) == ERROR_SUCCESS;n++) {
1038 WCHAR clsidW[40];
1039
1040 /* get CLSID to extension */
1041 size = sizeof(clsidW);
1042 if (RegQueryValueW(hKey, szFileExt, clsidW, &size) != ERROR_SUCCESS)
1043 break;
1044
1045 /* search if the CLSID is already known */
1046 for (i = 1; i <= count; i++) {
1047 if (lstrcmpW(lp[i].szClsid, clsidW) == 0)
1048 break; /* a new one */
1049 }
1050
1051 if (i == count + 1) {
1052 /* it's a new CLSID */
1053
1054 /* FIXME: How do we get info's about read/write capabilities? */
1055
1056 if (count >= MAX_FILTERS) {
1057 /* try to inform user of our full fixed size table */
1058 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1059 break;
1060 }
1061
1062 lstrcpyW(lp[i].szClsid, clsidW);
1063
1064 count++;
1065 }
1066
1067 /* append extension to the filter */
1068 wsprintfW(szValue, szExtensionFmt, szFileExt);
1069 if (lp[i].szExtensions[0] == 0)
1070 lstrcatW(lp[i].szExtensions, szValue + 1);
1071 else
1072 lstrcatW(lp[i].szExtensions, szValue);
1073
1074 /* also append to the "all multimedia"-filter */
1075 if (lp[0].szExtensions[0] == 0)
1076 lstrcatW(lp[0].szExtensions, szValue + 1);
1077 else
1078 lstrcatW(lp[0].szExtensions, szValue);
1079 }
1080 RegCloseKey(hKey);
1081
1082 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1083 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != ERROR_SUCCESS) {
1084 HeapFree(GetProcessHeap(), 0, lp);
1085 return AVIERR_ERROR;
1086 }
1087 for (n = 0; n <= count; n++) {
1088 /* first the description */
1089 if (n != 0) {
1090 size = sizeof(szValue);
1091 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == ERROR_SUCCESS) {
1092 size = lstrlenW(szValue);
1093 lstrcpynW(szFilter, szValue, cbFilter);
1094 }
1095 } else
1096 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1097
1098 /* check for enough space */
1099 size++;
1100 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1101 szFilter[0] = 0;
1102 szFilter[1] = 0;
1103 HeapFree(GetProcessHeap(), 0, lp);
1104 RegCloseKey(hKey);
1105 return AVIERR_BUFFERTOOSMALL;
1106 }
1107 cbFilter -= size;
1108 szFilter += size;
1109
1110 /* and then the filter */
1111 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1112 size = lstrlenW(lp[n].szExtensions) + 1;
1113 cbFilter -= size;
1114 szFilter += size;
1115 }
1116
1117 RegCloseKey(hKey);
1118 HeapFree(GetProcessHeap(), 0, lp);
1119
1120 /* add "All files" "*.*" filter if enough space left */
1121 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES, szAllFiles,
1122 ARRAY_SIZE(szAllFiles) - ARRAY_SIZE(all_files)) + 1;
1123 memcpy( szAllFiles + size, all_files, sizeof(all_files) );
1124 size += ARRAY_SIZE(all_files);
1125
1126 if (cbFilter > size) {
1127 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1128 return AVIERR_OK;
1129 } else {
1130 szFilter[0] = 0;
1131 return AVIERR_BUFFERTOOSMALL;
1132 }
1133 }
1134
AVISaveOptionsFmtChoose(HWND hWnd)1135 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1136 {
1137 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1138 AVISTREAMINFOW sInfo;
1139
1140 TRACE("(%p)\n", hWnd);
1141
1142 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1143 ERR(": bad state!\n");
1144 return FALSE;
1145 }
1146
1147 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1148 &sInfo, sizeof(sInfo)))) {
1149 ERR(": AVIStreamInfoW failed!\n");
1150 return FALSE;
1151 }
1152
1153 if (sInfo.fccType == streamtypeVIDEO) {
1154 COMPVARS cv;
1155 BOOL ret;
1156
1157 memset(&cv, 0, sizeof(cv));
1158
1159 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1160 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1161 pOptions->fccType = streamtypeVIDEO;
1162 pOptions->fccHandler = comptypeDIB;
1163 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1164 }
1165
1166 cv.cbSize = sizeof(cv);
1167 cv.dwFlags = ICMF_COMPVARS_VALID;
1168 /*cv.fccType = pOptions->fccType; */
1169 cv.fccHandler = pOptions->fccHandler;
1170 cv.lQ = pOptions->dwQuality;
1171 cv.lpState = pOptions->lpParms;
1172 cv.cbState = pOptions->cbParms;
1173 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1174 cv.lKey = pOptions->dwKeyFrameEvery;
1175 else
1176 cv.lKey = 0;
1177 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1178 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1179 else
1180 cv.lDataRate = 0;
1181
1182 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1183 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1184
1185 if (ret) {
1186 pOptions->fccHandler = cv.fccHandler;
1187 pOptions->lpParms = cv.lpState;
1188 pOptions->cbParms = cv.cbState;
1189 pOptions->dwQuality = cv.lQ;
1190 if (cv.lKey != 0) {
1191 pOptions->dwKeyFrameEvery = cv.lKey;
1192 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1193 } else
1194 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1195 if (cv.lDataRate != 0) {
1196 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1197 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1198 } else
1199 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1200 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1201 }
1202 ICCompressorFree(&cv);
1203
1204 return ret;
1205 } else if (sInfo.fccType == streamtypeAUDIO) {
1206 ACMFORMATCHOOSEW afmtc;
1207 MMRESULT ret;
1208 LONG size;
1209
1210 /* FIXME: check ACM version -- Which version is needed? */
1211
1212 memset(&afmtc, 0, sizeof(afmtc));
1213 afmtc.cbStruct = sizeof(afmtc);
1214 afmtc.fdwStyle = 0;
1215 afmtc.hwndOwner = hWnd;
1216
1217 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1218 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1219 pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1220 if (!pOptions->lpFormat) return FALSE;
1221 pOptions->cbFormat = size;
1222 } else if (pOptions->cbFormat < (DWORD)size) {
1223 void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size);
1224 if (!new_buffer) return FALSE;
1225 pOptions->lpFormat = new_buffer;
1226 pOptions->cbFormat = size;
1227 }
1228 afmtc.pwfx = pOptions->lpFormat;
1229 afmtc.cbwfx = pOptions->cbFormat;
1230
1231 size = 0;
1232 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1233 sInfo.dwStart, &size);
1234 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1235 size = sizeof(PCMWAVEFORMAT);
1236 afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size);
1237 if (afmtc.pwfxEnum != NULL) {
1238 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1239 sInfo.dwStart, afmtc.pwfxEnum, &size);
1240 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1241 }
1242
1243 ret = acmFormatChooseW(&afmtc);
1244 if (ret == S_OK)
1245 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1246
1247 HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum);
1248 return ret == S_OK;
1249 } else {
1250 ERR(": unknown streamtype 0x%08X\n", sInfo.fccType);
1251 return FALSE;
1252 }
1253 }
1254
AVISaveOptionsUpdate(HWND hWnd)1255 static void AVISaveOptionsUpdate(HWND hWnd)
1256 {
1257 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1258 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1259
1260 WCHAR szFormat[128];
1261 AVISTREAMINFOW sInfo;
1262 LPVOID lpFormat;
1263 LONG size;
1264
1265 TRACE("(%p)\n", hWnd);
1266
1267 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1268 if (SaveOpts.nCurrent < 0)
1269 return;
1270
1271 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1272 return;
1273
1274 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1275 if (size > 0) {
1276 szFormat[0] = 0;
1277
1278 /* read format to build format description string */
1279 lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1280 if (lpFormat != NULL) {
1281 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1282 if (sInfo.fccType == streamtypeVIDEO) {
1283 LPBITMAPINFOHEADER lpbi = lpFormat;
1284 ICINFO icinfo;
1285
1286 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1287 lpbi->biHeight, lpbi->biBitCount);
1288
1289 if (lpbi->biCompression != BI_RGB) {
1290 HIC hic;
1291
1292 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1293 NULL, ICMODE_DECOMPRESS);
1294 if (hic != NULL) {
1295 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1296 lstrcatW(szFormat, icinfo.szDescription);
1297 ICClose(hic);
1298 }
1299 } else {
1300 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1301 icinfo.szDescription,
1302 ARRAY_SIZE(icinfo.szDescription));
1303 lstrcatW(szFormat, icinfo.szDescription);
1304 }
1305 } else if (sInfo.fccType == streamtypeAUDIO) {
1306 ACMFORMATTAGDETAILSW aftd;
1307 ACMFORMATDETAILSW afd;
1308
1309 memset(&aftd, 0, sizeof(aftd));
1310 memset(&afd, 0, sizeof(afd));
1311
1312 aftd.cbStruct = sizeof(aftd);
1313 aftd.dwFormatTag = afd.dwFormatTag =
1314 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1315 aftd.cbFormatSize = afd.cbwfx = size;
1316
1317 afd.cbStruct = sizeof(afd);
1318 afd.pwfx = lpFormat;
1319
1320 if (acmFormatTagDetailsW(NULL, &aftd,
1321 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1322 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1323 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1324 }
1325 }
1326 }
1327 HeapFree(GetProcessHeap(), 0, lpFormat);
1328 }
1329
1330 /* set text for format description */
1331 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1332
1333 /* Disable option button for unsupported streamtypes */
1334 if (sInfo.fccType == streamtypeVIDEO ||
1335 sInfo.fccType == streamtypeAUDIO)
1336 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1337 else
1338 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1339 }
1340
1341 }
1342
AVISaveOptionsDlgProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1343 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1344 WPARAM wParam, LPARAM lParam)
1345 {
1346 DWORD dwInterleave;
1347 BOOL bIsInterleaved;
1348 INT n;
1349
1350 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1351
1352 switch (uMsg) {
1353 case WM_INITDIALOG:
1354 SaveOpts.nCurrent = 0;
1355 if (SaveOpts.nStreams == 1) {
1356 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1357 return TRUE;
1358 }
1359
1360 /* add streams */
1361 for (n = 0; n < SaveOpts.nStreams; n++) {
1362 AVISTREAMINFOW sInfo;
1363
1364 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1365 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1366 0L, (LPARAM)sInfo.szName);
1367 }
1368
1369 /* select first stream */
1370 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1371 SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd);
1372
1373 /* initialize interleave */
1374 if (SaveOpts.ppOptions[0] != NULL &&
1375 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1376 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1377 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1378 } else {
1379 bIsInterleaved = TRUE;
1380 dwInterleave = 0;
1381 }
1382 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1383 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1384 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1385 break;
1386 case WM_COMMAND:
1387 switch (LOWORD(wParam)) {
1388 case IDOK:
1389 /* get data from controls and save them */
1390 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1391 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1392 for (n = 0; n < SaveOpts.nStreams; n++) {
1393 if (SaveOpts.ppOptions[n] != NULL) {
1394 if (bIsInterleaved) {
1395 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1396 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1397 } else
1398 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1399 }
1400 }
1401 /* fall through */
1402 case IDCANCEL:
1403 EndDialog(hWnd, LOWORD(wParam) == IDOK);
1404 break;
1405 case IDC_INTERLEAVE:
1406 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1407 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1408 break;
1409 case IDC_STREAM:
1410 if (HIWORD(wParam) == CBN_SELCHANGE) {
1411 /* update control elements */
1412 AVISaveOptionsUpdate(hWnd);
1413 }
1414 break;
1415 case IDC_OPTIONS:
1416 AVISaveOptionsFmtChoose(hWnd);
1417 break;
1418 };
1419 return TRUE;
1420 };
1421
1422 return FALSE;
1423 }
1424
1425 /***********************************************************************
1426 * AVISaveOptions (AVIFIL32.@)
1427 */
AVISaveOptions(HWND hWnd,UINT uFlags,INT nStreams,PAVISTREAM * ppavi,LPAVICOMPRESSOPTIONS * ppOptions)1428 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1429 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1430 {
1431 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1432 INT ret, n;
1433
1434 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1435 ppavi, ppOptions);
1436
1437 /* check parameters */
1438 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1439 return AVIERR_BADPARAM;
1440
1441 /* save options in case the user presses cancel */
1442 if (nStreams > 1) {
1443 pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS));
1444 if (pSavedOptions == NULL)
1445 return FALSE;
1446
1447 for (n = 0; n < nStreams; n++) {
1448 if (ppOptions[n] != NULL)
1449 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1450 }
1451 }
1452
1453 SaveOpts.uFlags = uFlags;
1454 SaveOpts.nStreams = nStreams;
1455 SaveOpts.ppavis = ppavi;
1456 SaveOpts.ppOptions = ppOptions;
1457
1458 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1459 hWnd, AVISaveOptionsDlgProc);
1460
1461 if (ret == -1)
1462 ret = FALSE;
1463
1464 /* restore options when user pressed cancel */
1465 if (pSavedOptions != NULL) {
1466 if (ret == FALSE) {
1467 for (n = 0; n < nStreams; n++) {
1468 if (ppOptions[n] != NULL)
1469 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1470 }
1471 }
1472 HeapFree(GetProcessHeap(), 0, pSavedOptions);
1473 }
1474
1475 return ret;
1476 }
1477
1478 /***********************************************************************
1479 * AVISaveOptionsFree (AVIFIL32.@)
1480 */
AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS * ppOptions)1481 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1482 {
1483 TRACE("(%d,%p)\n", nStreams, ppOptions);
1484
1485 if (nStreams < 0 || ppOptions == NULL)
1486 return AVIERR_BADPARAM;
1487
1488 for (nStreams--; nStreams >= 0; nStreams--) {
1489 if (ppOptions[nStreams] != NULL) {
1490 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1491
1492 if (ppOptions[nStreams]->lpParms != NULL) {
1493 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms);
1494 ppOptions[nStreams]->lpParms = NULL;
1495 ppOptions[nStreams]->cbParms = 0;
1496 }
1497 if (ppOptions[nStreams]->lpFormat != NULL) {
1498 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat);
1499 ppOptions[nStreams]->lpFormat = NULL;
1500 ppOptions[nStreams]->cbFormat = 0;
1501 }
1502 }
1503 }
1504
1505 return AVIERR_OK;
1506 }
1507
1508 /***********************************************************************
1509 * AVISaveVA (AVIFIL32.@)
1510 */
AVISaveVA(LPCSTR szFile,CLSID * pclsidHandler,AVISAVECALLBACK lpfnCallback,int nStream,PAVISTREAM * ppavi,LPAVICOMPRESSOPTIONS * plpOptions)1511 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1512 AVISAVECALLBACK lpfnCallback, int nStream,
1513 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1514 {
1515 LPWSTR wszFile = NULL;
1516 HRESULT hr;
1517 int len;
1518
1519 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1520 lpfnCallback, nStream, ppavi, plpOptions);
1521
1522 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1523 return AVIERR_BADPARAM;
1524
1525 /* convert ASCII string to Unicode and call Unicode function */
1526 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1527 if (len <= 0)
1528 return AVIERR_BADPARAM;
1529
1530 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1531 if (wszFile == NULL)
1532 return AVIERR_MEMORY;
1533
1534 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
1535
1536 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1537 nStream, ppavi, plpOptions);
1538
1539 HeapFree(GetProcessHeap(), 0, wszFile);
1540
1541 return hr;
1542 }
1543
1544 /***********************************************************************
1545 * AVIFILE_AVISaveDefaultCallback (internal)
1546 */
AVIFILE_AVISaveDefaultCallback(INT progress)1547 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1548 {
1549 TRACE("(%d)\n", progress);
1550
1551 return FALSE;
1552 }
1553
1554 /***********************************************************************
1555 * AVISaveVW (AVIFIL32.@)
1556 */
AVISaveVW(LPCWSTR szFile,CLSID * pclsidHandler,AVISAVECALLBACK lpfnCallback,int nStreams,PAVISTREAM * ppavi,LPAVICOMPRESSOPTIONS * plpOptions)1557 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1558 AVISAVECALLBACK lpfnCallback, int nStreams,
1559 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1560 {
1561 LONG lStart[MAX_AVISTREAMS];
1562 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1563 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1564 AVIFILEINFOW fInfo;
1565 AVISTREAMINFOW sInfo;
1566
1567 PAVIFILE pfile = NULL; /* the output AVI file */
1568 LONG lFirstVideo = -1;
1569 int curStream;
1570
1571 /* for interleaving ... */
1572 DWORD dwInterleave = 0; /* interleave rate */
1573 DWORD dwFileInitialFrames;
1574 LONG lFileLength;
1575 LONG lSampleInc;
1576
1577 /* for reading/writing the data ... */
1578 LPVOID lpBuffer = NULL;
1579 LONG cbBuffer; /* real size of lpBuffer */
1580 LONG lBufferSize; /* needed bytes for format(s), etc. */
1581 LONG lReadBytes;
1582 LONG lReadSamples;
1583 HRESULT hres;
1584
1585 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1586 lpfnCallback, nStreams, ppavi, plpOptions);
1587
1588 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1589 return AVIERR_BADPARAM;
1590 if (nStreams >= MAX_AVISTREAMS) {
1591 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1592 return AVIERR_INTERNAL;
1593 }
1594
1595 if (lpfnCallback == NULL)
1596 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1597
1598 /* clear local variable(s) */
1599 for (curStream = 0; curStream < nStreams; curStream++) {
1600 pInStreams[curStream] = NULL;
1601 pOutStreams[curStream] = NULL;
1602 }
1603
1604 /* open output AVI file (create it if it doesn't exist) */
1605 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1606 pclsidHandler);
1607 if (FAILED(hres))
1608 return hres;
1609 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1610
1611 /* initialize our data structures part 1 */
1612 for (curStream = 0; curStream < nStreams; curStream++) {
1613 PAVISTREAM pCurStream = ppavi[curStream];
1614
1615 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1616 if (FAILED(hres))
1617 goto error;
1618
1619 /* search first video stream and check for interleaving */
1620 if (sInfo.fccType == streamtypeVIDEO) {
1621 /* remember first video stream -- needed for interleaving */
1622 if (lFirstVideo < 0)
1623 lFirstVideo = curStream;
1624 } else if (!dwInterleave) {
1625 /* check if any non-video stream wants to be interleaved */
1626 WARN("options.flags=0x%X options.dwInterleave=%u\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1627 if (plpOptions[curStream] != NULL &&
1628 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1629 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1630 }
1631
1632 /* create de-/compressed stream interface if needed */
1633 pInStreams[curStream] = NULL;
1634 if (plpOptions[curStream] != NULL) {
1635 if (plpOptions[curStream]->fccHandler ||
1636 plpOptions[curStream]->lpFormat != NULL) {
1637 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1638
1639 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1640 plpOptions[curStream]->dwKeyFrameEvery = 1;
1641
1642 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1643 plpOptions[curStream], NULL);
1644 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1645 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1646 pInStreams[curStream] = NULL;
1647 goto error;
1648 }
1649
1650 /* test stream interface and update stream-info */
1651 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1652 if (FAILED(hres))
1653 goto error;
1654 }
1655 }
1656
1657 /* now handle streams which will only be copied */
1658 if (pInStreams[curStream] == NULL) {
1659 pCurStream = pInStreams[curStream] = ppavi[curStream];
1660 AVIStreamAddRef(pCurStream);
1661 } else
1662 pCurStream = pInStreams[curStream];
1663
1664 lStart[curStream] = sInfo.dwStart;
1665 } /* for all streams */
1666
1667 /* check that first video stream is the first stream */
1668 if (lFirstVideo > 0) {
1669 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1670 LONG lTmp = lStart[lFirstVideo];
1671
1672 pInStreams[lFirstVideo] = pInStreams[0];
1673 pInStreams[0] = pTmp;
1674 lStart[lFirstVideo] = lStart[0];
1675 lStart[0] = lTmp;
1676 lFirstVideo = 0;
1677 }
1678
1679 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
1680 cbBuffer = 0x00010000;
1681 lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer);
1682 if (lpBuffer == NULL) {
1683 hres = AVIERR_MEMORY;
1684 goto error;
1685 }
1686
1687 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
1688 lFileLength = sInfo.dwLength;
1689 dwFileInitialFrames = 0;
1690 if (lFirstVideo >= 0) {
1691 /* check for correct version of the format
1692 * -- need at least BITMAPINFOHEADER or newer
1693 */
1694 lSampleInc = 1;
1695 lBufferSize = cbBuffer;
1696 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
1697 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
1698 hres = AVIERR_INTERNAL;
1699 if (FAILED(hres))
1700 goto error;
1701 } else /* use one second blocks for interleaving if no video present */
1702 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
1703
1704 /* create output streams */
1705 for (curStream = 0; curStream < nStreams; curStream++) {
1706 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1707
1708 sInfo.dwInitialFrames = 0;
1709 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
1710 /* 750 ms initial frames for non-video streams */
1711 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
1712 }
1713
1714 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
1715 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
1716 /* copy initial format for this stream */
1717 lBufferSize = cbBuffer;
1718 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1719 lpBuffer, &lBufferSize);
1720 if (FAILED(hres))
1721 goto error;
1722 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
1723 if (FAILED(hres))
1724 goto error;
1725
1726 /* try to copy stream handler data */
1727 lBufferSize = cbBuffer;
1728 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
1729 lpBuffer, &lBufferSize);
1730 if (SUCCEEDED(hres) && lBufferSize > 0) {
1731 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
1732 lpBuffer, lBufferSize);
1733 if (FAILED(hres))
1734 goto error;
1735 }
1736
1737 if (dwFileInitialFrames < sInfo.dwInitialFrames)
1738 dwFileInitialFrames = sInfo.dwInitialFrames;
1739 lReadBytes =
1740 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
1741 sInfo.dwLength);
1742 if (lFileLength < lReadBytes)
1743 lFileLength = lReadBytes;
1744 } else {
1745 /* creation of de-/compression stream interface failed */
1746 WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
1747 AVIStreamRelease(pInStreams[curStream]);
1748 if (curStream + 1 >= nStreams) {
1749 /* move the others one up */
1750 PAVISTREAM *ppas = &pInStreams[curStream];
1751 int n = nStreams - (curStream + 1);
1752
1753 do {
1754 *ppas = pInStreams[curStream + 1];
1755 } while (--n);
1756 }
1757 nStreams--;
1758 curStream--;
1759 }
1760 } /* create output streams for all input streams */
1761
1762 /* have we still something to write, or lost everything? */
1763 if (nStreams <= 0)
1764 goto error;
1765
1766 if (dwInterleave) {
1767 LONG lCurFrame = -dwFileInitialFrames;
1768
1769 /* interleaved file */
1770 if (dwInterleave == 1)
1771 AVIFileEndRecord(pfile);
1772
1773 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
1774 for (curStream = 0; curStream < nStreams; curStream++) {
1775 LONG lLastSample;
1776
1777 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
1778 if (FAILED(hres))
1779 goto error;
1780
1781 /* initial frames phase at the end for this stream? */
1782 if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
1783 continue;
1784
1785 if ((lFileLength - lSampleInc) <= lCurFrame) {
1786 lLastSample = AVIStreamLength(pInStreams[curStream]);
1787 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
1788 } else {
1789 if (curStream != 0) {
1790 lFirstVideo =
1791 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
1792 (sInfo.fccType == streamtypeVIDEO ?
1793 (LONG)dwInterleave : lSampleInc) +
1794 sInfo.dwInitialFrames + lCurFrame);
1795 } else
1796 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
1797
1798 lLastSample = AVIStreamEnd(pInStreams[curStream]);
1799 if (lLastSample <= lFirstVideo)
1800 lFirstVideo = lLastSample;
1801 }
1802
1803 /* copy needed samples now */
1804 WARN("copy from stream %d samples %d to %d...\n",curStream,
1805 lStart[curStream],lFirstVideo);
1806 while (lFirstVideo > lStart[curStream]) {
1807 DWORD flags = 0;
1808
1809 /* copy format in case it can change */
1810 lBufferSize = cbBuffer;
1811 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
1812 lpBuffer, &lBufferSize);
1813 if (FAILED(hres))
1814 goto error;
1815 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
1816 lpBuffer, lBufferSize);
1817
1818 /* try to read data until we got it, or error */
1819 do {
1820 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
1821 lFirstVideo - lStart[curStream], lpBuffer,
1822 cbBuffer, &lReadBytes, &lReadSamples);
1823 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1824 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1825 if (lpBuffer == NULL)
1826 hres = AVIERR_MEMORY;
1827 if (FAILED(hres))
1828 goto error;
1829
1830 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1831 flags = AVIIF_KEYFRAME;
1832 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1833 lpBuffer, lReadBytes, flags, NULL, NULL);
1834 if (FAILED(hres))
1835 goto error;
1836
1837 lStart[curStream] += lReadSamples;
1838 }
1839 lStart[curStream] = lFirstVideo;
1840 } /* stream by stream */
1841
1842 /* need to close this block? */
1843 if (dwInterleave == 1) {
1844 hres = AVIFileEndRecord(pfile);
1845 if (FAILED(hres))
1846 break;
1847 }
1848
1849 /* show progress */
1850 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
1851 dwFileInitialFrames + lFileLength))) {
1852 hres = AVIERR_USERABORT;
1853 break;
1854 }
1855 } /* copy frame by frame */
1856 } else {
1857 /* non-interleaved file */
1858
1859 for (curStream = 0; curStream < nStreams; curStream++) {
1860 /* show progress */
1861 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
1862 hres = AVIERR_USERABORT;
1863 goto error;
1864 }
1865
1866 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1867
1868 if (sInfo.dwSampleSize != 0) {
1869 /* sample-based data like audio */
1870 while (sInfo.dwStart < sInfo.dwLength) {
1871 LONG lSamples = cbBuffer / sInfo.dwSampleSize;
1872
1873 /* copy format in case it can change */
1874 lBufferSize = cbBuffer;
1875 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1876 lpBuffer, &lBufferSize);
1877 if (FAILED(hres))
1878 goto error;
1879 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1880 lpBuffer, lBufferSize);
1881
1882 /* limit to stream boundaries */
1883 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
1884 lSamples = sInfo.dwLength - sInfo.dwStart;
1885
1886 /* now try to read until we get it, or an error occurs */
1887 do {
1888 lReadBytes = cbBuffer;
1889 lReadSamples = 0;
1890 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
1891 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
1892 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1893 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1894 if (lpBuffer == NULL)
1895 hres = AVIERR_MEMORY;
1896 if (FAILED(hres))
1897 goto error;
1898 if (lReadSamples != 0) {
1899 sInfo.dwStart += lReadSamples;
1900 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1901 lpBuffer, lReadBytes, 0, NULL , NULL);
1902 if (FAILED(hres))
1903 goto error;
1904
1905 /* show progress */
1906 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1907 MulDiv(curStream, 100, nStreams))) {
1908 hres = AVIERR_USERABORT;
1909 goto error;
1910 }
1911 } else {
1912 if ((sInfo.dwLength - sInfo.dwStart) != 1) {
1913 hres = AVIERR_FILEREAD;
1914 goto error;
1915 }
1916 }
1917 }
1918 } else {
1919 /* block-based data like video */
1920 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
1921 DWORD flags = 0;
1922
1923 /* copy format in case it can change */
1924 lBufferSize = cbBuffer;
1925 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1926 lpBuffer, &lBufferSize);
1927 if (FAILED(hres))
1928 goto error;
1929 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1930 lpBuffer, lBufferSize);
1931
1932 /* try to read block and resize buffer if necessary */
1933 do {
1934 lReadSamples = 0;
1935 lReadBytes = cbBuffer;
1936 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
1937 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
1938 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1939 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1940 if (lpBuffer == NULL)
1941 hres = AVIERR_MEMORY;
1942 if (FAILED(hres))
1943 goto error;
1944 if (lReadSamples != 1) {
1945 hres = AVIERR_FILEREAD;
1946 goto error;
1947 }
1948
1949 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1950 flags = AVIIF_KEYFRAME;
1951 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1952 lpBuffer, lReadBytes, flags, NULL, NULL);
1953 if (FAILED(hres))
1954 goto error;
1955
1956 /* show progress */
1957 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1958 MulDiv(curStream, 100, nStreams))) {
1959 hres = AVIERR_USERABORT;
1960 goto error;
1961 }
1962 } /* copy all blocks */
1963 }
1964 } /* copy data stream by stream */
1965 }
1966
1967 error:
1968 HeapFree(GetProcessHeap(), 0, lpBuffer);
1969 if (pfile != NULL) {
1970 for (curStream = 0; curStream < nStreams; curStream++) {
1971 if (pOutStreams[curStream] != NULL)
1972 AVIStreamRelease(pOutStreams[curStream]);
1973 if (pInStreams[curStream] != NULL)
1974 AVIStreamRelease(pInStreams[curStream]);
1975 }
1976
1977 AVIFileRelease(pfile);
1978 }
1979
1980 return hres;
1981 }
1982
1983 /***********************************************************************
1984 * EditStreamClone (AVIFIL32.@)
1985 */
EditStreamClone(PAVISTREAM pStream,PAVISTREAM * ppResult)1986 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
1987 {
1988 PAVIEDITSTREAM pEdit = NULL;
1989 HRESULT hr;
1990
1991 TRACE("(%p,%p)\n", pStream, ppResult);
1992
1993 if (pStream == NULL)
1994 return AVIERR_BADHANDLE;
1995 if (ppResult == NULL)
1996 return AVIERR_BADPARAM;
1997
1998 *ppResult = NULL;
1999
2000 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2001 if (SUCCEEDED(hr) && pEdit != NULL) {
2002 hr = IAVIEditStream_Clone(pEdit, ppResult);
2003
2004 IAVIEditStream_Release(pEdit);
2005 } else
2006 hr = AVIERR_UNSUPPORTED;
2007
2008 return hr;
2009 }
2010
2011 /***********************************************************************
2012 * EditStreamCopy (AVIFIL32.@)
2013 */
EditStreamCopy(PAVISTREAM pStream,LONG * plStart,LONG * plLength,PAVISTREAM * ppResult)2014 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2015 LONG *plLength, PAVISTREAM *ppResult)
2016 {
2017 PAVIEDITSTREAM pEdit = NULL;
2018 HRESULT hr;
2019
2020 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2021
2022 if (pStream == NULL)
2023 return AVIERR_BADHANDLE;
2024 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2025 return AVIERR_BADPARAM;
2026
2027 *ppResult = NULL;
2028
2029 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2030 if (SUCCEEDED(hr) && pEdit != NULL) {
2031 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2032
2033 IAVIEditStream_Release(pEdit);
2034 } else
2035 hr = AVIERR_UNSUPPORTED;
2036
2037 return hr;
2038 }
2039
2040 /***********************************************************************
2041 * EditStreamCut (AVIFIL32.@)
2042 */
EditStreamCut(PAVISTREAM pStream,LONG * plStart,LONG * plLength,PAVISTREAM * ppResult)2043 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2044 LONG *plLength, PAVISTREAM *ppResult)
2045 {
2046 PAVIEDITSTREAM pEdit = NULL;
2047 HRESULT hr;
2048
2049 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2050
2051 if (ppResult != NULL)
2052 *ppResult = NULL;
2053 if (pStream == NULL)
2054 return AVIERR_BADHANDLE;
2055 if (plStart == NULL || plLength == NULL)
2056 return AVIERR_BADPARAM;
2057
2058 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2059 if (SUCCEEDED(hr) && pEdit != NULL) {
2060 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2061
2062 IAVIEditStream_Release(pEdit);
2063 } else
2064 hr = AVIERR_UNSUPPORTED;
2065
2066 return hr;
2067 }
2068
2069 /***********************************************************************
2070 * EditStreamPaste (AVIFIL32.@)
2071 */
EditStreamPaste(PAVISTREAM pDest,LONG * plStart,LONG * plLength,PAVISTREAM pSource,LONG lStart,LONG lEnd)2072 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2073 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2074 {
2075 PAVIEDITSTREAM pEdit = NULL;
2076 HRESULT hr;
2077
2078 TRACE("(%p,%p,%p,%p,%d,%d)\n", pDest, plStart, plLength,
2079 pSource, lStart, lEnd);
2080
2081 if (pDest == NULL || pSource == NULL)
2082 return AVIERR_BADHANDLE;
2083 if (plStart == NULL || plLength == NULL || lStart < 0)
2084 return AVIERR_BADPARAM;
2085
2086 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2087 if (SUCCEEDED(hr) && pEdit != NULL) {
2088 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2089
2090 IAVIEditStream_Release(pEdit);
2091 } else
2092 hr = AVIERR_UNSUPPORTED;
2093
2094 return hr;
2095 }
2096
2097 /***********************************************************************
2098 * EditStreamSetInfoA (AVIFIL32.@)
2099 */
EditStreamSetInfoA(PAVISTREAM pstream,LPAVISTREAMINFOA asi,LONG size)2100 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2101 LONG size)
2102 {
2103 AVISTREAMINFOW asiw;
2104
2105 TRACE("(%p,%p,%d)\n", pstream, asi, size);
2106
2107 if (size >= 0 && size < sizeof(AVISTREAMINFOA))
2108 return AVIERR_BADSIZE;
2109
2110 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2111 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1, asiw.szName, ARRAY_SIZE(asiw.szName));
2112
2113 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2114 }
2115
2116 /***********************************************************************
2117 * EditStreamSetInfoW (AVIFIL32.@)
2118 */
EditStreamSetInfoW(PAVISTREAM pstream,LPAVISTREAMINFOW asi,LONG size)2119 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2120 LONG size)
2121 {
2122 PAVIEDITSTREAM pEdit = NULL;
2123 HRESULT hr;
2124
2125 TRACE("(%p,%p,%d)\n", pstream, asi, size);
2126
2127 if (size >= 0 && size < sizeof(AVISTREAMINFOA))
2128 return AVIERR_BADSIZE;
2129
2130 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2131 if (SUCCEEDED(hr) && pEdit != NULL) {
2132 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2133
2134 IAVIEditStream_Release(pEdit);
2135 } else
2136 hr = AVIERR_UNSUPPORTED;
2137
2138 return hr;
2139 }
2140
2141 /***********************************************************************
2142 * EditStreamSetNameA (AVIFIL32.@)
2143 */
EditStreamSetNameA(PAVISTREAM pstream,LPCSTR szName)2144 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2145 {
2146 AVISTREAMINFOA asia;
2147 HRESULT hres;
2148
2149 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2150
2151 if (pstream == NULL)
2152 return AVIERR_BADHANDLE;
2153 if (szName == NULL)
2154 return AVIERR_BADPARAM;
2155
2156 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2157 if (FAILED(hres))
2158 return hres;
2159
2160 memset(asia.szName, 0, sizeof(asia.szName));
2161 lstrcpynA(asia.szName, szName, ARRAY_SIZE(asia.szName));
2162
2163 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2164 }
2165
2166 /***********************************************************************
2167 * EditStreamSetNameW (AVIFIL32.@)
2168 */
EditStreamSetNameW(PAVISTREAM pstream,LPCWSTR szName)2169 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2170 {
2171 AVISTREAMINFOW asiw;
2172 HRESULT hres;
2173
2174 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2175
2176 if (pstream == NULL)
2177 return AVIERR_BADHANDLE;
2178 if (szName == NULL)
2179 return AVIERR_BADPARAM;
2180
2181 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2182 if (FAILED(hres))
2183 return hres;
2184
2185 memset(asiw.szName, 0, sizeof(asiw.szName));
2186 lstrcpynW(asiw.szName, szName, ARRAY_SIZE(asiw.szName));
2187
2188 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2189 }
2190
2191 /***********************************************************************
2192 * AVIClearClipboard (AVIFIL32.@)
2193 */
AVIClearClipboard(void)2194 HRESULT WINAPI AVIClearClipboard(void)
2195 {
2196 TRACE("()\n");
2197
2198 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2199 }
2200
2201 /***********************************************************************
2202 * AVIGetFromClipboard (AVIFIL32.@)
2203 */
AVIGetFromClipboard(PAVIFILE * ppfile)2204 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2205 {
2206 FIXME("(%p), stub!\n", ppfile);
2207
2208 *ppfile = NULL;
2209
2210 return AVIERR_UNSUPPORTED;
2211 }
2212
2213 /***********************************************************************
2214 * AVIMakeStreamFromClipboard (AVIFIL32.@)
2215 */
AVIMakeStreamFromClipboard(UINT cfFormat,HANDLE hGlobal,PAVISTREAM * ppstream)2216 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
2217 PAVISTREAM * ppstream)
2218 {
2219 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
2220
2221 if (ppstream == NULL)
2222 return AVIERR_BADHANDLE;
2223
2224 return AVIERR_UNSUPPORTED;
2225 }
2226
2227 /***********************************************************************
2228 * AVIPutFileOnClipboard (AVIFIL32.@)
2229 */
AVIPutFileOnClipboard(PAVIFILE pfile)2230 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2231 {
2232 FIXME("(%p), stub!\n", pfile);
2233
2234 if (pfile == NULL)
2235 return AVIERR_BADHANDLE;
2236
2237 return AVIERR_UNSUPPORTED;
2238 }
2239
AVISaveA(LPCSTR szFile,CLSID * pclsidHandler,AVISAVECALLBACK lpfnCallback,int nStreams,PAVISTREAM pavi,LPAVICOMPRESSOPTIONS lpOptions,...)2240 HRESULT WINAPIV AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2241 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2242 {
2243 __ms_va_list vl;
2244 int i;
2245 HRESULT ret;
2246 PAVISTREAM *streams;
2247 LPAVICOMPRESSOPTIONS *options;
2248
2249 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
2250 nStreams, pavi, lpOptions);
2251
2252 if (nStreams <= 0) return AVIERR_BADPARAM;
2253
2254 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams));
2255 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options));
2256 if (!streams || !options)
2257 {
2258 ret = AVIERR_MEMORY;
2259 goto error;
2260 }
2261
2262 streams[0] = pavi;
2263 options[0] = lpOptions;
2264
2265 __ms_va_start(vl, lpOptions);
2266 for (i = 1; i < nStreams; i++)
2267 {
2268 streams[i] = va_arg(vl, PAVISTREAM);
2269 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS);
2270 }
2271 __ms_va_end(vl);
2272
2273 for (i = 0; i < nStreams; i++)
2274 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]);
2275
2276 ret = AVISaveVA(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options);
2277 error:
2278 HeapFree(GetProcessHeap(), 0, streams);
2279 HeapFree(GetProcessHeap(), 0, options);
2280 return ret;
2281 }
2282
AVISaveW(LPCWSTR szFile,CLSID * pclsidHandler,AVISAVECALLBACK lpfnCallback,int nStreams,PAVISTREAM pavi,LPAVICOMPRESSOPTIONS lpOptions,...)2283 HRESULT WINAPIV AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2284 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2285 {
2286 __ms_va_list vl;
2287 int i;
2288 HRESULT ret;
2289 PAVISTREAM *streams;
2290 LPAVICOMPRESSOPTIONS *options;
2291
2292 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
2293 nStreams, pavi, lpOptions);
2294
2295 if (nStreams <= 0) return AVIERR_BADPARAM;
2296
2297 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams));
2298 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options));
2299 if (!streams || !options)
2300 {
2301 ret = AVIERR_MEMORY;
2302 goto error;
2303 }
2304
2305 streams[0] = pavi;
2306 options[0] = lpOptions;
2307
2308 __ms_va_start(vl, lpOptions);
2309 for (i = 1; i < nStreams; i++)
2310 {
2311 streams[i] = va_arg(vl, PAVISTREAM);
2312 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS);
2313 }
2314 __ms_va_end(vl);
2315
2316 for (i = 0; i < nStreams; i++)
2317 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]);
2318
2319 ret = AVISaveVW(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options);
2320 error:
2321 HeapFree(GetProcessHeap(), 0, streams);
2322 HeapFree(GetProcessHeap(), 0, options);
2323 return ret;
2324 }
2325