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