gdiplus/metafile: Implement playback for EmfPlusRecordTypeDrawArc.
[wine.git] / dlls / avifil32 / api.c
blob5c15c1fe837c4dba6327b57cb9e130ec751272e6
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"
41 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
46 /***********************************************************************
47 * for AVIBuildFilterW -- uses fixed size table
49 #define MAX_FILTERS 30 /* 30 => 7kB */
51 typedef struct _AVIFilter {
52 WCHAR szClsid[40];
53 WCHAR szExtensions[MAX_FILTERS * 7];
54 } AVIFilter;
56 /***********************************************************************
57 * for AVISaveOptions
59 static struct {
60 UINT uFlags;
61 INT nStreams;
62 PAVISTREAM *ppavis;
63 LPAVICOMPRESSOPTIONS *ppOptions;
64 INT nCurrent;
65 } SaveOpts;
67 /***********************************************************************
68 * copied from dlls/ole32/compobj.c
70 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
72 BYTE const *s;
73 BYTE *p;
74 INT i;
75 BYTE table[256];
77 if (!idstr) {
78 memset(id, 0, sizeof(CLSID));
79 return S_OK;
82 /* validate the CLSID string */
83 if (lstrlenA(idstr) != 38)
84 return CO_E_CLASSSTRING;
86 s = (BYTE const*)idstr;
87 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
88 (s[24]!='-') || (s[37]!='}'))
89 return CO_E_CLASSSTRING;
91 for (i = 1; i < 37; i++) {
92 if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
93 continue;
94 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
95 ((s[i] >= 'a') && (s[i] <= 'f')) ||
96 ((s[i] >= 'A') && (s[i] <= 'F')))
98 return CO_E_CLASSSTRING;
101 TRACE("%s -> %p\n", s, id);
103 /* quick lookup table */
104 memset(table, 0, 256);
106 for (i = 0; i < 10; i++)
107 table['0' + i] = i;
109 for (i = 0; i < 6; i++) {
110 table['A' + i] = i+10;
111 table['a' + i] = i+10;
114 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
115 p = (BYTE *) id;
117 s++; /* skip leading brace */
118 for (i = 0; i < 4; i++) {
119 p[3 - i] = table[*s]<<4 | table[*(s+1)];
120 s += 2;
122 p += 4;
123 s++; /* skip - */
125 for (i = 0; i < 2; i++) {
126 p[1-i] = table[*s]<<4 | table[*(s+1)];
127 s += 2;
129 p += 2;
130 s++; /* skip - */
132 for (i = 0; i < 2; i++) {
133 p[1-i] = table[*s]<<4 | table[*(s+1)];
134 s += 2;
136 p += 2;
137 s++; /* skip - */
139 /* these are just sequential bytes */
140 for (i = 0; i < 2; i++) {
141 *p++ = table[*s]<<4 | table[*(s+1)];
142 s += 2;
144 s++; /* skip - */
146 for (i = 0; i < 6; i++) {
147 *p++ = table[*s]<<4 | table[*(s+1)];
148 s += 2;
151 return S_OK;
154 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
156 CHAR szRegKey[25];
157 CHAR szValue[100];
158 LPWSTR szExt = strrchrW(szFile, '.');
159 LONG len = sizeof(szValue) / sizeof(szValue[0]);
161 if (szExt == NULL)
162 return FALSE;
164 szExt++;
166 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
167 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
168 return FALSE;
170 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
173 /***********************************************************************
174 * AVIFileInit (AVIFIL32.@)
176 void WINAPI AVIFileInit(void) {
177 OleInitialize(NULL);
180 /***********************************************************************
181 * AVIFileExit (AVIFIL32.@)
183 void WINAPI AVIFileExit(void) {
184 /* need to free ole32.dll if we are the last exit call */
185 /* OleUninitialize() */
186 FIXME("(): stub!\n");
189 /***********************************************************************
190 * AVIFileOpen (AVIFIL32.@)
191 * AVIFileOpenA (AVIFIL32.@)
193 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
194 LPCLSID lpHandler)
196 LPWSTR wszFile = NULL;
197 HRESULT hr;
198 int len;
200 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
201 debugstr_guid(lpHandler));
203 /* check parameters */
204 if (ppfile == NULL || szFile == NULL)
205 return AVIERR_BADPARAM;
207 /* convert ASCII string to Unicode and call unicode function */
208 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
209 if (len <= 0)
210 return AVIERR_BADPARAM;
212 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
213 if (wszFile == NULL)
214 return AVIERR_MEMORY;
216 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
218 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
220 HeapFree(GetProcessHeap(), 0, wszFile);
222 return hr;
225 /***********************************************************************
226 * AVIFileOpenW (AVIFIL32.@)
228 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
229 LPCLSID lpHandler)
231 IPersistFile *ppersist = NULL;
232 CLSID clsidHandler;
233 HRESULT hr;
235 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
236 debugstr_guid(lpHandler));
238 /* check parameters */
239 if (ppfile == NULL || szFile == NULL)
240 return AVIERR_BADPARAM;
242 *ppfile = NULL;
244 /* if no handler then try guessing it by extension */
245 if (lpHandler == NULL) {
246 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
247 clsidHandler = CLSID_AVIFile;
248 } else
249 clsidHandler = *lpHandler;
251 /* create instance of handler */
252 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile);
253 if (FAILED(hr) || *ppfile == NULL)
254 return hr;
256 /* ask for IPersistFile interface for loading/creating the file */
257 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
258 if (FAILED(hr) || ppersist == NULL) {
259 IAVIFile_Release(*ppfile);
260 *ppfile = NULL;
261 return hr;
264 hr = IPersistFile_Load(ppersist, szFile, uMode);
265 IPersistFile_Release(ppersist);
266 if (FAILED(hr)) {
267 IAVIFile_Release(*ppfile);
268 *ppfile = NULL;
271 return hr;
274 /***********************************************************************
275 * AVIFileAddRef (AVIFIL32.@)
277 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
279 TRACE("(%p)\n", pfile);
281 if (pfile == NULL) {
282 ERR(": bad handle passed!\n");
283 return 0;
286 return IAVIFile_AddRef(pfile);
289 /***********************************************************************
290 * AVIFileRelease (AVIFIL32.@)
292 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
294 TRACE("(%p)\n", pfile);
296 if (pfile == NULL) {
297 ERR(": bad handle passed!\n");
298 return 0;
301 return IAVIFile_Release(pfile);
304 /***********************************************************************
305 * AVIFileInfo (AVIFIL32.@)
306 * AVIFileInfoA (AVIFIL32.@)
308 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
310 AVIFILEINFOW afiw;
311 HRESULT hres;
313 TRACE("(%p,%p,%d)\n", pfile, afi, size);
315 if (pfile == NULL)
316 return AVIERR_BADHANDLE;
317 if ((DWORD)size < sizeof(AVIFILEINFOA))
318 return AVIERR_BADSIZE;
320 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
322 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
323 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
324 sizeof(afi->szFileType), NULL, NULL);
325 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
327 return hres;
330 /***********************************************************************
331 * AVIFileInfoW (AVIFIL32.@)
333 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
335 TRACE("(%p,%p,%d)\n", pfile, afiw, size);
337 if (pfile == NULL)
338 return AVIERR_BADHANDLE;
340 return IAVIFile_Info(pfile, afiw, size);
343 /***********************************************************************
344 * AVIFileGetStream (AVIFIL32.@)
346 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
347 DWORD fccType, LONG lParam)
349 TRACE("(%p,%p,'%4.4s',%d)\n", pfile, avis, (char*)&fccType, lParam);
351 if (pfile == NULL)
352 return AVIERR_BADHANDLE;
354 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
357 /***********************************************************************
358 * AVIFileCreateStream (AVIFIL32.@)
359 * AVIFileCreateStreamA (AVIFIL32.@)
361 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
362 LPAVISTREAMINFOA psi)
364 AVISTREAMINFOW psiw;
366 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
368 if (pfile == NULL)
369 return AVIERR_BADHANDLE;
371 /* Only the szName at the end is different */
372 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
373 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
374 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
376 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
379 /***********************************************************************
380 * AVIFileCreateStreamW (AVIFIL32.@)
382 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
383 LPAVISTREAMINFOW asi)
385 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
387 if (pfile == NULL)
388 return AVIERR_BADHANDLE;
390 return IAVIFile_CreateStream(pfile, avis, asi);
393 /***********************************************************************
394 * AVIFileWriteData (AVIFIL32.@)
396 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
398 TRACE("(%p,'%4.4s',%p,%d)\n", pfile, (char*)&fcc, lp, size);
400 if (pfile == NULL)
401 return AVIERR_BADHANDLE;
403 return IAVIFile_WriteData(pfile, fcc, lp, size);
406 /***********************************************************************
407 * AVIFileReadData (AVIFIL32.@)
409 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
411 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
413 if (pfile == NULL)
414 return AVIERR_BADHANDLE;
416 return IAVIFile_ReadData(pfile, fcc, lp, size);
419 /***********************************************************************
420 * AVIFileEndRecord (AVIFIL32.@)
422 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
424 TRACE("(%p)\n", pfile);
426 if (pfile == NULL)
427 return AVIERR_BADHANDLE;
429 return IAVIFile_EndRecord(pfile);
432 /***********************************************************************
433 * AVIStreamAddRef (AVIFIL32.@)
435 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
437 TRACE("(%p)\n", pstream);
439 if (pstream == NULL) {
440 ERR(": bad handle passed!\n");
441 return 0;
444 return IAVIStream_AddRef(pstream);
447 /***********************************************************************
448 * AVIStreamRelease (AVIFIL32.@)
450 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
452 TRACE("(%p)\n", pstream);
454 if (pstream == NULL) {
455 ERR(": bad handle passed!\n");
456 return 0;
459 return IAVIStream_Release(pstream);
462 /***********************************************************************
463 * AVIStreamCreate (AVIFIL32.@)
465 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
466 LPCLSID pclsidHandler)
468 HRESULT hr;
470 TRACE("(%p,0x%08X,0x%08X,%s)\n", ppavi, lParam1, lParam2,
471 debugstr_guid(pclsidHandler));
473 if (ppavi == NULL)
474 return AVIERR_BADPARAM;
476 *ppavi = NULL;
477 if (pclsidHandler == NULL)
478 return AVIERR_UNSUPPORTED;
480 hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi);
481 if (FAILED(hr) || *ppavi == NULL)
482 return hr;
484 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
485 if (FAILED(hr)) {
486 IAVIStream_Release(*ppavi);
487 *ppavi = NULL;
490 return hr;
493 /***********************************************************************
494 * AVIStreamInfo (AVIFIL32.@)
495 * AVIStreamInfoA (AVIFIL32.@)
497 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
498 LONG size)
500 AVISTREAMINFOW asiw;
501 HRESULT hres;
503 TRACE("(%p,%p,%d)\n", pstream, asi, size);
505 if (pstream == NULL)
506 return AVIERR_BADHANDLE;
507 if ((DWORD)size < sizeof(AVISTREAMINFOA))
508 return AVIERR_BADSIZE;
510 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
512 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
513 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
514 sizeof(asi->szName), NULL, NULL);
515 asi->szName[sizeof(asi->szName) - 1] = 0;
517 return hres;
520 /***********************************************************************
521 * AVIStreamInfoW (AVIFIL32.@)
523 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
524 LONG size)
526 TRACE("(%p,%p,%d)\n", pstream, asi, size);
528 if (pstream == NULL)
529 return AVIERR_BADHANDLE;
531 return IAVIStream_Info(pstream, asi, size);
534 /***********************************************************************
535 * AVIStreamFindSample (AVIFIL32.@)
537 LONG WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, LONG flags)
539 TRACE("(%p,%d,0x%X)\n", pstream, pos, flags);
541 if (pstream == NULL)
542 return -1;
544 return IAVIStream_FindSample(pstream, pos, flags);
547 /***********************************************************************
548 * AVIStreamReadFormat (AVIFIL32.@)
550 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
551 LPVOID format, LPLONG formatsize)
553 TRACE("(%p,%d,%p,%p)\n", pstream, pos, format, formatsize);
555 if (pstream == NULL)
556 return AVIERR_BADHANDLE;
558 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
561 /***********************************************************************
562 * AVIStreamSetFormat (AVIFIL32.@)
564 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
565 LPVOID format, LONG formatsize)
567 TRACE("(%p,%d,%p,%d)\n", pstream, pos, format, formatsize);
569 if (pstream == NULL)
570 return AVIERR_BADHANDLE;
572 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
575 /***********************************************************************
576 * AVIStreamRead (AVIFIL32.@)
578 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
579 LPVOID buffer, LONG buffersize,
580 LPLONG bytesread, LPLONG samplesread)
582 TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", pstream, start, samples, buffer,
583 buffersize, bytesread, samplesread);
585 if (pstream == NULL)
586 return AVIERR_BADHANDLE;
588 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
589 bytesread, samplesread);
592 /***********************************************************************
593 * AVIStreamWrite (AVIFIL32.@)
595 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
596 LPVOID buffer, LONG buffersize, DWORD flags,
597 LPLONG sampwritten, LPLONG byteswritten)
599 TRACE("(%p,%d,%d,%p,%d,0x%X,%p,%p)\n", pstream, start, samples, buffer,
600 buffersize, flags, sampwritten, byteswritten);
602 if (pstream == NULL)
603 return AVIERR_BADHANDLE;
605 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
606 flags, sampwritten, byteswritten);
609 /***********************************************************************
610 * AVIStreamReadData (AVIFIL32.@)
612 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
613 LPLONG lpread)
615 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
617 if (pstream == NULL)
618 return AVIERR_BADHANDLE;
620 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
623 /***********************************************************************
624 * AVIStreamWriteData (AVIFIL32.@)
626 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
627 LONG size)
629 TRACE("(%p,'%4.4s',%p,%d)\n", pstream, (char*)&fcc, lp, size);
631 if (pstream == NULL)
632 return AVIERR_BADHANDLE;
634 return IAVIStream_WriteData(pstream, fcc, lp, size);
637 /***********************************************************************
638 * AVIStreamGetFrameOpen (AVIFIL32.@)
640 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
641 LPBITMAPINFOHEADER lpbiWanted)
643 PGETFRAME pg = NULL;
645 TRACE("(%p,%p)\n", pstream, lpbiWanted);
647 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
648 pg == NULL) {
649 pg = AVIFILE_CreateGetFrame(pstream);
650 if (pg == NULL)
651 return NULL;
654 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
655 IGetFrame_Release(pg);
656 return NULL;
659 return pg;
662 /***********************************************************************
663 * AVIStreamGetFrame (AVIFIL32.@)
665 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
667 TRACE("(%p,%d)\n", pg, pos);
669 if (pg == NULL)
670 return NULL;
672 return IGetFrame_GetFrame(pg, pos);
675 /***********************************************************************
676 * AVIStreamGetFrameClose (AVIFIL32.@)
678 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
680 TRACE("(%p)\n", pg);
682 if (pg != NULL)
683 return IGetFrame_Release(pg);
684 return 0;
687 /***********************************************************************
688 * AVIMakeCompressedStream (AVIFIL32.@)
690 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
691 PAVISTREAM psSource,
692 LPAVICOMPRESSOPTIONS aco,
693 LPCLSID pclsidHandler)
695 AVISTREAMINFOW asiw;
696 CHAR szRegKey[25];
697 CHAR szValue[100];
698 CLSID clsidHandler;
699 HRESULT hr;
700 LONG size = sizeof(szValue);
702 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
703 debugstr_guid(pclsidHandler));
705 if (ppsCompressed == NULL)
706 return AVIERR_BADPARAM;
707 if (psSource == NULL)
708 return AVIERR_BADHANDLE;
710 *ppsCompressed = NULL;
712 /* if no handler given get default ones based on streamtype */
713 if (pclsidHandler == NULL) {
714 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
715 if (FAILED(hr))
716 return hr;
718 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
719 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
720 return AVIERR_UNSUPPORTED;
721 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
722 return AVIERR_UNSUPPORTED;
723 } else
724 clsidHandler = *pclsidHandler;
726 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed);
727 if (FAILED(hr) || *ppsCompressed == NULL)
728 return hr;
730 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
731 if (FAILED(hr)) {
732 IAVIStream_Release(*ppsCompressed);
733 *ppsCompressed = NULL;
736 return hr;
739 /***********************************************************************
740 * AVIMakeFileFromStreams (AVIFIL32.@)
742 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
743 PAVISTREAM *ppStreams)
745 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
747 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
748 return AVIERR_BADPARAM;
750 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
751 if (*ppfile == NULL)
752 return AVIERR_MEMORY;
754 return AVIERR_OK;
757 /***********************************************************************
758 * AVIStreamOpenFromFile (AVIFIL32.@)
759 * AVIStreamOpenFromFileA (AVIFIL32.@)
761 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
762 DWORD fccType, LONG lParam,
763 UINT mode, LPCLSID pclsidHandler)
765 PAVIFILE pfile = NULL;
766 HRESULT hr;
768 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_a(szFile),
769 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
771 if (ppavi == NULL || szFile == NULL)
772 return AVIERR_BADPARAM;
774 *ppavi = NULL;
776 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
777 if (FAILED(hr) || pfile == NULL)
778 return hr;
780 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
781 IAVIFile_Release(pfile);
783 return hr;
786 /***********************************************************************
787 * AVIStreamOpenFromFileW (AVIFIL32.@)
789 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
790 DWORD fccType, LONG lParam,
791 UINT mode, LPCLSID pclsidHandler)
793 PAVIFILE pfile = NULL;
794 HRESULT hr;
796 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_w(szFile),
797 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
799 if (ppavi == NULL || szFile == NULL)
800 return AVIERR_BADPARAM;
802 *ppavi = NULL;
804 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
805 if (FAILED(hr) || pfile == NULL)
806 return hr;
808 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
809 IAVIFile_Release(pfile);
811 return hr;
814 /***********************************************************************
815 * AVIStreamBeginStreaming (AVIFIL32.@)
817 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
819 IAVIStreaming* pstream = NULL;
820 HRESULT hr;
822 TRACE("(%p,%d,%d,%d)\n", pavi, lStart, lEnd, lRate);
824 if (pavi == NULL)
825 return AVIERR_BADHANDLE;
827 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
828 if (SUCCEEDED(hr) && pstream != NULL) {
829 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
830 IAVIStreaming_Release(pstream);
831 } else
832 hr = AVIERR_OK;
834 return hr;
837 /***********************************************************************
838 * AVIStreamEndStreaming (AVIFIL32.@)
840 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
842 IAVIStreaming* pstream = NULL;
843 HRESULT hr;
845 TRACE("(%p)\n", pavi);
847 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
848 if (SUCCEEDED(hr) && pstream != NULL) {
849 IAVIStreaming_End(pstream);
850 IAVIStreaming_Release(pstream);
853 return AVIERR_OK;
856 /***********************************************************************
857 * AVIStreamStart (AVIFIL32.@)
859 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
861 AVISTREAMINFOW asiw;
863 TRACE("(%p)\n", pstream);
865 if (pstream == NULL)
866 return 0;
868 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
869 return 0;
871 return asiw.dwStart;
874 /***********************************************************************
875 * AVIStreamLength (AVIFIL32.@)
877 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
879 AVISTREAMINFOW asiw;
881 TRACE("(%p)\n", pstream);
883 if (pstream == NULL)
884 return 0;
886 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
887 return 0;
889 return asiw.dwLength;
892 /***********************************************************************
893 * AVIStreamSampleToTime (AVIFIL32.@)
895 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
897 AVISTREAMINFOW asiw;
898 LONG time;
900 TRACE("(%p,%d)\n", pstream, lSample);
902 if (pstream == NULL)
903 return -1;
905 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
906 return -1;
907 if (asiw.dwRate == 0)
908 return -1;
910 /* limit to stream bounds */
911 if (lSample < asiw.dwStart)
912 lSample = asiw.dwStart;
913 if (lSample > asiw.dwStart + asiw.dwLength)
914 lSample = asiw.dwStart + asiw.dwLength;
916 if (asiw.dwRate / asiw.dwScale < 1000)
917 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
918 else
919 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
921 TRACE(" -> %d\n",time);
922 return time;
925 /***********************************************************************
926 * AVIStreamTimeToSample (AVIFIL32.@)
928 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
930 AVISTREAMINFOW asiw;
931 ULONG sample;
933 TRACE("(%p,%d)\n", pstream, lTime);
935 if (pstream == NULL || lTime < 0)
936 return -1;
938 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
939 return -1;
940 if (asiw.dwScale == 0)
941 return -1;
943 if (asiw.dwRate / asiw.dwScale < 1000)
944 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
945 else
946 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
948 /* limit to stream bounds */
949 if (sample < asiw.dwStart)
950 sample = asiw.dwStart;
951 if (sample > asiw.dwStart + asiw.dwLength)
952 sample = asiw.dwStart + asiw.dwLength;
954 TRACE(" -> %d\n", sample);
955 return sample;
958 /***********************************************************************
959 * AVIBuildFilter (AVIFIL32.@)
960 * AVIBuildFilterA (AVIFIL32.@)
962 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
964 LPWSTR wszFilter;
965 HRESULT hr;
967 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving);
969 /* check parameters */
970 if (szFilter == NULL)
971 return AVIERR_BADPARAM;
972 if (cbFilter < 2)
973 return AVIERR_BADSIZE;
975 szFilter[0] = 0;
976 szFilter[1] = 0;
978 wszFilter = HeapAlloc(GetProcessHeap(), 0, cbFilter * sizeof(WCHAR));
979 if (wszFilter == NULL)
980 return AVIERR_MEMORY;
982 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
983 if (SUCCEEDED(hr)) {
984 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
985 szFilter, cbFilter, NULL, NULL);
988 HeapFree(GetProcessHeap(), 0, wszFilter);
990 return hr;
993 /***********************************************************************
994 * AVIBuildFilterW (AVIFIL32.@)
996 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
998 static const WCHAR all_files[] = { '*','.','*',0,0 };
999 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
1000 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1001 static const WCHAR szAVIFileExtensions[] =
1002 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1004 AVIFilter *lp;
1005 WCHAR szAllFiles[40];
1006 WCHAR szFileExt[10];
1007 WCHAR szValue[128];
1008 HKEY hKey;
1009 DWORD n, i;
1010 LONG size;
1011 DWORD count = 0;
1013 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving);
1015 /* check parameters */
1016 if (szFilter == NULL)
1017 return AVIERR_BADPARAM;
1018 if (cbFilter < 2)
1019 return AVIERR_BADSIZE;
1021 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_FILTERS * sizeof(AVIFilter));
1022 if (lp == NULL)
1023 return AVIERR_MEMORY;
1026 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1027 * extensions and CLSIDs
1028 * 2. iterate over collected CLSIDs and copy its description and its
1029 * extensions to szFilter if it fits
1031 * First filter is named "All multimedia files" and its filter is a
1032 * collection of all possible extensions except "*.*".
1034 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != ERROR_SUCCESS) {
1035 HeapFree(GetProcessHeap(), 0, lp);
1036 return AVIERR_ERROR;
1038 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)/sizeof(szFileExt[0])) == ERROR_SUCCESS;n++) {
1039 WCHAR clsidW[40];
1041 /* get CLSID to extension */
1042 size = sizeof(clsidW);
1043 if (RegQueryValueW(hKey, szFileExt, clsidW, &size) != ERROR_SUCCESS)
1044 break;
1046 /* search if the CLSID is already known */
1047 for (i = 1; i <= count; i++) {
1048 if (lstrcmpW(lp[i].szClsid, clsidW) == 0)
1049 break; /* a new one */
1052 if (i == count + 1) {
1053 /* it's a new CLSID */
1055 /* FIXME: How do we get info's about read/write capabilities? */
1057 if (count >= MAX_FILTERS) {
1058 /* try to inform user of our full fixed size table */
1059 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1060 break;
1063 lstrcpyW(lp[i].szClsid, clsidW);
1065 count++;
1068 /* append extension to the filter */
1069 wsprintfW(szValue, szExtensionFmt, szFileExt);
1070 if (lp[i].szExtensions[0] == 0)
1071 lstrcatW(lp[i].szExtensions, szValue + 1);
1072 else
1073 lstrcatW(lp[i].szExtensions, szValue);
1075 /* also append to the "all multimedia"-filter */
1076 if (lp[0].szExtensions[0] == 0)
1077 lstrcatW(lp[0].szExtensions, szValue + 1);
1078 else
1079 lstrcatW(lp[0].szExtensions, szValue);
1081 RegCloseKey(hKey);
1083 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1084 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != ERROR_SUCCESS) {
1085 HeapFree(GetProcessHeap(), 0, lp);
1086 return AVIERR_ERROR;
1088 for (n = 0; n <= count; n++) {
1089 /* first the description */
1090 if (n != 0) {
1091 size = sizeof(szValue);
1092 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == ERROR_SUCCESS) {
1093 size = lstrlenW(szValue);
1094 lstrcpynW(szFilter, szValue, cbFilter);
1096 } else
1097 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1099 /* check for enough space */
1100 size++;
1101 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1102 szFilter[0] = 0;
1103 szFilter[1] = 0;
1104 HeapFree(GetProcessHeap(), 0, lp);
1105 RegCloseKey(hKey);
1106 return AVIERR_BUFFERTOOSMALL;
1108 cbFilter -= size;
1109 szFilter += size;
1111 /* and then the filter */
1112 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1113 size = lstrlenW(lp[n].szExtensions) + 1;
1114 cbFilter -= size;
1115 szFilter += size;
1118 RegCloseKey(hKey);
1119 HeapFree(GetProcessHeap(), 0, lp);
1121 /* add "All files" "*.*" filter if enough space left */
1122 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1123 szAllFiles, (sizeof(szAllFiles) - sizeof(all_files))/sizeof(WCHAR)) + 1;
1124 memcpy( szAllFiles + size, all_files, sizeof(all_files) );
1125 size += sizeof(all_files) / sizeof(WCHAR);
1127 if (cbFilter > size) {
1128 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1129 return AVIERR_OK;
1130 } else {
1131 szFilter[0] = 0;
1132 return AVIERR_BUFFERTOOSMALL;
1136 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1138 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1139 AVISTREAMINFOW sInfo;
1141 TRACE("(%p)\n", hWnd);
1143 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1144 ERR(": bad state!\n");
1145 return FALSE;
1148 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1149 &sInfo, sizeof(sInfo)))) {
1150 ERR(": AVIStreamInfoW failed!\n");
1151 return FALSE;
1154 if (sInfo.fccType == streamtypeVIDEO) {
1155 COMPVARS cv;
1156 BOOL ret;
1158 memset(&cv, 0, sizeof(cv));
1160 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1161 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1162 pOptions->fccType = streamtypeVIDEO;
1163 pOptions->fccHandler = comptypeDIB;
1164 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1167 cv.cbSize = sizeof(cv);
1168 cv.dwFlags = ICMF_COMPVARS_VALID;
1169 /*cv.fccType = pOptions->fccType; */
1170 cv.fccHandler = pOptions->fccHandler;
1171 cv.lQ = pOptions->dwQuality;
1172 cv.lpState = pOptions->lpParms;
1173 cv.cbState = pOptions->cbParms;
1174 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1175 cv.lKey = pOptions->dwKeyFrameEvery;
1176 else
1177 cv.lKey = 0;
1178 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1179 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1180 else
1181 cv.lDataRate = 0;
1183 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1184 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1186 if (ret) {
1187 pOptions->fccHandler = cv.fccHandler;
1188 pOptions->lpParms = cv.lpState;
1189 pOptions->cbParms = cv.cbState;
1190 pOptions->dwQuality = cv.lQ;
1191 if (cv.lKey != 0) {
1192 pOptions->dwKeyFrameEvery = cv.lKey;
1193 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1194 } else
1195 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1196 if (cv.lDataRate != 0) {
1197 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1198 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1199 } else
1200 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1201 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1203 ICCompressorFree(&cv);
1205 return ret;
1206 } else if (sInfo.fccType == streamtypeAUDIO) {
1207 ACMFORMATCHOOSEW afmtc;
1208 MMRESULT ret;
1209 LONG size;
1211 /* FIXME: check ACM version -- Which version is needed? */
1213 memset(&afmtc, 0, sizeof(afmtc));
1214 afmtc.cbStruct = sizeof(afmtc);
1215 afmtc.fdwStyle = 0;
1216 afmtc.hwndOwner = hWnd;
1218 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1219 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1220 pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1221 if (!pOptions->lpFormat) return FALSE;
1222 pOptions->cbFormat = size;
1223 } else if (pOptions->cbFormat < (DWORD)size) {
1224 void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size);
1225 if (!new_buffer) return FALSE;
1226 pOptions->lpFormat = new_buffer;
1227 pOptions->cbFormat = size;
1229 afmtc.pwfx = pOptions->lpFormat;
1230 afmtc.cbwfx = pOptions->cbFormat;
1232 size = 0;
1233 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1234 sInfo.dwStart, &size);
1235 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1236 size = sizeof(PCMWAVEFORMAT);
1237 afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size);
1238 if (afmtc.pwfxEnum != NULL) {
1239 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1240 sInfo.dwStart, afmtc.pwfxEnum, &size);
1241 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1244 ret = acmFormatChooseW(&afmtc);
1245 if (ret == S_OK)
1246 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1248 HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum);
1249 return ret == S_OK;
1250 } else {
1251 ERR(": unknown streamtype 0x%08X\n", sInfo.fccType);
1252 return FALSE;
1256 static void AVISaveOptionsUpdate(HWND hWnd)
1258 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1259 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1261 WCHAR szFormat[128];
1262 AVISTREAMINFOW sInfo;
1263 LPVOID lpFormat;
1264 LONG size;
1266 TRACE("(%p)\n", hWnd);
1268 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1269 if (SaveOpts.nCurrent < 0)
1270 return;
1272 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1273 return;
1275 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1276 if (size > 0) {
1277 szFormat[0] = 0;
1279 /* read format to build format description string */
1280 lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1281 if (lpFormat != NULL) {
1282 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1283 if (sInfo.fccType == streamtypeVIDEO) {
1284 LPBITMAPINFOHEADER lpbi = lpFormat;
1285 ICINFO icinfo;
1287 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1288 lpbi->biHeight, lpbi->biBitCount);
1290 if (lpbi->biCompression != BI_RGB) {
1291 HIC hic;
1293 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1294 NULL, ICMODE_DECOMPRESS);
1295 if (hic != NULL) {
1296 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1297 lstrcatW(szFormat, icinfo.szDescription);
1298 ICClose(hic);
1300 } else {
1301 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1302 icinfo.szDescription,
1303 sizeof(icinfo.szDescription)/sizeof(icinfo.szDescription[0]));
1304 lstrcatW(szFormat, icinfo.szDescription);
1306 } else if (sInfo.fccType == streamtypeAUDIO) {
1307 ACMFORMATTAGDETAILSW aftd;
1308 ACMFORMATDETAILSW afd;
1310 memset(&aftd, 0, sizeof(aftd));
1311 memset(&afd, 0, sizeof(afd));
1313 aftd.cbStruct = sizeof(aftd);
1314 aftd.dwFormatTag = afd.dwFormatTag =
1315 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1316 aftd.cbFormatSize = afd.cbwfx = size;
1318 afd.cbStruct = sizeof(afd);
1319 afd.pwfx = lpFormat;
1321 if (acmFormatTagDetailsW(NULL, &aftd,
1322 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1323 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1324 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1328 HeapFree(GetProcessHeap(), 0, lpFormat);
1331 /* set text for format description */
1332 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1334 /* Disable option button for unsupported streamtypes */
1335 if (sInfo.fccType == streamtypeVIDEO ||
1336 sInfo.fccType == streamtypeAUDIO)
1337 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1338 else
1339 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1344 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1345 WPARAM wParam, LPARAM lParam)
1347 DWORD dwInterleave;
1348 BOOL bIsInterleaved;
1349 INT n;
1351 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1353 switch (uMsg) {
1354 case WM_INITDIALOG:
1355 SaveOpts.nCurrent = 0;
1356 if (SaveOpts.nStreams == 1) {
1357 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1358 return TRUE;
1361 /* add streams */
1362 for (n = 0; n < SaveOpts.nStreams; n++) {
1363 AVISTREAMINFOW sInfo;
1365 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1366 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1367 0L, (LPARAM)sInfo.szName);
1370 /* select first stream */
1371 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1372 SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd);
1374 /* initialize interleave */
1375 if (SaveOpts.ppOptions[0] != NULL &&
1376 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1377 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1378 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1379 } else {
1380 bIsInterleaved = TRUE;
1381 dwInterleave = 0;
1383 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1384 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1385 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1386 break;
1387 case WM_COMMAND:
1388 switch (LOWORD(wParam)) {
1389 case IDOK:
1390 /* get data from controls and save them */
1391 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1392 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1393 for (n = 0; n < SaveOpts.nStreams; n++) {
1394 if (SaveOpts.ppOptions[n] != NULL) {
1395 if (bIsInterleaved) {
1396 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1397 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1398 } else
1399 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1402 /* fall through */
1403 case IDCANCEL:
1404 EndDialog(hWnd, LOWORD(wParam) == IDOK);
1405 break;
1406 case IDC_INTERLEAVE:
1407 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1408 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1409 break;
1410 case IDC_STREAM:
1411 if (HIWORD(wParam) == CBN_SELCHANGE) {
1412 /* update control elements */
1413 AVISaveOptionsUpdate(hWnd);
1415 break;
1416 case IDC_OPTIONS:
1417 AVISaveOptionsFmtChoose(hWnd);
1418 break;
1420 return TRUE;
1423 return FALSE;
1426 /***********************************************************************
1427 * AVISaveOptions (AVIFIL32.@)
1429 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1430 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1432 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1433 INT ret, n;
1435 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1436 ppavi, ppOptions);
1438 /* check parameters */
1439 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1440 return AVIERR_BADPARAM;
1442 /* save options in case the user presses cancel */
1443 if (nStreams > 1) {
1444 pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS));
1445 if (pSavedOptions == NULL)
1446 return FALSE;
1448 for (n = 0; n < nStreams; n++) {
1449 if (ppOptions[n] != NULL)
1450 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1454 SaveOpts.uFlags = uFlags;
1455 SaveOpts.nStreams = nStreams;
1456 SaveOpts.ppavis = ppavi;
1457 SaveOpts.ppOptions = ppOptions;
1459 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1460 hWnd, AVISaveOptionsDlgProc);
1462 if (ret == -1)
1463 ret = FALSE;
1465 /* restore options when user pressed cancel */
1466 if (pSavedOptions != NULL) {
1467 if (ret == FALSE) {
1468 for (n = 0; n < nStreams; n++) {
1469 if (ppOptions[n] != NULL)
1470 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1473 HeapFree(GetProcessHeap(), 0, pSavedOptions);
1476 return ret;
1479 /***********************************************************************
1480 * AVISaveOptionsFree (AVIFIL32.@)
1482 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1484 TRACE("(%d,%p)\n", nStreams, ppOptions);
1486 if (nStreams < 0 || ppOptions == NULL)
1487 return AVIERR_BADPARAM;
1489 for (nStreams--; nStreams >= 0; nStreams--) {
1490 if (ppOptions[nStreams] != NULL) {
1491 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1493 if (ppOptions[nStreams]->lpParms != NULL) {
1494 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms);
1495 ppOptions[nStreams]->lpParms = NULL;
1496 ppOptions[nStreams]->cbParms = 0;
1498 if (ppOptions[nStreams]->lpFormat != NULL) {
1499 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat);
1500 ppOptions[nStreams]->lpFormat = NULL;
1501 ppOptions[nStreams]->cbFormat = 0;
1506 return AVIERR_OK;
1509 /***********************************************************************
1510 * AVISaveVA (AVIFIL32.@)
1512 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1513 AVISAVECALLBACK lpfnCallback, int nStream,
1514 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1516 LPWSTR wszFile = NULL;
1517 HRESULT hr;
1518 int len;
1520 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1521 lpfnCallback, nStream, ppavi, plpOptions);
1523 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1524 return AVIERR_BADPARAM;
1526 /* convert ASCII string to Unicode and call Unicode function */
1527 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1528 if (len <= 0)
1529 return AVIERR_BADPARAM;
1531 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1532 if (wszFile == NULL)
1533 return AVIERR_MEMORY;
1535 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
1537 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1538 nStream, ppavi, plpOptions);
1540 HeapFree(GetProcessHeap(), 0, wszFile);
1542 return hr;
1545 /***********************************************************************
1546 * AVIFILE_AVISaveDefaultCallback (internal)
1548 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1550 TRACE("(%d)\n", progress);
1552 return FALSE;
1555 /***********************************************************************
1556 * AVISaveVW (AVIFIL32.@)
1558 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1559 AVISAVECALLBACK lpfnCallback, int nStreams,
1560 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1562 LONG lStart[MAX_AVISTREAMS];
1563 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1564 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1565 AVIFILEINFOW fInfo;
1566 AVISTREAMINFOW sInfo;
1568 PAVIFILE pfile = NULL; /* the output AVI file */
1569 LONG lFirstVideo = -1;
1570 int curStream;
1572 /* for interleaving ... */
1573 DWORD dwInterleave = 0; /* interleave rate */
1574 DWORD dwFileInitialFrames;
1575 LONG lFileLength;
1576 LONG lSampleInc;
1578 /* for reading/writing the data ... */
1579 LPVOID lpBuffer = NULL;
1580 LONG cbBuffer; /* real size of lpBuffer */
1581 LONG lBufferSize; /* needed bytes for format(s), etc. */
1582 LONG lReadBytes;
1583 LONG lReadSamples;
1584 HRESULT hres;
1586 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1587 lpfnCallback, nStreams, ppavi, plpOptions);
1589 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1590 return AVIERR_BADPARAM;
1591 if (nStreams >= MAX_AVISTREAMS) {
1592 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1593 return AVIERR_INTERNAL;
1596 if (lpfnCallback == NULL)
1597 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1599 /* clear local variable(s) */
1600 for (curStream = 0; curStream < nStreams; curStream++) {
1601 pInStreams[curStream] = NULL;
1602 pOutStreams[curStream] = NULL;
1605 /* open output AVI file (create it if it doesn't exist) */
1606 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1607 pclsidHandler);
1608 if (FAILED(hres))
1609 return hres;
1610 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1612 /* initialize our data structures part 1 */
1613 for (curStream = 0; curStream < nStreams; curStream++) {
1614 PAVISTREAM pCurStream = ppavi[curStream];
1616 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1617 if (FAILED(hres))
1618 goto error;
1620 /* search first video stream and check for interleaving */
1621 if (sInfo.fccType == streamtypeVIDEO) {
1622 /* remember first video stream -- needed for interleaving */
1623 if (lFirstVideo < 0)
1624 lFirstVideo = curStream;
1625 } else if (!dwInterleave) {
1626 /* check if any non-video stream wants to be interleaved */
1627 WARN("options.flags=0x%X options.dwInterleave=%u\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1628 if (plpOptions[curStream] != NULL &&
1629 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1630 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1633 /* create de-/compressed stream interface if needed */
1634 pInStreams[curStream] = NULL;
1635 if (plpOptions[curStream] != NULL) {
1636 if (plpOptions[curStream]->fccHandler ||
1637 plpOptions[curStream]->lpFormat != NULL) {
1638 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1640 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1641 plpOptions[curStream]->dwKeyFrameEvery = 1;
1643 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1644 plpOptions[curStream], NULL);
1645 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1646 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1647 pInStreams[curStream] = NULL;
1648 goto error;
1651 /* test stream interface and update stream-info */
1652 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1653 if (FAILED(hres))
1654 goto error;
1658 /* now handle streams which will only be copied */
1659 if (pInStreams[curStream] == NULL) {
1660 pCurStream = pInStreams[curStream] = ppavi[curStream];
1661 AVIStreamAddRef(pCurStream);
1662 } else
1663 pCurStream = pInStreams[curStream];
1665 lStart[curStream] = sInfo.dwStart;
1666 } /* for all streams */
1668 /* check that first video stream is the first stream */
1669 if (lFirstVideo > 0) {
1670 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1671 LONG lTmp = lStart[lFirstVideo];
1673 pInStreams[lFirstVideo] = pInStreams[0];
1674 pInStreams[0] = pTmp;
1675 lStart[lFirstVideo] = lStart[0];
1676 lStart[0] = lTmp;
1677 lFirstVideo = 0;
1680 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
1681 cbBuffer = 0x00010000;
1682 lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer);
1683 if (lpBuffer == NULL) {
1684 hres = AVIERR_MEMORY;
1685 goto error;
1688 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
1689 lFileLength = sInfo.dwLength;
1690 dwFileInitialFrames = 0;
1691 if (lFirstVideo >= 0) {
1692 /* check for correct version of the format
1693 * -- need at least BITMAPINFOHEADER or newer
1695 lSampleInc = 1;
1696 lBufferSize = cbBuffer;
1697 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
1698 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
1699 hres = AVIERR_INTERNAL;
1700 if (FAILED(hres))
1701 goto error;
1702 } else /* use one second blocks for interleaving if no video present */
1703 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
1705 /* create output streams */
1706 for (curStream = 0; curStream < nStreams; curStream++) {
1707 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1709 sInfo.dwInitialFrames = 0;
1710 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
1711 /* 750 ms initial frames for non-video streams */
1712 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
1715 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
1716 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
1717 /* copy initial format for this stream */
1718 lBufferSize = cbBuffer;
1719 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1720 lpBuffer, &lBufferSize);
1721 if (FAILED(hres))
1722 goto error;
1723 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
1724 if (FAILED(hres))
1725 goto error;
1727 /* try to copy stream handler data */
1728 lBufferSize = cbBuffer;
1729 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
1730 lpBuffer, &lBufferSize);
1731 if (SUCCEEDED(hres) && lBufferSize > 0) {
1732 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
1733 lpBuffer, lBufferSize);
1734 if (FAILED(hres))
1735 goto error;
1738 if (dwFileInitialFrames < sInfo.dwInitialFrames)
1739 dwFileInitialFrames = sInfo.dwInitialFrames;
1740 lReadBytes =
1741 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
1742 sInfo.dwLength);
1743 if (lFileLength < lReadBytes)
1744 lFileLength = lReadBytes;
1745 } else {
1746 /* creation of de-/compression stream interface failed */
1747 WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
1748 AVIStreamRelease(pInStreams[curStream]);
1749 if (curStream + 1 >= nStreams) {
1750 /* move the others one up */
1751 PAVISTREAM *ppas = &pInStreams[curStream];
1752 int n = nStreams - (curStream + 1);
1754 do {
1755 *ppas = pInStreams[curStream + 1];
1756 } while (--n);
1758 nStreams--;
1759 curStream--;
1761 } /* create output streams for all input streams */
1763 /* have we still something to write, or lost everything? */
1764 if (nStreams <= 0)
1765 goto error;
1767 if (dwInterleave) {
1768 LONG lCurFrame = -dwFileInitialFrames;
1770 /* interleaved file */
1771 if (dwInterleave == 1)
1772 AVIFileEndRecord(pfile);
1774 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
1775 for (curStream = 0; curStream < nStreams; curStream++) {
1776 LONG lLastSample;
1778 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
1779 if (FAILED(hres))
1780 goto error;
1782 /* initial frames phase at the end for this stream? */
1783 if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
1784 continue;
1786 if ((lFileLength - lSampleInc) <= lCurFrame) {
1787 lLastSample = AVIStreamLength(pInStreams[curStream]);
1788 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
1789 } else {
1790 if (curStream != 0) {
1791 lFirstVideo =
1792 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
1793 (sInfo.fccType == streamtypeVIDEO ?
1794 (LONG)dwInterleave : lSampleInc) +
1795 sInfo.dwInitialFrames + lCurFrame);
1796 } else
1797 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
1799 lLastSample = AVIStreamEnd(pInStreams[curStream]);
1800 if (lLastSample <= lFirstVideo)
1801 lFirstVideo = lLastSample;
1804 /* copy needed samples now */
1805 WARN("copy from stream %d samples %d to %d...\n",curStream,
1806 lStart[curStream],lFirstVideo);
1807 while (lFirstVideo > lStart[curStream]) {
1808 DWORD flags = 0;
1810 /* copy format in case it can change */
1811 lBufferSize = cbBuffer;
1812 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
1813 lpBuffer, &lBufferSize);
1814 if (FAILED(hres))
1815 goto error;
1816 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
1817 lpBuffer, lBufferSize);
1819 /* try to read data until we got it, or error */
1820 do {
1821 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
1822 lFirstVideo - lStart[curStream], lpBuffer,
1823 cbBuffer, &lReadBytes, &lReadSamples);
1824 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1825 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1826 if (lpBuffer == NULL)
1827 hres = AVIERR_MEMORY;
1828 if (FAILED(hres))
1829 goto error;
1831 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1832 flags = AVIIF_KEYFRAME;
1833 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1834 lpBuffer, lReadBytes, flags, NULL, NULL);
1835 if (FAILED(hres))
1836 goto error;
1838 lStart[curStream] += lReadSamples;
1840 lStart[curStream] = lFirstVideo;
1841 } /* stream by stream */
1843 /* need to close this block? */
1844 if (dwInterleave == 1) {
1845 hres = AVIFileEndRecord(pfile);
1846 if (FAILED(hres))
1847 break;
1850 /* show progress */
1851 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
1852 dwFileInitialFrames + lFileLength))) {
1853 hres = AVIERR_USERABORT;
1854 break;
1856 } /* copy frame by frame */
1857 } else {
1858 /* non-interleaved file */
1860 for (curStream = 0; curStream < nStreams; curStream++) {
1861 /* show progress */
1862 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
1863 hres = AVIERR_USERABORT;
1864 goto error;
1867 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1869 if (sInfo.dwSampleSize != 0) {
1870 /* sample-based data like audio */
1871 while (sInfo.dwStart < sInfo.dwLength) {
1872 LONG lSamples = cbBuffer / sInfo.dwSampleSize;
1874 /* copy format in case it can change */
1875 lBufferSize = cbBuffer;
1876 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1877 lpBuffer, &lBufferSize);
1878 if (FAILED(hres))
1879 goto error;
1880 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1881 lpBuffer, lBufferSize);
1883 /* limit to stream boundaries */
1884 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
1885 lSamples = sInfo.dwLength - sInfo.dwStart;
1887 /* now try to read until we get it, or an error occurs */
1888 do {
1889 lReadBytes = cbBuffer;
1890 lReadSamples = 0;
1891 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
1892 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
1893 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1894 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1895 if (lpBuffer == NULL)
1896 hres = AVIERR_MEMORY;
1897 if (FAILED(hres))
1898 goto error;
1899 if (lReadSamples != 0) {
1900 sInfo.dwStart += lReadSamples;
1901 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1902 lpBuffer, lReadBytes, 0, NULL , NULL);
1903 if (FAILED(hres))
1904 goto error;
1906 /* show progress */
1907 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1908 MulDiv(curStream, 100, nStreams))) {
1909 hres = AVIERR_USERABORT;
1910 goto error;
1912 } else {
1913 if ((sInfo.dwLength - sInfo.dwStart) != 1) {
1914 hres = AVIERR_FILEREAD;
1915 goto error;
1919 } else {
1920 /* block-based data like video */
1921 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
1922 DWORD flags = 0;
1924 /* copy format in case it can change */
1925 lBufferSize = cbBuffer;
1926 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1927 lpBuffer, &lBufferSize);
1928 if (FAILED(hres))
1929 goto error;
1930 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1931 lpBuffer, lBufferSize);
1933 /* try to read block and resize buffer if necessary */
1934 do {
1935 lReadSamples = 0;
1936 lReadBytes = cbBuffer;
1937 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
1938 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
1939 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1940 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1941 if (lpBuffer == NULL)
1942 hres = AVIERR_MEMORY;
1943 if (FAILED(hres))
1944 goto error;
1945 if (lReadSamples != 1) {
1946 hres = AVIERR_FILEREAD;
1947 goto error;
1950 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1951 flags = AVIIF_KEYFRAME;
1952 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1953 lpBuffer, lReadBytes, flags, NULL, NULL);
1954 if (FAILED(hres))
1955 goto error;
1957 /* show progress */
1958 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1959 MulDiv(curStream, 100, nStreams))) {
1960 hres = AVIERR_USERABORT;
1961 goto error;
1963 } /* copy all blocks */
1965 } /* copy data stream by stream */
1968 error:
1969 HeapFree(GetProcessHeap(), 0, lpBuffer);
1970 if (pfile != NULL) {
1971 for (curStream = 0; curStream < nStreams; curStream++) {
1972 if (pOutStreams[curStream] != NULL)
1973 AVIStreamRelease(pOutStreams[curStream]);
1974 if (pInStreams[curStream] != NULL)
1975 AVIStreamRelease(pInStreams[curStream]);
1978 AVIFileRelease(pfile);
1981 return hres;
1984 /***********************************************************************
1985 * EditStreamClone (AVIFIL32.@)
1987 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
1989 PAVIEDITSTREAM pEdit = NULL;
1990 HRESULT hr;
1992 TRACE("(%p,%p)\n", pStream, ppResult);
1994 if (pStream == NULL)
1995 return AVIERR_BADHANDLE;
1996 if (ppResult == NULL)
1997 return AVIERR_BADPARAM;
1999 *ppResult = NULL;
2001 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2002 if (SUCCEEDED(hr) && pEdit != NULL) {
2003 hr = IAVIEditStream_Clone(pEdit, ppResult);
2005 IAVIEditStream_Release(pEdit);
2006 } else
2007 hr = AVIERR_UNSUPPORTED;
2009 return hr;
2012 /***********************************************************************
2013 * EditStreamCopy (AVIFIL32.@)
2015 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2016 LONG *plLength, PAVISTREAM *ppResult)
2018 PAVIEDITSTREAM pEdit = NULL;
2019 HRESULT hr;
2021 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2023 if (pStream == NULL)
2024 return AVIERR_BADHANDLE;
2025 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2026 return AVIERR_BADPARAM;
2028 *ppResult = NULL;
2030 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2031 if (SUCCEEDED(hr) && pEdit != NULL) {
2032 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2034 IAVIEditStream_Release(pEdit);
2035 } else
2036 hr = AVIERR_UNSUPPORTED;
2038 return hr;
2041 /***********************************************************************
2042 * EditStreamCut (AVIFIL32.@)
2044 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2045 LONG *plLength, PAVISTREAM *ppResult)
2047 PAVIEDITSTREAM pEdit = NULL;
2048 HRESULT hr;
2050 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2052 if (ppResult != NULL)
2053 *ppResult = NULL;
2054 if (pStream == NULL)
2055 return AVIERR_BADHANDLE;
2056 if (plStart == NULL || plLength == NULL)
2057 return AVIERR_BADPARAM;
2059 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2060 if (SUCCEEDED(hr) && pEdit != NULL) {
2061 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2063 IAVIEditStream_Release(pEdit);
2064 } else
2065 hr = AVIERR_UNSUPPORTED;
2067 return hr;
2070 /***********************************************************************
2071 * EditStreamPaste (AVIFIL32.@)
2073 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2074 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2076 PAVIEDITSTREAM pEdit = NULL;
2077 HRESULT hr;
2079 TRACE("(%p,%p,%p,%p,%d,%d)\n", pDest, plStart, plLength,
2080 pSource, lStart, lEnd);
2082 if (pDest == NULL || pSource == NULL)
2083 return AVIERR_BADHANDLE;
2084 if (plStart == NULL || plLength == NULL || lStart < 0)
2085 return AVIERR_BADPARAM;
2087 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2088 if (SUCCEEDED(hr) && pEdit != NULL) {
2089 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2091 IAVIEditStream_Release(pEdit);
2092 } else
2093 hr = AVIERR_UNSUPPORTED;
2095 return hr;
2098 /***********************************************************************
2099 * EditStreamSetInfoA (AVIFIL32.@)
2101 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2102 LONG size)
2104 AVISTREAMINFOW asiw;
2106 TRACE("(%p,%p,%d)\n", pstream, asi, size);
2108 if (size >= 0 && size < sizeof(AVISTREAMINFOA))
2109 return AVIERR_BADSIZE;
2111 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2112 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
2113 asiw.szName, sizeof(asiw.szName)/sizeof(WCHAR));
2115 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2118 /***********************************************************************
2119 * EditStreamSetInfoW (AVIFIL32.@)
2121 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2122 LONG size)
2124 PAVIEDITSTREAM pEdit = NULL;
2125 HRESULT hr;
2127 TRACE("(%p,%p,%d)\n", pstream, asi, size);
2129 if (size >= 0 && size < sizeof(AVISTREAMINFOA))
2130 return AVIERR_BADSIZE;
2132 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2133 if (SUCCEEDED(hr) && pEdit != NULL) {
2134 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2136 IAVIEditStream_Release(pEdit);
2137 } else
2138 hr = AVIERR_UNSUPPORTED;
2140 return hr;
2143 /***********************************************************************
2144 * EditStreamSetNameA (AVIFIL32.@)
2146 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2148 AVISTREAMINFOA asia;
2149 HRESULT hres;
2151 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2153 if (pstream == NULL)
2154 return AVIERR_BADHANDLE;
2155 if (szName == NULL)
2156 return AVIERR_BADPARAM;
2158 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2159 if (FAILED(hres))
2160 return hres;
2162 memset(asia.szName, 0, sizeof(asia.szName));
2163 lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
2165 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2168 /***********************************************************************
2169 * EditStreamSetNameW (AVIFIL32.@)
2171 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2173 AVISTREAMINFOW asiw;
2174 HRESULT hres;
2176 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2178 if (pstream == NULL)
2179 return AVIERR_BADHANDLE;
2180 if (szName == NULL)
2181 return AVIERR_BADPARAM;
2183 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2184 if (FAILED(hres))
2185 return hres;
2187 memset(asiw.szName, 0, sizeof(asiw.szName));
2188 lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
2190 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2193 /***********************************************************************
2194 * AVIClearClipboard (AVIFIL32.@)
2196 HRESULT WINAPI AVIClearClipboard(void)
2198 TRACE("()\n");
2200 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2203 /***********************************************************************
2204 * AVIGetFromClipboard (AVIFIL32.@)
2206 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2208 FIXME("(%p), stub!\n", ppfile);
2210 *ppfile = NULL;
2212 return AVIERR_UNSUPPORTED;
2215 /***********************************************************************
2216 * AVIMakeStreamFromClipboard (AVIFIL32.@)
2218 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
2219 PAVISTREAM * ppstream)
2221 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
2223 if (ppstream == NULL)
2224 return AVIERR_BADHANDLE;
2226 return AVIERR_UNSUPPORTED;
2229 /***********************************************************************
2230 * AVIPutFileOnClipboard (AVIFIL32.@)
2232 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2234 FIXME("(%p), stub!\n", pfile);
2236 if (pfile == NULL)
2237 return AVIERR_BADHANDLE;
2239 return AVIERR_UNSUPPORTED;
2242 HRESULT WINAPIV AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2243 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2245 __ms_va_list vl;
2246 int i;
2247 HRESULT ret;
2248 PAVISTREAM *streams;
2249 LPAVICOMPRESSOPTIONS *options;
2251 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
2252 nStreams, pavi, lpOptions);
2254 if (nStreams <= 0) return AVIERR_BADPARAM;
2256 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams));
2257 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options));
2258 if (!streams || !options)
2260 ret = AVIERR_MEMORY;
2261 goto error;
2264 streams[0] = pavi;
2265 options[0] = lpOptions;
2267 __ms_va_start(vl, lpOptions);
2268 for (i = 1; i < nStreams; i++)
2270 streams[i] = va_arg(vl, PAVISTREAM);
2271 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS);
2273 __ms_va_end(vl);
2275 for (i = 0; i < nStreams; i++)
2276 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]);
2278 ret = AVISaveVA(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options);
2279 error:
2280 HeapFree(GetProcessHeap(), 0, streams);
2281 HeapFree(GetProcessHeap(), 0, options);
2282 return ret;
2285 HRESULT WINAPIV AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2286 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2288 __ms_va_list vl;
2289 int i;
2290 HRESULT ret;
2291 PAVISTREAM *streams;
2292 LPAVICOMPRESSOPTIONS *options;
2294 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
2295 nStreams, pavi, lpOptions);
2297 if (nStreams <= 0) return AVIERR_BADPARAM;
2299 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams));
2300 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options));
2301 if (!streams || !options)
2303 ret = AVIERR_MEMORY;
2304 goto error;
2307 streams[0] = pavi;
2308 options[0] = lpOptions;
2310 __ms_va_start(vl, lpOptions);
2311 for (i = 1; i < nStreams; i++)
2313 streams[i] = va_arg(vl, PAVISTREAM);
2314 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS);
2316 __ms_va_end(vl);
2318 for (i = 0; i < nStreams; i++)
2319 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]);
2321 ret = AVISaveVW(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options);
2322 error:
2323 HeapFree(GetProcessHeap(), 0, streams);
2324 HeapFree(GetProcessHeap(), 0, options);
2325 return ret;