Fix a typo in a comment.
[wine/multimedia.git] / dlls / avifil32 / api.c
blob8be7900edc86010771a7f968c7871799731b12c6
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 /* need to load ole32.dll if not already done and get some functions */
180 FIXME("(): stub!\n");
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 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 = SHCoCreateInstance(NULL, &clsidHandler, NULL,
257 &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 = SHCoCreateInstance(NULL, pclsidHandler, NULL,
497 &IID_IAVIStream, (LPVOID*)ppavi);
498 if (FAILED(hr) || *ppavi == NULL)
499 return hr;
501 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
502 if (FAILED(hr)) {
503 IAVIStream_Release(*ppavi);
504 *ppavi = NULL;
507 return hr;
510 /***********************************************************************
511 * AVIStreamInfo (AVIFIL32.@)
512 * AVIStreamInfoA (AVIFIL32.@)
513 * AVIStreamInfo (AVIFILE.162)
515 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
516 LONG size)
518 AVISTREAMINFOW asiw;
519 HRESULT hres;
521 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
523 if (pstream == NULL)
524 return AVIERR_BADHANDLE;
525 if ((DWORD)size < sizeof(AVISTREAMINFOA))
526 return AVIERR_BADSIZE;
528 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
530 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
531 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
532 sizeof(asi->szName), NULL, NULL);
533 asi->szName[sizeof(asi->szName) - 1] = 0;
535 return hres;
538 /***********************************************************************
539 * AVIStreamInfoW (AVIFIL32.@)
541 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
542 LONG size)
544 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
546 if (pstream == NULL)
547 return AVIERR_BADHANDLE;
549 return IAVIStream_Info(pstream, asi, size);
552 /***********************************************************************
553 * AVIStreamFindSample (AVIFIL32.@)
554 * AVIStreamFindSample (AVIFILE.163)
556 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
558 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
560 if (pstream == NULL)
561 return -1;
563 return IAVIStream_FindSample(pstream, pos, flags);
566 /***********************************************************************
567 * AVIStreamReadFormat (AVIFIL32.@)
568 * AVIStreamReadFormat (AVIFILE.164)
570 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
571 LPVOID format, LPLONG formatsize)
573 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
575 if (pstream == NULL)
576 return AVIERR_BADHANDLE;
578 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
581 /***********************************************************************
582 * AVIStreamSetFormat (AVIFIL32.@)
583 * AVIStreamSetFormat (AVIFILE.169)
585 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
586 LPVOID format, LONG formatsize)
588 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
590 if (pstream == NULL)
591 return AVIERR_BADHANDLE;
593 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
596 /***********************************************************************
597 * AVIStreamRead (AVIFIL32.@)
598 * AVIStreamRead (AVIFILE.167)
600 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
601 LPVOID buffer, LONG buffersize,
602 LPLONG bytesread, LPLONG samplesread)
604 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
605 buffersize, bytesread, samplesread);
607 if (pstream == NULL)
608 return AVIERR_BADHANDLE;
610 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
611 bytesread, samplesread);
614 /***********************************************************************
615 * AVIStreamWrite (AVIFIL32.@)
616 * AVIStreamWrite (AVIFILE.168)
618 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
619 LPVOID buffer, LONG buffersize, DWORD flags,
620 LPLONG sampwritten, LPLONG byteswritten)
622 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
623 buffersize, flags, sampwritten, byteswritten);
625 if (pstream == NULL)
626 return AVIERR_BADHANDLE;
628 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
629 flags, sampwritten, byteswritten);
632 /***********************************************************************
633 * AVIStreamReadData (AVIFIL32.@)
634 * AVIStreamReadData (AVIFILE.165)
636 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
637 LPLONG lpread)
639 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
641 if (pstream == NULL)
642 return AVIERR_BADHANDLE;
644 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
647 /***********************************************************************
648 * AVIStreamWriteData (AVIFIL32.@)
649 * AVIStreamWriteData (AVIFILE.166)
651 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
652 LONG size)
654 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
656 if (pstream == NULL)
657 return AVIERR_BADHANDLE;
659 return IAVIStream_WriteData(pstream, fcc, lp, size);
662 /***********************************************************************
663 * AVIStreamGetFrameOpen (AVIFIL32.@)
664 * AVIStreamGetFrameOpen (AVIFILE.112)
666 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
667 LPBITMAPINFOHEADER lpbiWanted)
669 PGETFRAME pg = NULL;
671 TRACE("(%p,%p)\n", pstream, lpbiWanted);
673 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
674 pg == NULL) {
675 pg = AVIFILE_CreateGetFrame(pstream);
676 if (pg == NULL)
677 return NULL;
680 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
681 IGetFrame_Release(pg);
682 return NULL;
685 return pg;
688 /***********************************************************************
689 * AVIStreamGetFrame (AVIFIL32.@)
690 * AVIStreamGetFrame (AVIFILE.110)
692 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
694 TRACE("(%p,%ld)\n", pg, pos);
696 if (pg == NULL)
697 return NULL;
699 return IGetFrame_GetFrame(pg, pos);
702 /***********************************************************************
703 * AVIStreamGetFrameClose (AVIFIL32.@)
704 * AVIStreamGetFrameClose (AVIFILE.111)
706 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
708 TRACE("(%p)\n", pg);
710 if (pg != NULL)
711 return IGetFrame_Release(pg);
712 return 0;
715 /***********************************************************************
716 * AVIMakeCompressedStream (AVIFIL32.@)
718 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
719 PAVISTREAM psSource,
720 LPAVICOMPRESSOPTIONS aco,
721 LPCLSID pclsidHandler)
723 AVISTREAMINFOW asiw;
724 CHAR szRegKey[25];
725 CHAR szValue[100];
726 CLSID clsidHandler;
727 HRESULT hr;
728 LONG size = sizeof(szValue);
730 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
731 debugstr_guid(pclsidHandler));
733 if (ppsCompressed == NULL)
734 return AVIERR_BADPARAM;
735 if (psSource == NULL)
736 return AVIERR_BADHANDLE;
738 *ppsCompressed = NULL;
740 /* if no handler given get default ones based on streamtype */
741 if (pclsidHandler == NULL) {
742 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
743 if (FAILED(hr))
744 return hr;
746 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
747 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
748 return AVIERR_UNSUPPORTED;
749 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
750 return AVIERR_UNSUPPORTED;
751 } else
752 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
754 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
755 &IID_IAVIStream, (LPVOID*)ppsCompressed);
756 if (FAILED(hr) || *ppsCompressed == NULL)
757 return hr;
759 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
760 if (FAILED(hr)) {
761 IAVIStream_Release(*ppsCompressed);
762 *ppsCompressed = NULL;
765 return hr;
768 /***********************************************************************
769 * AVIMakeFileFromStreams (AVIFIL32.@)
771 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
772 PAVISTREAM *ppStreams)
774 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
776 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
777 return AVIERR_BADPARAM;
779 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
780 if (*ppfile == NULL)
781 return AVIERR_MEMORY;
783 return AVIERR_OK;
786 /***********************************************************************
787 * AVIStreamOpenFromFile (AVIFIL32.@)
788 * AVIStreamOpenFromFileA (AVIFIL32.@)
789 * AVIStreamOpenFromFile (AVIFILE.103)
791 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
792 DWORD fccType, LONG lParam,
793 UINT mode, LPCLSID pclsidHandler)
795 PAVIFILE pfile = NULL;
796 HRESULT hr;
798 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
799 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
801 if (ppavi == NULL || szFile == NULL)
802 return AVIERR_BADPARAM;
804 *ppavi = NULL;
806 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
807 if (FAILED(hr) || pfile == NULL)
808 return hr;
810 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
811 IAVIFile_Release(pfile);
813 return hr;
816 /***********************************************************************
817 * AVIStreamOpenFromFileW (AVIFIL32.@)
819 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
820 DWORD fccType, LONG lParam,
821 UINT mode, LPCLSID pclsidHandler)
823 PAVIFILE pfile = NULL;
824 HRESULT hr;
826 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
827 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
829 if (ppavi == NULL || szFile == NULL)
830 return AVIERR_BADPARAM;
832 *ppavi = NULL;
834 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
835 if (FAILED(hr) || pfile == NULL)
836 return hr;
838 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
839 IAVIFile_Release(pfile);
841 return hr;
844 /***********************************************************************
845 * AVIStreamBeginStreaming (AVIFIL32.@)
847 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
849 IAVIStreaming* pstream = NULL;
850 HRESULT hr;
852 TRACE("(%p,%ld,%ld,%ld)\n", pavi, lStart, lEnd, lRate);
854 if (pavi == NULL)
855 return AVIERR_BADHANDLE;
857 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
858 if (SUCCEEDED(hr) && pstream != NULL) {
859 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
860 IAVIStreaming_Release(pstream);
861 } else
862 hr = AVIERR_OK;
864 return hr;
867 /***********************************************************************
868 * AVIStreamEndStreaming (AVIFIL32.@)
870 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
872 IAVIStreaming* pstream = NULL;
873 HRESULT hr;
875 TRACE("(%p)\n", pavi);
877 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
878 if (SUCCEEDED(hr) && pstream != NULL) {
879 IAVIStreaming_End(pstream);
880 IAVIStreaming_Release(pstream);
883 return AVIERR_OK;
886 /***********************************************************************
887 * AVIStreamStart (AVIFILE.130)
888 * AVIStreamStart (AVIFIL32.@)
890 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
892 AVISTREAMINFOW asiw;
894 TRACE("(%p)\n", pstream);
896 if (pstream == NULL)
897 return 0;
899 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
900 return 0;
902 return asiw.dwStart;
905 /***********************************************************************
906 * AVIStreamLength (AVIFILE.131)
907 * AVIStreamLength (AVIFIL32.@)
909 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
911 AVISTREAMINFOW asiw;
913 TRACE("(%p)\n", pstream);
915 if (pstream == NULL)
916 return 0;
918 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
919 return 0;
921 return asiw.dwLength;
924 /***********************************************************************
925 * AVIStreamSampleToTime (AVIFILE.133)
926 * AVIStreamSampleToTime (AVIFIL32.@)
928 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
930 AVISTREAMINFOW asiw;
931 LONG time;
933 TRACE("(%p,%ld)\n", pstream, lSample);
935 if (pstream == NULL)
936 return -1;
938 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
939 return -1;
940 if (asiw.dwRate == 0)
941 return -1;
943 /* limit to stream bounds */
944 if (lSample < asiw.dwStart)
945 lSample = asiw.dwStart;
946 if (lSample > asiw.dwStart + asiw.dwLength)
947 lSample = asiw.dwStart + asiw.dwLength;
949 if (asiw.dwRate / asiw.dwScale < 1000)
950 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
951 else
952 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
954 TRACE(" -> %ld\n",time);
955 return time;
958 /***********************************************************************
959 * AVIStreamTimeToSample (AVIFILE.132)
960 * AVIStreamTimeToSample (AVIFIL32.@)
962 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
964 AVISTREAMINFOW asiw;
965 ULONG sample;
967 TRACE("(%p,%ld)\n", pstream, lTime);
969 if (pstream == NULL || lTime < 0)
970 return -1;
972 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
973 return -1;
974 if (asiw.dwScale == 0)
975 return -1;
977 if (asiw.dwRate / asiw.dwScale < 1000)
978 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
979 else
980 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
982 /* limit to stream bounds */
983 if (sample < asiw.dwStart)
984 sample = asiw.dwStart;
985 if (sample > asiw.dwStart + asiw.dwLength)
986 sample = asiw.dwStart + asiw.dwLength;
988 TRACE(" -> %ld\n", sample);
989 return sample;
992 /***********************************************************************
993 * AVIBuildFilter (AVIFIL32.@)
994 * AVIBuildFilterA (AVIFIL32.@)
995 * AVIBuildFilter (AVIFILE.123)
997 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
999 LPWSTR wszFilter;
1000 HRESULT hr;
1002 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1004 /* check parameters */
1005 if (szFilter == NULL)
1006 return AVIERR_BADPARAM;
1007 if (cbFilter < 2)
1008 return AVIERR_BADSIZE;
1010 szFilter[0] = 0;
1011 szFilter[1] = 0;
1013 wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter * sizeof(WCHAR));
1014 if (wszFilter == NULL)
1015 return AVIERR_MEMORY;
1017 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
1018 if (SUCCEEDED(hr)) {
1019 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
1020 szFilter, cbFilter, NULL, NULL);
1023 GlobalFreePtr(wszFilter);
1025 return hr;
1028 /***********************************************************************
1029 * AVIBuildFilterW (AVIFIL32.@)
1031 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
1033 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
1034 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1035 static const WCHAR szAVIFileExtensions[] =
1036 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1038 AVIFilter *lp;
1039 WCHAR szAllFiles[40];
1040 WCHAR szFileExt[10];
1041 WCHAR szValue[128];
1042 HKEY hKey;
1043 DWORD n, i;
1044 LONG size;
1045 DWORD count = 0;
1047 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1049 /* check parameters */
1050 if (szFilter == NULL)
1051 return AVIERR_BADPARAM;
1052 if (cbFilter < 2)
1053 return AVIERR_BADSIZE;
1055 lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
1056 if (lp == NULL)
1057 return AVIERR_MEMORY;
1060 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1061 * extensions and CLSID's
1062 * 2. iterate over collected CLSID's and copy its description and its
1063 * extensions to szFilter if it fits
1065 * First filter is named "All multimedia files" and its filter is a
1066 * collection of all possible extensions except "*.*".
1068 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
1069 GlobalFreePtr(lp);
1070 return AVIERR_ERROR;
1072 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
1073 /* get CLSID to extension */
1074 size = sizeof(szValue)/sizeof(szValue[0]);
1075 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
1076 break;
1078 /* search if the CLSID is already known */
1079 for (i = 1; i <= count; i++) {
1080 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
1081 break; /* a new one */
1084 if (count - i == -1U) {
1085 /* it's a new CLSID */
1087 /* FIXME: How do we get info's about read/write capabilities? */
1089 if (count >= MAX_FILTERS) {
1090 /* try to inform user of our full fixed size table */
1091 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1092 break;
1095 lstrcpyW(lp[i].szClsid, szValue);
1097 count++;
1100 /* append extension to the filter */
1101 wsprintfW(szValue, szExtensionFmt, szFileExt);
1102 if (lp[i].szExtensions[0] == 0)
1103 lstrcatW(lp[i].szExtensions, szValue + 1);
1104 else
1105 lstrcatW(lp[i].szExtensions, szValue);
1107 /* also append to the "all multimedia"-filter */
1108 if (lp[0].szExtensions[0] == 0)
1109 lstrcatW(lp[0].szExtensions, szValue + 1);
1110 else
1111 lstrcatW(lp[0].szExtensions, szValue);
1113 RegCloseKey(hKey);
1115 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1116 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1117 GlobalFreePtr(lp);
1118 return AVIERR_ERROR;
1120 for (n = 0; n <= count; n++) {
1121 /* first the description */
1122 if (n != 0) {
1123 size = sizeof(szValue)/sizeof(szValue[0]);
1124 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1125 size = lstrlenW(szValue);
1126 lstrcpynW(szFilter, szValue, cbFilter);
1128 } else
1129 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1131 /* check for enough space */
1132 size++;
1133 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1134 szFilter[0] = 0;
1135 szFilter[1] = 0;
1136 GlobalFreePtr(lp);
1137 RegCloseKey(hKey);
1138 return AVIERR_BUFFERTOOSMALL;
1140 cbFilter -= size;
1141 szFilter += size;
1143 /* and then the filter */
1144 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1145 size = lstrlenW(lp[n].szExtensions) + 1;
1146 cbFilter -= size;
1147 szFilter += size;
1150 RegCloseKey(hKey);
1151 GlobalFreePtr(lp);
1153 /* add "All files" "*.*" filter if enough space left */
1154 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1155 szAllFiles, sizeof(szAllFiles)) + 1;
1156 if (cbFilter > size) {
1157 int i;
1159 /* replace '@' with \000 to separate description of filter */
1160 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1161 if (szAllFiles[i] == '@') {
1162 szAllFiles[i] = 0;
1163 break;
1167 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1168 szFilter += size;
1169 szFilter[0] = 0;
1171 return AVIERR_OK;
1172 } else {
1173 szFilter[0] = 0;
1174 return AVIERR_BUFFERTOOSMALL;
1178 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1180 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1181 AVISTREAMINFOW sInfo;
1183 TRACE("(%p)\n", hWnd);
1185 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1186 ERR(": bad state!\n");
1187 return FALSE;
1190 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1191 &sInfo, sizeof(sInfo)))) {
1192 ERR(": AVIStreamInfoW failed!\n");
1193 return FALSE;
1196 if (sInfo.fccType == streamtypeVIDEO) {
1197 COMPVARS cv;
1198 BOOL ret;
1200 memset(&cv, 0, sizeof(cv));
1202 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1203 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1204 pOptions->fccType = streamtypeVIDEO;
1205 pOptions->fccHandler = comptypeDIB;
1206 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1209 cv.cbSize = sizeof(cv);
1210 cv.dwFlags = ICMF_COMPVARS_VALID;
1211 /*cv.fccType = pOptions->fccType; */
1212 cv.fccHandler = pOptions->fccHandler;
1213 cv.lQ = pOptions->dwQuality;
1214 cv.lpState = pOptions->lpParms;
1215 cv.cbState = pOptions->cbParms;
1216 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1217 cv.lKey = pOptions->dwKeyFrameEvery;
1218 else
1219 cv.lKey = 0;
1220 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1221 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1222 else
1223 cv.lDataRate = 0;
1225 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1226 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1228 if (ret) {
1229 pOptions->fccHandler = cv.fccHandler;
1230 pOptions->lpParms = cv.lpState;
1231 pOptions->cbParms = cv.cbState;
1232 pOptions->dwQuality = cv.lQ;
1233 if (cv.lKey != 0) {
1234 pOptions->dwKeyFrameEvery = cv.lKey;
1235 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1236 } else
1237 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1238 if (cv.lDataRate != 0) {
1239 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1240 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1241 } else
1242 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1243 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1245 ICCompressorFree(&cv);
1247 return ret;
1248 } else if (sInfo.fccType == streamtypeAUDIO) {
1249 ACMFORMATCHOOSEW afmtc;
1250 MMRESULT ret;
1251 LONG size;
1253 /* FIXME: check ACM version -- Which version is needed? */
1255 memset(&afmtc, 0, sizeof(afmtc));
1256 afmtc.cbStruct = sizeof(afmtc);
1257 afmtc.fdwStyle = 0;
1258 afmtc.hwndOwner = hWnd;
1260 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1261 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1262 pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1263 pOptions->cbFormat = size;
1264 } else if (pOptions->cbFormat < (DWORD)size) {
1265 pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1266 pOptions->cbFormat = size;
1268 if (pOptions->lpFormat == NULL)
1269 return FALSE;
1270 afmtc.pwfx = pOptions->lpFormat;
1271 afmtc.cbwfx = pOptions->cbFormat;
1273 size = 0;
1274 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1275 sInfo.dwStart, &size);
1276 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1277 size = sizeof(PCMWAVEFORMAT);
1278 afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1279 if (afmtc.pwfxEnum != NULL) {
1280 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1281 sInfo.dwStart, afmtc.pwfxEnum, &size);
1282 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1285 ret = acmFormatChooseW(&afmtc);
1286 if (ret == S_OK)
1287 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1289 if (afmtc.pwfxEnum != NULL)
1290 GlobalFreePtr(afmtc.pwfxEnum);
1292 return (ret == S_OK ? TRUE : FALSE);
1293 } else {
1294 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1295 return FALSE;
1299 static void AVISaveOptionsUpdate(HWND hWnd)
1301 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1302 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1304 WCHAR szFormat[128];
1305 AVISTREAMINFOW sInfo;
1306 LPVOID lpFormat;
1307 LONG size;
1309 TRACE("(%p)\n", hWnd);
1311 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1312 if (SaveOpts.nCurrent < 0)
1313 return;
1315 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1316 return;
1318 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1319 if (size > 0) {
1320 szFormat[0] = 0;
1322 /* read format to build format description string */
1323 lpFormat = GlobalAllocPtr(GHND, size);
1324 if (lpFormat != NULL) {
1325 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1326 if (sInfo.fccType == streamtypeVIDEO) {
1327 LPBITMAPINFOHEADER lpbi = lpFormat;
1328 ICINFO icinfo;
1330 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1331 lpbi->biHeight, lpbi->biBitCount);
1333 if (lpbi->biCompression != BI_RGB) {
1334 HIC hic;
1336 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1337 NULL, ICMODE_DECOMPRESS);
1338 if (hic != NULL) {
1339 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1340 lstrcatW(szFormat, icinfo.szDescription);
1341 ICClose(hic);
1343 } else {
1344 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1345 icinfo.szDescription, sizeof(icinfo.szDescription));
1346 lstrcatW(szFormat, icinfo.szDescription);
1348 } else if (sInfo.fccType == streamtypeAUDIO) {
1349 ACMFORMATTAGDETAILSW aftd;
1350 ACMFORMATDETAILSW afd;
1352 memset(&aftd, 0, sizeof(aftd));
1353 memset(&afd, 0, sizeof(afd));
1355 aftd.cbStruct = sizeof(aftd);
1356 aftd.dwFormatTag = afd.dwFormatTag =
1357 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1358 aftd.cbFormatSize = afd.cbwfx = size;
1360 afd.cbStruct = sizeof(afd);
1361 afd.pwfx = lpFormat;
1363 if (acmFormatTagDetailsW(NULL, &aftd,
1364 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1365 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1366 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1370 GlobalFreePtr(lpFormat);
1373 /* set text for format description */
1374 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1376 /* Disable option button for unsupported streamtypes */
1377 if (sInfo.fccType == streamtypeVIDEO ||
1378 sInfo.fccType == streamtypeAUDIO)
1379 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1380 else
1381 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1386 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1387 WPARAM wParam, LPARAM lParam)
1389 DWORD dwInterleave;
1390 BOOL bIsInterleaved;
1391 INT n;
1393 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1395 switch (uMsg) {
1396 case WM_INITDIALOG:
1397 SaveOpts.nCurrent = 0;
1398 if (SaveOpts.nStreams == 1) {
1399 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1400 return TRUE;
1403 /* add streams */
1404 for (n = 0; n < SaveOpts.nStreams; n++) {
1405 AVISTREAMINFOW sInfo;
1407 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1408 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1409 0L, (LPARAM)sInfo.szName);
1412 /* select first stream */
1413 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1414 SendMessageW(hWnd, WM_COMMAND,
1415 GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1417 /* initialize interleave */
1418 if (SaveOpts.ppOptions[0] != NULL &&
1419 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1420 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1421 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1422 } else {
1423 bIsInterleaved = TRUE;
1424 dwInterleave = 0;
1426 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1427 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1428 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1429 break;
1430 case WM_COMMAND:
1431 switch (GET_WM_COMMAND_ID(wParam, lParam)) {
1432 case IDOK:
1433 /* get data from controls and save them */
1434 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1435 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1436 for (n = 0; n < SaveOpts.nStreams; n++) {
1437 if (SaveOpts.ppOptions[n] != NULL) {
1438 if (bIsInterleaved) {
1439 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1440 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1441 } else
1442 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1445 /* fall through */
1446 case IDCANCEL:
1447 EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
1448 break;
1449 case IDC_INTERLEAVE:
1450 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1451 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1452 break;
1453 case IDC_STREAM:
1454 if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1455 /* update control elements */
1456 AVISaveOptionsUpdate(hWnd);
1458 break;
1459 case IDC_OPTIONS:
1460 AVISaveOptionsFmtChoose(hWnd);
1461 break;
1463 return TRUE;
1466 return FALSE;
1469 /***********************************************************************
1470 * AVISaveOptions (AVIFIL32.@)
1472 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1473 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1475 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1476 INT ret, n;
1478 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1479 ppavi, ppOptions);
1481 /* check parameters */
1482 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1483 return AVIERR_BADPARAM;
1485 /* save options in case the user presses cancel */
1486 if (ppOptions != NULL && nStreams > 1) {
1487 pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1488 if (pSavedOptions == NULL)
1489 return FALSE;
1491 for (n = 0; n < nStreams; n++) {
1492 if (ppOptions[n] != NULL)
1493 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1497 SaveOpts.uFlags = uFlags;
1498 SaveOpts.nStreams = nStreams;
1499 SaveOpts.ppavis = ppavi;
1500 SaveOpts.ppOptions = ppOptions;
1502 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1503 hWnd, AVISaveOptionsDlgProc);
1505 if (ret == -1)
1506 ret = FALSE;
1508 /* restore options when user pressed cancel */
1509 if (pSavedOptions != NULL) {
1510 if (ret == FALSE) {
1511 for (n = 0; n < nStreams; n++) {
1512 if (ppOptions[n] != NULL)
1513 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1516 GlobalFreePtr(pSavedOptions);
1519 return (BOOL)ret;
1522 /***********************************************************************
1523 * AVISaveOptionsFree (AVIFIL32.@)
1524 * AVISaveOptionsFree (AVIFILE.124)
1526 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1528 TRACE("(%d,%p)\n", nStreams, ppOptions);
1530 if (nStreams < 0 || ppOptions == NULL)
1531 return AVIERR_BADPARAM;
1533 for (; nStreams > 0; nStreams--) {
1534 if (ppOptions[nStreams] != NULL) {
1535 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1537 if (ppOptions[nStreams]->lpParms != NULL) {
1538 GlobalFreePtr(ppOptions[nStreams]->lpParms);
1539 ppOptions[nStreams]->lpParms = NULL;
1540 ppOptions[nStreams]->cbParms = 0;
1542 if (ppOptions[nStreams]->lpFormat != NULL) {
1543 GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1544 ppOptions[nStreams]->lpFormat = NULL;
1545 ppOptions[nStreams]->cbFormat = 0;
1550 return AVIERR_OK;
1553 /***********************************************************************
1554 * AVISaveVA (AVIFIL32.@)
1556 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1557 AVISAVECALLBACK lpfnCallback, int nStream,
1558 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1560 LPWSTR wszFile = NULL;
1561 HRESULT hr;
1562 int len;
1564 TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1565 lpfnCallback, nStream, ppavi, plpOptions);
1567 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1568 return AVIERR_BADPARAM;
1570 /* convert ASCII string to Unicode and call Unicode function */
1571 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1572 if (len <= 0)
1573 return AVIERR_BADPARAM;
1575 wszFile = LocalAlloc(LPTR, len * sizeof(WCHAR));
1576 if (wszFile == NULL)
1577 return AVIERR_MEMORY;
1579 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
1581 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1582 nStream, ppavi, plpOptions);
1584 LocalFree((HLOCAL)wszFile);
1586 return hr;
1589 /***********************************************************************
1590 * AVIFILE_AVISaveDefaultCallback (internal)
1592 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1594 TRACE("(%d)\n", progress);
1596 return FALSE;
1599 /***********************************************************************
1600 * AVISaveVW (AVIFIL32.@)
1602 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1603 AVISAVECALLBACK lpfnCallback, int nStreams,
1604 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1606 LONG lStart[MAX_AVISTREAMS];
1607 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1608 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1609 AVIFILEINFOW fInfo;
1610 AVISTREAMINFOW sInfo;
1612 PAVIFILE pfile = NULL; /* the output AVI file */
1613 LONG lFirstVideo = -1;
1614 int curStream;
1616 /* for interleaving ... */
1617 DWORD dwInterleave = 0; /* interleave rate */
1618 DWORD dwFileInitialFrames;
1619 LONG lFileLength;
1620 LONG lSampleInc;
1622 /* for reading/writing the data ... */
1623 LPVOID lpBuffer = NULL;
1624 LONG cbBuffer; /* real size of lpBuffer */
1625 LONG lBufferSize; /* needed bytes for format(s), etc. */
1626 LONG lReadBytes;
1627 LONG lReadSamples;
1628 HRESULT hres;
1630 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1631 lpfnCallback, nStreams, ppavi, plpOptions);
1633 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1634 return AVIERR_BADPARAM;
1635 if (nStreams >= MAX_AVISTREAMS) {
1636 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1637 return AVIERR_INTERNAL;
1640 if (lpfnCallback == NULL)
1641 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1643 /* clear local variable(s) */
1644 for (curStream = 0; curStream < nStreams; curStream++) {
1645 pInStreams[curStream] = NULL;
1646 pOutStreams[curStream] = NULL;
1649 /* open output AVI file (create it if it doesn't exist) */
1650 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1651 pclsidHandler);
1652 if (FAILED(hres))
1653 return hres;
1654 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1656 /* initialize our data structures part 1 */
1657 for (curStream = 0; curStream < nStreams; curStream++) {
1658 PAVISTREAM pCurStream = ppavi[curStream];
1660 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1661 if (FAILED(hres))
1662 goto error;
1664 /* search first video stream and check for interleaving */
1665 if (sInfo.fccType == streamtypeVIDEO) {
1666 /* remember first video stream -- needed for interleaving */
1667 if (lFirstVideo < 0)
1668 lFirstVideo = curStream;
1669 } else if (!dwInterleave && plpOptions != NULL) {
1670 /* check if any non-video stream wants to be interleaved */
1671 WARN("options.flags=0x%lX options.dwInterleave=%lu\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1672 if (plpOptions[curStream] != NULL &&
1673 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1674 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1677 /* create de-/compressed stream interface if needed */
1678 pInStreams[curStream] = NULL;
1679 if (plpOptions != NULL && plpOptions[curStream] != NULL) {
1680 if (plpOptions[curStream]->fccHandler ||
1681 plpOptions[curStream]->lpFormat != NULL) {
1682 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1684 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1685 plpOptions[curStream]->dwKeyFrameEvery = 1;
1687 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1688 plpOptions[curStream], NULL);
1689 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1690 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1691 pInStreams[curStream] = NULL;
1692 goto error;
1695 /* test stream interface and update stream-info */
1696 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1697 if (FAILED(hres))
1698 goto error;
1702 /* now handle streams which will only be copied */
1703 if (pInStreams[curStream] == NULL) {
1704 pCurStream = pInStreams[curStream] = ppavi[curStream];
1705 AVIStreamAddRef(pCurStream);
1706 } else
1707 pCurStream = pInStreams[curStream];
1709 lStart[curStream] = sInfo.dwStart;
1710 } /* for all streams */
1712 /* check that first video stream is the first stream */
1713 if (lFirstVideo > 0) {
1714 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1715 LONG lTmp = lStart[lFirstVideo];
1717 pInStreams[lFirstVideo] = pInStreams[0];
1718 pInStreams[0] = pTmp;
1719 lStart[lFirstVideo] = lStart[0];
1720 lStart[0] = lTmp;
1721 lFirstVideo = 0;
1724 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
1725 lpBuffer = GlobalAllocPtr(GPTR, cbBuffer = 0x00010000);
1726 if (lpBuffer == NULL) {
1727 hres = AVIERR_MEMORY;
1728 goto error;
1731 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
1732 lFileLength = sInfo.dwLength;
1733 dwFileInitialFrames = 0;
1734 if (lFirstVideo >= 0) {
1735 /* check for correct version of the format
1736 * -- need at least BITMAPINFOHEADER or newer
1738 lSampleInc = 1;
1739 lBufferSize = cbBuffer;
1740 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
1741 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
1742 hres = AVIERR_INTERNAL;
1743 if (FAILED(hres))
1744 goto error;
1745 } else /* use one second blocks for interleaving if no video present */
1746 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
1748 /* create output streams */
1749 for (curStream = 0; curStream < nStreams; curStream++) {
1750 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1752 sInfo.dwInitialFrames = 0;
1753 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
1754 /* 750 ms initial frames for non-video streams */
1755 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
1758 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
1759 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
1760 /* copy initial format for this stream */
1761 lBufferSize = cbBuffer;
1762 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1763 lpBuffer, &lBufferSize);
1764 if (FAILED(hres))
1765 goto error;
1766 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
1767 if (FAILED(hres))
1768 goto error;
1770 /* try to copy stream handler data */
1771 lBufferSize = cbBuffer;
1772 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
1773 lpBuffer, &lBufferSize);
1774 if (SUCCEEDED(hres) && lBufferSize > 0) {
1775 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
1776 lpBuffer, lBufferSize);
1777 if (FAILED(hres))
1778 goto error;
1781 if (dwFileInitialFrames < sInfo.dwInitialFrames)
1782 dwFileInitialFrames = sInfo.dwInitialFrames;
1783 lReadBytes =
1784 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
1785 sInfo.dwLength);
1786 if (lFileLength < lReadBytes)
1787 lFileLength = lReadBytes;
1788 } else {
1789 /* creation of de-/compression stream interface failed */
1790 WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
1791 AVIStreamRelease(pInStreams[curStream]);
1792 if (curStream + 1 >= nStreams) {
1793 /* move the others one up */
1794 PAVISTREAM *ppas = &pInStreams[curStream];
1795 int n = nStreams - (curStream + 1);
1797 do {
1798 *ppas = pInStreams[curStream + 1];
1799 } while (--n);
1801 nStreams--;
1802 curStream--;
1804 } /* create output streams for all input streams */
1806 /* have we still something to write, or lost everything? */
1807 if (nStreams <= 0)
1808 goto error;
1810 if (dwInterleave) {
1811 LONG lCurFrame = -dwFileInitialFrames;
1813 /* interleaved file */
1814 if (dwInterleave == 1)
1815 AVIFileEndRecord(pfile);
1817 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
1818 for (curStream = 0; curStream < nStreams; curStream++) {
1819 LONG lLastSample;
1821 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
1822 if (FAILED(hres))
1823 goto error;
1825 /* initial frames phase at the end for this stream? */
1826 if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
1827 continue;
1829 if ((lFileLength - lSampleInc) <= lCurFrame) {
1830 lLastSample = AVIStreamLength(pInStreams[curStream]);
1831 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
1832 } else {
1833 if (curStream != 0) {
1834 lFirstVideo =
1835 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
1836 (sInfo.fccType == streamtypeVIDEO ?
1837 (LONG)dwInterleave : lSampleInc) +
1838 sInfo.dwInitialFrames + lCurFrame);
1839 } else
1840 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
1842 lLastSample = AVIStreamEnd(pInStreams[curStream]);
1843 if (lLastSample <= lFirstVideo)
1844 lFirstVideo = lLastSample;
1847 /* copy needed samples now */
1848 WARN("copy from stream %d samples %ld to %ld...\n",curStream,
1849 lStart[curStream],lFirstVideo);
1850 while (lFirstVideo > lStart[curStream]) {
1851 DWORD flags = 0;
1853 /* copy format in case it can change */
1854 lBufferSize = cbBuffer;
1855 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
1856 lpBuffer, &lBufferSize);
1857 if (FAILED(hres))
1858 goto error;
1859 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
1860 lpBuffer, lBufferSize);
1862 /* try to read data until we got it, or error */
1863 do {
1864 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
1865 lFirstVideo - lStart[curStream], lpBuffer,
1866 cbBuffer, &lReadBytes, &lReadSamples);
1867 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1868 (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
1869 if (lpBuffer == NULL)
1870 hres = AVIERR_MEMORY;
1871 if (FAILED(hres))
1872 goto error;
1874 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1875 flags = AVIIF_KEYFRAME;
1876 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1877 lpBuffer, lReadBytes, flags, NULL, NULL);
1878 if (FAILED(hres))
1879 goto error;
1881 lStart[curStream] += lReadSamples;
1883 lStart[curStream] = lFirstVideo;
1884 } /* stream by stream */
1886 /* need to close this block? */
1887 if (dwInterleave == 1) {
1888 hres = AVIFileEndRecord(pfile);
1889 if (FAILED(hres))
1890 break;
1893 /* show progress */
1894 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
1895 dwFileInitialFrames + lFileLength))) {
1896 hres = AVIERR_USERABORT;
1897 break;
1899 } /* copy frame by frame */
1900 } else {
1901 /* non-interleaved file */
1903 for (curStream = 0; curStream < nStreams; curStream++) {
1904 /* show progress */
1905 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
1906 hres = AVIERR_USERABORT;
1907 goto error;
1910 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1912 if (sInfo.dwSampleSize != 0) {
1913 /* sample-based data like audio */
1914 while (sInfo.dwStart < sInfo.dwLength) {
1915 LONG lSamples = cbBuffer / sInfo.dwSampleSize;
1917 /* copy format in case it can change */
1918 lBufferSize = cbBuffer;
1919 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1920 lpBuffer, &lBufferSize);
1921 if (FAILED(hres))
1922 return hres;
1923 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1924 lpBuffer, lBufferSize);
1926 /* limit to stream boundaries */
1927 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
1928 lSamples = sInfo.dwLength - sInfo.dwStart;
1930 /* now try to read until we get it, or an error occurs */
1931 do {
1932 lReadBytes = cbBuffer;
1933 lReadSamples = 0;
1934 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
1935 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
1936 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1937 (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
1938 if (lpBuffer == NULL)
1939 hres = AVIERR_MEMORY;
1940 if (FAILED(hres))
1941 goto error;
1942 if (lReadSamples != 0) {
1943 sInfo.dwStart += lReadSamples;
1944 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1945 lpBuffer, lReadBytes, 0, NULL , NULL);
1946 if (FAILED(hres))
1947 goto error;
1949 /* show progress */
1950 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
1951 MulDiv(curStream, 100, nStreams))) {
1952 hres = AVIERR_USERABORT;
1953 goto error;
1955 } else {
1956 if ((sInfo.dwLength - sInfo.dwStart) != 1) {
1957 hres = AVIERR_FILEREAD;
1958 goto error;
1962 } else {
1963 /* block-based data like video */
1964 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
1965 DWORD flags = 0;
1967 /* copy format in case it can change */
1968 lBufferSize = cbBuffer;
1969 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
1970 lpBuffer, &lBufferSize);
1971 if (FAILED(hres))
1972 goto error;
1973 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
1974 lpBuffer, lBufferSize);
1976 /* try to read block and resize buffer if necessary */
1977 do {
1978 lReadSamples = 0;
1979 lReadBytes = cbBuffer;
1980 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
1981 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
1982 } while ((hres == AVIERR_BUFFERTOOSMALL) &&
1983 (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
1984 if (lpBuffer == NULL)
1985 hres = AVIERR_MEMORY;
1986 if (FAILED(hres))
1987 goto error;
1988 if (lReadSamples != 1) {
1989 hres = AVIERR_FILEREAD;
1990 goto error;
1993 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
1994 flags = AVIIF_KEYFRAME;
1995 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
1996 lpBuffer, lReadBytes, flags, NULL, NULL);
1997 if (FAILED(hres))
1998 goto error;
2000 /* show progress */
2001 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
2002 MulDiv(curStream, 100, nStreams))) {
2003 hres = AVIERR_USERABORT;
2004 goto error;
2006 } /* copy all blocks */
2008 } /* copy data stream by stream */
2011 error:
2012 if (lpBuffer != NULL)
2013 GlobalFreePtr(lpBuffer);
2014 if (pfile != NULL) {
2015 for (curStream = 0; curStream < nStreams; curStream++) {
2016 if (pOutStreams[curStream] != NULL)
2017 AVIStreamRelease(pOutStreams[curStream]);
2018 if (pInStreams[curStream] != NULL)
2019 AVIStreamRelease(pInStreams[curStream]);
2022 AVIFileRelease(pfile);
2025 return hres;
2028 /***********************************************************************
2029 * CreateEditableStream (AVIFIL32.@)
2031 HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
2033 IAVIEditStream *pEdit = NULL;
2034 HRESULT hr;
2036 TRACE("(%p,%p)\n", ppEditable, pSource);
2038 if (ppEditable == NULL)
2039 return AVIERR_BADPARAM;
2041 *ppEditable = NULL;
2043 if (pSource != NULL) {
2044 hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream,
2045 (LPVOID*)&pEdit);
2046 if (SUCCEEDED(hr) && pEdit != NULL) {
2047 hr = IAVIEditStream_Clone(pEdit, ppEditable);
2048 IAVIEditStream_Release(pEdit);
2050 return hr;
2054 /* need own implementation of IAVIEditStream */
2055 pEdit = AVIFILE_CreateEditStream(pSource);
2056 if (pEdit == NULL)
2057 return AVIERR_MEMORY;
2059 hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream,
2060 (LPVOID*)ppEditable);
2061 IAVIEditStream_Release(pEdit);
2063 return hr;
2066 /***********************************************************************
2067 * EditStreamClone (AVIFIL32.@)
2069 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
2071 PAVIEDITSTREAM pEdit = NULL;
2072 HRESULT hr;
2074 TRACE("(%p,%p)\n", pStream, ppResult);
2076 if (pStream == NULL)
2077 return AVIERR_BADHANDLE;
2078 if (ppResult == NULL)
2079 return AVIERR_BADPARAM;
2081 *ppResult = NULL;
2083 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2084 if (SUCCEEDED(hr) && pEdit != NULL) {
2085 hr = IAVIEditStream_Clone(pEdit, ppResult);
2087 IAVIEditStream_Release(pEdit);
2088 } else
2089 hr = AVIERR_UNSUPPORTED;
2091 return hr;
2094 /***********************************************************************
2095 * EditStreamCopy (AVIFIL32.@)
2097 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2098 LONG *plLength, PAVISTREAM *ppResult)
2100 PAVIEDITSTREAM pEdit = NULL;
2101 HRESULT hr;
2103 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2105 if (pStream == NULL)
2106 return AVIERR_BADHANDLE;
2107 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2108 return AVIERR_BADPARAM;
2110 *ppResult = NULL;
2112 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2113 if (SUCCEEDED(hr) && pEdit != NULL) {
2114 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2116 IAVIEditStream_Release(pEdit);
2117 } else
2118 hr = AVIERR_UNSUPPORTED;
2120 return hr;
2123 /***********************************************************************
2124 * EditStreamCut (AVIFIL32.@)
2126 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2127 LONG *plLength, PAVISTREAM *ppResult)
2129 PAVIEDITSTREAM pEdit = NULL;
2130 HRESULT hr;
2132 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2134 if (ppResult != NULL)
2135 *ppResult = NULL;
2136 if (pStream == NULL)
2137 return AVIERR_BADHANDLE;
2138 if (plStart == NULL || plLength == NULL)
2139 return AVIERR_BADPARAM;
2141 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2142 if (SUCCEEDED(hr) && pEdit != NULL) {
2143 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2145 IAVIEditStream_Release(pEdit);
2146 } else
2147 hr = AVIERR_UNSUPPORTED;
2149 return hr;
2152 /***********************************************************************
2153 * EditStreamPaste (AVIFIL32.@)
2155 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2156 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2158 PAVIEDITSTREAM pEdit = NULL;
2159 HRESULT hr;
2161 TRACE("(%p,%p,%p,%p,%ld,%ld)\n", pDest, plStart, plLength,
2162 pSource, lStart, lEnd);
2164 if (pDest == NULL || pSource == NULL)
2165 return AVIERR_BADHANDLE;
2166 if (plStart == NULL || plLength == NULL || lStart < 0)
2167 return AVIERR_BADPARAM;
2169 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2170 if (SUCCEEDED(hr) && pEdit != NULL) {
2171 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2173 IAVIEditStream_Release(pEdit);
2174 } else
2175 hr = AVIERR_UNSUPPORTED;
2177 return hr;
2180 /***********************************************************************
2181 * EditStreamSetInfoA (AVIFIL32.@)
2183 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2184 LONG size)
2186 AVISTREAMINFOW asiw;
2188 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2190 if (pstream == NULL)
2191 return AVIERR_BADHANDLE;
2192 if ((DWORD)size < sizeof(AVISTREAMINFOA))
2193 return AVIERR_BADSIZE;
2195 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2196 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
2197 asiw.szName, sizeof(asiw.szName));
2199 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2202 /***********************************************************************
2203 * EditStreamSetInfoW (AVIFIL32.@)
2205 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2206 LONG size)
2208 PAVIEDITSTREAM pEdit = NULL;
2209 HRESULT hr;
2211 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2213 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2214 if (SUCCEEDED(hr) && pEdit != NULL) {
2215 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2217 IAVIEditStream_Release(pEdit);
2218 } else
2219 hr = AVIERR_UNSUPPORTED;
2221 return hr;
2224 /***********************************************************************
2225 * EditStreamSetNameA (AVIFIL32.@)
2227 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2229 AVISTREAMINFOA asia;
2230 HRESULT hres;
2232 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2234 if (pstream == NULL)
2235 return AVIERR_BADHANDLE;
2236 if (szName == NULL)
2237 return AVIERR_BADPARAM;
2239 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2240 if (FAILED(hres))
2241 return hres;
2243 memset(asia.szName, 0, sizeof(asia.szName));
2244 lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
2246 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2249 /***********************************************************************
2250 * EditStreamSetNameW (AVIFIL32.@)
2252 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2254 AVISTREAMINFOW asiw;
2255 HRESULT hres;
2257 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2259 if (pstream == NULL)
2260 return AVIERR_BADHANDLE;
2261 if (szName == NULL)
2262 return AVIERR_BADPARAM;
2264 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2265 if (FAILED(hres))
2266 return hres;
2268 memset(asiw.szName, 0, sizeof(asiw.szName));
2269 lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
2271 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2274 /***********************************************************************
2275 * AVIClearClipboard (AVIFIL32.@)
2277 HRESULT WINAPI AVIClearClipboard(void)
2279 TRACE("()\n");
2281 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2284 /***********************************************************************
2285 * AVIGetFromClipboard (AVIFIL32.@)
2287 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2289 FIXME("(%p), stub!\n", ppfile);
2291 *ppfile = NULL;
2293 return AVIERR_UNSUPPORTED;
2296 /***********************************************************************
2297 * AVIMakeStreamFromClipboard (AVIFIL32.@)
2299 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
2300 PAVISTREAM * ppstream)
2302 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
2304 if (ppstream == NULL)
2305 return AVIERR_BADHANDLE;
2307 return AVIERR_UNSUPPORTED;
2310 /***********************************************************************
2311 * AVIPutFileOnClipboard (AVIFIL32.@)
2313 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2315 FIXME("(%p), stub!\n", pfile);
2317 if (pfile == NULL)
2318 return AVIERR_BADHANDLE;
2320 return AVIERR_UNSUPPORTED;
2323 HRESULT CDECL AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2324 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2326 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
2327 nStreams, pavi, lpOptions);
2329 return AVIERR_UNSUPPORTED;
2332 HRESULT CDECL AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
2333 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
2335 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
2336 nStreams, pavi, lpOptions);
2338 return AVIERR_UNSUPPORTED;