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