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