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