Fix some DPA functions so they pass the new tests.
[wine/multimedia.git] / dlls / avifil32 / api.c
blob8f0067ffdd905d547c4f2cf1982c2974f4e61b9e
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <assert.h>
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define COM_NO_WINDOWS_H
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winreg.h"
32 #include "winerror.h"
33 #include "windowsx.h"
35 #include "ole2.h"
36 #include "shellapi.h"
37 #include "shlobj.h"
38 #include "vfw.h"
39 #include "msacm.h"
41 #include "avifile_private.h"
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
49 /***********************************************************************
50 * for AVIBuildFilterW -- uses fixed size table
52 #define MAX_FILTERS 30 /* 30 => 7kB */
54 typedef struct _AVIFilter {
55 WCHAR szClsid[40];
56 WCHAR szExtensions[MAX_FILTERS * 7];
57 } AVIFilter;
59 /***********************************************************************
60 * for AVISaveOptions
62 static struct {
63 UINT uFlags;
64 INT nStreams;
65 PAVISTREAM *ppavis;
66 LPAVICOMPRESSOPTIONS *ppOptions;
67 INT nCurrent;
68 } SaveOpts;
70 /***********************************************************************
71 * copied from dlls/ole32/compobj.c
73 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
75 BYTE const *s = (BYTE const*)idstr;
76 BYTE *p;
77 INT i;
78 BYTE table[256];
80 if (!s) {
81 memset(id, 0, sizeof(CLSID));
82 return S_OK;
83 } else { /* validate the CLSID string */
84 if (lstrlenA(s) != 38)
85 return CO_E_CLASSSTRING;
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;
102 TRACE("%s -> %p\n", s, id);
104 /* quick lookup table */
105 memset(table, 0, 256);
107 for (i = 0; i < 10; i++)
108 table['0' + i] = i;
110 for (i = 0; i < 6; i++) {
111 table['A' + i] = i+10;
112 table['a' + i] = i+10;
115 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
116 p = (BYTE *) id;
118 s++; /* skip leading brace */
119 for (i = 0; i < 4; i++) {
120 p[3 - i] = table[*s]<<4 | table[*(s+1)];
121 s += 2;
123 p += 4;
124 s++; /* skip - */
126 for (i = 0; i < 2; i++) {
127 p[1-i] = table[*s]<<4 | table[*(s+1)];
128 s += 2;
130 p += 2;
131 s++; /* skip - */
133 for (i = 0; i < 2; i++) {
134 p[1-i] = table[*s]<<4 | table[*(s+1)];
135 s += 2;
137 p += 2;
138 s++; /* skip - */
140 /* these are just sequential bytes */
141 for (i = 0; i < 2; i++) {
142 *p++ = table[*s]<<4 | table[*(s+1)];
143 s += 2;
145 s++; /* skip - */
147 for (i = 0; i < 6; i++) {
148 *p++ = table[*s]<<4 | table[*(s+1)];
149 s += 2;
152 return S_OK;
155 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
157 CHAR szRegKey[25];
158 CHAR szValue[100];
159 LPWSTR szExt = strrchrW(szFile, '.');
160 LONG len = sizeof(szValue) / sizeof(szValue[0]);
162 if (szExt == NULL)
163 return FALSE;
165 szExt++;
167 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
168 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
169 return FALSE;
171 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
174 /***********************************************************************
175 * AVIFileInit (AVIFIL32.@)
176 * AVIFileInit (AVIFILE.100)
178 void WINAPI AVIFileInit(void) {
179 OleInitialize(NULL);
182 /***********************************************************************
183 * AVIFileExit (AVIFIL32.@)
184 * AVIFileExit (AVIFILE.101)
186 void WINAPI AVIFileExit(void) {
187 /* need to free ole32.dll if we are the last exit call */
188 /* OleUnitialize() */
189 FIXME("(): stub!\n");
192 /***********************************************************************
193 * AVIFileOpen (AVIFIL32.@)
194 * AVIFileOpenA (AVIFIL32.@)
195 * AVIFileOpen (AVIFILE.102)
197 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
198 LPCLSID lpHandler)
200 LPWSTR wszFile = NULL;
201 HRESULT hr;
202 int len;
204 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
205 debugstr_guid(lpHandler));
207 /* check parameters */
208 if (ppfile == NULL || szFile == NULL)
209 return AVIERR_BADPARAM;
211 /* convert ASCII string to Unicode and call unicode function */
212 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
213 if (len <= 0)
214 return AVIERR_BADPARAM;
216 wszFile = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
217 if (wszFile == NULL)
218 return AVIERR_MEMORY;
220 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
222 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
224 LocalFree((HLOCAL)wszFile);
226 return hr;
229 /***********************************************************************
230 * AVIFileOpenW (AVIFIL32.@)
232 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
233 LPCLSID lpHandler)
235 IPersistFile *ppersist = NULL;
236 CLSID clsidHandler;
237 HRESULT hr;
239 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
240 debugstr_guid(lpHandler));
242 /* check parameters */
243 if (ppfile == NULL || szFile == NULL)
244 return AVIERR_BADPARAM;
246 *ppfile = NULL;
248 /* if no handler then try guessing it by extension */
249 if (lpHandler == NULL) {
250 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
251 return AVIERR_UNSUPPORTED;
252 } else
253 memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
255 /* create instance of handler */
256 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile);
257 if (FAILED(hr) || *ppfile == NULL)
258 return hr;
260 /* ask for IPersistFile interface for loading/creating the file */
261 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
262 if (FAILED(hr) || ppersist == NULL) {
263 IAVIFile_Release(*ppfile);
264 *ppfile = NULL;
265 return hr;
268 hr = IPersistFile_Load(ppersist, szFile, uMode);
269 IPersistFile_Release(ppersist);
270 if (FAILED(hr)) {
271 IAVIFile_Release(*ppfile);
272 *ppfile = NULL;
275 return hr;
278 /***********************************************************************
279 * AVIFileAddRef (AVIFIL32.@)
280 * AVIFileAddRef (AVIFILE.140)
282 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
284 TRACE("(%p)\n", pfile);
286 if (pfile == NULL) {
287 ERR(": bad handle passed!\n");
288 return 0;
291 return IAVIFile_AddRef(pfile);
294 /***********************************************************************
295 * AVIFileRelease (AVIFIL32.@)
296 * AVIFileRelease (AVIFILE.141)
298 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
300 TRACE("(%p)\n", pfile);
302 if (pfile == NULL) {
303 ERR(": bad handle passed!\n");
304 return 0;
307 return IAVIFile_Release(pfile);
310 /***********************************************************************
311 * AVIFileInfo (AVIFIL32.@)
312 * AVIFileInfoA (AVIFIL32.@)
313 * AVIFileInfo (AVIFILE.142)
315 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
317 AVIFILEINFOW afiw;
318 HRESULT hres;
320 TRACE("(%p,%p,%ld)\n", pfile, afi, size);
322 if (pfile == NULL)
323 return AVIERR_BADHANDLE;
324 if ((DWORD)size < sizeof(AVIFILEINFOA))
325 return AVIERR_BADSIZE;
327 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
329 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
330 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
331 sizeof(afi->szFileType), NULL, NULL);
332 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
334 return hres;
337 /***********************************************************************
338 * AVIFileInfoW (AVIFIL32.@)
340 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
342 TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
344 if (pfile == NULL)
345 return AVIERR_BADHANDLE;
347 return IAVIFile_Info(pfile, afiw, size);
350 /***********************************************************************
351 * AVIFileGetStream (AVIFIL32.@)
352 * AVIFileGetStream (AVIFILE.143)
354 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
355 DWORD fccType, LONG lParam)
357 TRACE("(%p,%p,'%4.4s',%ld)\n", pfile, avis, (char*)&fccType, lParam);
359 if (pfile == NULL)
360 return AVIERR_BADHANDLE;
362 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
365 /***********************************************************************
366 * AVIFileCreateStream (AVIFIL32.@)
367 * AVIFileCreateStreamA (AVIFIL32.@)
368 * AVIFileCreateStream (AVIFILE.144)
370 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
371 LPAVISTREAMINFOA psi)
373 AVISTREAMINFOW psiw;
375 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
377 if (pfile == NULL)
378 return AVIERR_BADHANDLE;
380 /* Only the szName at the end is different */
381 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
382 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
383 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
385 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
388 /***********************************************************************
389 * AVIFileCreateStreamW (AVIFIL32.@)
391 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
392 LPAVISTREAMINFOW asi)
394 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
396 if (pfile == NULL)
397 return AVIERR_BADHANDLE;
399 return IAVIFile_CreateStream(pfile, avis, asi);
402 /***********************************************************************
403 * AVIFileWriteData (AVIFIL32.@)
404 * AVIFileWriteData (AVIFILE.146)
406 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
408 TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
410 if (pfile == NULL)
411 return AVIERR_BADHANDLE;
413 return IAVIFile_WriteData(pfile, fcc, lp, size);
416 /***********************************************************************
417 * AVIFileReadData (AVIFIL32.@)
418 * AVIFileReadData (AVIFILE.147)
420 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
422 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
424 if (pfile == NULL)
425 return AVIERR_BADHANDLE;
427 return IAVIFile_ReadData(pfile, fcc, lp, size);
430 /***********************************************************************
431 * AVIFileEndRecord (AVIFIL32.@)
432 * AVIFileEndRecord (AVIFILE.148)
434 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
436 TRACE("(%p)\n", pfile);
438 if (pfile == NULL)
439 return AVIERR_BADHANDLE;
441 return IAVIFile_EndRecord(pfile);
444 /***********************************************************************
445 * AVIStreamAddRef (AVIFIL32.@)
446 * AVIStreamAddRef (AVIFILE.160)
448 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
450 TRACE("(%p)\n", pstream);
452 if (pstream == NULL) {
453 ERR(": bad handle passed!\n");
454 return 0;
457 return IAVIStream_AddRef(pstream);
460 /***********************************************************************
461 * AVIStreamRelease (AVIFIL32.@)
462 * AVIStreamRelease (AVIFILE.161)
464 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
466 TRACE("(%p)\n", pstream);
468 if (pstream == NULL) {
469 ERR(": bad handle passed!\n");
470 return 0;
473 return IAVIStream_Release(pstream);
476 /***********************************************************************
477 * AVIStreamCreate (AVIFIL32.@)
478 * AVIStreamCreate (AVIFILE.104)
480 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
481 LPCLSID pclsidHandler)
483 HRESULT hr;
485 TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
486 debugstr_guid(pclsidHandler));
488 if (ppavi == NULL)
489 return AVIERR_BADPARAM;
491 *ppavi = NULL;
492 if (pclsidHandler == NULL)
493 return AVIERR_UNSUPPORTED;
495 hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi);
496 if (FAILED(hr) || *ppavi == NULL)
497 return hr;
499 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
500 if (FAILED(hr)) {
501 IAVIStream_Release(*ppavi);
502 *ppavi = NULL;
505 return hr;
508 /***********************************************************************
509 * AVIStreamInfo (AVIFIL32.@)
510 * AVIStreamInfoA (AVIFIL32.@)
511 * AVIStreamInfo (AVIFILE.162)
513 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
514 LONG size)
516 AVISTREAMINFOW asiw;
517 HRESULT hres;
519 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
521 if (pstream == NULL)
522 return AVIERR_BADHANDLE;
523 if ((DWORD)size < sizeof(AVISTREAMINFOA))
524 return AVIERR_BADSIZE;
526 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
528 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
529 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
530 sizeof(asi->szName), NULL, NULL);
531 asi->szName[sizeof(asi->szName) - 1] = 0;
533 return hres;
536 /***********************************************************************
537 * AVIStreamInfoW (AVIFIL32.@)
539 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
540 LONG size)
542 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
544 if (pstream == NULL)
545 return AVIERR_BADHANDLE;
547 return IAVIStream_Info(pstream, asi, size);
550 /***********************************************************************
551 * AVIStreamFindSample (AVIFIL32.@)
552 * AVIStreamFindSample (AVIFILE.163)
554 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
556 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
558 if (pstream == NULL)
559 return -1;
561 return IAVIStream_FindSample(pstream, pos, flags);
564 /***********************************************************************
565 * AVIStreamReadFormat (AVIFIL32.@)
566 * AVIStreamReadFormat (AVIFILE.164)
568 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
569 LPVOID format, LPLONG formatsize)
571 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
573 if (pstream == NULL)
574 return AVIERR_BADHANDLE;
576 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
579 /***********************************************************************
580 * AVIStreamSetFormat (AVIFIL32.@)
581 * AVIStreamSetFormat (AVIFILE.169)
583 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
584 LPVOID format, LONG formatsize)
586 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
588 if (pstream == NULL)
589 return AVIERR_BADHANDLE;
591 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
594 /***********************************************************************
595 * AVIStreamRead (AVIFIL32.@)
596 * AVIStreamRead (AVIFILE.167)
598 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
599 LPVOID buffer, LONG buffersize,
600 LPLONG bytesread, LPLONG samplesread)
602 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
603 buffersize, bytesread, samplesread);
605 if (pstream == NULL)
606 return AVIERR_BADHANDLE;
608 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
609 bytesread, samplesread);
612 /***********************************************************************
613 * AVIStreamWrite (AVIFIL32.@)
614 * AVIStreamWrite (AVIFILE.168)
616 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
617 LPVOID buffer, LONG buffersize, DWORD flags,
618 LPLONG sampwritten, LPLONG byteswritten)
620 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
621 buffersize, flags, sampwritten, byteswritten);
623 if (pstream == NULL)
624 return AVIERR_BADHANDLE;
626 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
627 flags, sampwritten, byteswritten);
630 /***********************************************************************
631 * AVIStreamReadData (AVIFIL32.@)
632 * AVIStreamReadData (AVIFILE.165)
634 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
635 LPLONG lpread)
637 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
639 if (pstream == NULL)
640 return AVIERR_BADHANDLE;
642 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
645 /***********************************************************************
646 * AVIStreamWriteData (AVIFIL32.@)
647 * AVIStreamWriteData (AVIFILE.166)
649 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
650 LONG size)
652 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
654 if (pstream == NULL)
655 return AVIERR_BADHANDLE;
657 return IAVIStream_WriteData(pstream, fcc, lp, size);
660 /***********************************************************************
661 * AVIStreamGetFrameOpen (AVIFIL32.@)
662 * AVIStreamGetFrameOpen (AVIFILE.112)
664 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
665 LPBITMAPINFOHEADER lpbiWanted)
667 PGETFRAME pg = NULL;
669 TRACE("(%p,%p)\n", pstream, lpbiWanted);
671 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
672 pg == NULL) {
673 pg = AVIFILE_CreateGetFrame(pstream);
674 if (pg == NULL)
675 return NULL;
678 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
679 IGetFrame_Release(pg);
680 return NULL;
683 return pg;
686 /***********************************************************************
687 * AVIStreamGetFrame (AVIFIL32.@)
688 * AVIStreamGetFrame (AVIFILE.110)
690 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
692 TRACE("(%p,%ld)\n", pg, pos);
694 if (pg == NULL)
695 return NULL;
697 return IGetFrame_GetFrame(pg, pos);
700 /***********************************************************************
701 * AVIStreamGetFrameClose (AVIFIL32.@)
702 * AVIStreamGetFrameClose (AVIFILE.111)
704 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
706 TRACE("(%p)\n", pg);
708 if (pg != NULL)
709 return IGetFrame_Release(pg);
710 return 0;
713 /***********************************************************************
714 * AVIMakeCompressedStream (AVIFIL32.@)
716 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
717 PAVISTREAM psSource,
718 LPAVICOMPRESSOPTIONS aco,
719 LPCLSID pclsidHandler)
721 AVISTREAMINFOW asiw;
722 CHAR szRegKey[25];
723 CHAR szValue[100];
724 CLSID clsidHandler;
725 HRESULT hr;
726 LONG size = sizeof(szValue);
728 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
729 debugstr_guid(pclsidHandler));
731 if (ppsCompressed == NULL)
732 return AVIERR_BADPARAM;
733 if (psSource == NULL)
734 return AVIERR_BADHANDLE;
736 *ppsCompressed = NULL;
738 /* if no handler given get default ones based on streamtype */
739 if (pclsidHandler == NULL) {
740 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
741 if (FAILED(hr))
742 return hr;
744 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
745 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
746 return AVIERR_UNSUPPORTED;
747 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
748 return AVIERR_UNSUPPORTED;
749 } else
750 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
752 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed);
753 if (FAILED(hr) || *ppsCompressed == NULL)
754 return hr;
756 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
757 if (FAILED(hr)) {
758 IAVIStream_Release(*ppsCompressed);
759 *ppsCompressed = NULL;
762 return hr;
765 /***********************************************************************
766 * AVIMakeFileFromStreams (AVIFIL32.@)
768 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
769 PAVISTREAM *ppStreams)
771 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
773 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
774 return AVIERR_BADPARAM;
776 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
777 if (*ppfile == NULL)
778 return AVIERR_MEMORY;
780 return AVIERR_OK;
783 /***********************************************************************
784 * AVIStreamOpenFromFile (AVIFIL32.@)
785 * AVIStreamOpenFromFileA (AVIFIL32.@)
786 * AVIStreamOpenFromFile (AVIFILE.103)
788 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
789 DWORD fccType, LONG lParam,
790 UINT mode, LPCLSID pclsidHandler)
792 PAVIFILE pfile = NULL;
793 HRESULT hr;
795 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
796 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
798 if (ppavi == NULL || szFile == NULL)
799 return AVIERR_BADPARAM;
801 *ppavi = NULL;
803 hr = AVIFileOpenA(&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 * AVIStreamOpenFromFileW (AVIFIL32.@)
816 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
817 DWORD fccType, LONG lParam,
818 UINT mode, LPCLSID pclsidHandler)
820 PAVIFILE pfile = NULL;
821 HRESULT hr;
823 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
824 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
826 if (ppavi == NULL || szFile == NULL)
827 return AVIERR_BADPARAM;
829 *ppavi = NULL;
831 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
832 if (FAILED(hr) || pfile == NULL)
833 return hr;
835 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
836 IAVIFile_Release(pfile);
838 return hr;
841 /***********************************************************************
842 * AVIStreamBeginStreaming (AVIFIL32.@)
844 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
846 IAVIStreaming* pstream = NULL;
847 HRESULT hr;
849 TRACE("(%p,%ld,%ld,%ld)\n", pavi, lStart, lEnd, lRate);
851 if (pavi == NULL)
852 return AVIERR_BADHANDLE;
854 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
855 if (SUCCEEDED(hr) && pstream != NULL) {
856 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
857 IAVIStreaming_Release(pstream);
858 } else
859 hr = AVIERR_OK;
861 return hr;
864 /***********************************************************************
865 * AVIStreamEndStreaming (AVIFIL32.@)
867 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
869 IAVIStreaming* pstream = NULL;
870 HRESULT hr;
872 TRACE("(%p)\n", pavi);
874 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
875 if (SUCCEEDED(hr) && pstream != NULL) {
876 IAVIStreaming_End(pstream);
877 IAVIStreaming_Release(pstream);
880 return AVIERR_OK;
883 /***********************************************************************
884 * AVIStreamStart (AVIFILE.130)
885 * AVIStreamStart (AVIFIL32.@)
887 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
889 AVISTREAMINFOW asiw;
891 TRACE("(%p)\n", pstream);
893 if (pstream == NULL)
894 return 0;
896 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
897 return 0;
899 return asiw.dwStart;
902 /***********************************************************************
903 * AVIStreamLength (AVIFILE.131)
904 * AVIStreamLength (AVIFIL32.@)
906 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
908 AVISTREAMINFOW asiw;
910 TRACE("(%p)\n", pstream);
912 if (pstream == NULL)
913 return 0;
915 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
916 return 0;
918 return asiw.dwLength;
921 /***********************************************************************
922 * AVIStreamSampleToTime (AVIFILE.133)
923 * AVIStreamSampleToTime (AVIFIL32.@)
925 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
927 AVISTREAMINFOW asiw;
928 LONG time;
930 TRACE("(%p,%ld)\n", pstream, lSample);
932 if (pstream == NULL)
933 return -1;
935 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
936 return -1;
937 if (asiw.dwRate == 0)
938 return -1;
940 /* limit to stream bounds */
941 if (lSample < asiw.dwStart)
942 lSample = asiw.dwStart;
943 if (lSample > asiw.dwStart + asiw.dwLength)
944 lSample = asiw.dwStart + asiw.dwLength;
946 if (asiw.dwRate / asiw.dwScale < 1000)
947 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
948 else
949 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
951 TRACE(" -> %ld\n",time);
952 return time;
955 /***********************************************************************
956 * AVIStreamTimeToSample (AVIFILE.132)
957 * AVIStreamTimeToSample (AVIFIL32.@)
959 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
961 AVISTREAMINFOW asiw;
962 ULONG sample;
964 TRACE("(%p,%ld)\n", pstream, lTime);
966 if (pstream == NULL || lTime < 0)
967 return -1;
969 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
970 return -1;
971 if (asiw.dwScale == 0)
972 return -1;
974 if (asiw.dwRate / asiw.dwScale < 1000)
975 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
976 else
977 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
979 /* limit to stream bounds */
980 if (sample < asiw.dwStart)
981 sample = asiw.dwStart;
982 if (sample > asiw.dwStart + asiw.dwLength)
983 sample = asiw.dwStart + asiw.dwLength;
985 TRACE(" -> %ld\n", sample);
986 return sample;
989 /***********************************************************************
990 * AVIBuildFilter (AVIFIL32.@)
991 * AVIBuildFilterA (AVIFIL32.@)
992 * AVIBuildFilter (AVIFILE.123)
994 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
996 LPWSTR wszFilter;
997 HRESULT hr;
999 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1001 /* check parameters */
1002 if (szFilter == NULL)
1003 return AVIERR_BADPARAM;
1004 if (cbFilter < 2)
1005 return AVIERR_BADSIZE;
1007 szFilter[0] = 0;
1008 szFilter[1] = 0;
1010 wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter * sizeof(WCHAR));
1011 if (wszFilter == NULL)
1012 return AVIERR_MEMORY;
1014 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
1015 if (SUCCEEDED(hr)) {
1016 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
1017 szFilter, cbFilter, NULL, NULL);
1020 GlobalFreePtr(wszFilter);
1022 return hr;
1025 /***********************************************************************
1026 * AVIBuildFilterW (AVIFIL32.@)
1028 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
1030 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
1031 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1032 static const WCHAR szAVIFileExtensions[] =
1033 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1035 AVIFilter *lp;
1036 WCHAR szAllFiles[40];
1037 WCHAR szFileExt[10];
1038 WCHAR szValue[128];
1039 HKEY hKey;
1040 DWORD n, i;
1041 LONG size;
1042 DWORD count = 0;
1044 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1046 /* check parameters */
1047 if (szFilter == NULL)
1048 return AVIERR_BADPARAM;
1049 if (cbFilter < 2)
1050 return AVIERR_BADSIZE;
1052 lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
1053 if (lp == NULL)
1054 return AVIERR_MEMORY;
1057 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1058 * extensions and CLSID's
1059 * 2. iterate over collected CLSID's and copy its description and its
1060 * extensions to szFilter if it fits
1062 * First filter is named "All multimedia files" and its filter is a
1063 * collection of all possible extensions except "*.*".
1065 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
1066 GlobalFreePtr(lp);
1067 return AVIERR_ERROR;
1069 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
1070 /* get CLSID to extension */
1071 size = sizeof(szValue)/sizeof(szValue[0]);
1072 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
1073 break;
1075 /* search if the CLSID is already known */
1076 for (i = 1; i <= count; i++) {
1077 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
1078 break; /* a new one */
1081 if (count - i == -1U) {
1082 /* it's a new CLSID */
1084 /* FIXME: How do we get info's about read/write capabilities? */
1086 if (count >= MAX_FILTERS) {
1087 /* try to inform user of our full fixed size table */
1088 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1089 break;
1092 lstrcpyW(lp[i].szClsid, szValue);
1094 count++;
1097 /* append extension to the filter */
1098 wsprintfW(szValue, szExtensionFmt, szFileExt);
1099 if (lp[i].szExtensions[0] == 0)
1100 lstrcatW(lp[i].szExtensions, szValue + 1);
1101 else
1102 lstrcatW(lp[i].szExtensions, szValue);
1104 /* also append to the "all multimedia"-filter */
1105 if (lp[0].szExtensions[0] == 0)
1106 lstrcatW(lp[0].szExtensions, szValue + 1);
1107 else
1108 lstrcatW(lp[0].szExtensions, szValue);
1110 RegCloseKey(hKey);
1112 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1113 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1114 GlobalFreePtr(lp);
1115 return AVIERR_ERROR;
1117 for (n = 0; n <= count; n++) {
1118 /* first the description */
1119 if (n != 0) {
1120 size = sizeof(szValue)/sizeof(szValue[0]);
1121 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1122 size = lstrlenW(szValue);
1123 lstrcpynW(szFilter, szValue, cbFilter);
1125 } else
1126 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1128 /* check for enough space */
1129 size++;
1130 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1131 szFilter[0] = 0;
1132 szFilter[1] = 0;
1133 GlobalFreePtr(lp);
1134 RegCloseKey(hKey);
1135 return AVIERR_BUFFERTOOSMALL;
1137 cbFilter -= size;
1138 szFilter += size;
1140 /* and then the filter */
1141 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1142 size = lstrlenW(lp[n].szExtensions) + 1;
1143 cbFilter -= size;
1144 szFilter += size;
1147 RegCloseKey(hKey);
1148 GlobalFreePtr(lp);
1150 /* add "All files" "*.*" filter if enough space left */
1151 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1152 szAllFiles, sizeof(szAllFiles)) + 1;
1153 if (cbFilter > size) {
1154 int i;
1156 /* replace '@' with \000 to separate description of filter */
1157 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1158 if (szAllFiles[i] == '@') {
1159 szAllFiles[i] = 0;
1160 break;
1164 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1165 szFilter += size;
1166 szFilter[0] = 0;
1168 return AVIERR_OK;
1169 } else {
1170 szFilter[0] = 0;
1171 return AVIERR_BUFFERTOOSMALL;
1175 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1177 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1178 AVISTREAMINFOW sInfo;
1180 TRACE("(%p)\n", hWnd);
1182 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1183 ERR(": bad state!\n");
1184 return FALSE;
1187 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1188 &sInfo, sizeof(sInfo)))) {
1189 ERR(": AVIStreamInfoW failed!\n");
1190 return FALSE;
1193 if (sInfo.fccType == streamtypeVIDEO) {
1194 COMPVARS cv;
1195 BOOL ret;
1197 memset(&cv, 0, sizeof(cv));
1199 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1200 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1201 pOptions->fccType = streamtypeVIDEO;
1202 pOptions->fccHandler = comptypeDIB;
1203 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1206 cv.cbSize = sizeof(cv);
1207 cv.dwFlags = ICMF_COMPVARS_VALID;
1208 /*cv.fccType = pOptions->fccType; */
1209 cv.fccHandler = pOptions->fccHandler;
1210 cv.lQ = pOptions->dwQuality;
1211 cv.lpState = pOptions->lpParms;
1212 cv.cbState = pOptions->cbParms;
1213 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1214 cv.lKey = pOptions->dwKeyFrameEvery;
1215 else
1216 cv.lKey = 0;
1217 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1218 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1219 else
1220 cv.lDataRate = 0;
1222 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1223 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1225 if (ret) {
1226 pOptions->fccHandler = cv.fccHandler;
1227 pOptions->lpParms = cv.lpState;
1228 pOptions->cbParms = cv.cbState;
1229 pOptions->dwQuality = cv.lQ;
1230 if (cv.lKey != 0) {
1231 pOptions->dwKeyFrameEvery = cv.lKey;
1232 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1233 } else
1234 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1235 if (cv.lDataRate != 0) {
1236 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1237 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1238 } else
1239 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1240 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1242 ICCompressorFree(&cv);
1244 return ret;
1245 } else if (sInfo.fccType == streamtypeAUDIO) {
1246 ACMFORMATCHOOSEW afmtc;
1247 MMRESULT ret;
1248 LONG size;
1250 /* FIXME: check ACM version -- Which version is needed? */
1252 memset(&afmtc, 0, sizeof(afmtc));
1253 afmtc.cbStruct = sizeof(afmtc);
1254 afmtc.fdwStyle = 0;
1255 afmtc.hwndOwner = hWnd;
1257 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1258 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1259 pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1260 pOptions->cbFormat = size;
1261 } else if (pOptions->cbFormat < (DWORD)size) {
1262 pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1263 pOptions->cbFormat = size;
1265 if (pOptions->lpFormat == NULL)
1266 return FALSE;
1267 afmtc.pwfx = pOptions->lpFormat;
1268 afmtc.cbwfx = pOptions->cbFormat;
1270 size = 0;
1271 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1272 sInfo.dwStart, &size);
1273 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1274 size = sizeof(PCMWAVEFORMAT);
1275 afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1276 if (afmtc.pwfxEnum != NULL) {
1277 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1278 sInfo.dwStart, afmtc.pwfxEnum, &size);
1279 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1282 ret = acmFormatChooseW(&afmtc);
1283 if (ret == S_OK)
1284 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1286 if (afmtc.pwfxEnum != NULL)
1287 GlobalFreePtr(afmtc.pwfxEnum);
1289 return (ret == S_OK ? TRUE : FALSE);
1290 } else {
1291 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1292 return FALSE;
1296 static void AVISaveOptionsUpdate(HWND hWnd)
1298 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1299 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1301 WCHAR szFormat[128];
1302 AVISTREAMINFOW sInfo;
1303 LPVOID lpFormat;
1304 LONG size;
1306 TRACE("(%p)\n", hWnd);
1308 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1309 if (SaveOpts.nCurrent < 0)
1310 return;
1312 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1313 return;
1315 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1316 if (size > 0) {
1317 szFormat[0] = 0;
1319 /* read format to build format description string */
1320 lpFormat = GlobalAllocPtr(GHND, size);
1321 if (lpFormat != NULL) {
1322 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1323 if (sInfo.fccType == streamtypeVIDEO) {
1324 LPBITMAPINFOHEADER lpbi = lpFormat;
1325 ICINFO icinfo;
1327 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1328 lpbi->biHeight, lpbi->biBitCount);
1330 if (lpbi->biCompression != BI_RGB) {
1331 HIC hic;
1333 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1334 NULL, ICMODE_DECOMPRESS);
1335 if (hic != NULL) {
1336 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1337 lstrcatW(szFormat, icinfo.szDescription);
1338 ICClose(hic);
1340 } else {
1341 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1342 icinfo.szDescription, sizeof(icinfo.szDescription));
1343 lstrcatW(szFormat, icinfo.szDescription);
1345 } else if (sInfo.fccType == streamtypeAUDIO) {
1346 ACMFORMATTAGDETAILSW aftd;
1347 ACMFORMATDETAILSW afd;
1349 memset(&aftd, 0, sizeof(aftd));
1350 memset(&afd, 0, sizeof(afd));
1352 aftd.cbStruct = sizeof(aftd);
1353 aftd.dwFormatTag = afd.dwFormatTag =
1354 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1355 aftd.cbFormatSize = afd.cbwfx = size;
1357 afd.cbStruct = sizeof(afd);
1358 afd.pwfx = lpFormat;
1360 if (acmFormatTagDetailsW(NULL, &aftd,
1361 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1362 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1363 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1367 GlobalFreePtr(lpFormat);
1370 /* set text for format description */
1371 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1373 /* Disable option button for unsupported streamtypes */
1374 if (sInfo.fccType == streamtypeVIDEO ||
1375 sInfo.fccType == streamtypeAUDIO)
1376 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1377 else
1378 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1383 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1384 WPARAM wParam, LPARAM lParam)
1386 DWORD dwInterleave;
1387 BOOL bIsInterleaved;
1388 INT n;
1390 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1392 switch (uMsg) {
1393 case WM_INITDIALOG:
1394 SaveOpts.nCurrent = 0;
1395 if (SaveOpts.nStreams == 1) {
1396 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1397 return TRUE;
1400 /* add streams */
1401 for (n = 0; n < SaveOpts.nStreams; n++) {
1402 AVISTREAMINFOW sInfo;
1404 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1405 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1406 0L, (LPARAM)sInfo.szName);
1409 /* select first stream */
1410 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1411 SendMessageW(hWnd, WM_COMMAND,
1412 GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1414 /* initialize interleave */
1415 if (SaveOpts.ppOptions[0] != NULL &&
1416 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1417 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1418 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1419 } else {
1420 bIsInterleaved = TRUE;
1421 dwInterleave = 0;
1423 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1424 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1425 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1426 break;
1427 case WM_COMMAND:
1428 switch (GET_WM_COMMAND_ID(wParam, lParam)) {
1429 case IDOK:
1430 /* get data from controls and save them */
1431 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1432 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1433 for (n = 0; n < SaveOpts.nStreams; n++) {
1434 if (SaveOpts.ppOptions[n] != NULL) {
1435 if (bIsInterleaved) {
1436 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1437 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1438 } else
1439 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1442 /* fall through */
1443 case IDCANCEL:
1444 EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
1445 break;
1446 case IDC_INTERLEAVE:
1447 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1448 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1449 break;
1450 case IDC_STREAM:
1451 if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1452 /* update control elements */
1453 AVISaveOptionsUpdate(hWnd);
1455 break;
1456 case IDC_OPTIONS:
1457 AVISaveOptionsFmtChoose(hWnd);
1458 break;
1460 return TRUE;
1463 return FALSE;
1466 /***********************************************************************
1467 * AVISaveOptions (AVIFIL32.@)
1469 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1470 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1472 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1473 INT ret, n;
1475 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1476 ppavi, ppOptions);
1478 /* check parameters */
1479 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1480 return AVIERR_BADPARAM;
1482 /* save options in case the user presses cancel */
1483 if (ppOptions != NULL && nStreams > 1) {
1484 pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1485 if (pSavedOptions == NULL)
1486 return FALSE;
1488 for (n = 0; n < nStreams; n++) {
1489 if (ppOptions[n] != NULL)
1490 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1494 SaveOpts.uFlags = uFlags;
1495 SaveOpts.nStreams = nStreams;
1496 SaveOpts.ppavis = ppavi;
1497 SaveOpts.ppOptions = ppOptions;
1499 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1500 hWnd, AVISaveOptionsDlgProc);
1502 if (ret == -1)
1503 ret = FALSE;
1505 /* restore options when user pressed cancel */
1506 if (pSavedOptions != NULL) {
1507 if (ret == FALSE) {
1508 for (n = 0; n < nStreams; n++) {
1509 if (ppOptions[n] != NULL)
1510 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1513 GlobalFreePtr(pSavedOptions);
1516 return (BOOL)ret;
1519 /***********************************************************************
1520 * AVISaveOptionsFree (AVIFIL32.@)
1521 * AVISaveOptionsFree (AVIFILE.124)
1523 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1525 TRACE("(%d,%p)\n", nStreams, ppOptions);
1527 if (nStreams < 0 || ppOptions == NULL)
1528 return AVIERR_BADPARAM;
1530 for (; nStreams > 0; nStreams--) {
1531 if (ppOptions[nStreams] != NULL) {
1532 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1534 if (ppOptions[nStreams]->lpParms != NULL) {
1535 GlobalFreePtr(ppOptions[nStreams]->lpParms);
1536 ppOptions[nStreams]->lpParms = NULL;
1537 ppOptions[nStreams]->cbParms = 0;
1539 if (ppOptions[nStreams]->lpFormat != NULL) {
1540 GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1541 ppOptions[nStreams]->lpFormat = NULL;
1542 ppOptions[nStreams]->cbFormat = 0;
1547 return AVIERR_OK;
1550 /***********************************************************************
1551 * AVISaveVA (AVIFIL32.@)
1553 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1554 AVISAVECALLBACK lpfnCallback, int nStream,
1555 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1557 LPWSTR wszFile = NULL;
1558 HRESULT hr;
1559 int len;
1561 TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1562 lpfnCallback, nStream, ppavi, plpOptions);
1564 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1565 return AVIERR_BADPARAM;
1567 /* convert ASCII string to Unicode and call Unicode function */
1568 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1569 if (len <= 0)
1570 return AVIERR_BADPARAM;
1572 wszFile = LocalAlloc(LPTR, len * sizeof(WCHAR));
1573 if (wszFile == NULL)
1574 return AVIERR_MEMORY;
1576 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
1578 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1579 nStream, ppavi, plpOptions);
1581 LocalFree((HLOCAL)wszFile);
1583 return hr;
1586 /***********************************************************************
1587 * AVIFILE_AVISaveDefaultCallback (internal)
1589 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1591 TRACE("(%d)\n", progress);
1593 return FALSE;
1596 /***********************************************************************
1597 * AVISaveVW (AVIFIL32.@)
1599 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1600 AVISAVECALLBACK lpfnCallback, int nStreams,
1601 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1603 LONG lStart[MAX_AVISTREAMS];
1604 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1605 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1606 AVIFILEINFOW fInfo;
1607 AVISTREAMINFOW sInfo;
1609 PAVIFILE pfile = NULL; /* the output AVI file */
1610 LONG lFirstVideo = -1;
1611 int curStream;
1613 /* for interleaving ... */
1614 DWORD dwInterleave = 0; /* interleave rate */
1615 DWORD dwFileInitialFrames;
1616 LONG lFileLength;
1617 LONG lSampleInc;
1619 /* for reading/writing the data ... */
1620 LPVOID lpBuffer = NULL;
1621 LONG cbBuffer; /* real size of lpBuffer */
1622 LONG lBufferSize; /* needed bytes for format(s), etc. */
1623 LONG lReadBytes;
1624 LONG lReadSamples;
1625 HRESULT hres;
1627 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1628 lpfnCallback, nStreams, ppavi, plpOptions);
1630 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1631 return AVIERR_BADPARAM;
1632 if (nStreams >= MAX_AVISTREAMS) {
1633 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1634 return AVIERR_INTERNAL;
1637 if (lpfnCallback == NULL)
1638 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1640 /* clear local variable(s) */
1641 for (curStream = 0; curStream < nStreams; curStream++) {
1642 pInStreams[curStream] = NULL;
1643 pOutStreams[curStream] = NULL;
1646 /* open output AVI file (create it if it doesn't exist) */
1647 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1648 pclsidHandler);
1649 if (FAILED(hres))
1650 return hres;
1651 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1653 /* initialize our data structures part 1 */
1654 for (curStream = 0; curStream < nStreams; curStream++) {
1655 PAVISTREAM pCurStream = ppavi[curStream];
1657 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1658 if (FAILED(hres))
1659 goto error;
1661 /* search first video stream and check for interleaving */
1662 if (sInfo.fccType == streamtypeVIDEO) {
1663 /* remember first video stream -- needed for interleaving */
1664 if (lFirstVideo < 0)
1665 lFirstVideo = curStream;
1666 } else if (!dwInterleave && plpOptions != NULL) {
1667 /* check if any non-video stream wants to be interleaved */
1668 WARN("options.flags=0x%lX options.dwInterleave=%lu\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1669 if (plpOptions[curStream] != NULL &&
1670 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1671 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1674 /* create de-/compressed stream interface if needed */
1675 pInStreams[curStream] = NULL;
1676 if (plpOptions != NULL && plpOptions[curStream] != NULL) {
1677 if (plpOptions[curStream]->fccHandler ||
1678 plpOptions[curStream]->lpFormat != NULL) {
1679 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1681 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1682 plpOptions[curStream]->dwKeyFrameEvery = 1;
1684 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1685 plpOptions[curStream], NULL);
1686 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1687 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1688 pInStreams[curStream] = NULL;
1689 goto error;
1692 /* test stream interface and update stream-info */
1693 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1694 if (FAILED(hres))
1695 goto error;
1699 /* now handle streams which will only be copied */
1700 if (pInStreams[curStream] == NULL) {
1701 pCurStream = pInStreams[curStream] = ppavi[curStream];
1702 AVIStreamAddRef(pCurStream);
1703 } else
1704 pCurStream = pInStreams[curStream];
1706 lStart[curStream] = sInfo.dwStart;
1707 } /* for all streams */
1709 /* check that first video stream is the first stream */
1710 if (lFirstVideo > 0) {
1711 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1712 LONG lTmp = lStart[lFirstVideo];
1714 pInStreams[lFirstVideo] = pInStreams[0];
1715 pInStreams[0] = pTmp;
1716 lStart[lFirstVideo] = lStart[0];
1717 lStart[0] = lTmp;
1718 lFirstVideo = 0;
1721 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
1722 lpBuffer = GlobalAllocPtr(GPTR, cbBuffer = 0x00010000);
1723 if (lpBuffer == NULL) {
1724 hres = AVIERR_MEMORY;
1725 goto error;
1728 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
1729 lFileLength = sInfo.dwLength;
1730 dwFileInitialFrames = 0;
1731 if (lFirstVideo >= 0) {
1732 /* check for correct version of the format
1733 * -- need at least BITMAPINFOHEADER or newer
1735 lSampleInc = 1;
1736 lBufferSize = cbBuffer;
1737 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
1738 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
1739 hres = AVIERR_INTERNAL;
1740 if (FAILED(hres))
1741 goto error;
1742 } else /* use one second blocks for interleaving if no video present */
1743 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
1745 /* create output streams */
1746 for (curStream = 0; curStream < nStreams; curStream++) {
1747 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1749 sInfo.dwInitialFrames = 0;
1750 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
1751 /* 750 ms initial frames for non-video streams */
1752 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
1755 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
1756 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
1757 /* copy initial format for this stream */
1758 lBufferSize = cbBuffer;
1759 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1760 lpBuffer, &lBufferSize);
1761 if (FAILED(hres))
1762 goto error;
1763 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
1764 if (FAILED(hres))
1765 goto error;
1767 /* try to copy stream handler data */
1768 lBufferSize = cbBuffer;
1769 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
1770 lpBuffer, &lBufferSize);
1771 if (SUCCEEDED(hres) && lBufferSize > 0) {
1772 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
1773 lpBuffer, lBufferSize);
1774 if (FAILED(hres))
1775 goto error;
1778 if (dwFileInitialFrames < sInfo.dwInitialFrames)
1779 dwFileInitialFrames = sInfo.dwInitialFrames;
1780 lReadBytes =
1781 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
1782 sInfo.dwLength);
1783 if (lFileLength < lReadBytes)
1784 lFileLength = lReadBytes;
1785 } else {
1786 /* creation of de-/compression stream interface failed */
1787 WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
1788 AVIStreamRelease(pInStreams[curStream]);
1789 if (curStream + 1 >= nStreams) {
1790 /* move the others one up */
1791 PAVISTREAM *ppas = &pInStreams[curStream];
1792 int n = nStreams - (curStream + 1);
1794 do {
1795 *ppas = pInStreams[curStream + 1];
1796 } while (--n);
1798 nStreams--;
1799 curStream--;
1801 } /* create output streams for all input streams */
1803 /* have we still something to write, or lost everything? */
1804 if (nStreams <= 0)
1805 goto error;
1807 if (dwInterleave) {
1808 LONG lCurFrame = -dwFileInitialFrames;
1810 /* interleaved file */
1811 if (dwInterleave == 1)
1812 AVIFileEndRecord(pfile);
1814 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
1815 for (curStream = 0; curStream < nStreams; curStream++) {
1816 LONG lLastSample;
1818 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
1819 if (FAILED(hres))
1820 goto error;
1822 /* initial frames phase at the end for this stream? */
1823 if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
1824 continue;
1826 if ((lFileLength - lSampleInc) <= lCurFrame) {
1827 lLastSample = AVIStreamLength(pInStreams[curStream]);
1828 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
1829 } else {
1830 if (curStream != 0) {
1831 lFirstVideo =
1832 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
1833 (sInfo.fccType == streamtypeVIDEO ?
1834 (LONG)dwInterleave : lSampleInc) +
1835 sInfo.dwInitialFrames + lCurFrame);
1836 } else
1837 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
1839 lLastSample = AVIStreamEnd(pInStreams[curStream]);
1840 if (lLastSample <= lFirstVideo)
1841 lFirstVideo = lLastSample;
1844 /* copy needed samples now */
1845 WARN("copy from stream %d samples %ld to %ld...\n",curStream,
1846 lStart[curStream],lFirstVideo);
1847 while (lFirstVideo > lStart[curStream]) {
1848 DWORD flags = 0;
1850 /* copy format in case it can change */
1851 lBufferSize = cbBuffer;
1852 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
1853 lpBuffer, &lBufferSize);
1854 if (FAILED(hres))
1855 goto error;
1856 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
1857 lpBuffer, lBufferSize);
1859 /* try to read data until we got it, or error */
1860 do {
1861 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
1862 lFirstVideo - lStart[curStream], lpBuffer,
1863 cbBuffer, &lReadBytes, &lReadSamples);
1864 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1865 (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
1866 if (lpBuffer == NULL)
1867 hres = AVIERR_MEMORY;
1868 if (FAILED(hres))
1869 goto error;
1871 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1872 flags = AVIIF_KEYFRAME;
1873 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1874 lpBuffer, lReadBytes, flags, NULL, NULL);
1875 if (FAILED(hres))
1876 goto error;
1878 lStart[curStream] += lReadSamples;
1880 lStart[curStream] = lFirstVideo;
1881 } /* stream by stream */
1883 /* need to close this block? */
1884 if (dwInterleave == 1) {
1885 hres = AVIFileEndRecord(pfile);
1886 if (FAILED(hres))
1887 break;
1890 /* show progress */
1891 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
1892 dwFileInitialFrames + lFileLength))) {
1893 hres = AVIERR_USERABORT;
1894 break;
1896 } /* copy frame by frame */
1897 } else {
1898 /* non-interleaved file */
1900 for (curStream = 0; curStream < nStreams; curStream++) {
1901 /* show progress */
1902 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
1903 hres = AVIERR_USERABORT;
1904 goto error;
1907 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1909 if (sInfo.dwSampleSize != 0) {
1910 /* sample-based data like audio */
1911 while (sInfo.dwStart < sInfo.dwLength) {
1912 LONG lSamples = cbBuffer / sInfo.dwSampleSize;
1914 /* copy format in case it can change */
1915 lBufferSize = cbBuffer;
1916 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1917 lpBuffer, &lBufferSize);
1918 if (FAILED(hres))
1919 return hres;
1920 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1921 lpBuffer, lBufferSize);
1923 /* limit to stream boundaries */
1924 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
1925 lSamples = sInfo.dwLength - sInfo.dwStart;
1927 /* now try to read until we get it, or an error occurs */
1928 do {
1929 lReadBytes = cbBuffer;
1930 lReadSamples = 0;
1931 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
1932 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
1933 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1934 (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
1935 if (lpBuffer == NULL)
1936 hres = AVIERR_MEMORY;
1937 if (FAILED(hres))
1938 goto error;
1939 if (lReadSamples != 0) {
1940 sInfo.dwStart += lReadSamples;
1941 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1942 lpBuffer, lReadBytes, 0, NULL , NULL);
1943 if (FAILED(hres))
1944 goto error;
1946 /* show progress */
1947 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1948 MulDiv(curStream, 100, nStreams))) {
1949 hres = AVIERR_USERABORT;
1950 goto error;
1952 } else {
1953 if ((sInfo.dwLength - sInfo.dwStart) != 1) {
1954 hres = AVIERR_FILEREAD;
1955 goto error;
1959 } else {
1960 /* block-based data like video */
1961 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
1962 DWORD flags = 0;
1964 /* copy format in case it can change */
1965 lBufferSize = cbBuffer;
1966 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1967 lpBuffer, &lBufferSize);
1968 if (FAILED(hres))
1969 goto error;
1970 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1971 lpBuffer, lBufferSize);
1973 /* try to read block and resize buffer if necessary */
1974 do {
1975 lReadSamples = 0;
1976 lReadBytes = cbBuffer;
1977 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
1978 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
1979 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1980 (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
1981 if (lpBuffer == NULL)
1982 hres = AVIERR_MEMORY;
1983 if (FAILED(hres))
1984 goto error;
1985 if (lReadSamples != 1) {
1986 hres = AVIERR_FILEREAD;
1987 goto error;
1990 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1991 flags = AVIIF_KEYFRAME;
1992 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1993 lpBuffer, lReadBytes, flags, NULL, NULL);
1994 if (FAILED(hres))
1995 goto error;
1997 /* show progress */
1998 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1999 MulDiv(curStream, 100, nStreams))) {
2000 hres = AVIERR_USERABORT;
2001 goto error;
2003 } /* copy all blocks */
2005 } /* copy data stream by stream */
2008 error:
2009 if (lpBuffer != NULL)
2010 GlobalFreePtr(lpBuffer);
2011 if (pfile != NULL) {
2012 for (curStream = 0; curStream < nStreams; curStream++) {
2013 if (pOutStreams[curStream] != NULL)
2014 AVIStreamRelease(pOutStreams[curStream]);
2015 if (pInStreams[curStream] != NULL)
2016 AVIStreamRelease(pInStreams[curStream]);
2019 AVIFileRelease(pfile);
2022 return hres;
2025 /***********************************************************************
2026 * CreateEditableStream (AVIFIL32.@)
2028 HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
2030 IAVIEditStream *pEdit = NULL;
2031 HRESULT hr;
2033 TRACE("(%p,%p)\n", ppEditable, pSource);
2035 if (ppEditable == NULL)
2036 return AVIERR_BADPARAM;
2038 *ppEditable = NULL;
2040 if (pSource != NULL) {
2041 hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream,
2042 (LPVOID*)&pEdit);
2043 if (SUCCEEDED(hr) && pEdit != NULL) {
2044 hr = IAVIEditStream_Clone(pEdit, ppEditable);
2045 IAVIEditStream_Release(pEdit);
2047 return hr;
2051 /* need own implementation of IAVIEditStream */
2052 pEdit = AVIFILE_CreateEditStream(pSource);
2053 if (pEdit == NULL)
2054 return AVIERR_MEMORY;
2056 hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream,
2057 (LPVOID*)ppEditable);
2058 IAVIEditStream_Release(pEdit);
2060 return hr;
2063 /***********************************************************************
2064 * EditStreamClone (AVIFIL32.@)
2066 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
2068 PAVIEDITSTREAM pEdit = NULL;
2069 HRESULT hr;
2071 TRACE("(%p,%p)\n", pStream, ppResult);
2073 if (pStream == NULL)
2074 return AVIERR_BADHANDLE;
2075 if (ppResult == NULL)
2076 return AVIERR_BADPARAM;
2078 *ppResult = NULL;
2080 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2081 if (SUCCEEDED(hr) && pEdit != NULL) {
2082 hr = IAVIEditStream_Clone(pEdit, ppResult);
2084 IAVIEditStream_Release(pEdit);
2085 } else
2086 hr = AVIERR_UNSUPPORTED;
2088 return hr;
2091 /***********************************************************************
2092 * EditStreamCopy (AVIFIL32.@)
2094 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2095 LONG *plLength, PAVISTREAM *ppResult)
2097 PAVIEDITSTREAM pEdit = NULL;
2098 HRESULT hr;
2100 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2102 if (pStream == NULL)
2103 return AVIERR_BADHANDLE;
2104 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2105 return AVIERR_BADPARAM;
2107 *ppResult = NULL;
2109 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2110 if (SUCCEEDED(hr) && pEdit != NULL) {
2111 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2113 IAVIEditStream_Release(pEdit);
2114 } else
2115 hr = AVIERR_UNSUPPORTED;
2117 return hr;
2120 /***********************************************************************
2121 * EditStreamCut (AVIFIL32.@)
2123 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2124 LONG *plLength, PAVISTREAM *ppResult)
2126 PAVIEDITSTREAM pEdit = NULL;
2127 HRESULT hr;
2129 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2131 if (ppResult != NULL)
2132 *ppResult = NULL;
2133 if (pStream == NULL)
2134 return AVIERR_BADHANDLE;
2135 if (plStart == NULL || plLength == NULL)
2136 return AVIERR_BADPARAM;
2138 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2139 if (SUCCEEDED(hr) && pEdit != NULL) {
2140 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2142 IAVIEditStream_Release(pEdit);
2143 } else
2144 hr = AVIERR_UNSUPPORTED;
2146 return hr;
2149 /***********************************************************************
2150 * EditStreamPaste (AVIFIL32.@)
2152 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2153 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2155 PAVIEDITSTREAM pEdit = NULL;
2156 HRESULT hr;
2158 TRACE("(%p,%p,%p,%p,%ld,%ld)\n", pDest, plStart, plLength,
2159 pSource, lStart, lEnd);
2161 if (pDest == NULL || pSource == NULL)
2162 return AVIERR_BADHANDLE;
2163 if (plStart == NULL || plLength == NULL || lStart < 0)
2164 return AVIERR_BADPARAM;
2166 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2167 if (SUCCEEDED(hr) && pEdit != NULL) {
2168 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2170 IAVIEditStream_Release(pEdit);
2171 } else
2172 hr = AVIERR_UNSUPPORTED;
2174 return hr;
2177 /***********************************************************************
2178 * EditStreamSetInfoA (AVIFIL32.@)
2180 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2181 LONG size)
2183 AVISTREAMINFOW asiw;
2185 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2187 if (pstream == NULL)
2188 return AVIERR_BADHANDLE;
2189 if ((DWORD)size < sizeof(AVISTREAMINFOA))
2190 return AVIERR_BADSIZE;
2192 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2193 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
2194 asiw.szName, sizeof(asiw.szName));
2196 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2199 /***********************************************************************
2200 * EditStreamSetInfoW (AVIFIL32.@)
2202 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2203 LONG size)
2205 PAVIEDITSTREAM pEdit = NULL;
2206 HRESULT hr;
2208 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2210 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2211 if (SUCCEEDED(hr) && pEdit != NULL) {
2212 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2214 IAVIEditStream_Release(pEdit);
2215 } else
2216 hr = AVIERR_UNSUPPORTED;
2218 return hr;
2221 /***********************************************************************
2222 * EditStreamSetNameA (AVIFIL32.@)
2224 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2226 AVISTREAMINFOA asia;
2227 HRESULT hres;
2229 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2231 if (pstream == NULL)
2232 return AVIERR_BADHANDLE;
2233 if (szName == NULL)
2234 return AVIERR_BADPARAM;
2236 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2237 if (FAILED(hres))
2238 return hres;
2240 memset(asia.szName, 0, sizeof(asia.szName));
2241 lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
2243 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2246 /***********************************************************************
2247 * EditStreamSetNameW (AVIFIL32.@)
2249 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2251 AVISTREAMINFOW asiw;
2252 HRESULT hres;
2254 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2256 if (pstream == NULL)
2257 return AVIERR_BADHANDLE;
2258 if (szName == NULL)
2259 return AVIERR_BADPARAM;
2261 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2262 if (FAILED(hres))
2263 return hres;
2265 memset(asiw.szName, 0, sizeof(asiw.szName));
2266 lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
2268 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2271 /***********************************************************************
2272 * AVIClearClipboard (AVIFIL32.@)
2274 HRESULT WINAPI AVIClearClipboard(void)
2276 TRACE("()\n");
2278 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2281 /***********************************************************************
2282 * AVIGetFromClipboard (AVIFIL32.@)
2284 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2286 FIXME("(%p), stub!\n", ppfile);
2288 *ppfile = NULL;
2290 return AVIERR_UNSUPPORTED;
2293 /***********************************************************************
2294 * AVIMakeStreamFromClipboard (AVIFIL32.@)
2296 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
2297 PAVISTREAM * ppstream)
2299 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
2301 if (ppstream == NULL)
2302 return AVIERR_BADHANDLE;
2304 return AVIERR_UNSUPPORTED;
2307 /***********************************************************************
2308 * AVIPutFileOnClipboard (AVIFIL32.@)
2310 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2312 FIXME("(%p), stub!\n", pfile);
2314 if (pfile == NULL)
2315 return AVIERR_BADHANDLE;
2317 return AVIERR_UNSUPPORTED;
2320 HRESULT CDECL AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2321 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2323 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
2324 nStreams, pavi, lpOptions);
2326 return AVIERR_UNSUPPORTED;
2329 HRESULT CDECL AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2330 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2332 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
2333 nStreams, pavi, lpOptions);
2335 return AVIERR_UNSUPPORTED;