SHCoCreateInstance is now documented (spotted by Francois Gouget).
[wine/wine-kai.git] / dlls / avifil32 / api.c
blob668aedb3a6c596fc4ae6be766b7b5c558d0ddec5
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 #define COM_NO_WINDOWS_H
21 #include <assert.h>
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31 #include "windowsx.h"
33 #include "ole2.h"
34 #include "shellapi.h"
35 #include "shlobj.h"
36 #include "vfw.h"
37 #include "msacm.h"
39 #include "avifile_private.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
47 /***********************************************************************
48 * for AVIBuildFilterW -- uses fixed size table
50 #define MAX_FILTERS 30 /* 30 => 7kB */
52 typedef struct _AVIFilter {
53 WCHAR szClsid[40];
54 WCHAR szExtensions[MAX_FILTERS * 7];
55 } AVIFilter;
57 /***********************************************************************
58 * for AVISaveOptions
60 static struct {
61 UINT uFlags;
62 INT nStreams;
63 PAVISTREAM *ppavis;
64 LPAVICOMPRESSOPTIONS *ppOptions;
65 INT nCurrent;
66 } SaveOpts;
68 /***********************************************************************
69 * copied from dlls/ole32/compobj.c
71 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
73 BYTE const *s = (BYTE const*)idstr;
74 BYTE *p;
75 INT i;
76 BYTE table[256];
78 if (!s) {
79 memset(id, 0, sizeof(CLSID));
80 return S_OK;
81 } else { /* validate the CLSID string */
82 if (lstrlenA(s) != 38)
83 return CO_E_CLASSSTRING;
85 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
86 (s[24]!='-') || (s[37]!='}'))
87 return CO_E_CLASSSTRING;
89 for (i = 1; i < 37; i++) {
90 if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
91 continue;
92 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
93 ((s[i] >= 'a') && (s[i] <= 'f')) ||
94 ((s[i] >= 'A') && (s[i] <= 'F')))
96 return CO_E_CLASSSTRING;
100 TRACE("%s -> %p\n", s, id);
102 /* quick lookup table */
103 memset(table, 0, 256);
105 for (i = 0; i < 10; i++)
106 table['0' + i] = i;
108 for (i = 0; i < 6; i++) {
109 table['A' + i] = i+10;
110 table['a' + i] = i+10;
113 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
114 p = (BYTE *) id;
116 s++; /* skip leading brace */
117 for (i = 0; i < 4; i++) {
118 p[3 - i] = table[*s]<<4 | table[*(s+1)];
119 s += 2;
121 p += 4;
122 s++; /* skip - */
124 for (i = 0; i < 2; i++) {
125 p[1-i] = table[*s]<<4 | table[*(s+1)];
126 s += 2;
128 p += 2;
129 s++; /* skip - */
131 for (i = 0; i < 2; i++) {
132 p[1-i] = table[*s]<<4 | table[*(s+1)];
133 s += 2;
135 p += 2;
136 s++; /* skip - */
138 /* these are just sequential bytes */
139 for (i = 0; i < 2; i++) {
140 *p++ = table[*s]<<4 | table[*(s+1)];
141 s += 2;
143 s++; /* skip - */
145 for (i = 0; i < 6; i++) {
146 *p++ = table[*s]<<4 | table[*(s+1)];
147 s += 2;
150 return S_OK;
153 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
155 CHAR szRegKey[25];
156 CHAR szValue[100];
157 LPWSTR szExt = strrchrW(szFile, '.');
158 LONG len = sizeof(szValue) / sizeof(szValue[0]);
160 if (szExt == NULL)
161 return FALSE;
163 szExt++;
165 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
166 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
167 return FALSE;
169 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
172 /***********************************************************************
173 * AVIFileInit (AVIFIL32.@)
174 * AVIFileInit (AVIFILE.100)
176 void WINAPI AVIFileInit(void) {
177 /* need to load ole32.dll if not already done and get some functions */
178 FIXME("(): stub!\n");
181 /***********************************************************************
182 * AVIFileExit (AVIFIL32.@)
183 * AVIFileExit (AVIFILE.101)
185 void WINAPI AVIFileExit(void) {
186 /* need to free ole32.dll if we are the last exit call */
187 FIXME("(): stub!\n");
190 /***********************************************************************
191 * AVIFileOpenA (AVIFIL32.@)
192 * AVIFileOpen (AVIFILE.102)
194 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
195 LPCLSID lpHandler)
197 LPWSTR wszFile = NULL;
198 HRESULT hr;
199 int len;
201 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
202 debugstr_guid(lpHandler));
204 /* check parameters */
205 if (ppfile == NULL || szFile == NULL)
206 return AVIERR_BADPARAM;
208 /* convert ASCII string to Unicode and call unicode function */
209 len = lstrlenA(szFile);
210 if (len <= 0)
211 return AVIERR_BADPARAM;
213 wszFile = (LPWSTR)LocalAlloc(LPTR, (len + 1) * sizeof(WCHAR));
214 if (wszFile == NULL)
215 return AVIERR_MEMORY;
217 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len + 1);
218 wszFile[len + 1] = 0;
220 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
222 LocalFree((HLOCAL)wszFile);
224 return hr;
227 /***********************************************************************
228 * AVIFileOpenW (AVIFIL32.@)
230 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
231 LPCLSID lpHandler)
233 IPersistFile *ppersist = NULL;
234 CLSID clsidHandler;
235 HRESULT hr;
237 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
238 debugstr_guid(lpHandler));
240 /* check parameters */
241 if (ppfile == NULL || szFile == NULL)
242 return AVIERR_BADPARAM;
244 *ppfile = NULL;
246 /* if no handler then try guessing it by extension */
247 if (lpHandler == NULL) {
248 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
249 return AVIERR_UNSUPPORTED;
250 } else
251 memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
253 /* crete instance of handler */
254 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
255 &IID_IAVIFile, (LPVOID*)ppfile);
256 if (FAILED(hr) || *ppfile == NULL)
257 return hr;
259 /* ask for IPersistFile interface for loading/creating the file */
260 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
261 if (FAILED(hr) || ppersist == NULL) {
262 IAVIFile_Release(*ppfile);
263 *ppfile = NULL;
264 return hr;
267 hr = IPersistFile_Load(ppersist, szFile, uMode);
268 IPersistFile_Release(ppersist);
269 if (FAILED(hr)) {
270 IAVIFile_Release(*ppfile);
271 *ppfile = NULL;
274 return hr;
277 /***********************************************************************
278 * AVIFileAddRef (AVIFIL32.@)
279 * AVIFileAddRef (AVIFILE.140)
281 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
283 TRACE("(%p)\n", pfile);
285 if (pfile == NULL) {
286 ERR(": bad handle passed!\n");
287 return 0;
290 return IAVIFile_AddRef(pfile);
293 /***********************************************************************
294 * AVIFileRelease (AVIFIL32.@)
295 * AVIFileRelease (AVIFILE.141)
297 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
299 TRACE("(%p)\n", pfile);
301 if (pfile == NULL) {
302 ERR(": bad handle passed!\n");
303 return 0;
306 return IAVIFile_Release(pfile);
309 /***********************************************************************
310 * AVIFileInfo (AVIFIL32.@)
311 * AVIFileInfoA (AVIFIL32.@)
312 * AVIFileInfo (AVIFILE.142)
314 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
316 AVIFILEINFOW afiw;
317 HRESULT hres;
319 TRACE("(%p,%p,%ld)\n", pfile, afi, size);
321 if (pfile == NULL)
322 return AVIERR_BADHANDLE;
323 if ((DWORD)size < sizeof(AVIFILEINFOA))
324 return AVIERR_BADSIZE;
326 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
328 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
329 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
330 sizeof(afi->szFileType), NULL, NULL);
331 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
333 return hres;
336 /***********************************************************************
337 * AVIFileInfoW (AVIFIL32.@)
339 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
341 TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
343 if (pfile == NULL)
344 return AVIERR_BADHANDLE;
346 return IAVIFile_Info(pfile, afiw, size);
349 /***********************************************************************
350 * AVIFileGetStream (AVIFIL32.@)
351 * AVIFileGetStream (AVIFILE.143)
353 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
354 DWORD fccType, LONG lParam)
356 TRACE("(%p,%p,'%4.4s',%ld)\n", pfile, avis, (char*)&fccType, lParam);
358 if (pfile == NULL)
359 return AVIERR_BADHANDLE;
361 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
364 /***********************************************************************
365 * AVIFileCreateStreamA (AVIFIL32.@)
366 * AVIFileCreateStream (AVIFILE.144)
368 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
369 LPAVISTREAMINFOA psi)
371 AVISTREAMINFOW psiw;
373 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
375 if (pfile == NULL)
376 return AVIERR_BADHANDLE;
378 /* Only the szName at the end is different */
379 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
380 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
381 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
383 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
386 /***********************************************************************
387 * AVIFileCreateStreamW (AVIFIL32.@)
389 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
390 LPAVISTREAMINFOW asi)
392 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
394 if (pfile == NULL)
395 return AVIERR_BADHANDLE;
397 return IAVIFile_CreateStream(pfile, avis, asi);
400 /***********************************************************************
401 * AVIFileWriteData (AVIFIL32.@)
402 * AVIFileWriteData (AVIFILE.146)
404 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
406 TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
408 if (pfile == NULL)
409 return AVIERR_BADHANDLE;
411 return IAVIFile_WriteData(pfile, fcc, lp, size);
414 /***********************************************************************
415 * AVIFileReadData (AVIFIL32.@)
416 * AVIFileReadData (AVIFILE.147)
418 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
420 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
422 if (pfile == NULL)
423 return AVIERR_BADHANDLE;
425 return IAVIFile_ReadData(pfile, fcc, lp, size);
428 /***********************************************************************
429 * AVIFileEndRecord (AVIFIL32.@)
430 * AVIFileEndRecord (AVIFILE.148)
432 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
434 TRACE("(%p)\n", pfile);
436 if (pfile == NULL)
437 return AVIERR_BADHANDLE;
439 return IAVIFile_EndRecord(pfile);
442 /***********************************************************************
443 * AVIStreamAddRef (AVIFIL32.@)
444 * AVIStreamAddRef (AVIFILE.160)
446 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
448 TRACE("(%p)\n", pstream);
450 if (pstream == NULL) {
451 ERR(": bad handle passed!\n");
452 return 0;
455 return IAVIStream_AddRef(pstream);
458 /***********************************************************************
459 * AVIStreamRelease (AVIFIL32.@)
460 * AVIStreamRelease (AVIFILE.161)
462 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
464 TRACE("(%p)\n", pstream);
466 if (pstream == NULL) {
467 ERR(": bad handle passed!\n");
468 return 0;
471 return IAVIStream_Release(pstream);
474 /***********************************************************************
475 * AVIStreamCreate (AVIFIL32.@)
476 * AVIStreamCreate (AVIFILE.104)
478 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
479 LPCLSID pclsidHandler)
481 HRESULT hr;
483 TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
484 debugstr_guid(pclsidHandler));
486 if (ppavi == NULL)
487 return AVIERR_BADPARAM;
489 *ppavi = NULL;
490 if (pclsidHandler == NULL)
491 return AVIERR_UNSUPPORTED;
493 hr = SHCoCreateInstance(NULL, pclsidHandler, NULL,
494 &IID_IAVIStream, (LPVOID*)ppavi);
495 if (FAILED(hr) || *ppavi == NULL)
496 return hr;
498 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
499 if (FAILED(hr)) {
500 IAVIStream_Release(*ppavi);
501 *ppavi = NULL;
504 return hr;
507 /***********************************************************************
508 * AVIStreamInfo (AVIFIL32.@)
509 * AVIStreamInfoA (AVIFIL32.@)
510 * AVIStreamInfo (AVIFILE.162)
512 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
513 LONG size)
515 AVISTREAMINFOW asiw;
516 HRESULT hres;
518 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
520 if (pstream == NULL)
521 return AVIERR_BADHANDLE;
522 if ((DWORD)size < sizeof(AVISTREAMINFOA))
523 return AVIERR_BADSIZE;
525 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
527 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
528 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
529 sizeof(asi->szName), NULL, NULL);
530 asi->szName[sizeof(asi->szName) - 1] = 0;
532 return hres;
535 /***********************************************************************
536 * AVIStreamInfoW (AVIFIL32.@)
538 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
539 LONG size)
541 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
543 if (pstream == NULL)
544 return AVIERR_BADHANDLE;
546 return IAVIStream_Info(pstream, asi, size);
549 /***********************************************************************
550 * AVIStreamFindSample (AVIFIL32.@)
551 * AVIStreamFindSample (AVIFILE.163)
553 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
555 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
557 if (pstream == NULL)
558 return -1;
560 return IAVIStream_FindSample(pstream, pos, flags);
563 /***********************************************************************
564 * AVIStreamReadFormat (AVIFIL32.@)
565 * AVIStreamReadFormat (AVIFILE.164)
567 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
568 LPVOID format, LPLONG formatsize)
570 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
572 if (pstream == NULL)
573 return AVIERR_BADHANDLE;
575 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
578 /***********************************************************************
579 * AVIStreamSetFormat (AVIFIL32.@)
580 * AVIStreamSetFormat (AVIFILE.169)
582 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
583 LPVOID format, LONG formatsize)
585 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
587 if (pstream == NULL)
588 return AVIERR_BADHANDLE;
590 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
593 /***********************************************************************
594 * AVIStreamRead (AVIFIL32.@)
595 * AVIStreamRead (AVIFILE.167)
597 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
598 LPVOID buffer, LONG buffersize,
599 LPLONG bytesread, LPLONG samplesread)
601 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
602 buffersize, bytesread, samplesread);
604 if (pstream == NULL)
605 return AVIERR_BADHANDLE;
607 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
608 bytesread, samplesread);
611 /***********************************************************************
612 * AVIStreamWrite (AVIFIL32.@)
613 * AVIStreamWrite (AVIFILE.168)
615 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
616 LPVOID buffer, LONG buffersize, DWORD flags,
617 LPLONG sampwritten, LPLONG byteswritten)
619 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
620 buffersize, flags, sampwritten, byteswritten);
622 if (pstream == NULL)
623 return AVIERR_BADHANDLE;
625 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
626 flags, sampwritten, byteswritten);
629 /***********************************************************************
630 * AVIStreamReadData (AVIFIL32.@)
631 * AVIStreamReadData (AVIFILE.165)
633 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
634 LPLONG lpread)
636 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
638 if (pstream == NULL)
639 return AVIERR_BADHANDLE;
641 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
644 /***********************************************************************
645 * AVIStreamWriteData (AVIFIL32.@)
646 * AVIStreamWriteData (AVIFILE.166)
648 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
649 LONG size)
651 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
653 if (pstream == NULL)
654 return AVIERR_BADHANDLE;
656 return IAVIStream_WriteData(pstream, fcc, lp, size);
659 /***********************************************************************
660 * AVIStreamGetFrameOpen (AVIFIL32.@)
661 * AVIStreamGetFrameOpen (AVIFILE.112)
663 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
664 LPBITMAPINFOHEADER lpbiWanted)
666 PGETFRAME pg = NULL;
668 TRACE("(%p,%p)\n", pstream, lpbiWanted);
670 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
671 pg == NULL) {
672 pg = AVIFILE_CreateGetFrame(pstream);
673 if (pg == NULL)
674 return NULL;
677 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
678 IGetFrame_Release(pg);
679 return NULL;
682 return pg;
685 /***********************************************************************
686 * AVIStreamGetFrame (AVIFIL32.@)
687 * AVIStreamGetFrame (AVIFILE.110)
689 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
691 TRACE("(%p,%ld)\n", pg, pos);
693 if (pg == NULL)
694 return NULL;
696 return IGetFrame_GetFrame(pg, pos);
699 /***********************************************************************
700 * AVIStreamGetFrameClose (AVIFIL32.@)
701 * AVIStreamGetFrameClose (AVIFILE.111)
703 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
705 TRACE("(%p)\n", pg);
707 if (pg != NULL)
708 return IGetFrame_Release(pg);
709 return 0;
712 /***********************************************************************
713 * AVIMakeCompressedStream (AVIFIL32.@)
715 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
716 PAVISTREAM psSource,
717 LPAVICOMPRESSOPTIONS aco,
718 LPCLSID pclsidHandler)
720 AVISTREAMINFOW asiw;
721 CHAR szRegKey[25];
722 CHAR szValue[100];
723 CLSID clsidHandler;
724 HRESULT hr;
725 LONG size = sizeof(szValue);
727 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
728 debugstr_guid(pclsidHandler));
730 if (ppsCompressed == NULL)
731 return AVIERR_BADPARAM;
732 if (psSource == NULL)
733 return AVIERR_BADHANDLE;
735 *ppsCompressed = NULL;
737 /* if no handler given get default ones based on streamtype */
738 if (pclsidHandler == NULL) {
739 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
740 if (FAILED(hr))
741 return hr;
743 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
744 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
745 return AVIERR_UNSUPPORTED;
746 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
747 return AVIERR_UNSUPPORTED;
748 } else
749 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
751 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
752 &IID_IAVIStream, (LPVOID*)ppsCompressed);
753 if (FAILED(hr) || *ppsCompressed == NULL)
754 return hr;
756 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
757 if (FAILED(hr)) {
758 IAVIStream_Release(*ppsCompressed);
759 *ppsCompressed = NULL;
762 return hr;
765 /***********************************************************************
766 * AVIMakeFileFromStreams (AVIFIL32.@)
768 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
769 PAVISTREAM *ppStreams)
771 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
773 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
774 return AVIERR_BADPARAM;
776 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
777 if (*ppfile == NULL)
778 return AVIERR_MEMORY;
780 return AVIERR_OK;
783 /***********************************************************************
784 * AVIStreamOpenFromFile (AVIFILE.103)
785 * AVIStreamOpenFromFileA (AVIFIL32.@)
787 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
788 DWORD fccType, LONG lParam,
789 UINT mode, LPCLSID pclsidHandler)
791 PAVIFILE pfile = NULL;
792 HRESULT hr;
794 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
795 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
797 if (ppavi == NULL || szFile == NULL)
798 return AVIERR_BADPARAM;
800 *ppavi = NULL;
802 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
803 if (FAILED(hr) || pfile == NULL)
804 return hr;
806 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
807 IAVIFile_Release(pfile);
809 return hr;
812 /***********************************************************************
813 * AVIStreamOpenFromFileW (AVIFIL32.@)
815 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
816 DWORD fccType, LONG lParam,
817 UINT mode, LPCLSID pclsidHandler)
819 PAVIFILE pfile = NULL;
820 HRESULT hr;
822 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
823 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
825 if (ppavi == NULL || szFile == NULL)
826 return AVIERR_BADPARAM;
828 *ppavi = NULL;
830 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
831 if (FAILED(hr) || pfile == NULL)
832 return hr;
834 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
835 IAVIFile_Release(pfile);
837 return hr;
840 /***********************************************************************
841 * AVIStreamBeginStreaming (AVIFIL32.@)
843 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
845 IAVIStreaming* pstream = NULL;
846 HRESULT hr;
848 TRACE("(%p,%ld,%ld,%ld)\n", pavi, lStart, lEnd, lRate);
850 if (pavi == NULL)
851 return AVIERR_BADHANDLE;
853 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
854 if (SUCCEEDED(hr) && pstream != NULL) {
855 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
856 IAVIStreaming_Release(pstream);
857 } else
858 hr = AVIERR_OK;
860 return hr;
863 /***********************************************************************
864 * AVIStreamEndStreaming (AVIFIL32.@)
866 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
868 IAVIStreaming* pstream = NULL;
869 HRESULT hr;
871 TRACE("(%p)\n", pavi);
873 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
874 if (SUCCEEDED(hr) && pstream != NULL) {
875 IAVIStreaming_End(pstream);
876 IAVIStreaming_Release(pstream);
879 return AVIERR_OK;
882 /***********************************************************************
883 * AVIStreamStart (AVIFILE.130)
884 * AVIStreamStart (AVIFIL32.@)
886 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
888 AVISTREAMINFOW asiw;
890 TRACE("(%p)\n", pstream);
892 if (pstream == NULL)
893 return 0;
895 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
896 return 0;
898 return asiw.dwStart;
901 /***********************************************************************
902 * AVIStreamLength (AVIFILE.131)
903 * AVIStreamLength (AVIFIL32.@)
905 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
907 AVISTREAMINFOW asiw;
909 TRACE("(%p)\n", pstream);
911 if (pstream == NULL)
912 return 0;
914 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
915 return 0;
917 return asiw.dwLength;
920 /***********************************************************************
921 * AVIStreamSampleToTime (AVIFILE.133)
922 * AVIStreamSampleToTime (AVIFIL32.@)
924 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
926 AVISTREAMINFOW asiw;
927 LONG time;
929 TRACE("(%p,%ld)\n", pstream, lSample);
931 if (pstream == NULL)
932 return -1;
934 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
935 return -1;
936 if (asiw.dwRate == 0)
937 return -1;
939 /* limit to stream bounds */
940 if (lSample < asiw.dwStart)
941 lSample = asiw.dwStart;
942 if (lSample > asiw.dwStart + asiw.dwLength)
943 lSample = asiw.dwStart + asiw.dwLength;
945 if (asiw.dwRate / asiw.dwScale < 1000)
946 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
947 else
948 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
950 TRACE(" -> %ld\n",time);
951 return time;
954 /***********************************************************************
955 * AVIStreamTimeToSample (AVIFILE.132)
956 * AVIStreamTimeToSample (AVIFIL32.@)
958 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
960 AVISTREAMINFOW asiw;
961 LONG sample;
963 TRACE("(%p,%ld)\n", pstream, lTime);
965 if (pstream == NULL || lTime < 0)
966 return -1;
968 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
969 return -1;
970 if (asiw.dwScale == 0)
971 return -1;
973 if (asiw.dwRate / asiw.dwScale < 1000)
974 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
975 else
976 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
978 /* limit to stream bounds */
979 if (sample < asiw.dwStart)
980 sample = asiw.dwStart;
981 if (sample > asiw.dwStart + asiw.dwLength)
982 sample = asiw.dwStart + asiw.dwLength;
984 TRACE(" -> %ld\n", sample);
985 return sample;
988 /***********************************************************************
989 * AVIBuildFilterA (AVIFIL32.@)
990 * AVIBuildFilter (AVIFILE.123)
992 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
994 LPWSTR wszFilter;
995 HRESULT hr;
997 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
999 /* check parameters */
1000 if (szFilter == NULL)
1001 return AVIERR_BADPARAM;
1002 if (cbFilter < 2)
1003 return AVIERR_BADSIZE;
1005 szFilter[0] = 0;
1006 szFilter[1] = 0;
1008 wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter * sizeof(WCHAR));
1009 if (wszFilter == NULL)
1010 return AVIERR_MEMORY;
1012 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
1013 if (SUCCEEDED(hr)) {
1014 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
1015 szFilter, cbFilter, NULL, NULL);
1018 GlobalFreePtr(wszFilter);
1020 return hr;
1023 /***********************************************************************
1024 * AVIBuildFilterW (AVIFIL32.@)
1026 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
1028 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
1029 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1030 static const WCHAR szAVIFileExtensions[] =
1031 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1033 AVIFilter *lp;
1034 WCHAR szAllFiles[40];
1035 WCHAR szFileExt[10];
1036 WCHAR szValue[128];
1037 HKEY hKey;
1038 DWORD n, i;
1039 LONG size;
1040 DWORD count = 0;
1042 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1044 /* check parameters */
1045 if (szFilter == NULL)
1046 return AVIERR_BADPARAM;
1047 if (cbFilter < 2)
1048 return AVIERR_BADSIZE;
1050 lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
1051 if (lp == NULL)
1052 return AVIERR_MEMORY;
1055 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1056 * extensions and CLSID's
1057 * 2. iterate over collected CLSID's and copy it's description and it's
1058 * extensions to szFilter if it fits
1060 * First filter is named "All multimedia files" and it's filter is a
1061 * collection of all possible extensions except "*.*".
1063 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
1064 GlobalFreePtr(lp);
1065 return AVIERR_ERROR;
1067 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
1068 /* get CLSID to extension */
1069 size = sizeof(szValue)/sizeof(szValue[0]);
1070 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
1071 break;
1073 /* search if the CLSID is already known */
1074 for (i = 1; i <= count; i++) {
1075 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
1076 break; /* a new one */
1079 if (count - i == -1U) {
1080 /* it's a new CLSID */
1082 /* FIXME: How do we get info's about read/write capabilities? */
1084 if (count >= MAX_FILTERS) {
1085 /* try to inform user of our full fixed size table */
1086 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1087 break;
1090 lstrcpyW(lp[i].szClsid, szValue);
1092 count++;
1095 /* append extension to the filter */
1096 wsprintfW(szValue, szExtensionFmt, szFileExt);
1097 if (lp[i].szExtensions[0] == 0)
1098 lstrcatW(lp[i].szExtensions, szValue + 1);
1099 else
1100 lstrcatW(lp[i].szExtensions, szValue);
1102 /* also append to the "all multimedia"-filter */
1103 if (lp[0].szExtensions[0] == 0)
1104 lstrcatW(lp[0].szExtensions, szValue + 1);
1105 else
1106 lstrcatW(lp[0].szExtensions, szValue);
1108 RegCloseKey(hKey);
1110 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1111 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1112 GlobalFreePtr(lp);
1113 return AVIERR_ERROR;
1115 for (n = 0; n <= count; n++) {
1116 /* first the description */
1117 if (n != 0) {
1118 size = sizeof(szValue)/sizeof(szValue[0]);
1119 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1120 size = lstrlenW(szValue);
1121 lstrcpynW(szFilter, szValue, cbFilter);
1123 } else
1124 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1126 /* check for enough space */
1127 size++;
1128 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1129 szFilter[0] = 0;
1130 szFilter[1] = 0;
1131 GlobalFreePtr(lp);
1132 RegCloseKey(hKey);
1133 return AVIERR_BUFFERTOOSMALL;
1135 cbFilter -= size;
1136 szFilter += size;
1138 /* and then the filter */
1139 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1140 size = lstrlenW(lp[n].szExtensions) + 1;
1141 cbFilter -= size;
1142 szFilter += size;
1145 RegCloseKey(hKey);
1146 GlobalFreePtr(lp);
1148 /* add "All files" "*.*" filter if enough space left */
1149 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1150 szAllFiles, sizeof(szAllFiles)) + 1;
1151 if (cbFilter > size) {
1152 int i;
1154 /* replace '@' with \000 to separate description of filter */
1155 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1156 if (szAllFiles[i] == '@') {
1157 szAllFiles[i] = 0;
1158 break;
1162 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1163 szFilter += size;
1164 szFilter[0] = 0;
1166 return AVIERR_OK;
1167 } else {
1168 szFilter[0] = 0;
1169 return AVIERR_BUFFERTOOSMALL;
1173 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1175 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1176 AVISTREAMINFOW sInfo;
1178 TRACE("(%p)\n", hWnd);
1180 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1181 ERR(": bad state!\n");
1182 return FALSE;
1185 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1186 &sInfo, sizeof(sInfo)))) {
1187 ERR(": AVIStreamInfoW failed!\n");
1188 return FALSE;
1191 if (sInfo.fccType == streamtypeVIDEO) {
1192 COMPVARS cv;
1193 BOOL ret;
1195 memset(&cv, 0, sizeof(cv));
1197 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1198 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1199 pOptions->fccType = streamtypeVIDEO;
1200 pOptions->fccHandler = comptypeDIB;
1201 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1204 cv.cbSize = sizeof(cv);
1205 cv.dwFlags = ICMF_COMPVARS_VALID;
1206 /*cv.fccType = pOptions->fccType; */
1207 cv.fccHandler = pOptions->fccHandler;
1208 cv.lQ = pOptions->dwQuality;
1209 cv.lpState = pOptions->lpParms;
1210 cv.cbState = pOptions->cbParms;
1211 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1212 cv.lKey = pOptions->dwKeyFrameEvery;
1213 else
1214 cv.lKey = 0;
1215 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1216 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1217 else
1218 cv.lDataRate = 0;
1220 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1221 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1223 if (ret) {
1224 pOptions->fccHandler = cv.fccHandler;
1225 pOptions->lpParms = cv.lpState;
1226 pOptions->cbParms = cv.cbState;
1227 pOptions->dwQuality = cv.lQ;
1228 if (cv.lKey != 0) {
1229 pOptions->dwKeyFrameEvery = cv.lKey;
1230 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1231 } else
1232 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1233 if (cv.lDataRate != 0) {
1234 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1235 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1236 } else
1237 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1238 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1240 ICCompressorFree(&cv);
1242 return ret;
1243 } else if (sInfo.fccType == streamtypeAUDIO) {
1244 ACMFORMATCHOOSEW afmtc;
1245 MMRESULT ret;
1246 LONG size;
1248 /* FIXME: check ACM version -- Which version is needed? */
1250 memset(&afmtc, 0, sizeof(afmtc));
1251 afmtc.cbStruct = sizeof(afmtc);
1252 afmtc.fdwStyle = 0;
1253 afmtc.hwndOwner = hWnd;
1255 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1256 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1257 pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1258 pOptions->cbFormat = size;
1259 } else if (pOptions->cbFormat < (DWORD)size) {
1260 pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1261 pOptions->cbFormat = size;
1263 if (pOptions->lpFormat == NULL)
1264 return FALSE;
1265 afmtc.pwfx = pOptions->lpFormat;
1266 afmtc.cbwfx = pOptions->cbFormat;
1268 size = 0;
1269 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1270 sInfo.dwStart, &size);
1271 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1272 size = sizeof(PCMWAVEFORMAT);
1273 afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1274 if (afmtc.pwfxEnum != NULL) {
1275 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1276 sInfo.dwStart, afmtc.pwfxEnum, &size);
1277 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1280 ret = acmFormatChooseW(&afmtc);
1281 if (ret == S_OK)
1282 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1284 if (afmtc.pwfxEnum != NULL)
1285 GlobalFreePtr(afmtc.pwfxEnum);
1287 return (ret == S_OK ? TRUE : FALSE);
1288 } else {
1289 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1290 return FALSE;
1294 static void AVISaveOptionsUpdate(HWND hWnd)
1296 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1297 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1299 WCHAR szFormat[128];
1300 AVISTREAMINFOW sInfo;
1301 LPVOID lpFormat;
1302 LONG size;
1304 TRACE("(%p)\n", hWnd);
1306 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1307 if (SaveOpts.nCurrent < 0)
1308 return;
1310 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1311 return;
1313 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1314 if (size > 0) {
1315 szFormat[0] = 0;
1317 /* read format to build format descriotion string */
1318 lpFormat = GlobalAllocPtr(GHND, size);
1319 if (lpFormat != NULL) {
1320 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1321 if (sInfo.fccType == streamtypeVIDEO) {
1322 LPBITMAPINFOHEADER lpbi = lpFormat;
1323 ICINFO icinfo;
1325 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1326 lpbi->biHeight, lpbi->biBitCount);
1328 if (lpbi->biCompression != BI_RGB) {
1329 HIC hic;
1331 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1332 NULL, ICMODE_DECOMPRESS);
1333 if (hic != NULL) {
1334 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1335 lstrcatW(szFormat, icinfo.szDescription);
1336 ICClose(hic);
1338 } else {
1339 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1340 icinfo.szDescription, sizeof(icinfo.szDescription));
1341 lstrcatW(szFormat, icinfo.szDescription);
1343 } else if (sInfo.fccType == streamtypeAUDIO) {
1344 ACMFORMATTAGDETAILSW aftd;
1345 ACMFORMATDETAILSW afd;
1347 memset(&aftd, 0, sizeof(aftd));
1348 memset(&afd, 0, sizeof(afd));
1350 aftd.cbStruct = sizeof(aftd);
1351 aftd.dwFormatTag = afd.dwFormatTag =
1352 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1353 aftd.cbFormatSize = afd.cbwfx = size;
1355 afd.cbStruct = sizeof(afd);
1356 afd.pwfx = lpFormat;
1358 if (acmFormatTagDetailsW(NULL, &aftd,
1359 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1360 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1361 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1365 GlobalFreePtr(lpFormat);
1368 /* set text for format description */
1369 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1371 /* Disable option button for unsupported streamtypes */
1372 if (sInfo.fccType == streamtypeVIDEO ||
1373 sInfo.fccType == streamtypeAUDIO)
1374 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1375 else
1376 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1381 INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1382 WPARAM wParam, LPARAM lParam)
1384 DWORD dwInterleave;
1385 BOOL bIsInterleaved;
1386 INT n;
1388 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1390 switch (uMsg) {
1391 case WM_INITDIALOG:
1392 SaveOpts.nCurrent = 0;
1393 if (SaveOpts.nStreams == 1) {
1394 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1395 return TRUE;
1398 /* add streams */
1399 for (n = 0; n < SaveOpts.nStreams; n++) {
1400 AVISTREAMINFOW sInfo;
1402 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1403 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1404 0L, (LPARAM)sInfo.szName);
1407 /* select first stream */
1408 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1409 SendMessageW(hWnd, WM_COMMAND,
1410 GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
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 (GET_WM_COMMAND_ID(wParam, lParam)) {
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, GET_WM_COMMAND_ID(wParam, lParam) == 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 (GET_WM_COMMAND_CMD(wParam, lParam) == 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 for case user press cancel */
1481 if (ppOptions != NULL && nStreams > 1) {
1482 pSavedOptions = GlobalAllocPtr(GHND,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 GlobalFreePtr(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 GlobalFreePtr(ppOptions[nStreams]->lpParms);
1534 ppOptions[nStreams]->lpParms = NULL;
1535 ppOptions[nStreams]->cbParms = 0;
1537 if (ppOptions[nStreams]->lpFormat != NULL) {
1538 GlobalFreePtr(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 = lstrlenA(szFile);
1567 if (len <= 0)
1568 return AVIERR_BADPARAM;
1570 wszFile = (LPWSTR)LocalAlloc(LPTR, (len + 1) * sizeof(WCHAR));
1571 if (wszFile == NULL)
1572 return AVIERR_MEMORY;
1574 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len + 1);
1575 wszFile[len + 1] = 0;
1577 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1578 nStream, ppavi, plpOptions);
1580 LocalFree((HLOCAL)wszFile);
1582 return hr;
1585 /***********************************************************************
1586 * AVIFILE_AVISaveDefaultCallback (internal)
1588 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
1590 TRACE("(%d)\n", progress);
1592 return FALSE;
1595 /***********************************************************************
1596 * AVISaveVW (AVIFIL32.@)
1598 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1599 AVISAVECALLBACK lpfnCallback, int nStreams,
1600 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1602 LONG lStart[MAX_AVISTREAMS];
1603 PAVISTREAM pOutStreams[MAX_AVISTREAMS];
1604 PAVISTREAM pInStreams[MAX_AVISTREAMS];
1605 AVIFILEINFOW fInfo;
1606 AVISTREAMINFOW sInfo;
1608 PAVIFILE pfile = NULL; /* the output AVI file */
1609 LONG lFirstVideo = -1;
1610 int curStream;
1612 /* for interleaving ... */
1613 DWORD dwInterleave = 0; /* interleave rate */
1614 DWORD dwFileInitialFrames;
1615 LONG lFileLength;
1616 LONG lSampleInc;
1618 /* for reading/writing the data ... */
1619 LPVOID lpBuffer = NULL;
1620 LONG cbBuffer; /* real size of lpBuffer */
1621 LONG lBufferSize; /* needed bytes for format(s), etc. */
1622 LONG lReadBytes;
1623 LONG lReadSamples;
1624 HRESULT hres;
1626 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
1627 lpfnCallback, nStreams, ppavi, plpOptions);
1629 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1630 return AVIERR_BADPARAM;
1631 if (nStreams >= MAX_AVISTREAMS) {
1632 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
1633 return AVIERR_INTERNAL;
1636 if (lpfnCallback == NULL)
1637 lpfnCallback = AVIFILE_AVISaveDefaultCallback;
1639 /* clear local variable(s) */
1640 for (curStream = 0; curStream < nStreams; curStream++) {
1641 pInStreams[curStream] = NULL;
1642 pOutStreams[curStream] = NULL;
1645 /* open output AVI file (create it if it doesn't exist) */
1646 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
1647 pclsidHandler);
1648 if (FAILED(hres))
1649 return hres;
1650 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
1652 /* initialize our data structures part 1 */
1653 for (curStream = 0; curStream < nStreams; curStream++) {
1654 PAVISTREAM pCurStream = ppavi[curStream];
1656 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
1657 if (FAILED(hres))
1658 goto error;
1660 /* search first video stream and check for interleaving */
1661 if (sInfo.fccType == streamtypeVIDEO) {
1662 /* remember first video stream -- needed for interleaving */
1663 if (lFirstVideo < 0)
1664 lFirstVideo = curStream;
1665 } else if (!dwInterleave && plpOptions != NULL) {
1666 /* check if any non-video stream wants to be interleaved */
1667 WARN("options.flags=0x%lX options.dwInterleave=%lu\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
1668 if (plpOptions[curStream] != NULL &&
1669 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
1670 dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
1673 /* create de-/compressed stream interface if needed */
1674 pInStreams[curStream] = NULL;
1675 if (plpOptions != NULL && plpOptions[curStream] != NULL) {
1676 if (plpOptions[curStream]->fccHandler ||
1677 plpOptions[curStream]->lpFormat != NULL) {
1678 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
1680 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
1681 plpOptions[curStream]->dwKeyFrameEvery = 1;
1683 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
1684 plpOptions[curStream], NULL);
1685 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
1686 if (FAILED(hres) || pInStreams[curStream] == NULL) {
1687 pInStreams[curStream] = NULL;
1688 goto error;
1691 /* test stream interface and update stream-info */
1692 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
1693 if (FAILED(hres))
1694 goto error;
1698 /* now handle streams which will only be copied */
1699 if (pInStreams[curStream] == NULL) {
1700 pCurStream = pInStreams[curStream] = ppavi[curStream];
1701 AVIStreamAddRef(pCurStream);
1702 } else
1703 pCurStream = pInStreams[curStream];
1705 lStart[curStream] = sInfo.dwStart;
1706 } /* for all streams */
1708 /* check that first video stream is the first stream */
1709 if (lFirstVideo > 0) {
1710 PAVISTREAM pTmp = pInStreams[lFirstVideo];
1711 LONG lTmp = lStart[lFirstVideo];
1713 pInStreams[lFirstVideo] = pInStreams[0];
1714 pInStreams[0] = pTmp;
1715 lStart[lFirstVideo] = lStart[0];
1716 lStart[0] = lTmp;
1717 lFirstVideo = 0;
1720 /* allocate buffer for formats, data, etc. of an initiale size of 64 kByte */
1721 lpBuffer = GlobalAllocPtr(GPTR, cbBuffer = 0x00010000);
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 atleast 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 for 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 = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != 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 for 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 got it, or error occures */
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 = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != 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 for 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 = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != 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 if (lpBuffer != NULL)
2009 GlobalFreePtr(lpBuffer);
2010 if (pfile != NULL) {
2011 for (curStream = 0; curStream < nStreams; curStream++) {
2012 if (pOutStreams[curStream] != NULL)
2013 AVIStreamRelease(pOutStreams[curStream]);
2014 if (pInStreams[curStream] != NULL)
2015 AVIStreamRelease(pInStreams[curStream]);
2018 AVIFileRelease(pfile);
2021 return hres;
2024 /***********************************************************************
2025 * CreateEditableStream (AVIFIL32.@)
2027 HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
2029 IAVIEditStream *pEdit = NULL;
2030 HRESULT hr;
2032 TRACE("(%p,%p)\n", ppEditable, pSource);
2034 if (ppEditable == NULL)
2035 return AVIERR_BADPARAM;
2037 *ppEditable = NULL;
2039 if (pSource != NULL) {
2040 hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream,
2041 (LPVOID*)&pEdit);
2042 if (SUCCEEDED(hr) && pEdit != NULL) {
2043 hr = IAVIEditStream_Clone(pEdit, ppEditable);
2044 IAVIEditStream_Release(pEdit);
2046 return hr;
2050 /* need own implementation of IAVIEditStream */
2051 pEdit = AVIFILE_CreateEditStream(pSource);
2052 if (pEdit == NULL)
2053 return AVIERR_MEMORY;
2055 hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream,
2056 (LPVOID*)ppEditable);
2057 IAVIEditStream_Release(pEdit);
2059 return hr;
2062 /***********************************************************************
2063 * EditStreamClone (AVIFIL32.@)
2065 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
2067 PAVIEDITSTREAM pEdit = NULL;
2068 HRESULT hr;
2070 TRACE("(%p,%p)\n", pStream, ppResult);
2072 if (pStream == NULL)
2073 return AVIERR_BADHANDLE;
2074 if (ppResult == NULL)
2075 return AVIERR_BADPARAM;
2077 *ppResult = NULL;
2079 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2080 if (SUCCEEDED(hr) && pEdit != NULL) {
2081 hr = IAVIEditStream_Clone(pEdit, ppResult);
2083 IAVIEditStream_Release(pEdit);
2084 } else
2085 hr = AVIERR_UNSUPPORTED;
2087 return hr;
2090 /***********************************************************************
2091 * EditStreamCopy (AVIFIL32.@)
2093 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
2094 LONG *plLength, PAVISTREAM *ppResult)
2096 PAVIEDITSTREAM pEdit = NULL;
2097 HRESULT hr;
2099 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2101 if (pStream == NULL)
2102 return AVIERR_BADHANDLE;
2103 if (plStart == NULL || plLength == NULL || ppResult == NULL)
2104 return AVIERR_BADPARAM;
2106 *ppResult = NULL;
2108 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2109 if (SUCCEEDED(hr) && pEdit != NULL) {
2110 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
2112 IAVIEditStream_Release(pEdit);
2113 } else
2114 hr = AVIERR_UNSUPPORTED;
2116 return hr;
2119 /***********************************************************************
2120 * EditStreamCut (AVIFIL32.@)
2122 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
2123 LONG *plLength, PAVISTREAM *ppResult)
2125 PAVIEDITSTREAM pEdit = NULL;
2126 HRESULT hr;
2128 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
2130 if (ppResult != NULL)
2131 *ppResult = NULL;
2132 if (pStream == NULL)
2133 return AVIERR_BADHANDLE;
2134 if (plStart == NULL || plLength == NULL)
2135 return AVIERR_BADPARAM;
2137 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2138 if (SUCCEEDED(hr) && pEdit != NULL) {
2139 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
2141 IAVIEditStream_Release(pEdit);
2142 } else
2143 hr = AVIERR_UNSUPPORTED;
2145 return hr;
2148 /***********************************************************************
2149 * EditStreamPaste (AVIFIL32.@)
2151 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
2152 PAVISTREAM pSource, LONG lStart, LONG lEnd)
2154 PAVIEDITSTREAM pEdit = NULL;
2155 HRESULT hr;
2157 TRACE("(%p,%p,%p,%p,%ld,%ld)\n", pDest, plStart, plLength,
2158 pSource, lStart, lEnd);
2160 if (pDest == NULL || pSource == NULL)
2161 return AVIERR_BADHANDLE;
2162 if (plStart == NULL || plLength == NULL || lStart < 0)
2163 return AVIERR_BADPARAM;
2165 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2166 if (SUCCEEDED(hr) && pEdit != NULL) {
2167 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
2169 IAVIEditStream_Release(pEdit);
2170 } else
2171 hr = AVIERR_UNSUPPORTED;
2173 return hr;
2176 /***********************************************************************
2177 * EditStreamSetInfoA (AVIFIL32.@)
2179 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
2180 LONG size)
2182 AVISTREAMINFOW asiw;
2184 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2186 if (pstream == NULL)
2187 return AVIERR_BADHANDLE;
2188 if ((DWORD)size < sizeof(AVISTREAMINFOA))
2189 return AVIERR_BADSIZE;
2191 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
2192 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
2193 asiw.szName, sizeof(asiw.szName));
2195 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2198 /***********************************************************************
2199 * EditStreamSetInfoW (AVIFIL32.@)
2201 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
2202 LONG size)
2204 PAVIEDITSTREAM pEdit = NULL;
2205 HRESULT hr;
2207 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
2209 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
2210 if (SUCCEEDED(hr) && pEdit != NULL) {
2211 hr = IAVIEditStream_SetInfo(pEdit, asi, size);
2213 IAVIEditStream_Release(pEdit);
2214 } else
2215 hr = AVIERR_UNSUPPORTED;
2217 return hr;
2220 /***********************************************************************
2221 * EditStreamSetNameA (AVIFIL32.@)
2223 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
2225 AVISTREAMINFOA asia;
2226 HRESULT hres;
2228 TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
2230 if (pstream == NULL)
2231 return AVIERR_BADHANDLE;
2232 if (szName == NULL)
2233 return AVIERR_BADPARAM;
2235 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
2236 if (FAILED(hres))
2237 return hres;
2239 memset(asia.szName, 0, sizeof(asia.szName));
2240 lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
2242 return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
2245 /***********************************************************************
2246 * EditStreamSetNameW (AVIFIL32.@)
2248 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
2250 AVISTREAMINFOW asiw;
2251 HRESULT hres;
2253 TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
2255 if (pstream == NULL)
2256 return AVIERR_BADHANDLE;
2257 if (szName == NULL)
2258 return AVIERR_BADPARAM;
2260 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
2261 if (FAILED(hres))
2262 return hres;
2264 memset(asiw.szName, 0, sizeof(asiw.szName));
2265 lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
2267 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
2270 /***********************************************************************
2271 * AVIClearClipboard (AVIFIL32.@)
2273 HRESULT WINAPI AVIClearClipboard(void)
2275 TRACE("()\n");
2277 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
2280 /***********************************************************************
2281 * AVIGetFromClipboard (AVIFIL32.@)
2283 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
2285 FIXME("(%p), stub!\n", ppfile);
2287 *ppfile = NULL;
2289 return AVIERR_UNSUPPORTED;
2292 /***********************************************************************
2293 * AVIPutFileOnClipboard (AVIFIL32.@)
2295 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
2297 FIXME("(%p), stub!\n", pfile);
2299 if (pfile == NULL)
2300 return AVIERR_BADHANDLE;
2302 return AVIERR_UNSUPPORTED;