Release 0.9.14.
[wine/multimedia.git] / dlls / avifil32 / api.c
blobc53b7241c52a2a37c71bc2cfb24031046f8a7e08
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 <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"
34 #include "ole2.h"
35 #include "shellapi.h"
36 #include "shlobj.h"
37 #include "vfw.h"
38 #include "msacm.h"
40 #include "avifile_private.h"
42 #include "wine/debug.h"
43 #include "wine/unicode.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
48 /***********************************************************************
49 * for AVIBuildFilterW -- uses fixed size table
51 #define MAX_FILTERS 30 /* 30 => 7kB */
53 typedef struct _AVIFilter {
54 WCHAR szClsid[40];
55 WCHAR szExtensions[MAX_FILTERS * 7];
56 } AVIFilter;
58 /***********************************************************************
59 * for AVISaveOptions
61 static struct {
62 UINT uFlags;
63 INT nStreams;
64 PAVISTREAM *ppavis;
65 LPAVICOMPRESSOPTIONS *ppOptions;
66 INT nCurrent;
67 } SaveOpts;
69 /***********************************************************************
70 * copied from dlls/ole32/compobj.c
72 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
74 BYTE const *s;
75 BYTE *p;
76 INT i;
77 BYTE table[256];
79 if (!idstr) {
80 memset(id, 0, sizeof(CLSID));
81 return S_OK;
84 /* validate the CLSID string */
85 if (lstrlenA(idstr) != 38)
86 return CO_E_CLASSSTRING;
88 s = (BYTE const*)idstr;
89 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
90 (s[24]!='-') || (s[37]!='}'))
91 return CO_E_CLASSSTRING;
93 for (i = 1; i < 37; i++) {
94 if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
95 continue;
96 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
97 ((s[i] >= 'a') && (s[i] <= 'f')) ||
98 ((s[i] >= 'A') && (s[i] <= 'F')))
100 return CO_E_CLASSSTRING;
103 TRACE("%s -> %p\n", s, id);
105 /* quick lookup table */
106 memset(table, 0, 256);
108 for (i = 0; i < 10; i++)
109 table['0' + i] = i;
111 for (i = 0; i < 6; i++) {
112 table['A' + i] = i+10;
113 table['a' + i] = i+10;
116 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
117 p = (BYTE *) id;
119 s++; /* skip leading brace */
120 for (i = 0; i < 4; i++) {
121 p[3 - i] = table[*s]<<4 | table[*(s+1)];
122 s += 2;
124 p += 4;
125 s++; /* skip - */
127 for (i = 0; i < 2; i++) {
128 p[1-i] = table[*s]<<4 | table[*(s+1)];
129 s += 2;
131 p += 2;
132 s++; /* skip - */
134 for (i = 0; i < 2; i++) {
135 p[1-i] = table[*s]<<4 | table[*(s+1)];
136 s += 2;
138 p += 2;
139 s++; /* skip - */
141 /* these are just sequential bytes */
142 for (i = 0; i < 2; i++) {
143 *p++ = table[*s]<<4 | table[*(s+1)];
144 s += 2;
146 s++; /* skip - */
148 for (i = 0; i < 6; i++) {
149 *p++ = table[*s]<<4 | table[*(s+1)];
150 s += 2;
153 return S_OK;
156 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
158 CHAR szRegKey[25];
159 CHAR szValue[100];
160 LPWSTR szExt = strrchrW(szFile, '.');
161 LONG len = sizeof(szValue) / sizeof(szValue[0]);
163 if (szExt == NULL)
164 return FALSE;
166 szExt++;
168 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
169 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
170 return FALSE;
172 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
175 /***********************************************************************
176 * AVIFileInit (AVIFIL32.@)
177 * AVIFileInit (AVIFILE.100)
179 void WINAPI AVIFileInit(void) {
180 OleInitialize(NULL);
183 /***********************************************************************
184 * AVIFileExit (AVIFIL32.@)
185 * AVIFileExit (AVIFILE.101)
187 void WINAPI AVIFileExit(void) {
188 /* need to free ole32.dll if we are the last exit call */
189 /* OleUnitialize() */
190 FIXME("(): stub!\n");
193 /***********************************************************************
194 * AVIFileOpen (AVIFIL32.@)
195 * AVIFileOpenA (AVIFIL32.@)
196 * AVIFileOpen (AVIFILE.102)
198 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
199 LPCLSID lpHandler)
201 LPWSTR wszFile = NULL;
202 HRESULT hr;
203 int len;
205 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
206 debugstr_guid(lpHandler));
208 /* check parameters */
209 if (ppfile == NULL || szFile == NULL)
210 return AVIERR_BADPARAM;
212 /* convert ASCII string to Unicode and call unicode function */
213 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
214 if (len <= 0)
215 return AVIERR_BADPARAM;
217 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
218 if (wszFile == NULL)
219 return AVIERR_MEMORY;
221 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
223 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
225 HeapFree(GetProcessHeap(), 0, wszFile);
227 return hr;
230 /***********************************************************************
231 * AVIFileOpenW (AVIFIL32.@)
233 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
234 LPCLSID lpHandler)
236 IPersistFile *ppersist = NULL;
237 CLSID clsidHandler;
238 HRESULT hr;
240 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
241 debugstr_guid(lpHandler));
243 /* check parameters */
244 if (ppfile == NULL || szFile == NULL)
245 return AVIERR_BADPARAM;
247 *ppfile = NULL;
249 /* if no handler then try guessing it by extension */
250 if (lpHandler == NULL) {
251 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
252 return AVIERR_UNSUPPORTED;
253 } else
254 memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
256 /* create instance of handler */
257 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile);
258 if (FAILED(hr) || *ppfile == NULL)
259 return hr;
261 /* ask for IPersistFile interface for loading/creating the file */
262 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
263 if (FAILED(hr) || ppersist == NULL) {
264 IAVIFile_Release(*ppfile);
265 *ppfile = NULL;
266 return hr;
269 hr = IPersistFile_Load(ppersist, szFile, uMode);
270 IPersistFile_Release(ppersist);
271 if (FAILED(hr)) {
272 IAVIFile_Release(*ppfile);
273 *ppfile = NULL;
276 return hr;
279 /***********************************************************************
280 * AVIFileAddRef (AVIFIL32.@)
281 * AVIFileAddRef (AVIFILE.140)
283 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
285 TRACE("(%p)\n", pfile);
287 if (pfile == NULL) {
288 ERR(": bad handle passed!\n");
289 return 0;
292 return IAVIFile_AddRef(pfile);
295 /***********************************************************************
296 * AVIFileRelease (AVIFIL32.@)
297 * AVIFileRelease (AVIFILE.141)
299 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
301 TRACE("(%p)\n", pfile);
303 if (pfile == NULL) {
304 ERR(": bad handle passed!\n");
305 return 0;
308 return IAVIFile_Release(pfile);
311 /***********************************************************************
312 * AVIFileInfo (AVIFIL32.@)
313 * AVIFileInfoA (AVIFIL32.@)
314 * AVIFileInfo (AVIFILE.142)
316 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
318 AVIFILEINFOW afiw;
319 HRESULT hres;
321 TRACE("(%p,%p,%ld)\n", pfile, afi, size);
323 if (pfile == NULL)
324 return AVIERR_BADHANDLE;
325 if ((DWORD)size < sizeof(AVIFILEINFOA))
326 return AVIERR_BADSIZE;
328 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
330 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
331 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
332 sizeof(afi->szFileType), NULL, NULL);
333 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
335 return hres;
338 /***********************************************************************
339 * AVIFileInfoW (AVIFIL32.@)
341 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
343 TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
345 if (pfile == NULL)
346 return AVIERR_BADHANDLE;
348 return IAVIFile_Info(pfile, afiw, size);
351 /***********************************************************************
352 * AVIFileGetStream (AVIFIL32.@)
353 * AVIFileGetStream (AVIFILE.143)
355 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
356 DWORD fccType, LONG lParam)
358 TRACE("(%p,%p,'%4.4s',%ld)\n", pfile, avis, (char*)&fccType, lParam);
360 if (pfile == NULL)
361 return AVIERR_BADHANDLE;
363 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
366 /***********************************************************************
367 * AVIFileCreateStream (AVIFIL32.@)
368 * AVIFileCreateStreamA (AVIFIL32.@)
369 * AVIFileCreateStream (AVIFILE.144)
371 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
372 LPAVISTREAMINFOA psi)
374 AVISTREAMINFOW psiw;
376 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
378 if (pfile == NULL)
379 return AVIERR_BADHANDLE;
381 /* Only the szName at the end is different */
382 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
383 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
384 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
386 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
389 /***********************************************************************
390 * AVIFileCreateStreamW (AVIFIL32.@)
392 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
393 LPAVISTREAMINFOW asi)
395 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
397 if (pfile == NULL)
398 return AVIERR_BADHANDLE;
400 return IAVIFile_CreateStream(pfile, avis, asi);
403 /***********************************************************************
404 * AVIFileWriteData (AVIFIL32.@)
405 * AVIFileWriteData (AVIFILE.146)
407 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
409 TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
411 if (pfile == NULL)
412 return AVIERR_BADHANDLE;
414 return IAVIFile_WriteData(pfile, fcc, lp, size);
417 /***********************************************************************
418 * AVIFileReadData (AVIFIL32.@)
419 * AVIFileReadData (AVIFILE.147)
421 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
423 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
425 if (pfile == NULL)
426 return AVIERR_BADHANDLE;
428 return IAVIFile_ReadData(pfile, fcc, lp, size);
431 /***********************************************************************
432 * AVIFileEndRecord (AVIFIL32.@)
433 * AVIFileEndRecord (AVIFILE.148)
435 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
437 TRACE("(%p)\n", pfile);
439 if (pfile == NULL)
440 return AVIERR_BADHANDLE;
442 return IAVIFile_EndRecord(pfile);
445 /***********************************************************************
446 * AVIStreamAddRef (AVIFIL32.@)
447 * AVIStreamAddRef (AVIFILE.160)
449 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
451 TRACE("(%p)\n", pstream);
453 if (pstream == NULL) {
454 ERR(": bad handle passed!\n");
455 return 0;
458 return IAVIStream_AddRef(pstream);
461 /***********************************************************************
462 * AVIStreamRelease (AVIFIL32.@)
463 * AVIStreamRelease (AVIFILE.161)
465 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
467 TRACE("(%p)\n", pstream);
469 if (pstream == NULL) {
470 ERR(": bad handle passed!\n");
471 return 0;
474 return IAVIStream_Release(pstream);
477 /***********************************************************************
478 * AVIStreamCreate (AVIFIL32.@)
479 * AVIStreamCreate (AVIFILE.104)
481 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
482 LPCLSID pclsidHandler)
484 HRESULT hr;
486 TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
487 debugstr_guid(pclsidHandler));
489 if (ppavi == NULL)
490 return AVIERR_BADPARAM;
492 *ppavi = NULL;
493 if (pclsidHandler == NULL)
494 return AVIERR_UNSUPPORTED;
496 hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi);
497 if (FAILED(hr) || *ppavi == NULL)
498 return hr;
500 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
501 if (FAILED(hr)) {
502 IAVIStream_Release(*ppavi);
503 *ppavi = NULL;
506 return hr;
509 /***********************************************************************
510 * AVIStreamInfo (AVIFIL32.@)
511 * AVIStreamInfoA (AVIFIL32.@)
512 * AVIStreamInfo (AVIFILE.162)
514 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
515 LONG size)
517 AVISTREAMINFOW asiw;
518 HRESULT hres;
520 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
522 if (pstream == NULL)
523 return AVIERR_BADHANDLE;
524 if ((DWORD)size < sizeof(AVISTREAMINFOA))
525 return AVIERR_BADSIZE;
527 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
529 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
530 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
531 sizeof(asi->szName), NULL, NULL);
532 asi->szName[sizeof(asi->szName) - 1] = 0;
534 return hres;
537 /***********************************************************************
538 * AVIStreamInfoW (AVIFIL32.@)
540 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
541 LONG size)
543 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
545 if (pstream == NULL)
546 return AVIERR_BADHANDLE;
548 return IAVIStream_Info(pstream, asi, size);
551 /***********************************************************************
552 * AVIStreamFindSample (AVIFIL32.@)
553 * AVIStreamFindSample (AVIFILE.163)
555 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
557 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
559 if (pstream == NULL)
560 return -1;
562 return IAVIStream_FindSample(pstream, pos, flags);
565 /***********************************************************************
566 * AVIStreamReadFormat (AVIFIL32.@)
567 * AVIStreamReadFormat (AVIFILE.164)
569 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
570 LPVOID format, LPLONG formatsize)
572 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
574 if (pstream == NULL)
575 return AVIERR_BADHANDLE;
577 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
580 /***********************************************************************
581 * AVIStreamSetFormat (AVIFIL32.@)
582 * AVIStreamSetFormat (AVIFILE.169)
584 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
585 LPVOID format, LONG formatsize)
587 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
589 if (pstream == NULL)
590 return AVIERR_BADHANDLE;
592 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
595 /***********************************************************************
596 * AVIStreamRead (AVIFIL32.@)
597 * AVIStreamRead (AVIFILE.167)
599 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
600 LPVOID buffer, LONG buffersize,
601 LPLONG bytesread, LPLONG samplesread)
603 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
604 buffersize, bytesread, samplesread);
606 if (pstream == NULL)
607 return AVIERR_BADHANDLE;
609 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
610 bytesread, samplesread);
613 /***********************************************************************
614 * AVIStreamWrite (AVIFIL32.@)
615 * AVIStreamWrite (AVIFILE.168)
617 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
618 LPVOID buffer, LONG buffersize, DWORD flags,
619 LPLONG sampwritten, LPLONG byteswritten)
621 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
622 buffersize, flags, sampwritten, byteswritten);
624 if (pstream == NULL)
625 return AVIERR_BADHANDLE;
627 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
628 flags, sampwritten, byteswritten);
631 /***********************************************************************
632 * AVIStreamReadData (AVIFIL32.@)
633 * AVIStreamReadData (AVIFILE.165)
635 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
636 LPLONG lpread)
638 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
640 if (pstream == NULL)
641 return AVIERR_BADHANDLE;
643 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
646 /***********************************************************************
647 * AVIStreamWriteData (AVIFIL32.@)
648 * AVIStreamWriteData (AVIFILE.166)
650 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
651 LONG size)
653 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
655 if (pstream == NULL)
656 return AVIERR_BADHANDLE;
658 return IAVIStream_WriteData(pstream, fcc, lp, size);
661 /***********************************************************************
662 * AVIStreamGetFrameOpen (AVIFIL32.@)
663 * AVIStreamGetFrameOpen (AVIFILE.112)
665 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
666 LPBITMAPINFOHEADER lpbiWanted)
668 PGETFRAME pg = NULL;
670 TRACE("(%p,%p)\n", pstream, lpbiWanted);
672 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
673 pg == NULL) {
674 pg = AVIFILE_CreateGetFrame(pstream);
675 if (pg == NULL)
676 return NULL;
679 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
680 IGetFrame_Release(pg);
681 return NULL;
684 return pg;
687 /***********************************************************************
688 * AVIStreamGetFrame (AVIFIL32.@)
689 * AVIStreamGetFrame (AVIFILE.110)
691 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
693 TRACE("(%p,%ld)\n", pg, pos);
695 if (pg == NULL)
696 return NULL;
698 return IGetFrame_GetFrame(pg, pos);
701 /***********************************************************************
702 * AVIStreamGetFrameClose (AVIFIL32.@)
703 * AVIStreamGetFrameClose (AVIFILE.111)
705 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
707 TRACE("(%p)\n", pg);
709 if (pg != NULL)
710 return IGetFrame_Release(pg);
711 return 0;
714 /***********************************************************************
715 * AVIMakeCompressedStream (AVIFIL32.@)
717 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
718 PAVISTREAM psSource,
719 LPAVICOMPRESSOPTIONS aco,
720 LPCLSID pclsidHandler)
722 AVISTREAMINFOW asiw;
723 CHAR szRegKey[25];
724 CHAR szValue[100];
725 CLSID clsidHandler;
726 HRESULT hr;
727 LONG size = sizeof(szValue);
729 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
730 debugstr_guid(pclsidHandler));
732 if (ppsCompressed == NULL)
733 return AVIERR_BADPARAM;
734 if (psSource == NULL)
735 return AVIERR_BADHANDLE;
737 *ppsCompressed = NULL;
739 /* if no handler given get default ones based on streamtype */
740 if (pclsidHandler == NULL) {
741 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
742 if (FAILED(hr))
743 return hr;
745 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
746 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
747 return AVIERR_UNSUPPORTED;
748 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
749 return AVIERR_UNSUPPORTED;
750 } else
751 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
753 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed);
754 if (FAILED(hr) || *ppsCompressed == NULL)
755 return hr;
757 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
758 if (FAILED(hr)) {
759 IAVIStream_Release(*ppsCompressed);
760 *ppsCompressed = NULL;
763 return hr;
766 /***********************************************************************
767 * AVIMakeFileFromStreams (AVIFIL32.@)
769 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
770 PAVISTREAM *ppStreams)
772 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
774 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
775 return AVIERR_BADPARAM;
777 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
778 if (*ppfile == NULL)
779 return AVIERR_MEMORY;
781 return AVIERR_OK;
784 /***********************************************************************
785 * AVIStreamOpenFromFile (AVIFIL32.@)
786 * AVIStreamOpenFromFileA (AVIFIL32.@)
787 * AVIStreamOpenFromFile (AVIFILE.103)
789 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
790 DWORD fccType, LONG lParam,
791 UINT mode, LPCLSID pclsidHandler)
793 PAVIFILE pfile = NULL;
794 HRESULT hr;
796 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
797 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
799 if (ppavi == NULL || szFile == NULL)
800 return AVIERR_BADPARAM;
802 *ppavi = NULL;
804 hr = AVIFileOpenA(&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 * AVIStreamOpenFromFileW (AVIFIL32.@)
817 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
818 DWORD fccType, LONG lParam,
819 UINT mode, LPCLSID pclsidHandler)
821 PAVIFILE pfile = NULL;
822 HRESULT hr;
824 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
825 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
827 if (ppavi == NULL || szFile == NULL)
828 return AVIERR_BADPARAM;
830 *ppavi = NULL;
832 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
833 if (FAILED(hr) || pfile == NULL)
834 return hr;
836 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
837 IAVIFile_Release(pfile);
839 return hr;
842 /***********************************************************************
843 * AVIStreamBeginStreaming (AVIFIL32.@)
845 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
847 IAVIStreaming* pstream = NULL;
848 HRESULT hr;
850 TRACE("(%p,%ld,%ld,%ld)\n", pavi, lStart, lEnd, lRate);
852 if (pavi == NULL)
853 return AVIERR_BADHANDLE;
855 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
856 if (SUCCEEDED(hr) && pstream != NULL) {
857 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
858 IAVIStreaming_Release(pstream);
859 } else
860 hr = AVIERR_OK;
862 return hr;
865 /***********************************************************************
866 * AVIStreamEndStreaming (AVIFIL32.@)
868 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
870 IAVIStreaming* pstream = NULL;
871 HRESULT hr;
873 TRACE("(%p)\n", pavi);
875 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
876 if (SUCCEEDED(hr) && pstream != NULL) {
877 IAVIStreaming_End(pstream);
878 IAVIStreaming_Release(pstream);
881 return AVIERR_OK;
884 /***********************************************************************
885 * AVIStreamStart (AVIFILE.130)
886 * AVIStreamStart (AVIFIL32.@)
888 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
890 AVISTREAMINFOW asiw;
892 TRACE("(%p)\n", pstream);
894 if (pstream == NULL)
895 return 0;
897 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
898 return 0;
900 return asiw.dwStart;
903 /***********************************************************************
904 * AVIStreamLength (AVIFILE.131)
905 * AVIStreamLength (AVIFIL32.@)
907 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
909 AVISTREAMINFOW asiw;
911 TRACE("(%p)\n", pstream);
913 if (pstream == NULL)
914 return 0;
916 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
917 return 0;
919 return asiw.dwLength;
922 /***********************************************************************
923 * AVIStreamSampleToTime (AVIFILE.133)
924 * AVIStreamSampleToTime (AVIFIL32.@)
926 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
928 AVISTREAMINFOW asiw;
929 LONG time;
931 TRACE("(%p,%ld)\n", pstream, lSample);
933 if (pstream == NULL)
934 return -1;
936 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
937 return -1;
938 if (asiw.dwRate == 0)
939 return -1;
941 /* limit to stream bounds */
942 if (lSample < asiw.dwStart)
943 lSample = asiw.dwStart;
944 if (lSample > asiw.dwStart + asiw.dwLength)
945 lSample = asiw.dwStart + asiw.dwLength;
947 if (asiw.dwRate / asiw.dwScale < 1000)
948 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
949 else
950 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
952 TRACE(" -> %ld\n",time);
953 return time;
956 /***********************************************************************
957 * AVIStreamTimeToSample (AVIFILE.132)
958 * AVIStreamTimeToSample (AVIFIL32.@)
960 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
962 AVISTREAMINFOW asiw;
963 ULONG sample;
965 TRACE("(%p,%ld)\n", pstream, lTime);
967 if (pstream == NULL || lTime < 0)
968 return -1;
970 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
971 return -1;
972 if (asiw.dwScale == 0)
973 return -1;
975 if (asiw.dwRate / asiw.dwScale < 1000)
976 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
977 else
978 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
980 /* limit to stream bounds */
981 if (sample < asiw.dwStart)
982 sample = asiw.dwStart;
983 if (sample > asiw.dwStart + asiw.dwLength)
984 sample = asiw.dwStart + asiw.dwLength;
986 TRACE(" -> %ld\n", sample);
987 return sample;
990 /***********************************************************************
991 * AVIBuildFilter (AVIFIL32.@)
992 * AVIBuildFilterA (AVIFIL32.@)
993 * AVIBuildFilter (AVIFILE.123)
995 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
997 LPWSTR wszFilter;
998 HRESULT hr;
1000 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1002 /* check parameters */
1003 if (szFilter == NULL)
1004 return AVIERR_BADPARAM;
1005 if (cbFilter < 2)
1006 return AVIERR_BADSIZE;
1008 szFilter[0] = 0;
1009 szFilter[1] = 0;
1011 wszFilter = HeapAlloc(GetProcessHeap(), 0, cbFilter * sizeof(WCHAR));
1012 if (wszFilter == NULL)
1013 return AVIERR_MEMORY;
1015 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
1016 if (SUCCEEDED(hr)) {
1017 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
1018 szFilter, cbFilter, NULL, NULL);
1021 HeapFree(GetProcessHeap(), 0, wszFilter);
1023 return hr;
1026 /***********************************************************************
1027 * AVIBuildFilterW (AVIFIL32.@)
1029 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
1031 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
1032 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1033 static const WCHAR szAVIFileExtensions[] =
1034 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1036 AVIFilter *lp;
1037 WCHAR szAllFiles[40];
1038 WCHAR szFileExt[10];
1039 WCHAR szValue[128];
1040 HKEY hKey;
1041 DWORD n, i;
1042 LONG size;
1043 DWORD count = 0;
1045 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1047 /* check parameters */
1048 if (szFilter == NULL)
1049 return AVIERR_BADPARAM;
1050 if (cbFilter < 2)
1051 return AVIERR_BADSIZE;
1053 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_FILTERS * sizeof(AVIFilter));
1054 if (lp == NULL)
1055 return AVIERR_MEMORY;
1058 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1059 * extensions and CLSID's
1060 * 2. iterate over collected CLSID's and copy its description and its
1061 * extensions to szFilter if it fits
1063 * First filter is named "All multimedia files" and its filter is a
1064 * collection of all possible extensions except "*.*".
1066 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
1067 HeapFree(GetProcessHeap(), 0, lp);
1068 return AVIERR_ERROR;
1070 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
1071 /* get CLSID to extension */
1072 size = sizeof(szValue)/sizeof(szValue[0]);
1073 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
1074 break;
1076 /* search if the CLSID is already known */
1077 for (i = 1; i <= count; i++) {
1078 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
1079 break; /* a new one */
1082 if (count - i == -1U) {
1083 /* it's a new CLSID */
1085 /* FIXME: How do we get info's about read/write capabilities? */
1087 if (count >= MAX_FILTERS) {
1088 /* try to inform user of our full fixed size table */
1089 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1090 break;
1093 lstrcpyW(lp[i].szClsid, szValue);
1095 count++;
1098 /* append extension to the filter */
1099 wsprintfW(szValue, szExtensionFmt, szFileExt);
1100 if (lp[i].szExtensions[0] == 0)
1101 lstrcatW(lp[i].szExtensions, szValue + 1);
1102 else
1103 lstrcatW(lp[i].szExtensions, szValue);
1105 /* also append to the "all multimedia"-filter */
1106 if (lp[0].szExtensions[0] == 0)
1107 lstrcatW(lp[0].szExtensions, szValue + 1);
1108 else
1109 lstrcatW(lp[0].szExtensions, szValue);
1111 RegCloseKey(hKey);
1113 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1114 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1115 HeapFree(GetProcessHeap(), 0, lp);
1116 return AVIERR_ERROR;
1118 for (n = 0; n <= count; n++) {
1119 /* first the description */
1120 if (n != 0) {
1121 size = sizeof(szValue)/sizeof(szValue[0]);
1122 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1123 size = lstrlenW(szValue);
1124 lstrcpynW(szFilter, szValue, cbFilter);
1126 } else
1127 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1129 /* check for enough space */
1130 size++;
1131 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1132 szFilter[0] = 0;
1133 szFilter[1] = 0;
1134 HeapFree(GetProcessHeap(), 0, lp);
1135 RegCloseKey(hKey);
1136 return AVIERR_BUFFERTOOSMALL;
1138 cbFilter -= size;
1139 szFilter += size;
1141 /* and then the filter */
1142 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1143 size = lstrlenW(lp[n].szExtensions) + 1;
1144 cbFilter -= size;
1145 szFilter += size;
1148 RegCloseKey(hKey);
1149 HeapFree(GetProcessHeap(), 0, lp);
1151 /* add "All files" "*.*" filter if enough space left */
1152 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1153 szAllFiles, sizeof(szAllFiles)) + 1;
1154 if (cbFilter > size) {
1155 int i;
1157 /* replace '@' with \000 to separate description of filter */
1158 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1159 if (szAllFiles[i] == '@') {
1160 szAllFiles[i] = 0;
1161 break;
1165 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1166 szFilter += size;
1167 szFilter[0] = 0;
1169 return AVIERR_OK;
1170 } else {
1171 szFilter[0] = 0;
1172 return AVIERR_BUFFERTOOSMALL;
1176 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1178 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1179 AVISTREAMINFOW sInfo;
1181 TRACE("(%p)\n", hWnd);
1183 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1184 ERR(": bad state!\n");
1185 return FALSE;
1188 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1189 &sInfo, sizeof(sInfo)))) {
1190 ERR(": AVIStreamInfoW failed!\n");
1191 return FALSE;
1194 if (sInfo.fccType == streamtypeVIDEO) {
1195 COMPVARS cv;
1196 BOOL ret;
1198 memset(&cv, 0, sizeof(cv));
1200 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1201 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1202 pOptions->fccType = streamtypeVIDEO;
1203 pOptions->fccHandler = comptypeDIB;
1204 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1207 cv.cbSize = sizeof(cv);
1208 cv.dwFlags = ICMF_COMPVARS_VALID;
1209 /*cv.fccType = pOptions->fccType; */
1210 cv.fccHandler = pOptions->fccHandler;
1211 cv.lQ = pOptions->dwQuality;
1212 cv.lpState = pOptions->lpParms;
1213 cv.cbState = pOptions->cbParms;
1214 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1215 cv.lKey = pOptions->dwKeyFrameEvery;
1216 else
1217 cv.lKey = 0;
1218 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1219 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1220 else
1221 cv.lDataRate = 0;
1223 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1224 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1226 if (ret) {
1227 pOptions->fccHandler = cv.fccHandler;
1228 pOptions->lpParms = cv.lpState;
1229 pOptions->cbParms = cv.cbState;
1230 pOptions->dwQuality = cv.lQ;
1231 if (cv.lKey != 0) {
1232 pOptions->dwKeyFrameEvery = cv.lKey;
1233 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1234 } else
1235 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1236 if (cv.lDataRate != 0) {
1237 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1238 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1239 } else
1240 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1241 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1243 ICCompressorFree(&cv);
1245 return ret;
1246 } else if (sInfo.fccType == streamtypeAUDIO) {
1247 ACMFORMATCHOOSEW afmtc;
1248 MMRESULT ret;
1249 LONG size;
1251 /* FIXME: check ACM version -- Which version is needed? */
1253 memset(&afmtc, 0, sizeof(afmtc));
1254 afmtc.cbStruct = sizeof(afmtc);
1255 afmtc.fdwStyle = 0;
1256 afmtc.hwndOwner = hWnd;
1258 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1259 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1260 pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1261 pOptions->cbFormat = size;
1262 } else if (pOptions->cbFormat < (DWORD)size) {
1263 pOptions->lpFormat = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size);
1264 pOptions->cbFormat = size;
1266 if (pOptions->lpFormat == NULL)
1267 return FALSE;
1268 afmtc.pwfx = pOptions->lpFormat;
1269 afmtc.cbwfx = pOptions->cbFormat;
1271 size = 0;
1272 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1273 sInfo.dwStart, &size);
1274 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1275 size = sizeof(PCMWAVEFORMAT);
1276 afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size);
1277 if (afmtc.pwfxEnum != NULL) {
1278 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1279 sInfo.dwStart, afmtc.pwfxEnum, &size);
1280 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1283 ret = acmFormatChooseW(&afmtc);
1284 if (ret == S_OK)
1285 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1287 HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum);
1288 return (ret == S_OK ? TRUE : FALSE);
1289 } else {
1290 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1291 return FALSE;
1295 static void AVISaveOptionsUpdate(HWND hWnd)
1297 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1298 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1300 WCHAR szFormat[128];
1301 AVISTREAMINFOW sInfo;
1302 LPVOID lpFormat;
1303 LONG size;
1305 TRACE("(%p)\n", hWnd);
1307 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1308 if (SaveOpts.nCurrent < 0)
1309 return;
1311 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1312 return;
1314 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1315 if (size > 0) {
1316 szFormat[0] = 0;
1318 /* read format to build format description string */
1319 lpFormat = HeapAlloc(GetProcessHeap(), 0, size);
1320 if (lpFormat != NULL) {
1321 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1322 if (sInfo.fccType == streamtypeVIDEO) {
1323 LPBITMAPINFOHEADER lpbi = lpFormat;
1324 ICINFO icinfo;
1326 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1327 lpbi->biHeight, lpbi->biBitCount);
1329 if (lpbi->biCompression != BI_RGB) {
1330 HIC hic;
1332 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1333 NULL, ICMODE_DECOMPRESS);
1334 if (hic != NULL) {
1335 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1336 lstrcatW(szFormat, icinfo.szDescription);
1337 ICClose(hic);
1339 } else {
1340 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1341 icinfo.szDescription, sizeof(icinfo.szDescription));
1342 lstrcatW(szFormat, icinfo.szDescription);
1344 } else if (sInfo.fccType == streamtypeAUDIO) {
1345 ACMFORMATTAGDETAILSW aftd;
1346 ACMFORMATDETAILSW afd;
1348 memset(&aftd, 0, sizeof(aftd));
1349 memset(&afd, 0, sizeof(afd));
1351 aftd.cbStruct = sizeof(aftd);
1352 aftd.dwFormatTag = afd.dwFormatTag =
1353 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1354 aftd.cbFormatSize = afd.cbwfx = size;
1356 afd.cbStruct = sizeof(afd);
1357 afd.pwfx = lpFormat;
1359 if (acmFormatTagDetailsW(NULL, &aftd,
1360 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1361 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1362 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1366 HeapFree(GetProcessHeap(), 0, lpFormat);
1369 /* set text for format description */
1370 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1372 /* Disable option button for unsupported streamtypes */
1373 if (sInfo.fccType == streamtypeVIDEO ||
1374 sInfo.fccType == streamtypeAUDIO)
1375 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1376 else
1377 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1382 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1383 WPARAM wParam, LPARAM lParam)
1385 DWORD dwInterleave;
1386 BOOL bIsInterleaved;
1387 INT n;
1389 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1391 switch (uMsg) {
1392 case WM_INITDIALOG:
1393 SaveOpts.nCurrent = 0;
1394 if (SaveOpts.nStreams == 1) {
1395 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1396 return TRUE;
1399 /* add streams */
1400 for (n = 0; n < SaveOpts.nStreams; n++) {
1401 AVISTREAMINFOW sInfo;
1403 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1404 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1405 0L, (LPARAM)sInfo.szName);
1408 /* select first stream */
1409 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1410 SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd);
1412 /* initialize interleave */
1413 if (SaveOpts.ppOptions[0] != NULL &&
1414 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1415 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1416 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1417 } else {
1418 bIsInterleaved = TRUE;
1419 dwInterleave = 0;
1421 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1422 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1423 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1424 break;
1425 case WM_COMMAND:
1426 switch (LOWORD(wParam)) {
1427 case IDOK:
1428 /* get data from controls and save them */
1429 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1430 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1431 for (n = 0; n < SaveOpts.nStreams; n++) {
1432 if (SaveOpts.ppOptions[n] != NULL) {
1433 if (bIsInterleaved) {
1434 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1435 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1436 } else
1437 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1440 /* fall through */
1441 case IDCANCEL:
1442 EndDialog(hWnd, LOWORD(wParam) == IDOK);
1443 break;
1444 case IDC_INTERLEAVE:
1445 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1446 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1447 break;
1448 case IDC_STREAM:
1449 if (HIWORD(wParam) == CBN_SELCHANGE) {
1450 /* update control elements */
1451 AVISaveOptionsUpdate(hWnd);
1453 break;
1454 case IDC_OPTIONS:
1455 AVISaveOptionsFmtChoose(hWnd);
1456 break;
1458 return TRUE;
1461 return FALSE;
1464 /***********************************************************************
1465 * AVISaveOptions (AVIFIL32.@)
1467 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1468 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1470 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1471 INT ret, n;
1473 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1474 ppavi, ppOptions);
1476 /* check parameters */
1477 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1478 return AVIERR_BADPARAM;
1480 /* save options in case the user presses cancel */
1481 if (ppOptions != NULL && nStreams > 1) {
1482 pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS));
1483 if (pSavedOptions == NULL)
1484 return FALSE;
1486 for (n = 0; n < nStreams; n++) {
1487 if (ppOptions[n] != NULL)
1488 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1492 SaveOpts.uFlags = uFlags;
1493 SaveOpts.nStreams = nStreams;
1494 SaveOpts.ppavis = ppavi;
1495 SaveOpts.ppOptions = ppOptions;
1497 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1498 hWnd, AVISaveOptionsDlgProc);
1500 if (ret == -1)
1501 ret = FALSE;
1503 /* restore options when user pressed cancel */
1504 if (pSavedOptions != NULL) {
1505 if (ret == FALSE) {
1506 for (n = 0; n < nStreams; n++) {
1507 if (ppOptions[n] != NULL)
1508 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1511 HeapFree(GetProcessHeap(), 0, pSavedOptions);
1514 return (BOOL)ret;
1517 /***********************************************************************
1518 * AVISaveOptionsFree (AVIFIL32.@)
1519 * AVISaveOptionsFree (AVIFILE.124)
1521 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1523 TRACE("(%d,%p)\n", nStreams, ppOptions);
1525 if (nStreams < 0 || ppOptions == NULL)
1526 return AVIERR_BADPARAM;
1528 for (; nStreams > 0; nStreams--) {
1529 if (ppOptions[nStreams] != NULL) {
1530 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1532 if (ppOptions[nStreams]->lpParms != NULL) {
1533 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms);
1534 ppOptions[nStreams]->lpParms = NULL;
1535 ppOptions[nStreams]->cbParms = 0;
1537 if (ppOptions[nStreams]->lpFormat != NULL) {
1538 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat);
1539 ppOptions[nStreams]->lpFormat = NULL;
1540 ppOptions[nStreams]->cbFormat = 0;
1545 return AVIERR_OK;
1548 /***********************************************************************
1549 * AVISaveVA (AVIFIL32.@)
1551 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1552 AVISAVECALLBACK lpfnCallback, int nStream,
1553 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1555 LPWSTR wszFile = NULL;
1556 HRESULT hr;
1557 int len;
1559 TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1560 lpfnCallback, nStream, ppavi, plpOptions);
1562 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1563 return AVIERR_BADPARAM;
1565 /* convert ASCII string to Unicode and call Unicode function */
1566 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1567 if (len <= 0)
1568 return AVIERR_BADPARAM;
1570 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1571 if (wszFile == NULL)
1572 return AVIERR_MEMORY;
1574 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
1576 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1577 nStream, ppavi, plpOptions);
1579 HeapFree(GetProcessHeap(), 0, wszFile);
1581 return hr;
1584 /***********************************************************************
1585 * AVIFILE_AVISaveDefaultCallback (internal)
1587 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1589 TRACE("(%d)\n", progress);
1591 return FALSE;
1594 /***********************************************************************
1595 * AVISaveVW (AVIFIL32.@)
1597 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1598 AVISAVECALLBACK lpfnCallback, int nStreams,
1599 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1601 LONG lStart[MAX_AVISTREAMS];
1602 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1603 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1604 AVIFILEINFOW fInfo;
1605 AVISTREAMINFOW sInfo;
1607 PAVIFILE pfile = NULL; /* the output AVI file */
1608 LONG lFirstVideo = -1;
1609 int curStream;
1611 /* for interleaving ... */
1612 DWORD dwInterleave = 0; /* interleave rate */
1613 DWORD dwFileInitialFrames;
1614 LONG lFileLength;
1615 LONG lSampleInc;
1617 /* for reading/writing the data ... */
1618 LPVOID lpBuffer = NULL;
1619 LONG cbBuffer; /* real size of lpBuffer */
1620 LONG lBufferSize; /* needed bytes for format(s), etc. */
1621 LONG lReadBytes;
1622 LONG lReadSamples;
1623 HRESULT hres;
1625 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1626 lpfnCallback, nStreams, ppavi, plpOptions);
1628 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1629 return AVIERR_BADPARAM;
1630 if (nStreams >= MAX_AVISTREAMS) {
1631 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1632 return AVIERR_INTERNAL;
1635 if (lpfnCallback == NULL)
1636 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1638 /* clear local variable(s) */
1639 for (curStream = 0; curStream < nStreams; curStream++) {
1640 pInStreams[curStream] = NULL;
1641 pOutStreams[curStream] = NULL;
1644 /* open output AVI file (create it if it doesn't exist) */
1645 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1646 pclsidHandler);
1647 if (FAILED(hres))
1648 return hres;
1649 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1651 /* initialize our data structures part 1 */
1652 for (curStream = 0; curStream < nStreams; curStream++) {
1653 PAVISTREAM pCurStream = ppavi[curStream];
1655 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1656 if (FAILED(hres))
1657 goto error;
1659 /* search first video stream and check for interleaving */
1660 if (sInfo.fccType == streamtypeVIDEO) {
1661 /* remember first video stream -- needed for interleaving */
1662 if (lFirstVideo < 0)
1663 lFirstVideo = curStream;
1664 } else if (!dwInterleave && plpOptions != NULL) {
1665 /* check if any non-video stream wants to be interleaved */
1666 WARN("options.flags=0x%lX options.dwInterleave=%lu\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1667 if (plpOptions[curStream] != NULL &&
1668 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1669 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1672 /* create de-/compressed stream interface if needed */
1673 pInStreams[curStream] = NULL;
1674 if (plpOptions != NULL && plpOptions[curStream] != NULL) {
1675 if (plpOptions[curStream]->fccHandler ||
1676 plpOptions[curStream]->lpFormat != NULL) {
1677 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1679 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1680 plpOptions[curStream]->dwKeyFrameEvery = 1;
1682 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1683 plpOptions[curStream], NULL);
1684 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1685 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1686 pInStreams[curStream] = NULL;
1687 goto error;
1690 /* test stream interface and update stream-info */
1691 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1692 if (FAILED(hres))
1693 goto error;
1697 /* now handle streams which will only be copied */
1698 if (pInStreams[curStream] == NULL) {
1699 pCurStream = pInStreams[curStream] = ppavi[curStream];
1700 AVIStreamAddRef(pCurStream);
1701 } else
1702 pCurStream = pInStreams[curStream];
1704 lStart[curStream] = sInfo.dwStart;
1705 } /* for all streams */
1707 /* check that first video stream is the first stream */
1708 if (lFirstVideo > 0) {
1709 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1710 LONG lTmp = lStart[lFirstVideo];
1712 pInStreams[lFirstVideo] = pInStreams[0];
1713 pInStreams[0] = pTmp;
1714 lStart[lFirstVideo] = lStart[0];
1715 lStart[0] = lTmp;
1716 lFirstVideo = 0;
1719 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
1720 cbBuffer = 0x00010000;
1721 lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer);
1722 if (lpBuffer == NULL) {
1723 hres = AVIERR_MEMORY;
1724 goto error;
1727 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
1728 lFileLength = sInfo.dwLength;
1729 dwFileInitialFrames = 0;
1730 if (lFirstVideo >= 0) {
1731 /* check for correct version of the format
1732 * -- need at least BITMAPINFOHEADER or newer
1734 lSampleInc = 1;
1735 lBufferSize = cbBuffer;
1736 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
1737 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
1738 hres = AVIERR_INTERNAL;
1739 if (FAILED(hres))
1740 goto error;
1741 } else /* use one second blocks for interleaving if no video present */
1742 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
1744 /* create output streams */
1745 for (curStream = 0; curStream < nStreams; curStream++) {
1746 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1748 sInfo.dwInitialFrames = 0;
1749 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
1750 /* 750 ms initial frames for non-video streams */
1751 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
1754 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
1755 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
1756 /* copy initial format for this stream */
1757 lBufferSize = cbBuffer;
1758 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1759 lpBuffer, &lBufferSize);
1760 if (FAILED(hres))
1761 goto error;
1762 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
1763 if (FAILED(hres))
1764 goto error;
1766 /* try to copy stream handler data */
1767 lBufferSize = cbBuffer;
1768 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
1769 lpBuffer, &lBufferSize);
1770 if (SUCCEEDED(hres) && lBufferSize > 0) {
1771 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
1772 lpBuffer, lBufferSize);
1773 if (FAILED(hres))
1774 goto error;
1777 if (dwFileInitialFrames < sInfo.dwInitialFrames)
1778 dwFileInitialFrames = sInfo.dwInitialFrames;
1779 lReadBytes =
1780 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
1781 sInfo.dwLength);
1782 if (lFileLength < lReadBytes)
1783 lFileLength = lReadBytes;
1784 } else {
1785 /* creation of de-/compression stream interface failed */
1786 WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
1787 AVIStreamRelease(pInStreams[curStream]);
1788 if (curStream + 1 >= nStreams) {
1789 /* move the others one up */
1790 PAVISTREAM *ppas = &pInStreams[curStream];
1791 int n = nStreams - (curStream + 1);
1793 do {
1794 *ppas = pInStreams[curStream + 1];
1795 } while (--n);
1797 nStreams--;
1798 curStream--;
1800 } /* create output streams for all input streams */
1802 /* have we still something to write, or lost everything? */
1803 if (nStreams <= 0)
1804 goto error;
1806 if (dwInterleave) {
1807 LONG lCurFrame = -dwFileInitialFrames;
1809 /* interleaved file */
1810 if (dwInterleave == 1)
1811 AVIFileEndRecord(pfile);
1813 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
1814 for (curStream = 0; curStream < nStreams; curStream++) {
1815 LONG lLastSample;
1817 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
1818 if (FAILED(hres))
1819 goto error;
1821 /* initial frames phase at the end for this stream? */
1822 if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
1823 continue;
1825 if ((lFileLength - lSampleInc) <= lCurFrame) {
1826 lLastSample = AVIStreamLength(pInStreams[curStream]);
1827 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
1828 } else {
1829 if (curStream != 0) {
1830 lFirstVideo =
1831 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
1832 (sInfo.fccType == streamtypeVIDEO ?
1833 (LONG)dwInterleave : lSampleInc) +
1834 sInfo.dwInitialFrames + lCurFrame);
1835 } else
1836 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
1838 lLastSample = AVIStreamEnd(pInStreams[curStream]);
1839 if (lLastSample <= lFirstVideo)
1840 lFirstVideo = lLastSample;
1843 /* copy needed samples now */
1844 WARN("copy from stream %d samples %ld to %ld...\n",curStream,
1845 lStart[curStream],lFirstVideo);
1846 while (lFirstVideo > lStart[curStream]) {
1847 DWORD flags = 0;
1849 /* copy format in case it can change */
1850 lBufferSize = cbBuffer;
1851 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
1852 lpBuffer, &lBufferSize);
1853 if (FAILED(hres))
1854 goto error;
1855 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
1856 lpBuffer, lBufferSize);
1858 /* try to read data until we got it, or error */
1859 do {
1860 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
1861 lFirstVideo - lStart[curStream], lpBuffer,
1862 cbBuffer, &lReadBytes, &lReadSamples);
1863 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1864 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1865 if (lpBuffer == NULL)
1866 hres = AVIERR_MEMORY;
1867 if (FAILED(hres))
1868 goto error;
1870 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1871 flags = AVIIF_KEYFRAME;
1872 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1873 lpBuffer, lReadBytes, flags, NULL, NULL);
1874 if (FAILED(hres))
1875 goto error;
1877 lStart[curStream] += lReadSamples;
1879 lStart[curStream] = lFirstVideo;
1880 } /* stream by stream */
1882 /* need to close this block? */
1883 if (dwInterleave == 1) {
1884 hres = AVIFileEndRecord(pfile);
1885 if (FAILED(hres))
1886 break;
1889 /* show progress */
1890 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
1891 dwFileInitialFrames + lFileLength))) {
1892 hres = AVIERR_USERABORT;
1893 break;
1895 } /* copy frame by frame */
1896 } else {
1897 /* non-interleaved file */
1899 for (curStream = 0; curStream < nStreams; curStream++) {
1900 /* show progress */
1901 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
1902 hres = AVIERR_USERABORT;
1903 goto error;
1906 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1908 if (sInfo.dwSampleSize != 0) {
1909 /* sample-based data like audio */
1910 while (sInfo.dwStart < sInfo.dwLength) {
1911 LONG lSamples = cbBuffer / sInfo.dwSampleSize;
1913 /* copy format in case it can change */
1914 lBufferSize = cbBuffer;
1915 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1916 lpBuffer, &lBufferSize);
1917 if (FAILED(hres))
1918 return hres;
1919 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1920 lpBuffer, lBufferSize);
1922 /* limit to stream boundaries */
1923 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
1924 lSamples = sInfo.dwLength - sInfo.dwStart;
1926 /* now try to read until we get it, or an error occurs */
1927 do {
1928 lReadBytes = cbBuffer;
1929 lReadSamples = 0;
1930 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
1931 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
1932 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1933 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1934 if (lpBuffer == NULL)
1935 hres = AVIERR_MEMORY;
1936 if (FAILED(hres))
1937 goto error;
1938 if (lReadSamples != 0) {
1939 sInfo.dwStart += lReadSamples;
1940 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1941 lpBuffer, lReadBytes, 0, NULL , NULL);
1942 if (FAILED(hres))
1943 goto error;
1945 /* show progress */
1946 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1947 MulDiv(curStream, 100, nStreams))) {
1948 hres = AVIERR_USERABORT;
1949 goto error;
1951 } else {
1952 if ((sInfo.dwLength - sInfo.dwStart) != 1) {
1953 hres = AVIERR_FILEREAD;
1954 goto error;
1958 } else {
1959 /* block-based data like video */
1960 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
1961 DWORD flags = 0;
1963 /* copy format in case it can change */
1964 lBufferSize = cbBuffer;
1965 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1966 lpBuffer, &lBufferSize);
1967 if (FAILED(hres))
1968 goto error;
1969 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1970 lpBuffer, lBufferSize);
1972 /* try to read block and resize buffer if necessary */
1973 do {
1974 lReadSamples = 0;
1975 lReadBytes = cbBuffer;
1976 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
1977 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
1978 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1979 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL);
1980 if (lpBuffer == NULL)
1981 hres = AVIERR_MEMORY;
1982 if (FAILED(hres))
1983 goto error;
1984 if (lReadSamples != 1) {
1985 hres = AVIERR_FILEREAD;
1986 goto error;
1989 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1990 flags = AVIIF_KEYFRAME;
1991 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1992 lpBuffer, lReadBytes, flags, NULL, NULL);
1993 if (FAILED(hres))
1994 goto error;
1996 /* show progress */
1997 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1998 MulDiv(curStream, 100, nStreams))) {
1999 hres = AVIERR_USERABORT;
2000 goto error;
2002 } /* copy all blocks */
2004 } /* copy data stream by stream */
2007 error:
2008 HeapFree(GetProcessHeap(), 0, lpBuffer);
2009 if (pfile != NULL) {
2010 for (curStream = 0; curStream < nStreams; curStream++) {
2011 if (pOutStreams[curStream] != NULL)
2012 AVIStreamRelease(pOutStreams[curStream]);
2013 if (pInStreams[curStream] != NULL)
2014 AVIStreamRelease(pInStreams[curStream]);
2017 AVIFileRelease(pfile);
2020 return hres;
2023 /***********************************************************************
2024 * CreateEditableStream (AVIFIL32.@)
2026 HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
2028 IAVIEditStream *pEdit = NULL;
2029 HRESULT hr;
2031 TRACE("(%p,%p)\n", ppEditable, pSource);
2033 if (ppEditable == NULL)
2034 return AVIERR_BADPARAM;
2036 *ppEditable = NULL;
2038 if (pSource != NULL) {
2039 hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream,
2040 (LPVOID*)&pEdit);
2041 if (SUCCEEDED(hr) && pEdit != NULL) {
2042 hr = IAVIEditStream_Clone(pEdit, ppEditable);
2043 IAVIEditStream_Release(pEdit);
2045 return hr;
2049 /* need own implementation of IAVIEditStream */
2050 pEdit = AVIFILE_CreateEditStream(pSource);
2051 if (pEdit == NULL)
2052 return AVIERR_MEMORY;
2054 hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream,
2055 (LPVOID*)ppEditable);
2056 IAVIEditStream_Release(pEdit);
2058 return hr;
2061 /***********************************************************************
2062 * EditStreamClone (AVIFIL32.@)
2064 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
2066 PAVIEDITSTREAM pEdit = NULL;
2067 HRESULT hr;
2069 TRACE("(%p,%p)\n", pStream, ppResult);
2071 if (pStream == NULL)
2072 return AVIERR_BADHANDLE;
2073 if (ppResult == NULL)
2074 return AVIERR_BADPARAM;
2076 *ppResult = NULL;
2078 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2079 if (SUCCEEDED(hr) && pEdit != NULL) {
2080 hr = IAVIEditStream_Clone(pEdit, ppResult);
2082 IAVIEditStream_Release(pEdit);
2083 } else
2084 hr = AVIERR_UNSUPPORTED;
2086 return hr;
2089 /***********************************************************************
2090 * EditStreamCopy (AVIFIL32.@)
2092 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2093 LONG *plLength, PAVISTREAM *ppResult)
2095 PAVIEDITSTREAM pEdit = NULL;
2096 HRESULT hr;
2098 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2100 if (pStream == NULL)
2101 return AVIERR_BADHANDLE;
2102 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2103 return AVIERR_BADPARAM;
2105 *ppResult = NULL;
2107 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2108 if (SUCCEEDED(hr) && pEdit != NULL) {
2109 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2111 IAVIEditStream_Release(pEdit);
2112 } else
2113 hr = AVIERR_UNSUPPORTED;
2115 return hr;
2118 /***********************************************************************
2119 * EditStreamCut (AVIFIL32.@)
2121 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2122 LONG *plLength, PAVISTREAM *ppResult)
2124 PAVIEDITSTREAM pEdit = NULL;
2125 HRESULT hr;
2127 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2129 if (ppResult != NULL)
2130 *ppResult = NULL;
2131 if (pStream == NULL)
2132 return AVIERR_BADHANDLE;
2133 if (plStart == NULL || plLength == NULL)
2134 return AVIERR_BADPARAM;
2136 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2137 if (SUCCEEDED(hr) && pEdit != NULL) {
2138 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2140 IAVIEditStream_Release(pEdit);
2141 } else
2142 hr = AVIERR_UNSUPPORTED;
2144 return hr;
2147 /***********************************************************************
2148 * EditStreamPaste (AVIFIL32.@)
2150 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2151 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2153 PAVIEDITSTREAM pEdit = NULL;
2154 HRESULT hr;
2156 TRACE("(%p,%p,%p,%p,%ld,%ld)\n", pDest, plStart, plLength,
2157 pSource, lStart, lEnd);
2159 if (pDest == NULL || pSource == NULL)
2160 return AVIERR_BADHANDLE;
2161 if (plStart == NULL || plLength == NULL || lStart < 0)
2162 return AVIERR_BADPARAM;
2164 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2165 if (SUCCEEDED(hr) && pEdit != NULL) {
2166 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2168 IAVIEditStream_Release(pEdit);
2169 } else
2170 hr = AVIERR_UNSUPPORTED;
2172 return hr;
2175 /***********************************************************************
2176 * EditStreamSetInfoA (AVIFIL32.@)
2178 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2179 LONG size)
2181 AVISTREAMINFOW asiw;
2183 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2185 if (pstream == NULL)
2186 return AVIERR_BADHANDLE;
2187 if ((DWORD)size < sizeof(AVISTREAMINFOA))
2188 return AVIERR_BADSIZE;
2190 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2191 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
2192 asiw.szName, sizeof(asiw.szName));
2194 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2197 /***********************************************************************
2198 * EditStreamSetInfoW (AVIFIL32.@)
2200 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2201 LONG size)
2203 PAVIEDITSTREAM pEdit = NULL;
2204 HRESULT hr;
2206 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2208 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2209 if (SUCCEEDED(hr) && pEdit != NULL) {
2210 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2212 IAVIEditStream_Release(pEdit);
2213 } else
2214 hr = AVIERR_UNSUPPORTED;
2216 return hr;
2219 /***********************************************************************
2220 * EditStreamSetNameA (AVIFIL32.@)
2222 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2224 AVISTREAMINFOA asia;
2225 HRESULT hres;
2227 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2229 if (pstream == NULL)
2230 return AVIERR_BADHANDLE;
2231 if (szName == NULL)
2232 return AVIERR_BADPARAM;
2234 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2235 if (FAILED(hres))
2236 return hres;
2238 memset(asia.szName, 0, sizeof(asia.szName));
2239 lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
2241 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2244 /***********************************************************************
2245 * EditStreamSetNameW (AVIFIL32.@)
2247 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2249 AVISTREAMINFOW asiw;
2250 HRESULT hres;
2252 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2254 if (pstream == NULL)
2255 return AVIERR_BADHANDLE;
2256 if (szName == NULL)
2257 return AVIERR_BADPARAM;
2259 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2260 if (FAILED(hres))
2261 return hres;
2263 memset(asiw.szName, 0, sizeof(asiw.szName));
2264 lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
2266 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2269 /***********************************************************************
2270 * AVIClearClipboard (AVIFIL32.@)
2272 HRESULT WINAPI AVIClearClipboard(void)
2274 TRACE("()\n");
2276 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2279 /***********************************************************************
2280 * AVIGetFromClipboard (AVIFIL32.@)
2282 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2284 FIXME("(%p), stub!\n", ppfile);
2286 *ppfile = NULL;
2288 return AVIERR_UNSUPPORTED;
2291 /***********************************************************************
2292 * AVIMakeStreamFromClipboard (AVIFIL32.@)
2294 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
2295 PAVISTREAM * ppstream)
2297 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
2299 if (ppstream == NULL)
2300 return AVIERR_BADHANDLE;
2302 return AVIERR_UNSUPPORTED;
2305 /***********************************************************************
2306 * AVIPutFileOnClipboard (AVIFIL32.@)
2308 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2310 FIXME("(%p), stub!\n", pfile);
2312 if (pfile == NULL)
2313 return AVIERR_BADHANDLE;
2315 return AVIERR_UNSUPPORTED;
2318 HRESULT CDECL AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2319 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2321 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
2322 nStreams, pavi, lpOptions);
2324 return AVIERR_UNSUPPORTED;
2327 HRESULT CDECL AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2328 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2330 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
2331 nStreams, pavi, lpOptions);
2333 return AVIERR_UNSUPPORTED;