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