widl: Always check the runtimeclass interfaces presence.
[wine/zf.git] / dlls / avifil32 / api.c
blob5a9985424e718aee4695778ed34828512e5bb0e2
1 /*
2 * Copyright 1999 Marcus Meissner
3 * Copyright 2002-2003 Michael Günnewig
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.
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.
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
20 #include <stdarg.h>
22 #define COBJMACROS
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"
32 #include "ole2.h"
33 #include "shellapi.h"
34 #include "shlobj.h"
35 #include "vfw.h"
36 #include "msacm.h"
38 #include "avifile_private.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
45 /***********************************************************************
46 * for AVIBuildFilterW -- uses fixed size table
48 #define MAX_FILTERS 30 /* 30 => 7kB */
50 typedef struct _AVIFilter {
51 WCHAR szClsid[40];
52 WCHAR szExtensions[MAX_FILTERS * 7];
53 } AVIFilter;
55 /***********************************************************************
56 * for AVISaveOptions
58 static struct {
59 UINT uFlags;
60 INT nStreams;
61 PAVISTREAM *ppavis;
62 LPAVICOMPRESSOPTIONS *ppOptions;
63 INT nCurrent;
64 } SaveOpts;
66 /***********************************************************************
67 * copied from dlls/ole32/compobj.c
69 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
71 BYTE const *s;
72 BYTE *p;
73 INT i;
74 BYTE table[256];
76 if (!idstr) {
77 memset(id, 0, sizeof(CLSID));
78 return S_OK;
81 /* validate the CLSID string */
82 if (lstrlenA(idstr) != 38)
83 return CO_E_CLASSSTRING;
85 s = (BYTE const*)idstr;
86 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
87 (s[24]!='-') || (s[37]!='}'))
88 return CO_E_CLASSSTRING;
90 for (i = 1; i < 37; i++) {
91 if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
92 continue;
93 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
94 ((s[i] >= 'a') && (s[i] <= 'f')) ||
95 ((s[i] >= 'A') && (s[i] <= 'F')))
97 return CO_E_CLASSSTRING;
100 TRACE("%s -> %p\n", s, id);
102 /* quick lookup table */
103 memset(table, 0, 256);
105 for (i = 0; i < 10; i++)
106 table['0' + i] = i;
108 for (i = 0; i < 6; i++) {
109 table['A' + i] = i+10;
110 table['a' + i] = i+10;
113 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
114 p = (BYTE *) id;
116 s++; /* skip leading brace */
117 for (i = 0; i < 4; i++) {
118 p[3 - i] = table[*s]<<4 | table[*(s+1)];
119 s += 2;
121 p += 4;
122 s++; /* skip - */
124 for (i = 0; i < 2; i++) {
125 p[1-i] = table[*s]<<4 | table[*(s+1)];
126 s += 2;
128 p += 2;
129 s++; /* skip - */
131 for (i = 0; i < 2; i++) {
132 p[1-i] = table[*s]<<4 | table[*(s+1)];
133 s += 2;
135 p += 2;
136 s++; /* skip - */
138 /* these are just sequential bytes */
139 for (i = 0; i < 2; i++) {
140 *p++ = table[*s]<<4 | table[*(s+1)];
141 s += 2;
143 s++; /* skip - */
145 for (i = 0; i < 6; i++) {
146 *p++ = table[*s]<<4 | table[*(s+1)];
147 s += 2;
150 return S_OK;
153 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
155 CHAR szRegKey[25];
156 CHAR szValue[100];
157 LPWSTR szExt = wcsrchr(szFile, '.');
158 LONG len = ARRAY_SIZE(szValue);
160 if (szExt == NULL)
161 return FALSE;
163 szExt++;
165 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
166 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
167 return FALSE;
169 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
172 /***********************************************************************
173 * AVIFileInit (AVIFIL32.@)
175 void WINAPI AVIFileInit(void) {
176 OleInitialize(NULL);
179 /***********************************************************************
180 * AVIFileExit (AVIFIL32.@)
182 void WINAPI AVIFileExit(void) {
183 /* need to free ole32.dll if we are the last exit call */
184 /* OleUninitialize() */
185 FIXME("(): stub!\n");
188 /***********************************************************************
189 * AVIFileOpen (AVIFIL32.@)
190 * AVIFileOpenA (AVIFIL32.@)
192 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
193 LPCLSID lpHandler)
195 LPWSTR wszFile = NULL;
196 HRESULT hr;
197 int len;
199 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
200 debugstr_guid(lpHandler));
202 /* check parameters */
203 if (ppfile == NULL || szFile == NULL)
204 return AVIERR_BADPARAM;
206 /* convert ASCII string to Unicode and call unicode function */
207 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
208 if (len <= 0)
209 return AVIERR_BADPARAM;
211 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
212 if (wszFile == NULL)
213 return AVIERR_MEMORY;
215 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
217 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
219 HeapFree(GetProcessHeap(), 0, wszFile);
221 return hr;
224 /***********************************************************************
225 * AVIFileOpenW (AVIFIL32.@)
227 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
228 LPCLSID lpHandler)
230 IPersistFile *ppersist = NULL;
231 CLSID clsidHandler;
232 HRESULT hr;
234 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
235 debugstr_guid(lpHandler));
237 /* check parameters */
238 if (ppfile == NULL || szFile == NULL)
239 return AVIERR_BADPARAM;
241 *ppfile = NULL;
243 /* if no handler then try guessing it by extension */
244 if (lpHandler == NULL) {
245 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
246 clsidHandler = CLSID_AVIFile;
247 } else
248 clsidHandler = *lpHandler;
250 /* create instance of handler */
251 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile);
252 if (FAILED(hr) || *ppfile == NULL)
253 return hr;
255 /* ask for IPersistFile interface for loading/creating the file */
256 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
257 if (FAILED(hr) || ppersist == NULL) {
258 IAVIFile_Release(*ppfile);
259 *ppfile = NULL;
260 return hr;
263 hr = IPersistFile_Load(ppersist, szFile, uMode);
264 IPersistFile_Release(ppersist);
265 if (FAILED(hr)) {
266 IAVIFile_Release(*ppfile);
267 *ppfile = NULL;
270 return hr;
273 /***********************************************************************
274 * AVIFileAddRef (AVIFIL32.@)
276 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
278 TRACE("(%p)\n", pfile);
280 if (pfile == NULL) {
281 ERR(": bad handle passed!\n");
282 return 0;
285 return IAVIFile_AddRef(pfile);
288 /***********************************************************************
289 * AVIFileRelease (AVIFIL32.@)
291 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
293 TRACE("(%p)\n", pfile);
295 if (pfile == NULL) {
296 ERR(": bad handle passed!\n");
297 return 0;
300 return IAVIFile_Release(pfile);
303 /***********************************************************************
304 * AVIFileInfo (AVIFIL32.@)
305 * AVIFileInfoA (AVIFIL32.@)
307 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
309 AVIFILEINFOW afiw;
310 HRESULT hres;
312 TRACE("(%p,%p,%d)\n", pfile, afi, size);
314 if (pfile == NULL)
315 return AVIERR_BADHANDLE;
316 if ((DWORD)size < sizeof(AVIFILEINFOA))
317 return AVIERR_BADSIZE;
319 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
321 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
322 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
323 sizeof(afi->szFileType), NULL, NULL);
324 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
326 return hres;
329 /***********************************************************************
330 * AVIFileInfoW (AVIFIL32.@)
332 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
334 TRACE("(%p,%p,%d)\n", pfile, afiw, size);
336 if (pfile == NULL)
337 return AVIERR_BADHANDLE;
339 return IAVIFile_Info(pfile, afiw, size);
342 /***********************************************************************
343 * AVIFileGetStream (AVIFIL32.@)
345 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
346 DWORD fccType, LONG lParam)
348 TRACE("(%p,%p,'%4.4s',%d)\n", pfile, avis, (char*)&fccType, lParam);
350 if (pfile == NULL)
351 return AVIERR_BADHANDLE;
353 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
356 /***********************************************************************
357 * AVIFileCreateStream (AVIFIL32.@)
358 * AVIFileCreateStreamA (AVIFIL32.@)
360 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
361 LPAVISTREAMINFOA psi)
363 AVISTREAMINFOW psiw;
365 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
367 if (pfile == NULL)
368 return AVIERR_BADHANDLE;
370 /* Only the szName at the end is different */
371 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
372 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
373 ARRAY_SIZE(psiw.szName));
375 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
378 /***********************************************************************
379 * AVIFileCreateStreamW (AVIFIL32.@)
381 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
382 LPAVISTREAMINFOW asi)
384 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
386 if (pfile == NULL)
387 return AVIERR_BADHANDLE;
389 return IAVIFile_CreateStream(pfile, avis, asi);
392 /***********************************************************************
393 * AVIFileWriteData (AVIFIL32.@)
395 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
397 TRACE("(%p,'%4.4s',%p,%d)\n", pfile, (char*)&fcc, lp, size);
399 if (pfile == NULL)
400 return AVIERR_BADHANDLE;
402 return IAVIFile_WriteData(pfile, fcc, lp, size);
405 /***********************************************************************
406 * AVIFileReadData (AVIFIL32.@)
408 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
410 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
412 if (pfile == NULL)
413 return AVIERR_BADHANDLE;
415 return IAVIFile_ReadData(pfile, fcc, lp, size);
418 /***********************************************************************
419 * AVIFileEndRecord (AVIFIL32.@)
421 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
423 TRACE("(%p)\n", pfile);
425 if (pfile == NULL)
426 return AVIERR_BADHANDLE;
428 return IAVIFile_EndRecord(pfile);
431 /***********************************************************************
432 * AVIStreamAddRef (AVIFIL32.@)
434 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
436 TRACE("(%p)\n", pstream);
438 if (pstream == NULL) {
439 ERR(": bad handle passed!\n");
440 return 0;
443 return IAVIStream_AddRef(pstream);
446 /***********************************************************************
447 * AVIStreamRelease (AVIFIL32.@)
449 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
451 TRACE("(%p)\n", pstream);
453 if (pstream == NULL) {
454 ERR(": bad handle passed!\n");
455 return 0;
458 return IAVIStream_Release(pstream);
461 /***********************************************************************
462 * AVIStreamCreate (AVIFIL32.@)
464 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
465 LPCLSID pclsidHandler)
467 HRESULT hr;
469 TRACE("(%p,0x%08X,0x%08X,%s)\n", ppavi, lParam1, lParam2,
470 debugstr_guid(pclsidHandler));
472 if (ppavi == NULL)
473 return AVIERR_BADPARAM;
475 *ppavi = NULL;
476 if (pclsidHandler == NULL)
477 return AVIERR_UNSUPPORTED;
479 hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi);
480 if (FAILED(hr) || *ppavi == NULL)
481 return hr;
483 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
484 if (FAILED(hr)) {
485 IAVIStream_Release(*ppavi);
486 *ppavi = NULL;
489 return hr;
492 /***********************************************************************
493 * AVIStreamInfo (AVIFIL32.@)
494 * AVIStreamInfoA (AVIFIL32.@)
496 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
497 LONG size)
499 AVISTREAMINFOW asiw;
500 HRESULT hres;
502 TRACE("(%p,%p,%d)\n", pstream, asi, size);
504 if (pstream == NULL)
505 return AVIERR_BADHANDLE;
506 if ((DWORD)size < sizeof(AVISTREAMINFOA))
507 return AVIERR_BADSIZE;
509 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
511 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
512 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
513 sizeof(asi->szName), NULL, NULL);
514 asi->szName[sizeof(asi->szName) - 1] = 0;
516 return hres;
519 /***********************************************************************
520 * AVIStreamInfoW (AVIFIL32.@)
522 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
523 LONG size)
525 TRACE("(%p,%p,%d)\n", pstream, asi, size);
527 if (pstream == NULL)
528 return AVIERR_BADHANDLE;
530 return IAVIStream_Info(pstream, asi, size);
533 /***********************************************************************
534 * AVIStreamFindSample (AVIFIL32.@)
536 LONG WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, LONG flags)
538 TRACE("(%p,%d,0x%X)\n", pstream, pos, flags);
540 if (pstream == NULL)
541 return -1;
543 return IAVIStream_FindSample(pstream, pos, flags);
546 /***********************************************************************
547 * AVIStreamReadFormat (AVIFIL32.@)
549 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
550 LPVOID format, LPLONG formatsize)
552 TRACE("(%p,%d,%p,%p)\n", pstream, pos, format, formatsize);
554 if (pstream == NULL)
555 return AVIERR_BADHANDLE;
557 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
560 /***********************************************************************
561 * AVIStreamSetFormat (AVIFIL32.@)
563 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
564 LPVOID format, LONG formatsize)
566 TRACE("(%p,%d,%p,%d)\n", pstream, pos, format, formatsize);
568 if (pstream == NULL)
569 return AVIERR_BADHANDLE;
571 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
574 /***********************************************************************
575 * AVIStreamRead (AVIFIL32.@)
577 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
578 LPVOID buffer, LONG buffersize,
579 LPLONG bytesread, LPLONG samplesread)
581 TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", pstream, start, samples, buffer,
582 buffersize, bytesread, samplesread);
584 if (pstream == NULL)
585 return AVIERR_BADHANDLE;
587 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
588 bytesread, samplesread);
591 /***********************************************************************
592 * AVIStreamWrite (AVIFIL32.@)
594 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
595 LPVOID buffer, LONG buffersize, DWORD flags,
596 LPLONG sampwritten, LPLONG byteswritten)
598 TRACE("(%p,%d,%d,%p,%d,0x%X,%p,%p)\n", pstream, start, samples, buffer,
599 buffersize, flags, sampwritten, byteswritten);
601 if (pstream == NULL)
602 return AVIERR_BADHANDLE;
604 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
605 flags, sampwritten, byteswritten);
608 /***********************************************************************
609 * AVIStreamReadData (AVIFIL32.@)
611 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
612 LPLONG lpread)
614 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
616 if (pstream == NULL)
617 return AVIERR_BADHANDLE;
619 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
622 /***********************************************************************
623 * AVIStreamWriteData (AVIFIL32.@)
625 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
626 LONG size)
628 TRACE("(%p,'%4.4s',%p,%d)\n", pstream, (char*)&fcc, lp, size);
630 if (pstream == NULL)
631 return AVIERR_BADHANDLE;
633 return IAVIStream_WriteData(pstream, fcc, lp, size);
636 /***********************************************************************
637 * AVIStreamGetFrameOpen (AVIFIL32.@)
639 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
640 LPBITMAPINFOHEADER lpbiWanted)
642 PGETFRAME pg = NULL;
644 TRACE("(%p,%p)\n", pstream, lpbiWanted);
646 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
647 pg == NULL) {
648 pg = AVIFILE_CreateGetFrame(pstream);
649 if (pg == NULL)
650 return NULL;
653 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
654 IGetFrame_Release(pg);
655 return NULL;
658 return pg;
661 /***********************************************************************
662 * AVIStreamGetFrame (AVIFIL32.@)
664 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
666 TRACE("(%p,%d)\n", pg, pos);
668 if (pg == NULL)
669 return NULL;
671 return IGetFrame_GetFrame(pg, pos);
674 /***********************************************************************
675 * AVIStreamGetFrameClose (AVIFIL32.@)
677 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
679 TRACE("(%p)\n", pg);
681 if (pg != NULL)
682 return IGetFrame_Release(pg);
683 return 0;
686 /***********************************************************************
687 * AVIMakeCompressedStream (AVIFIL32.@)
689 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
690 PAVISTREAM psSource,
691 LPAVICOMPRESSOPTIONS aco,
692 LPCLSID pclsidHandler)
694 AVISTREAMINFOW asiw;
695 CHAR szRegKey[25];
696 CHAR szValue[100];
697 CLSID clsidHandler;
698 HRESULT hr;
699 LONG size = sizeof(szValue);
701 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
702 debugstr_guid(pclsidHandler));
704 if (ppsCompressed == NULL)
705 return AVIERR_BADPARAM;
706 if (psSource == NULL)
707 return AVIERR_BADHANDLE;
709 *ppsCompressed = NULL;
711 /* if no handler given get default ones based on streamtype */
712 if (pclsidHandler == NULL) {
713 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
714 if (FAILED(hr))
715 return hr;
717 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
718 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
719 return AVIERR_UNSUPPORTED;
720 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
721 return AVIERR_UNSUPPORTED;
722 } else
723 clsidHandler = *pclsidHandler;
725 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed);
726 if (FAILED(hr) || *ppsCompressed == NULL)
727 return hr;
729 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
730 if (FAILED(hr)) {
731 IAVIStream_Release(*ppsCompressed);
732 *ppsCompressed = NULL;
735 return hr;
738 /***********************************************************************
739 * AVIMakeFileFromStreams (AVIFIL32.@)
741 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
742 PAVISTREAM *ppStreams)
744 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
746 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
747 return AVIERR_BADPARAM;
749 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
750 if (*ppfile == NULL)
751 return AVIERR_MEMORY;
753 return AVIERR_OK;
756 /***********************************************************************
757 * AVIStreamOpenFromFile (AVIFIL32.@)
758 * AVIStreamOpenFromFileA (AVIFIL32.@)
760 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
761 DWORD fccType, LONG lParam,
762 UINT mode, LPCLSID pclsidHandler)
764 PAVIFILE pfile = NULL;
765 HRESULT hr;
767 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_a(szFile),
768 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
770 if (ppavi == NULL || szFile == NULL)
771 return AVIERR_BADPARAM;
773 *ppavi = NULL;
775 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
776 if (FAILED(hr) || pfile == NULL)
777 return hr;
779 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
780 IAVIFile_Release(pfile);
782 return hr;
785 /***********************************************************************
786 * AVIStreamOpenFromFileW (AVIFIL32.@)
788 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
789 DWORD fccType, LONG lParam,
790 UINT mode, LPCLSID pclsidHandler)
792 PAVIFILE pfile = NULL;
793 HRESULT hr;
795 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_w(szFile),
796 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
798 if (ppavi == NULL || szFile == NULL)
799 return AVIERR_BADPARAM;
801 *ppavi = NULL;
803 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
804 if (FAILED(hr) || pfile == NULL)
805 return hr;
807 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
808 IAVIFile_Release(pfile);
810 return hr;
813 /***********************************************************************
814 * AVIStreamBeginStreaming (AVIFIL32.@)
816 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
818 IAVIStreaming* pstream = NULL;
819 HRESULT hr;
821 TRACE("(%p,%d,%d,%d)\n", pavi, lStart, lEnd, lRate);
823 if (pavi == NULL)
824 return AVIERR_BADHANDLE;
826 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
827 if (SUCCEEDED(hr) && pstream != NULL) {
828 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
829 IAVIStreaming_Release(pstream);
830 } else
831 hr = AVIERR_OK;
833 return hr;
836 /***********************************************************************
837 * AVIStreamEndStreaming (AVIFIL32.@)
839 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
841 IAVIStreaming* pstream = NULL;
842 HRESULT hr;
844 TRACE("(%p)\n", pavi);
846 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
847 if (SUCCEEDED(hr) && pstream != NULL) {
848 IAVIStreaming_End(pstream);
849 IAVIStreaming_Release(pstream);
852 return AVIERR_OK;
855 /***********************************************************************
856 * AVIStreamStart (AVIFIL32.@)
858 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
860 AVISTREAMINFOW asiw;
862 TRACE("(%p)\n", pstream);
864 if (pstream == NULL)
865 return 0;
867 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
868 return 0;
870 return asiw.dwStart;
873 /***********************************************************************
874 * AVIStreamLength (AVIFIL32.@)
876 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
878 AVISTREAMINFOW asiw;
880 TRACE("(%p)\n", pstream);
882 if (pstream == NULL)
883 return 0;
885 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
886 return 0;
888 return asiw.dwLength;
891 /***********************************************************************
892 * AVIStreamSampleToTime (AVIFIL32.@)
894 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
896 AVISTREAMINFOW asiw;
897 LONG time;
899 TRACE("(%p,%d)\n", pstream, lSample);
901 if (pstream == NULL)
902 return -1;
904 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
905 return -1;
906 if (asiw.dwRate == 0)
907 return -1;
909 /* limit to stream bounds */
910 if (lSample < asiw.dwStart)
911 lSample = asiw.dwStart;
912 if (lSample > asiw.dwStart + asiw.dwLength)
913 lSample = asiw.dwStart + asiw.dwLength;
915 if (asiw.dwRate / asiw.dwScale < 1000)
916 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
917 else
918 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
920 TRACE(" -> %d\n",time);
921 return time;
924 /***********************************************************************
925 * AVIStreamTimeToSample (AVIFIL32.@)
927 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
929 AVISTREAMINFOW asiw;
930 ULONG sample;
932 TRACE("(%p,%d)\n", pstream, lTime);
934 if (pstream == NULL || lTime < 0)
935 return -1;
937 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
938 return -1;
939 if (asiw.dwScale == 0)
940 return -1;
942 if (asiw.dwRate / asiw.dwScale < 1000)
943 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
944 else
945 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
947 /* limit to stream bounds */
948 if (sample < asiw.dwStart)
949 sample = asiw.dwStart;
950 if (sample > asiw.dwStart + asiw.dwLength)
951 sample = asiw.dwStart + asiw.dwLength;
953 TRACE(" -> %d\n", sample);
954 return sample;
957 /***********************************************************************
958 * AVIBuildFilter (AVIFIL32.@)
959 * AVIBuildFilterA (AVIFIL32.@)
961 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
963 LPWSTR wszFilter;
964 HRESULT hr;
966 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving);
968 /* check parameters */
969 if (szFilter == NULL)
970 return AVIERR_BADPARAM;
971 if (cbFilter < 2)
972 return AVIERR_BADSIZE;
974 szFilter[0] = 0;
975 szFilter[1] = 0;
977 wszFilter = HeapAlloc(GetProcessHeap(), 0, cbFilter * sizeof(WCHAR));
978 if (wszFilter == NULL)
979 return AVIERR_MEMORY;
981 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
982 if (SUCCEEDED(hr)) {
983 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
984 szFilter, cbFilter, NULL, NULL);
987 HeapFree(GetProcessHeap(), 0, wszFilter);
989 return hr;
992 /***********************************************************************
993 * AVIBuildFilterW (AVIFIL32.@)
995 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
997 static const WCHAR all_files[] = L"*.*\0";
999 AVIFilter *lp;
1000 WCHAR szAllFiles[40];
1001 WCHAR szFileExt[10];
1002 WCHAR szValue[128];
1003 HKEY hKey;
1004 DWORD n, i;
1005 LONG size;
1006 DWORD count = 0;
1008 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving);
1010 /* check parameters */
1011 if (szFilter == NULL)
1012 return AVIERR_BADPARAM;
1013 if (cbFilter < 2)
1014 return AVIERR_BADSIZE;
1016 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_FILTERS * sizeof(AVIFilter));
1017 if (lp == NULL)
1018 return AVIERR_MEMORY;
1021 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1022 * extensions and CLSIDs
1023 * 2. iterate over collected CLSIDs and copy its description and its
1024 * extensions to szFilter if it fits
1026 * First filter is named "All multimedia files" and its filter is a
1027 * collection of all possible extensions except "*.*".
1029 if (RegOpenKeyW(HKEY_CLASSES_ROOT, L"AVIFile\\Extensions", &hKey) != ERROR_SUCCESS) {
1030 HeapFree(GetProcessHeap(), 0, lp);
1031 return AVIERR_ERROR;
1033 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, ARRAY_SIZE(szFileExt)) == ERROR_SUCCESS;n++) {
1034 WCHAR clsidW[40];
1036 /* get CLSID to extension */
1037 size = sizeof(clsidW);
1038 if (RegQueryValueW(hKey, szFileExt, clsidW, &size) != ERROR_SUCCESS)
1039 break;
1041 /* search if the CLSID is already known */
1042 for (i = 1; i <= count; i++) {
1043 if (lstrcmpW(lp[i].szClsid, clsidW) == 0)
1044 break; /* a new one */
1047 if (i == count + 1) {
1048 /* it's a new CLSID */
1050 /* FIXME: How do we get info's about read/write capabilities? */
1052 if (count >= MAX_FILTERS) {
1053 /* try to inform user of our full fixed size table */
1054 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1055 break;
1058 lstrcpyW(lp[i].szClsid, clsidW);
1060 count++;
1063 /* append extension to the filter */
1064 wsprintfW(szValue, L";*.%s", szFileExt);
1065 if (lp[i].szExtensions[0] == 0)
1066 lstrcatW(lp[i].szExtensions, szValue + 1);
1067 else
1068 lstrcatW(lp[i].szExtensions, szValue);
1070 /* also append to the "all multimedia"-filter */
1071 if (lp[0].szExtensions[0] == 0)
1072 lstrcatW(lp[0].szExtensions, szValue + 1);
1073 else
1074 lstrcatW(lp[0].szExtensions, szValue);
1076 RegCloseKey(hKey);
1078 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1079 if (RegOpenKeyW(HKEY_CLASSES_ROOT, L"CLSID", &hKey) != ERROR_SUCCESS) {
1080 HeapFree(GetProcessHeap(), 0, lp);
1081 return AVIERR_ERROR;
1083 for (n = 0; n <= count; n++) {
1084 /* first the description */
1085 if (n != 0) {
1086 size = sizeof(szValue);
1087 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == ERROR_SUCCESS) {
1088 size = lstrlenW(szValue);
1089 lstrcpynW(szFilter, szValue, cbFilter);
1091 } else
1092 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1094 /* check for enough space */
1095 size++;
1096 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1097 szFilter[0] = 0;
1098 szFilter[1] = 0;
1099 HeapFree(GetProcessHeap(), 0, lp);
1100 RegCloseKey(hKey);
1101 return AVIERR_BUFFERTOOSMALL;
1103 cbFilter -= size;
1104 szFilter += size;
1106 /* and then the filter */
1107 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1108 size = lstrlenW(lp[n].szExtensions) + 1;
1109 cbFilter -= size;
1110 szFilter += size;
1113 RegCloseKey(hKey);
1114 HeapFree(GetProcessHeap(), 0, lp);
1116 /* add "All files" "*.*" filter if enough space left */
1117 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES, szAllFiles,
1118 ARRAY_SIZE(szAllFiles) - ARRAY_SIZE(all_files)) + 1;
1119 memcpy( szAllFiles + size, all_files, sizeof(all_files) );
1120 size += ARRAY_SIZE(all_files);
1122 if (cbFilter > size) {
1123 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1124 return AVIERR_OK;
1125 } else {
1126 szFilter[0] = 0;
1127 return AVIERR_BUFFERTOOSMALL;
1131 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1133 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1134 AVISTREAMINFOW sInfo;
1136 TRACE("(%p)\n", hWnd);
1138 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1139 ERR(": bad state!\n");
1140 return FALSE;
1143 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1144 &sInfo, sizeof(sInfo)))) {
1145 ERR(": AVIStreamInfoW failed!\n");
1146 return FALSE;
1149 if (sInfo.fccType == streamtypeVIDEO) {
1150 COMPVARS cv;
1151 BOOL ret;
1153 memset(&cv, 0, sizeof(cv));
1155 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1156 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1157 pOptions->fccType = streamtypeVIDEO;
1158 pOptions->fccHandler = comptypeDIB;
1159 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1162 cv.cbSize = sizeof(cv);
1163 cv.dwFlags = ICMF_COMPVARS_VALID;
1164 /*cv.fccType = pOptions->fccType; */
1165 cv.fccHandler = pOptions->fccHandler;
1166 cv.lQ = pOptions->dwQuality;
1167 cv.lpState = pOptions->lpParms;
1168 cv.cbState = pOptions->cbParms;
1169 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1170 cv.lKey = pOptions->dwKeyFrameEvery;
1171 else
1172 cv.lKey = 0;
1173 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1174 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1175 else
1176 cv.lDataRate = 0;
1178 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1179 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1181 if (ret) {
1182 pOptions->fccHandler = cv.fccHandler;
1183 pOptions->lpParms = cv.lpState;
1184 pOptions->cbParms = cv.cbState;
1185 pOptions->dwQuality = cv.lQ;
1186 if (cv.lKey != 0) {
1187 pOptions->dwKeyFrameEvery = cv.lKey;
1188 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1189 } else
1190 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1191 if (cv.lDataRate != 0) {
1192 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1193 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1194 } else
1195 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1196 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1198 ICCompressorFree(&cv);
1200 return ret;
1201 } else if (sInfo.fccType == streamtypeAUDIO) {
1202 ACMFORMATCHOOSEW afmtc;
1203 MMRESULT ret;
1204 LONG size;
1206 /* FIXME: check ACM version -- Which version is needed? */
1208 memset(&afmtc, 0, sizeof(afmtc));
1209 afmtc.cbStruct = sizeof(afmtc);
1210 afmtc.fdwStyle = 0;
1211 afmtc.hwndOwner = hWnd;
1213 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1214 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1215 pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1216 if (!pOptions->lpFormat) return FALSE;
1217 pOptions->cbFormat = size;
1218 } else if (pOptions->cbFormat < (DWORD)size) {
1219 void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size);
1220 if (!new_buffer) return FALSE;
1221 pOptions->lpFormat = new_buffer;
1222 pOptions->cbFormat = size;
1224 afmtc.pwfx = pOptions->lpFormat;
1225 afmtc.cbwfx = pOptions->cbFormat;
1227 size = 0;
1228 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1229 sInfo.dwStart, &size);
1230 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1231 size = sizeof(PCMWAVEFORMAT);
1232 afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size);
1233 if (afmtc.pwfxEnum != NULL) {
1234 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1235 sInfo.dwStart, afmtc.pwfxEnum, &size);
1236 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1239 ret = acmFormatChooseW(&afmtc);
1240 if (ret == S_OK)
1241 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1243 HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum);
1244 return ret == S_OK;
1245 } else {
1246 ERR(": unknown streamtype 0x%08X\n", sInfo.fccType);
1247 return FALSE;
1251 static void AVISaveOptionsUpdate(HWND hWnd)
1253 WCHAR szFormat[128];
1254 AVISTREAMINFOW sInfo;
1255 LPVOID lpFormat;
1256 LONG size;
1258 TRACE("(%p)\n", hWnd);
1260 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1261 if (SaveOpts.nCurrent < 0)
1262 return;
1264 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1265 return;
1267 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1268 if (size > 0) {
1269 szFormat[0] = 0;
1271 /* read format to build format description string */
1272 lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1273 if (lpFormat != NULL) {
1274 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1275 if (sInfo.fccType == streamtypeVIDEO) {
1276 LPBITMAPINFOHEADER lpbi = lpFormat;
1277 ICINFO icinfo;
1279 wsprintfW(szFormat, L"%ldx%ldx%d", lpbi->biWidth,
1280 lpbi->biHeight, lpbi->biBitCount);
1282 if (lpbi->biCompression != BI_RGB) {
1283 HIC hic;
1285 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1286 NULL, ICMODE_DECOMPRESS);
1287 if (hic != NULL) {
1288 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1289 lstrcatW(szFormat, icinfo.szDescription);
1290 ICClose(hic);
1292 } else {
1293 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1294 icinfo.szDescription,
1295 ARRAY_SIZE(icinfo.szDescription));
1296 lstrcatW(szFormat, icinfo.szDescription);
1298 } else if (sInfo.fccType == streamtypeAUDIO) {
1299 ACMFORMATTAGDETAILSW aftd;
1300 ACMFORMATDETAILSW afd;
1302 memset(&aftd, 0, sizeof(aftd));
1303 memset(&afd, 0, sizeof(afd));
1305 aftd.cbStruct = sizeof(aftd);
1306 aftd.dwFormatTag = afd.dwFormatTag =
1307 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1308 aftd.cbFormatSize = afd.cbwfx = size;
1310 afd.cbStruct = sizeof(afd);
1311 afd.pwfx = lpFormat;
1313 if (acmFormatTagDetailsW(NULL, &aftd,
1314 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1315 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1316 wsprintfW(szFormat, L"%s %s", afd.szFormat, aftd.szFormatTag);
1320 HeapFree(GetProcessHeap(), 0, lpFormat);
1323 /* set text for format description */
1324 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1326 /* Disable option button for unsupported streamtypes */
1327 if (sInfo.fccType == streamtypeVIDEO ||
1328 sInfo.fccType == streamtypeAUDIO)
1329 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1330 else
1331 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1336 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1337 WPARAM wParam, LPARAM lParam)
1339 DWORD dwInterleave;
1340 BOOL bIsInterleaved;
1341 INT n;
1343 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1345 switch (uMsg) {
1346 case WM_INITDIALOG:
1347 SaveOpts.nCurrent = 0;
1348 if (SaveOpts.nStreams == 1) {
1349 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1350 return TRUE;
1353 /* add streams */
1354 for (n = 0; n < SaveOpts.nStreams; n++) {
1355 AVISTREAMINFOW sInfo;
1357 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1358 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1359 0L, (LPARAM)sInfo.szName);
1362 /* select first stream */
1363 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1364 SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd);
1366 /* initialize interleave */
1367 if (SaveOpts.ppOptions[0] != NULL &&
1368 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1369 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1370 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1371 } else {
1372 bIsInterleaved = TRUE;
1373 dwInterleave = 0;
1375 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1376 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1377 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1378 break;
1379 case WM_COMMAND:
1380 switch (LOWORD(wParam)) {
1381 case IDOK:
1382 /* get data from controls and save them */
1383 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1384 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1385 for (n = 0; n < SaveOpts.nStreams; n++) {
1386 if (SaveOpts.ppOptions[n] != NULL) {
1387 if (bIsInterleaved) {
1388 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1389 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1390 } else
1391 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1394 /* fall through */
1395 case IDCANCEL:
1396 EndDialog(hWnd, LOWORD(wParam) == IDOK);
1397 break;
1398 case IDC_INTERLEAVE:
1399 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1400 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1401 break;
1402 case IDC_STREAM:
1403 if (HIWORD(wParam) == CBN_SELCHANGE) {
1404 /* update control elements */
1405 AVISaveOptionsUpdate(hWnd);
1407 break;
1408 case IDC_OPTIONS:
1409 AVISaveOptionsFmtChoose(hWnd);
1410 break;
1412 return TRUE;
1415 return FALSE;
1418 /***********************************************************************
1419 * AVISaveOptions (AVIFIL32.@)
1421 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1422 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1424 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1425 INT ret, n;
1427 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1428 ppavi, ppOptions);
1430 /* check parameters */
1431 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1432 return AVIERR_BADPARAM;
1434 /* save options in case the user presses cancel */
1435 if (nStreams > 1) {
1436 pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS));
1437 if (pSavedOptions == NULL)
1438 return FALSE;
1440 for (n = 0; n < nStreams; n++) {
1441 if (ppOptions[n] != NULL)
1442 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1446 SaveOpts.uFlags = uFlags;
1447 SaveOpts.nStreams = nStreams;
1448 SaveOpts.ppavis = ppavi;
1449 SaveOpts.ppOptions = ppOptions;
1451 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1452 hWnd, AVISaveOptionsDlgProc);
1454 if (ret == -1)
1455 ret = FALSE;
1457 /* restore options when user pressed cancel */
1458 if (pSavedOptions != NULL) {
1459 if (ret == FALSE) {
1460 for (n = 0; n < nStreams; n++) {
1461 if (ppOptions[n] != NULL)
1462 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1465 HeapFree(GetProcessHeap(), 0, pSavedOptions);
1468 return ret;
1471 /***********************************************************************
1472 * AVISaveOptionsFree (AVIFIL32.@)
1474 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1476 TRACE("(%d,%p)\n", nStreams, ppOptions);
1478 if (nStreams < 0 || ppOptions == NULL)
1479 return AVIERR_BADPARAM;
1481 for (nStreams--; nStreams >= 0; nStreams--) {
1482 if (ppOptions[nStreams] != NULL) {
1483 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1485 if (ppOptions[nStreams]->lpParms != NULL) {
1486 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms);
1487 ppOptions[nStreams]->lpParms = NULL;
1488 ppOptions[nStreams]->cbParms = 0;
1490 if (ppOptions[nStreams]->lpFormat != NULL) {
1491 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat);
1492 ppOptions[nStreams]->lpFormat = NULL;
1493 ppOptions[nStreams]->cbFormat = 0;
1498 return AVIERR_OK;
1501 /***********************************************************************
1502 * AVISaveVA (AVIFIL32.@)
1504 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1505 AVISAVECALLBACK lpfnCallback, int nStream,
1506 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1508 LPWSTR wszFile = NULL;
1509 HRESULT hr;
1510 int len;
1512 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1513 lpfnCallback, nStream, ppavi, plpOptions);
1515 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1516 return AVIERR_BADPARAM;
1518 /* convert ASCII string to Unicode and call Unicode function */
1519 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1520 if (len <= 0)
1521 return AVIERR_BADPARAM;
1523 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1524 if (wszFile == NULL)
1525 return AVIERR_MEMORY;
1527 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
1529 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1530 nStream, ppavi, plpOptions);
1532 HeapFree(GetProcessHeap(), 0, wszFile);
1534 return hr;
1537 /***********************************************************************
1538 * AVIFILE_AVISaveDefaultCallback (internal)
1540 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1542 TRACE("(%d)\n", progress);
1544 return FALSE;
1547 /***********************************************************************
1548 * AVISaveVW (AVIFIL32.@)
1550 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1551 AVISAVECALLBACK lpfnCallback, int nStreams,
1552 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1554 LONG lStart[MAX_AVISTREAMS];
1555 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1556 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1557 AVIFILEINFOW fInfo;
1558 AVISTREAMINFOW sInfo;
1560 PAVIFILE pfile = NULL; /* the output AVI file */
1561 LONG lFirstVideo = -1;
1562 int curStream;
1564 /* for interleaving ... */
1565 DWORD dwInterleave = 0; /* interleave rate */
1566 DWORD dwFileInitialFrames;
1567 LONG lFileLength;
1568 LONG lSampleInc;
1570 /* for reading/writing the data ... */
1571 LPVOID lpBuffer = NULL;
1572 LONG cbBuffer; /* real size of lpBuffer */
1573 LONG lBufferSize; /* needed bytes for format(s), etc. */
1574 LONG lReadBytes;
1575 LONG lReadSamples;
1576 HRESULT hres;
1578 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1579 lpfnCallback, nStreams, ppavi, plpOptions);
1581 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1582 return AVIERR_BADPARAM;
1583 if (nStreams >= MAX_AVISTREAMS) {
1584 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1585 return AVIERR_INTERNAL;
1588 if (lpfnCallback == NULL)
1589 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1591 /* clear local variable(s) */
1592 for (curStream = 0; curStream < nStreams; curStream++) {
1593 pInStreams[curStream] = NULL;
1594 pOutStreams[curStream] = NULL;
1597 /* open output AVI file (create it if it doesn't exist) */
1598 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1599 pclsidHandler);
1600 if (FAILED(hres))
1601 return hres;
1602 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1604 /* initialize our data structures part 1 */
1605 for (curStream = 0; curStream < nStreams; curStream++) {
1606 PAVISTREAM pCurStream = ppavi[curStream];
1608 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1609 if (FAILED(hres))
1610 goto error;
1612 /* search first video stream and check for interleaving */
1613 if (sInfo.fccType == streamtypeVIDEO) {
1614 /* remember first video stream -- needed for interleaving */
1615 if (lFirstVideo < 0)
1616 lFirstVideo = curStream;
1617 } else if (!dwInterleave) {
1618 /* check if any non-video stream wants to be interleaved */
1619 WARN("options.flags=0x%X options.dwInterleave=%u\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1620 if (plpOptions[curStream] != NULL &&
1621 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1622 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1625 /* create de-/compressed stream interface if needed */
1626 pInStreams[curStream] = NULL;
1627 if (plpOptions[curStream] != NULL) {
1628 if (plpOptions[curStream]->fccHandler ||
1629 plpOptions[curStream]->lpFormat != NULL) {
1630 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1632 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1633 plpOptions[curStream]->dwKeyFrameEvery = 1;
1635 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1636 plpOptions[curStream], NULL);
1637 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1638 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1639 pInStreams[curStream] = NULL;
1640 goto error;
1643 /* test stream interface and update stream-info */
1644 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1645 if (FAILED(hres))
1646 goto error;
1650 /* now handle streams which will only be copied */
1651 if (pInStreams[curStream] == NULL) {
1652 pCurStream = pInStreams[curStream] = ppavi[curStream];
1653 AVIStreamAddRef(pCurStream);
1654 } else
1655 pCurStream = pInStreams[curStream];
1657 lStart[curStream] = sInfo.dwStart;
1658 } /* for all streams */
1660 /* check that first video stream is the first stream */
1661 if (lFirstVideo > 0) {
1662 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1663 LONG lTmp = lStart[lFirstVideo];
1665 pInStreams[lFirstVideo] = pInStreams[0];
1666 pInStreams[0] = pTmp;
1667 lStart[lFirstVideo] = lStart[0];
1668 lStart[0] = lTmp;
1669 lFirstVideo = 0;
1672 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
1673 cbBuffer = 0x00010000;
1674 lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer);
1675 if (lpBuffer == NULL) {
1676 hres = AVIERR_MEMORY;
1677 goto error;
1680 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
1681 lFileLength = sInfo.dwLength;
1682 dwFileInitialFrames = 0;
1683 if (lFirstVideo >= 0) {
1684 /* check for correct version of the format
1685 * -- need at least BITMAPINFOHEADER or newer
1687 lSampleInc = 1;
1688 lBufferSize = cbBuffer;
1689 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
1690 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
1691 hres = AVIERR_INTERNAL;
1692 if (FAILED(hres))
1693 goto error;
1694 } else /* use one second blocks for interleaving if no video present */
1695 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
1697 /* create output streams */
1698 for (curStream = 0; curStream < nStreams; curStream++) {
1699 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1701 sInfo.dwInitialFrames = 0;
1702 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
1703 /* 750 ms initial frames for non-video streams */
1704 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
1707 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
1708 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
1709 /* copy initial format for this stream */
1710 lBufferSize = cbBuffer;
1711 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1712 lpBuffer, &lBufferSize);
1713 if (FAILED(hres))
1714 goto error;
1715 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
1716 if (FAILED(hres))
1717 goto error;
1719 /* try to copy stream handler data */
1720 lBufferSize = cbBuffer;
1721 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
1722 lpBuffer, &lBufferSize);
1723 if (SUCCEEDED(hres) && lBufferSize > 0) {
1724 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
1725 lpBuffer, lBufferSize);
1726 if (FAILED(hres))
1727 goto error;
1730 if (dwFileInitialFrames < sInfo.dwInitialFrames)
1731 dwFileInitialFrames = sInfo.dwInitialFrames;
1732 lReadBytes =
1733 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
1734 sInfo.dwLength);
1735 if (lFileLength < lReadBytes)
1736 lFileLength = lReadBytes;
1737 } else {
1738 /* creation of de-/compression stream interface failed */
1739 WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
1740 AVIStreamRelease(pInStreams[curStream]);
1741 if (curStream + 1 >= nStreams) {
1742 /* move the others one up */
1743 PAVISTREAM *ppas = &pInStreams[curStream];
1744 int n = nStreams - (curStream + 1);
1746 do {
1747 *ppas = pInStreams[curStream + 1];
1748 } while (--n);
1750 nStreams--;
1751 curStream--;
1753 } /* create output streams for all input streams */
1755 /* have we still something to write, or lost everything? */
1756 if (nStreams <= 0)
1757 goto error;
1759 if (dwInterleave) {
1760 LONG lCurFrame = -dwFileInitialFrames;
1762 /* interleaved file */
1763 if (dwInterleave == 1)
1764 AVIFileEndRecord(pfile);
1766 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
1767 for (curStream = 0; curStream < nStreams; curStream++) {
1768 LONG lLastSample;
1770 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
1771 if (FAILED(hres))
1772 goto error;
1774 /* initial frames phase at the end for this stream? */
1775 if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
1776 continue;
1778 if ((lFileLength - lSampleInc) <= lCurFrame) {
1779 lLastSample = AVIStreamLength(pInStreams[curStream]);
1780 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
1781 } else {
1782 if (curStream != 0) {
1783 lFirstVideo =
1784 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
1785 (sInfo.fccType == streamtypeVIDEO ?
1786 (LONG)dwInterleave : lSampleInc) +
1787 sInfo.dwInitialFrames + lCurFrame);
1788 } else
1789 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
1791 lLastSample = AVIStreamEnd(pInStreams[curStream]);
1792 if (lLastSample <= lFirstVideo)
1793 lFirstVideo = lLastSample;
1796 /* copy needed samples now */
1797 WARN("copy from stream %d samples %d to %d...\n",curStream,
1798 lStart[curStream],lFirstVideo);
1799 while (lFirstVideo > lStart[curStream]) {
1800 DWORD flags = 0;
1802 /* copy format in case it can change */
1803 lBufferSize = cbBuffer;
1804 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
1805 lpBuffer, &lBufferSize);
1806 if (FAILED(hres))
1807 goto error;
1808 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
1809 lpBuffer, lBufferSize);
1811 /* try to read data until we got it, or error */
1812 do {
1813 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
1814 lFirstVideo - lStart[curStream], lpBuffer,
1815 cbBuffer, &lReadBytes, &lReadSamples);
1816 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1817 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1818 if (lpBuffer == NULL)
1819 hres = AVIERR_MEMORY;
1820 if (FAILED(hres))
1821 goto error;
1823 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1824 flags = AVIIF_KEYFRAME;
1825 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1826 lpBuffer, lReadBytes, flags, NULL, NULL);
1827 if (FAILED(hres))
1828 goto error;
1830 lStart[curStream] += lReadSamples;
1832 lStart[curStream] = lFirstVideo;
1833 } /* stream by stream */
1835 /* need to close this block? */
1836 if (dwInterleave == 1) {
1837 hres = AVIFileEndRecord(pfile);
1838 if (FAILED(hres))
1839 break;
1842 /* show progress */
1843 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
1844 dwFileInitialFrames + lFileLength))) {
1845 hres = AVIERR_USERABORT;
1846 break;
1848 } /* copy frame by frame */
1849 } else {
1850 /* non-interleaved file */
1852 for (curStream = 0; curStream < nStreams; curStream++) {
1853 /* show progress */
1854 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
1855 hres = AVIERR_USERABORT;
1856 goto error;
1859 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1861 if (sInfo.dwSampleSize != 0) {
1862 /* sample-based data like audio */
1863 while (sInfo.dwStart < sInfo.dwLength) {
1864 LONG lSamples = cbBuffer / sInfo.dwSampleSize;
1866 /* copy format in case it can change */
1867 lBufferSize = cbBuffer;
1868 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1869 lpBuffer, &lBufferSize);
1870 if (FAILED(hres))
1871 goto error;
1872 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1873 lpBuffer, lBufferSize);
1875 /* limit to stream boundaries */
1876 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
1877 lSamples = sInfo.dwLength - sInfo.dwStart;
1879 /* now try to read until we get it, or an error occurs */
1880 do {
1881 lReadBytes = cbBuffer;
1882 lReadSamples = 0;
1883 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
1884 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
1885 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1886 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1887 if (lpBuffer == NULL)
1888 hres = AVIERR_MEMORY;
1889 if (FAILED(hres))
1890 goto error;
1891 if (lReadSamples != 0) {
1892 sInfo.dwStart += lReadSamples;
1893 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1894 lpBuffer, lReadBytes, 0, NULL , NULL);
1895 if (FAILED(hres))
1896 goto error;
1898 /* show progress */
1899 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1900 MulDiv(curStream, 100, nStreams))) {
1901 hres = AVIERR_USERABORT;
1902 goto error;
1904 } else {
1905 if ((sInfo.dwLength - sInfo.dwStart) != 1) {
1906 hres = AVIERR_FILEREAD;
1907 goto error;
1911 } else {
1912 /* block-based data like video */
1913 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
1914 DWORD flags = 0;
1916 /* copy format in case it can change */
1917 lBufferSize = cbBuffer;
1918 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1919 lpBuffer, &lBufferSize);
1920 if (FAILED(hres))
1921 goto error;
1922 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1923 lpBuffer, lBufferSize);
1925 /* try to read block and resize buffer if necessary */
1926 do {
1927 lReadSamples = 0;
1928 lReadBytes = cbBuffer;
1929 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
1930 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
1931 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1932 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1933 if (lpBuffer == NULL)
1934 hres = AVIERR_MEMORY;
1935 if (FAILED(hres))
1936 goto error;
1937 if (lReadSamples != 1) {
1938 hres = AVIERR_FILEREAD;
1939 goto error;
1942 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1943 flags = AVIIF_KEYFRAME;
1944 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1945 lpBuffer, lReadBytes, flags, NULL, NULL);
1946 if (FAILED(hres))
1947 goto error;
1949 /* show progress */
1950 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1951 MulDiv(curStream, 100, nStreams))) {
1952 hres = AVIERR_USERABORT;
1953 goto error;
1955 } /* copy all blocks */
1957 } /* copy data stream by stream */
1960 error:
1961 HeapFree(GetProcessHeap(), 0, lpBuffer);
1962 if (pfile != NULL) {
1963 for (curStream = 0; curStream < nStreams; curStream++) {
1964 if (pOutStreams[curStream] != NULL)
1965 AVIStreamRelease(pOutStreams[curStream]);
1966 if (pInStreams[curStream] != NULL)
1967 AVIStreamRelease(pInStreams[curStream]);
1970 AVIFileRelease(pfile);
1973 return hres;
1976 /***********************************************************************
1977 * EditStreamClone (AVIFIL32.@)
1979 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
1981 PAVIEDITSTREAM pEdit = NULL;
1982 HRESULT hr;
1984 TRACE("(%p,%p)\n", pStream, ppResult);
1986 if (pStream == NULL)
1987 return AVIERR_BADHANDLE;
1988 if (ppResult == NULL)
1989 return AVIERR_BADPARAM;
1991 *ppResult = NULL;
1993 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
1994 if (SUCCEEDED(hr) && pEdit != NULL) {
1995 hr = IAVIEditStream_Clone(pEdit, ppResult);
1997 IAVIEditStream_Release(pEdit);
1998 } else
1999 hr = AVIERR_UNSUPPORTED;
2001 return hr;
2004 /***********************************************************************
2005 * EditStreamCopy (AVIFIL32.@)
2007 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2008 LONG *plLength, PAVISTREAM *ppResult)
2010 PAVIEDITSTREAM pEdit = NULL;
2011 HRESULT hr;
2013 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2015 if (pStream == NULL)
2016 return AVIERR_BADHANDLE;
2017 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2018 return AVIERR_BADPARAM;
2020 *ppResult = NULL;
2022 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2023 if (SUCCEEDED(hr) && pEdit != NULL) {
2024 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2026 IAVIEditStream_Release(pEdit);
2027 } else
2028 hr = AVIERR_UNSUPPORTED;
2030 return hr;
2033 /***********************************************************************
2034 * EditStreamCut (AVIFIL32.@)
2036 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2037 LONG *plLength, PAVISTREAM *ppResult)
2039 PAVIEDITSTREAM pEdit = NULL;
2040 HRESULT hr;
2042 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2044 if (ppResult != NULL)
2045 *ppResult = NULL;
2046 if (pStream == NULL)
2047 return AVIERR_BADHANDLE;
2048 if (plStart == NULL || plLength == NULL)
2049 return AVIERR_BADPARAM;
2051 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2052 if (SUCCEEDED(hr) && pEdit != NULL) {
2053 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2055 IAVIEditStream_Release(pEdit);
2056 } else
2057 hr = AVIERR_UNSUPPORTED;
2059 return hr;
2062 /***********************************************************************
2063 * EditStreamPaste (AVIFIL32.@)
2065 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2066 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2068 PAVIEDITSTREAM pEdit = NULL;
2069 HRESULT hr;
2071 TRACE("(%p,%p,%p,%p,%d,%d)\n", pDest, plStart, plLength,
2072 pSource, lStart, lEnd);
2074 if (pDest == NULL || pSource == NULL)
2075 return AVIERR_BADHANDLE;
2076 if (plStart == NULL || plLength == NULL || lStart < 0)
2077 return AVIERR_BADPARAM;
2079 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2080 if (SUCCEEDED(hr) && pEdit != NULL) {
2081 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2083 IAVIEditStream_Release(pEdit);
2084 } else
2085 hr = AVIERR_UNSUPPORTED;
2087 return hr;
2090 /***********************************************************************
2091 * EditStreamSetInfoA (AVIFIL32.@)
2093 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2094 LONG size)
2096 AVISTREAMINFOW asiw;
2098 TRACE("(%p,%p,%d)\n", pstream, asi, size);
2100 if (size >= 0 && size < sizeof(AVISTREAMINFOA))
2101 return AVIERR_BADSIZE;
2103 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2104 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1, asiw.szName, ARRAY_SIZE(asiw.szName));
2106 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2109 /***********************************************************************
2110 * EditStreamSetInfoW (AVIFIL32.@)
2112 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2113 LONG size)
2115 PAVIEDITSTREAM pEdit = NULL;
2116 HRESULT hr;
2118 TRACE("(%p,%p,%d)\n", pstream, asi, size);
2120 if (size >= 0 && size < sizeof(AVISTREAMINFOA))
2121 return AVIERR_BADSIZE;
2123 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2124 if (SUCCEEDED(hr) && pEdit != NULL) {
2125 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2127 IAVIEditStream_Release(pEdit);
2128 } else
2129 hr = AVIERR_UNSUPPORTED;
2131 return hr;
2134 /***********************************************************************
2135 * EditStreamSetNameA (AVIFIL32.@)
2137 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2139 AVISTREAMINFOA asia;
2140 HRESULT hres;
2142 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2144 if (pstream == NULL)
2145 return AVIERR_BADHANDLE;
2146 if (szName == NULL)
2147 return AVIERR_BADPARAM;
2149 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2150 if (FAILED(hres))
2151 return hres;
2153 memset(asia.szName, 0, sizeof(asia.szName));
2154 lstrcpynA(asia.szName, szName, ARRAY_SIZE(asia.szName));
2156 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2159 /***********************************************************************
2160 * EditStreamSetNameW (AVIFIL32.@)
2162 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2164 AVISTREAMINFOW asiw;
2165 HRESULT hres;
2167 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2169 if (pstream == NULL)
2170 return AVIERR_BADHANDLE;
2171 if (szName == NULL)
2172 return AVIERR_BADPARAM;
2174 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2175 if (FAILED(hres))
2176 return hres;
2178 memset(asiw.szName, 0, sizeof(asiw.szName));
2179 lstrcpynW(asiw.szName, szName, ARRAY_SIZE(asiw.szName));
2181 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2184 /***********************************************************************
2185 * AVIClearClipboard (AVIFIL32.@)
2187 HRESULT WINAPI AVIClearClipboard(void)
2189 TRACE("()\n");
2191 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2194 /***********************************************************************
2195 * AVIGetFromClipboard (AVIFIL32.@)
2197 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2199 FIXME("(%p), stub!\n", ppfile);
2201 *ppfile = NULL;
2203 return AVIERR_UNSUPPORTED;
2206 /***********************************************************************
2207 * AVIMakeStreamFromClipboard (AVIFIL32.@)
2209 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
2210 PAVISTREAM * ppstream)
2212 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
2214 if (ppstream == NULL)
2215 return AVIERR_BADHANDLE;
2217 return AVIERR_UNSUPPORTED;
2220 /***********************************************************************
2221 * AVIPutFileOnClipboard (AVIFIL32.@)
2223 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2225 FIXME("(%p), stub!\n", pfile);
2227 if (pfile == NULL)
2228 return AVIERR_BADHANDLE;
2230 return AVIERR_UNSUPPORTED;
2233 HRESULT WINAPIV AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2234 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2236 __ms_va_list vl;
2237 int i;
2238 HRESULT ret;
2239 PAVISTREAM *streams;
2240 LPAVICOMPRESSOPTIONS *options;
2242 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
2243 nStreams, pavi, lpOptions);
2245 if (nStreams <= 0) return AVIERR_BADPARAM;
2247 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams));
2248 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options));
2249 if (!streams || !options)
2251 ret = AVIERR_MEMORY;
2252 goto error;
2255 streams[0] = pavi;
2256 options[0] = lpOptions;
2258 __ms_va_start(vl, lpOptions);
2259 for (i = 1; i < nStreams; i++)
2261 streams[i] = va_arg(vl, PAVISTREAM);
2262 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS);
2264 __ms_va_end(vl);
2266 for (i = 0; i < nStreams; i++)
2267 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]);
2269 ret = AVISaveVA(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options);
2270 error:
2271 HeapFree(GetProcessHeap(), 0, streams);
2272 HeapFree(GetProcessHeap(), 0, options);
2273 return ret;
2276 HRESULT WINAPIV AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2277 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2279 __ms_va_list vl;
2280 int i;
2281 HRESULT ret;
2282 PAVISTREAM *streams;
2283 LPAVICOMPRESSOPTIONS *options;
2285 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
2286 nStreams, pavi, lpOptions);
2288 if (nStreams <= 0) return AVIERR_BADPARAM;
2290 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams));
2291 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options));
2292 if (!streams || !options)
2294 ret = AVIERR_MEMORY;
2295 goto error;
2298 streams[0] = pavi;
2299 options[0] = lpOptions;
2301 __ms_va_start(vl, lpOptions);
2302 for (i = 1; i < nStreams; i++)
2304 streams[i] = va_arg(vl, PAVISTREAM);
2305 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS);
2307 __ms_va_end(vl);
2309 for (i = 0; i < nStreams; i++)
2310 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]);
2312 ret = AVISaveVW(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options);
2313 error:
2314 HeapFree(GetProcessHeap(), 0, streams);
2315 HeapFree(GetProcessHeap(), 0, options);
2316 return ret;