Don't define COBJMACROS in objbase.h.
[wine/multimedia.git] / dlls / avifil32 / api.c
blobc08ed5fc43b5bcc86a73e1a1bdc4dd657f5711bb
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 * AVIFileOpenA (AVIFIL32.@)
194 * AVIFileOpen (AVIFILE.102)
196 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
197 LPCLSID lpHandler)
199 LPWSTR wszFile = NULL;
200 HRESULT hr;
201 int len;
203 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
204 debugstr_guid(lpHandler));
206 /* check parameters */
207 if (ppfile == NULL || szFile == NULL)
208 return AVIERR_BADPARAM;
210 /* convert ASCII string to Unicode and call unicode function */
211 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
212 if (len <= 0)
213 return AVIERR_BADPARAM;
215 wszFile = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
216 if (wszFile == NULL)
217 return AVIERR_MEMORY;
219 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
221 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
223 LocalFree((HLOCAL)wszFile);
225 return hr;
228 /***********************************************************************
229 * AVIFileOpenW (AVIFIL32.@)
231 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
232 LPCLSID lpHandler)
234 IPersistFile *ppersist = NULL;
235 CLSID clsidHandler;
236 HRESULT hr;
238 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
239 debugstr_guid(lpHandler));
241 /* check parameters */
242 if (ppfile == NULL || szFile == NULL)
243 return AVIERR_BADPARAM;
245 *ppfile = NULL;
247 /* if no handler then try guessing it by extension */
248 if (lpHandler == NULL) {
249 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
250 return AVIERR_UNSUPPORTED;
251 } else
252 memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
254 /* crete instance of handler */
255 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
256 &IID_IAVIFile, (LPVOID*)ppfile);
257 if (FAILED(hr) || *ppfile == NULL)
258 return hr;
260 /* ask for IPersistFile interface for loading/creating the file */
261 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
262 if (FAILED(hr) || ppersist == NULL) {
263 IAVIFile_Release(*ppfile);
264 *ppfile = NULL;
265 return hr;
268 hr = IPersistFile_Load(ppersist, szFile, uMode);
269 IPersistFile_Release(ppersist);
270 if (FAILED(hr)) {
271 IAVIFile_Release(*ppfile);
272 *ppfile = NULL;
275 return hr;
278 /***********************************************************************
279 * AVIFileAddRef (AVIFIL32.@)
280 * AVIFileAddRef (AVIFILE.140)
282 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
284 TRACE("(%p)\n", pfile);
286 if (pfile == NULL) {
287 ERR(": bad handle passed!\n");
288 return 0;
291 return IAVIFile_AddRef(pfile);
294 /***********************************************************************
295 * AVIFileRelease (AVIFIL32.@)
296 * AVIFileRelease (AVIFILE.141)
298 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
300 TRACE("(%p)\n", pfile);
302 if (pfile == NULL) {
303 ERR(": bad handle passed!\n");
304 return 0;
307 return IAVIFile_Release(pfile);
310 /***********************************************************************
311 * AVIFileInfo (AVIFIL32.@)
312 * AVIFileInfoA (AVIFIL32.@)
313 * AVIFileInfo (AVIFILE.142)
315 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
317 AVIFILEINFOW afiw;
318 HRESULT hres;
320 TRACE("(%p,%p,%ld)\n", pfile, afi, size);
322 if (pfile == NULL)
323 return AVIERR_BADHANDLE;
324 if ((DWORD)size < sizeof(AVIFILEINFOA))
325 return AVIERR_BADSIZE;
327 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
329 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
330 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
331 sizeof(afi->szFileType), NULL, NULL);
332 afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
334 return hres;
337 /***********************************************************************
338 * AVIFileInfoW (AVIFIL32.@)
340 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
342 TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
344 if (pfile == NULL)
345 return AVIERR_BADHANDLE;
347 return IAVIFile_Info(pfile, afiw, size);
350 /***********************************************************************
351 * AVIFileGetStream (AVIFIL32.@)
352 * AVIFileGetStream (AVIFILE.143)
354 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
355 DWORD fccType, LONG lParam)
357 TRACE("(%p,%p,'%4.4s',%ld)\n", pfile, avis, (char*)&fccType, lParam);
359 if (pfile == NULL)
360 return AVIERR_BADHANDLE;
362 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
365 /***********************************************************************
366 * AVIFileCreateStreamA (AVIFIL32.@)
367 * AVIFileCreateStream (AVIFILE.144)
369 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
370 LPAVISTREAMINFOA psi)
372 AVISTREAMINFOW psiw;
374 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
376 if (pfile == NULL)
377 return AVIERR_BADHANDLE;
379 /* Only the szName at the end is different */
380 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
381 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
382 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
384 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
387 /***********************************************************************
388 * AVIFileCreateStreamW (AVIFIL32.@)
390 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
391 LPAVISTREAMINFOW asi)
393 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
395 if (pfile == NULL)
396 return AVIERR_BADHANDLE;
398 return IAVIFile_CreateStream(pfile, avis, asi);
401 /***********************************************************************
402 * AVIFileWriteData (AVIFIL32.@)
403 * AVIFileWriteData (AVIFILE.146)
405 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
407 TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
409 if (pfile == NULL)
410 return AVIERR_BADHANDLE;
412 return IAVIFile_WriteData(pfile, fcc, lp, size);
415 /***********************************************************************
416 * AVIFileReadData (AVIFIL32.@)
417 * AVIFileReadData (AVIFILE.147)
419 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
421 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
423 if (pfile == NULL)
424 return AVIERR_BADHANDLE;
426 return IAVIFile_ReadData(pfile, fcc, lp, size);
429 /***********************************************************************
430 * AVIFileEndRecord (AVIFIL32.@)
431 * AVIFileEndRecord (AVIFILE.148)
433 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
435 TRACE("(%p)\n", pfile);
437 if (pfile == NULL)
438 return AVIERR_BADHANDLE;
440 return IAVIFile_EndRecord(pfile);
443 /***********************************************************************
444 * AVIStreamAddRef (AVIFIL32.@)
445 * AVIStreamAddRef (AVIFILE.160)
447 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
449 TRACE("(%p)\n", pstream);
451 if (pstream == NULL) {
452 ERR(": bad handle passed!\n");
453 return 0;
456 return IAVIStream_AddRef(pstream);
459 /***********************************************************************
460 * AVIStreamRelease (AVIFIL32.@)
461 * AVIStreamRelease (AVIFILE.161)
463 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
465 TRACE("(%p)\n", pstream);
467 if (pstream == NULL) {
468 ERR(": bad handle passed!\n");
469 return 0;
472 return IAVIStream_Release(pstream);
475 /***********************************************************************
476 * AVIStreamCreate (AVIFIL32.@)
477 * AVIStreamCreate (AVIFILE.104)
479 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
480 LPCLSID pclsidHandler)
482 HRESULT hr;
484 TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
485 debugstr_guid(pclsidHandler));
487 if (ppavi == NULL)
488 return AVIERR_BADPARAM;
490 *ppavi = NULL;
491 if (pclsidHandler == NULL)
492 return AVIERR_UNSUPPORTED;
494 hr = SHCoCreateInstance(NULL, pclsidHandler, NULL,
495 &IID_IAVIStream, (LPVOID*)ppavi);
496 if (FAILED(hr) || *ppavi == NULL)
497 return hr;
499 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
500 if (FAILED(hr)) {
501 IAVIStream_Release(*ppavi);
502 *ppavi = NULL;
505 return hr;
508 /***********************************************************************
509 * AVIStreamInfo (AVIFIL32.@)
510 * AVIStreamInfoA (AVIFIL32.@)
511 * AVIStreamInfo (AVIFILE.162)
513 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
514 LONG size)
516 AVISTREAMINFOW asiw;
517 HRESULT hres;
519 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
521 if (pstream == NULL)
522 return AVIERR_BADHANDLE;
523 if ((DWORD)size < sizeof(AVISTREAMINFOA))
524 return AVIERR_BADSIZE;
526 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
528 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
529 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
530 sizeof(asi->szName), NULL, NULL);
531 asi->szName[sizeof(asi->szName) - 1] = 0;
533 return hres;
536 /***********************************************************************
537 * AVIStreamInfoW (AVIFIL32.@)
539 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
540 LONG size)
542 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
544 if (pstream == NULL)
545 return AVIERR_BADHANDLE;
547 return IAVIStream_Info(pstream, asi, size);
550 /***********************************************************************
551 * AVIStreamFindSample (AVIFIL32.@)
552 * AVIStreamFindSample (AVIFILE.163)
554 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
556 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
558 if (pstream == NULL)
559 return -1;
561 return IAVIStream_FindSample(pstream, pos, flags);
564 /***********************************************************************
565 * AVIStreamReadFormat (AVIFIL32.@)
566 * AVIStreamReadFormat (AVIFILE.164)
568 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
569 LPVOID format, LPLONG formatsize)
571 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
573 if (pstream == NULL)
574 return AVIERR_BADHANDLE;
576 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
579 /***********************************************************************
580 * AVIStreamSetFormat (AVIFIL32.@)
581 * AVIStreamSetFormat (AVIFILE.169)
583 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
584 LPVOID format, LONG formatsize)
586 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
588 if (pstream == NULL)
589 return AVIERR_BADHANDLE;
591 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
594 /***********************************************************************
595 * AVIStreamRead (AVIFIL32.@)
596 * AVIStreamRead (AVIFILE.167)
598 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
599 LPVOID buffer, LONG buffersize,
600 LPLONG bytesread, LPLONG samplesread)
602 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
603 buffersize, bytesread, samplesread);
605 if (pstream == NULL)
606 return AVIERR_BADHANDLE;
608 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
609 bytesread, samplesread);
612 /***********************************************************************
613 * AVIStreamWrite (AVIFIL32.@)
614 * AVIStreamWrite (AVIFILE.168)
616 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
617 LPVOID buffer, LONG buffersize, DWORD flags,
618 LPLONG sampwritten, LPLONG byteswritten)
620 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
621 buffersize, flags, sampwritten, byteswritten);
623 if (pstream == NULL)
624 return AVIERR_BADHANDLE;
626 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
627 flags, sampwritten, byteswritten);
630 /***********************************************************************
631 * AVIStreamReadData (AVIFIL32.@)
632 * AVIStreamReadData (AVIFILE.165)
634 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
635 LPLONG lpread)
637 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
639 if (pstream == NULL)
640 return AVIERR_BADHANDLE;
642 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
645 /***********************************************************************
646 * AVIStreamWriteData (AVIFIL32.@)
647 * AVIStreamWriteData (AVIFILE.166)
649 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
650 LONG size)
652 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
654 if (pstream == NULL)
655 return AVIERR_BADHANDLE;
657 return IAVIStream_WriteData(pstream, fcc, lp, size);
660 /***********************************************************************
661 * AVIStreamGetFrameOpen (AVIFIL32.@)
662 * AVIStreamGetFrameOpen (AVIFILE.112)
664 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
665 LPBITMAPINFOHEADER lpbiWanted)
667 PGETFRAME pg = NULL;
669 TRACE("(%p,%p)\n", pstream, lpbiWanted);
671 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
672 pg == NULL) {
673 pg = AVIFILE_CreateGetFrame(pstream);
674 if (pg == NULL)
675 return NULL;
678 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
679 IGetFrame_Release(pg);
680 return NULL;
683 return pg;
686 /***********************************************************************
687 * AVIStreamGetFrame (AVIFIL32.@)
688 * AVIStreamGetFrame (AVIFILE.110)
690 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
692 TRACE("(%p,%ld)\n", pg, pos);
694 if (pg == NULL)
695 return NULL;
697 return IGetFrame_GetFrame(pg, pos);
700 /***********************************************************************
701 * AVIStreamGetFrameClose (AVIFIL32.@)
702 * AVIStreamGetFrameClose (AVIFILE.111)
704 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
706 TRACE("(%p)\n", pg);
708 if (pg != NULL)
709 return IGetFrame_Release(pg);
710 return 0;
713 /***********************************************************************
714 * AVIMakeCompressedStream (AVIFIL32.@)
716 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
717 PAVISTREAM psSource,
718 LPAVICOMPRESSOPTIONS aco,
719 LPCLSID pclsidHandler)
721 AVISTREAMINFOW asiw;
722 CHAR szRegKey[25];
723 CHAR szValue[100];
724 CLSID clsidHandler;
725 HRESULT hr;
726 LONG size = sizeof(szValue);
728 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
729 debugstr_guid(pclsidHandler));
731 if (ppsCompressed == NULL)
732 return AVIERR_BADPARAM;
733 if (psSource == NULL)
734 return AVIERR_BADHANDLE;
736 *ppsCompressed = NULL;
738 /* if no handler given get default ones based on streamtype */
739 if (pclsidHandler == NULL) {
740 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
741 if (FAILED(hr))
742 return hr;
744 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
745 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
746 return AVIERR_UNSUPPORTED;
747 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
748 return AVIERR_UNSUPPORTED;
749 } else
750 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
752 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
753 &IID_IAVIStream, (LPVOID*)ppsCompressed);
754 if (FAILED(hr) || *ppsCompressed == NULL)
755 return hr;
757 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
758 if (FAILED(hr)) {
759 IAVIStream_Release(*ppsCompressed);
760 *ppsCompressed = NULL;
763 return hr;
766 /***********************************************************************
767 * AVIMakeFileFromStreams (AVIFIL32.@)
769 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
770 PAVISTREAM *ppStreams)
772 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
774 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
775 return AVIERR_BADPARAM;
777 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
778 if (*ppfile == NULL)
779 return AVIERR_MEMORY;
781 return AVIERR_OK;
784 /***********************************************************************
785 * AVIStreamOpenFromFile (AVIFILE.103)
786 * AVIStreamOpenFromFileA (AVIFIL32.@)
788 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
789 DWORD fccType, LONG lParam,
790 UINT mode, LPCLSID pclsidHandler)
792 PAVIFILE pfile = NULL;
793 HRESULT hr;
795 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
796 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
798 if (ppavi == NULL || szFile == NULL)
799 return AVIERR_BADPARAM;
801 *ppavi = NULL;
803 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
804 if (FAILED(hr) || pfile == NULL)
805 return hr;
807 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
808 IAVIFile_Release(pfile);
810 return hr;
813 /***********************************************************************
814 * AVIStreamOpenFromFileW (AVIFIL32.@)
816 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
817 DWORD fccType, LONG lParam,
818 UINT mode, LPCLSID pclsidHandler)
820 PAVIFILE pfile = NULL;
821 HRESULT hr;
823 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
824 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
826 if (ppavi == NULL || szFile == NULL)
827 return AVIERR_BADPARAM;
829 *ppavi = NULL;
831 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
832 if (FAILED(hr) || pfile == NULL)
833 return hr;
835 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
836 IAVIFile_Release(pfile);
838 return hr;
841 /***********************************************************************
842 * AVIStreamBeginStreaming (AVIFIL32.@)
844 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
846 IAVIStreaming* pstream = NULL;
847 HRESULT hr;
849 TRACE("(%p,%ld,%ld,%ld)\n", pavi, lStart, lEnd, lRate);
851 if (pavi == NULL)
852 return AVIERR_BADHANDLE;
854 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
855 if (SUCCEEDED(hr) && pstream != NULL) {
856 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
857 IAVIStreaming_Release(pstream);
858 } else
859 hr = AVIERR_OK;
861 return hr;
864 /***********************************************************************
865 * AVIStreamEndStreaming (AVIFIL32.@)
867 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
869 IAVIStreaming* pstream = NULL;
870 HRESULT hr;
872 TRACE("(%p)\n", pavi);
874 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
875 if (SUCCEEDED(hr) && pstream != NULL) {
876 IAVIStreaming_End(pstream);
877 IAVIStreaming_Release(pstream);
880 return AVIERR_OK;
883 /***********************************************************************
884 * AVIStreamStart (AVIFILE.130)
885 * AVIStreamStart (AVIFIL32.@)
887 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
889 AVISTREAMINFOW asiw;
891 TRACE("(%p)\n", pstream);
893 if (pstream == NULL)
894 return 0;
896 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
897 return 0;
899 return asiw.dwStart;
902 /***********************************************************************
903 * AVIStreamLength (AVIFILE.131)
904 * AVIStreamLength (AVIFIL32.@)
906 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
908 AVISTREAMINFOW asiw;
910 TRACE("(%p)\n", pstream);
912 if (pstream == NULL)
913 return 0;
915 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
916 return 0;
918 return asiw.dwLength;
921 /***********************************************************************
922 * AVIStreamSampleToTime (AVIFILE.133)
923 * AVIStreamSampleToTime (AVIFIL32.@)
925 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
927 AVISTREAMINFOW asiw;
928 LONG time;
930 TRACE("(%p,%ld)\n", pstream, lSample);
932 if (pstream == NULL)
933 return -1;
935 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
936 return -1;
937 if (asiw.dwRate == 0)
938 return -1;
940 /* limit to stream bounds */
941 if (lSample < asiw.dwStart)
942 lSample = asiw.dwStart;
943 if (lSample > asiw.dwStart + asiw.dwLength)
944 lSample = asiw.dwStart + asiw.dwLength;
946 if (asiw.dwRate / asiw.dwScale < 1000)
947 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
948 else
949 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
951 TRACE(" -> %ld\n",time);
952 return time;
955 /***********************************************************************
956 * AVIStreamTimeToSample (AVIFILE.132)
957 * AVIStreamTimeToSample (AVIFIL32.@)
959 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
961 AVISTREAMINFOW asiw;
962 ULONG sample;
964 TRACE("(%p,%ld)\n", pstream, lTime);
966 if (pstream == NULL || lTime < 0)
967 return -1;
969 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
970 return -1;
971 if (asiw.dwScale == 0)
972 return -1;
974 if (asiw.dwRate / asiw.dwScale < 1000)
975 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
976 else
977 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
979 /* limit to stream bounds */
980 if (sample < asiw.dwStart)
981 sample = asiw.dwStart;
982 if (sample > asiw.dwStart + asiw.dwLength)
983 sample = asiw.dwStart + asiw.dwLength;
985 TRACE(" -> %ld\n", sample);
986 return sample;
989 /***********************************************************************
990 * AVIBuildFilterA (AVIFIL32.@)
991 * AVIBuildFilter (AVIFILE.123)
993 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
995 LPWSTR wszFilter;
996 HRESULT hr;
998 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1000 /* check parameters */
1001 if (szFilter == NULL)
1002 return AVIERR_BADPARAM;
1003 if (cbFilter < 2)
1004 return AVIERR_BADSIZE;
1006 szFilter[0] = 0;
1007 szFilter[1] = 0;
1009 wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter * sizeof(WCHAR));
1010 if (wszFilter == NULL)
1011 return AVIERR_MEMORY;
1013 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
1014 if (SUCCEEDED(hr)) {
1015 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
1016 szFilter, cbFilter, NULL, NULL);
1019 GlobalFreePtr(wszFilter);
1021 return hr;
1024 /***********************************************************************
1025 * AVIBuildFilterW (AVIFIL32.@)
1027 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
1029 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
1030 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
1031 static const WCHAR szAVIFileExtensions[] =
1032 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1034 AVIFilter *lp;
1035 WCHAR szAllFiles[40];
1036 WCHAR szFileExt[10];
1037 WCHAR szValue[128];
1038 HKEY hKey;
1039 DWORD n, i;
1040 LONG size;
1041 DWORD count = 0;
1043 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
1045 /* check parameters */
1046 if (szFilter == NULL)
1047 return AVIERR_BADPARAM;
1048 if (cbFilter < 2)
1049 return AVIERR_BADSIZE;
1051 lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
1052 if (lp == NULL)
1053 return AVIERR_MEMORY;
1056 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
1057 * extensions and CLSID's
1058 * 2. iterate over collected CLSID's and copy it's description and it's
1059 * extensions to szFilter if it fits
1061 * First filter is named "All multimedia files" and it's filter is a
1062 * collection of all possible extensions except "*.*".
1064 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
1065 GlobalFreePtr(lp);
1066 return AVIERR_ERROR;
1068 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
1069 /* get CLSID to extension */
1070 size = sizeof(szValue)/sizeof(szValue[0]);
1071 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
1072 break;
1074 /* search if the CLSID is already known */
1075 for (i = 1; i <= count; i++) {
1076 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
1077 break; /* a new one */
1080 if (count - i == -1U) {
1081 /* it's a new CLSID */
1083 /* FIXME: How do we get info's about read/write capabilities? */
1085 if (count >= MAX_FILTERS) {
1086 /* try to inform user of our full fixed size table */
1087 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1088 break;
1091 lstrcpyW(lp[i].szClsid, szValue);
1093 count++;
1096 /* append extension to the filter */
1097 wsprintfW(szValue, szExtensionFmt, szFileExt);
1098 if (lp[i].szExtensions[0] == 0)
1099 lstrcatW(lp[i].szExtensions, szValue + 1);
1100 else
1101 lstrcatW(lp[i].szExtensions, szValue);
1103 /* also append to the "all multimedia"-filter */
1104 if (lp[0].szExtensions[0] == 0)
1105 lstrcatW(lp[0].szExtensions, szValue + 1);
1106 else
1107 lstrcatW(lp[0].szExtensions, szValue);
1109 RegCloseKey(hKey);
1111 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1112 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1113 GlobalFreePtr(lp);
1114 return AVIERR_ERROR;
1116 for (n = 0; n <= count; n++) {
1117 /* first the description */
1118 if (n != 0) {
1119 size = sizeof(szValue)/sizeof(szValue[0]);
1120 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1121 size = lstrlenW(szValue);
1122 lstrcpynW(szFilter, szValue, cbFilter);
1124 } else
1125 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1127 /* check for enough space */
1128 size++;
1129 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1130 szFilter[0] = 0;
1131 szFilter[1] = 0;
1132 GlobalFreePtr(lp);
1133 RegCloseKey(hKey);
1134 return AVIERR_BUFFERTOOSMALL;
1136 cbFilter -= size;
1137 szFilter += size;
1139 /* and then the filter */
1140 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1141 size = lstrlenW(lp[n].szExtensions) + 1;
1142 cbFilter -= size;
1143 szFilter += size;
1146 RegCloseKey(hKey);
1147 GlobalFreePtr(lp);
1149 /* add "All files" "*.*" filter if enough space left */
1150 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1151 szAllFiles, sizeof(szAllFiles)) + 1;
1152 if (cbFilter > size) {
1153 int i;
1155 /* replace '@' with \000 to separate description of filter */
1156 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1157 if (szAllFiles[i] == '@') {
1158 szAllFiles[i] = 0;
1159 break;
1163 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1164 szFilter += size;
1165 szFilter[0] = 0;
1167 return AVIERR_OK;
1168 } else {
1169 szFilter[0] = 0;
1170 return AVIERR_BUFFERTOOSMALL;
1174 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1176 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1177 AVISTREAMINFOW sInfo;
1179 TRACE("(%p)\n", hWnd);
1181 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1182 ERR(": bad state!\n");
1183 return FALSE;
1186 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1187 &sInfo, sizeof(sInfo)))) {
1188 ERR(": AVIStreamInfoW failed!\n");
1189 return FALSE;
1192 if (sInfo.fccType == streamtypeVIDEO) {
1193 COMPVARS cv;
1194 BOOL ret;
1196 memset(&cv, 0, sizeof(cv));
1198 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1199 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1200 pOptions->fccType = streamtypeVIDEO;
1201 pOptions->fccHandler = comptypeDIB;
1202 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
1205 cv.cbSize = sizeof(cv);
1206 cv.dwFlags = ICMF_COMPVARS_VALID;
1207 /*cv.fccType = pOptions->fccType; */
1208 cv.fccHandler = pOptions->fccHandler;
1209 cv.lQ = pOptions->dwQuality;
1210 cv.lpState = pOptions->lpParms;
1211 cv.cbState = pOptions->cbParms;
1212 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1213 cv.lKey = pOptions->dwKeyFrameEvery;
1214 else
1215 cv.lKey = 0;
1216 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1217 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1218 else
1219 cv.lDataRate = 0;
1221 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1222 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1224 if (ret) {
1225 pOptions->fccHandler = cv.fccHandler;
1226 pOptions->lpParms = cv.lpState;
1227 pOptions->cbParms = cv.cbState;
1228 pOptions->dwQuality = cv.lQ;
1229 if (cv.lKey != 0) {
1230 pOptions->dwKeyFrameEvery = cv.lKey;
1231 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1232 } else
1233 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1234 if (cv.lDataRate != 0) {
1235 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1236 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1237 } else
1238 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1239 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1241 ICCompressorFree(&cv);
1243 return ret;
1244 } else if (sInfo.fccType == streamtypeAUDIO) {
1245 ACMFORMATCHOOSEW afmtc;
1246 MMRESULT ret;
1247 LONG size;
1249 /* FIXME: check ACM version -- Which version is needed? */
1251 memset(&afmtc, 0, sizeof(afmtc));
1252 afmtc.cbStruct = sizeof(afmtc);
1253 afmtc.fdwStyle = 0;
1254 afmtc.hwndOwner = hWnd;
1256 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1257 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1258 pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1259 pOptions->cbFormat = size;
1260 } else if (pOptions->cbFormat < (DWORD)size) {
1261 pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1262 pOptions->cbFormat = size;
1264 if (pOptions->lpFormat == NULL)
1265 return FALSE;
1266 afmtc.pwfx = pOptions->lpFormat;
1267 afmtc.cbwfx = pOptions->cbFormat;
1269 size = 0;
1270 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1271 sInfo.dwStart, &size);
1272 if (size < (LONG)sizeof(PCMWAVEFORMAT))
1273 size = sizeof(PCMWAVEFORMAT);
1274 afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1275 if (afmtc.pwfxEnum != NULL) {
1276 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1277 sInfo.dwStart, afmtc.pwfxEnum, &size);
1278 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1281 ret = acmFormatChooseW(&afmtc);
1282 if (ret == S_OK)
1283 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1285 if (afmtc.pwfxEnum != NULL)
1286 GlobalFreePtr(afmtc.pwfxEnum);
1288 return (ret == S_OK ? TRUE : FALSE);
1289 } else {
1290 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1291 return FALSE;
1295 static void AVISaveOptionsUpdate(HWND hWnd)
1297 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1298 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1300 WCHAR szFormat[128];
1301 AVISTREAMINFOW sInfo;
1302 LPVOID lpFormat;
1303 LONG size;
1305 TRACE("(%p)\n", hWnd);
1307 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1308 if (SaveOpts.nCurrent < 0)
1309 return;
1311 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1312 return;
1314 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1315 if (size > 0) {
1316 szFormat[0] = 0;
1318 /* read format to build format descriotion string */
1319 lpFormat = GlobalAllocPtr(GHND, size);
1320 if (lpFormat != NULL) {
1321 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1322 if (sInfo.fccType == streamtypeVIDEO) {
1323 LPBITMAPINFOHEADER lpbi = lpFormat;
1324 ICINFO icinfo;
1326 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1327 lpbi->biHeight, lpbi->biBitCount);
1329 if (lpbi->biCompression != BI_RGB) {
1330 HIC hic;
1332 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1333 NULL, ICMODE_DECOMPRESS);
1334 if (hic != NULL) {
1335 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1336 lstrcatW(szFormat, icinfo.szDescription);
1337 ICClose(hic);
1339 } else {
1340 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1341 icinfo.szDescription, sizeof(icinfo.szDescription));
1342 lstrcatW(szFormat, icinfo.szDescription);
1344 } else if (sInfo.fccType == streamtypeAUDIO) {
1345 ACMFORMATTAGDETAILSW aftd;
1346 ACMFORMATDETAILSW afd;
1348 memset(&aftd, 0, sizeof(aftd));
1349 memset(&afd, 0, sizeof(afd));
1351 aftd.cbStruct = sizeof(aftd);
1352 aftd.dwFormatTag = afd.dwFormatTag =
1353 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1354 aftd.cbFormatSize = afd.cbwfx = size;
1356 afd.cbStruct = sizeof(afd);
1357 afd.pwfx = lpFormat;
1359 if (acmFormatTagDetailsW(NULL, &aftd,
1360 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1361 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1362 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1366 GlobalFreePtr(lpFormat);
1369 /* set text for format description */
1370 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1372 /* Disable option button for unsupported streamtypes */
1373 if (sInfo.fccType == streamtypeVIDEO ||
1374 sInfo.fccType == streamtypeAUDIO)
1375 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1376 else
1377 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1382 INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1383 WPARAM wParam, LPARAM lParam)
1385 DWORD dwInterleave;
1386 BOOL bIsInterleaved;
1387 INT n;
1389 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1391 switch (uMsg) {
1392 case WM_INITDIALOG:
1393 SaveOpts.nCurrent = 0;
1394 if (SaveOpts.nStreams == 1) {
1395 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1396 return TRUE;
1399 /* add streams */
1400 for (n = 0; n < SaveOpts.nStreams; n++) {
1401 AVISTREAMINFOW sInfo;
1403 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1404 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1405 0L, (LPARAM)sInfo.szName);
1408 /* select first stream */
1409 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1410 SendMessageW(hWnd, WM_COMMAND,
1411 GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1413 /* initialize interleave */
1414 if (SaveOpts.ppOptions[0] != NULL &&
1415 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1416 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1417 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1418 } else {
1419 bIsInterleaved = TRUE;
1420 dwInterleave = 0;
1422 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1423 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1424 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1425 break;
1426 case WM_COMMAND:
1427 switch (GET_WM_COMMAND_ID(wParam, lParam)) {
1428 case IDOK:
1429 /* get data from controls and save them */
1430 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1431 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1432 for (n = 0; n < SaveOpts.nStreams; n++) {
1433 if (SaveOpts.ppOptions[n] != NULL) {
1434 if (bIsInterleaved) {
1435 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1436 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1437 } else
1438 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1441 /* fall through */
1442 case IDCANCEL:
1443 EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
1444 break;
1445 case IDC_INTERLEAVE:
1446 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1447 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1448 break;
1449 case IDC_STREAM:
1450 if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1451 /* update control elements */
1452 AVISaveOptionsUpdate(hWnd);
1454 break;
1455 case IDC_OPTIONS:
1456 AVISaveOptionsFmtChoose(hWnd);
1457 break;
1459 return TRUE;
1462 return FALSE;
1465 /***********************************************************************
1466 * AVISaveOptions (AVIFIL32.@)
1468 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1469 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1471 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1472 INT ret, n;
1474 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1475 ppavi, ppOptions);
1477 /* check parameters */
1478 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1479 return AVIERR_BADPARAM;
1481 /* save options for case user press cancel */
1482 if (ppOptions != NULL && nStreams > 1) {
1483 pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1484 if (pSavedOptions == NULL)
1485 return FALSE;
1487 for (n = 0; n < nStreams; n++) {
1488 if (ppOptions[n] != NULL)
1489 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1493 SaveOpts.uFlags = uFlags;
1494 SaveOpts.nStreams = nStreams;
1495 SaveOpts.ppavis = ppavi;
1496 SaveOpts.ppOptions = ppOptions;
1498 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1499 hWnd, AVISaveOptionsDlgProc);
1501 if (ret == -1)
1502 ret = FALSE;
1504 /* restore options when user pressed cancel */
1505 if (pSavedOptions != NULL) {
1506 if (ret == FALSE) {
1507 for (n = 0; n < nStreams; n++) {
1508 if (ppOptions[n] != NULL)
1509 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1512 GlobalFreePtr(pSavedOptions);
1515 return (BOOL)ret;
1518 /***********************************************************************
1519 * AVISaveOptionsFree (AVIFIL32.@)
1520 * AVISaveOptionsFree (AVIFILE.124)
1522 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1524 TRACE("(%d,%p)\n", nStreams, ppOptions);
1526 if (nStreams < 0 || ppOptions == NULL)
1527 return AVIERR_BADPARAM;
1529 for (; nStreams > 0; nStreams--) {
1530 if (ppOptions[nStreams] != NULL) {
1531 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1533 if (ppOptions[nStreams]->lpParms != NULL) {
1534 GlobalFreePtr(ppOptions[nStreams]->lpParms);
1535 ppOptions[nStreams]->lpParms = NULL;
1536 ppOptions[nStreams]->cbParms = 0;
1538 if (ppOptions[nStreams]->lpFormat != NULL) {
1539 GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1540 ppOptions[nStreams]->lpFormat = NULL;
1541 ppOptions[nStreams]->cbFormat = 0;
1546 return AVIERR_OK;
1549 /***********************************************************************
1550 * AVISaveVA (AVIFIL32.@)
1552 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1553 AVISAVECALLBACK lpfnCallback, int nStream,
1554 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1556 LPWSTR wszFile = NULL;
1557 HRESULT hr;
1558 int len;
1560 TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1561 lpfnCallback, nStream, ppavi, plpOptions);
1563 if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1564 return AVIERR_BADPARAM;
1566 /* convert ASCII string to Unicode and call Unicode function */
1567 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
1568 if (len <= 0)
1569 return AVIERR_BADPARAM;
1571 wszFile = LocalAlloc(LPTR, len * sizeof(WCHAR));
1572 if (wszFile == NULL)
1573 return AVIERR_MEMORY;
1575 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
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;