2 * Copyright 1999 Marcus Meissner
3 * Copyright 2002 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
34 #include "avifile_private.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
41 /***********************************************************************
42 * copied from dlls/shell32/undocshell.h
44 HRESULT WINAPI SHCoCreateInstance(LPCSTR lpszClsid,REFCLSID rClsid,
45 LPUNKNOWN pUnkOuter,REFIID riid,LPVOID *ppv);
47 /***********************************************************************
48 * for AVIBuildFilterW -- uses fixed size table
50 #define MAX_FILTERS 30 /* 30 => 7kB */
52 typedef struct _AVIFilter {
54 WCHAR szExtensions[MAX_FILTERS * 7];
57 /***********************************************************************
64 LPAVICOMPRESSOPTIONS *ppOptions;
68 /***********************************************************************
69 * copied from dlls/ole32/compobj.c
71 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
73 BYTE *s = (BYTE*)idstr;
79 memset(s, 0, sizeof(CLSID));
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))
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++)
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} */
116 s++; /* skip leading brace */
117 for (i = 0; i < 4; i++) {
118 p[3 - i] = table[*s]<<4 | table[*(s+1)];
124 for (i = 0; i < 2; i++) {
125 p[1-i] = table[*s]<<4 | table[*(s+1)];
131 for (i = 0; i < 2; i++) {
132 p[1-i] = table[*s]<<4 | table[*(s+1)];
138 /* these are just sequential bytes */
139 for (i = 0; i < 2; i++) {
140 *p++ = table[*s]<<4 | table[*(s+1)];
145 for (i = 0; i < 6; i++) {
146 *p++ = table[*s]<<4 | table[*(s+1)];
153 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
157 LPWSTR szExt = strrchrW(szFile, '.');
158 LONG len = sizeof(szValue) / sizeof(szValue[0]);
165 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
166 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
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,
197 LPWSTR wszFile = NULL;
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);
211 return AVIERR_BADPARAM;
213 wszFile = (LPWSTR)LocalAlloc(LPTR, (len + 1) * sizeof(WCHAR));
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);
227 /***********************************************************************
228 * AVIFileOpenW (AVIFIL32.@)
230 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
233 IPersistFile *ppersist = NULL;
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;
246 /* if no handler then try guessing it by extension */
247 if (lpHandler == NULL) {
248 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
249 return AVIERR_UNSUPPORTED;
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)
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);
267 hr = IPersistFile_Load(ppersist, szFile, uMode);
268 IPersistFile_Release(ppersist);
270 IAVIFile_Release(*ppfile);
277 /***********************************************************************
278 * AVIFileAddRef (AVIFIL32.@)
279 * AVIFileAddRef (AVIFILE.140)
281 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
283 TRACE("(%p)\n", pfile);
286 ERR(": bad handle passed!\n");
290 return IAVIFile_AddRef(pfile);
293 /***********************************************************************
294 * AVIFileRelease (AVIFIL32.@)
295 * AVIFileRelease (AVIFILE.141)
297 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
299 TRACE("(%p)\n", pfile);
302 ERR(": bad handle passed!\n");
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)
319 TRACE("(%p,%p,%ld)\n", pfile, afi, size);
322 return AVIERR_BADHANDLE;
323 if (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;
336 /***********************************************************************
337 * AVIFileInfoW (AVIFIL32.@)
339 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
341 TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
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);
359 return AVIERR_BADHANDLE;
361 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
364 /***********************************************************************
365 * AVIFileCreateStreamA (AVIFIL32.@)
367 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
368 LPAVISTREAMINFOA psi)
372 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
375 return AVIERR_BADHANDLE;
377 /* Only the szName at the end is different */
378 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
379 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
380 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
382 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
385 /***********************************************************************
386 * AVIFileCreateStreamW (AVIFIL32.@)
388 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
389 LPAVISTREAMINFOW asi)
391 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
393 return IAVIFile_CreateStream(pfile, avis, asi);
396 /***********************************************************************
397 * AVIFileWriteData (AVIFIL32.@)
399 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
401 TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
404 return AVIERR_BADHANDLE;
406 return IAVIFile_WriteData(pfile, fcc, lp, size);
409 /***********************************************************************
410 * AVIFileReadData (AVIFIL32.@)
412 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
414 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
417 return AVIERR_BADHANDLE;
419 return IAVIFile_ReadData(pfile, fcc, lp, size);
422 /***********************************************************************
423 * AVIFileEndRecord (AVIFIL32.@)
424 * AVIFileEndRecord (AVIFILE.148)
426 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
428 TRACE("(%p)\n", pfile);
431 return AVIERR_BADHANDLE;
433 return IAVIFile_EndRecord(pfile);
436 /***********************************************************************
437 * AVIStreamAddRef (AVIFIL32.@)
438 * AVIStreamAddRef (AVIFILE.160)
440 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
442 TRACE("(%p)\n", pstream);
444 if (pstream == NULL) {
445 ERR(": bad handle passed!\n");
449 return IAVIStream_AddRef(pstream);
452 /***********************************************************************
453 * AVIStreamRelease (AVIFIL32.@)
454 * AVIStreamRelease (AVIFILE.161)
456 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
458 TRACE("(%p)\n", pstream);
460 if (pstream == NULL) {
461 ERR(": bad handle passed!\n");
465 return IAVIStream_Release(pstream);
468 /***********************************************************************
469 * AVIStreamCreate (AVIFIL32.@)
470 * AVIStreamCreate (AVIFILE.104)
472 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
473 LPCLSID pclsidHandler)
477 TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
478 debugstr_guid(pclsidHandler));
481 return AVIERR_BADPARAM;
484 if (pclsidHandler == NULL)
485 return AVIERR_UNSUPPORTED;
487 hr = SHCoCreateInstance(NULL, pclsidHandler, NULL,
488 &IID_IAVIStream, (LPVOID*)ppavi);
489 if (FAILED(hr) || *ppavi == NULL)
492 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
494 IAVIStream_Release(*ppavi);
501 /***********************************************************************
502 * AVIStreamInfoA (AVIFIL32.@)
504 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
510 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
513 return AVIERR_BADHANDLE;
514 if (size < sizeof(AVISTREAMINFOA))
515 return AVIERR_BADSIZE;
517 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
519 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
520 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
521 sizeof(asi->szName), NULL, NULL);
522 asi->szName[sizeof(asi->szName) - 1] = 0;
527 /***********************************************************************
528 * AVIStreamInfoW (AVIFIL32.@)
530 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
533 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
536 return AVIERR_BADHANDLE;
538 return IAVIStream_Info(pstream, asi, size);
541 /***********************************************************************
542 * AVIStreamFindSample (AVIFIL32.@)
544 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
546 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
551 return IAVIStream_FindSample(pstream, pos, flags);
554 /***********************************************************************
555 * AVIStreamReadFormat (AVIFIL32.@)
557 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
558 LPVOID format, LPLONG formatsize)
560 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
563 return AVIERR_BADHANDLE;
565 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
568 /***********************************************************************
569 * AVIStreamSetFormat (AVIFIL32.@)
571 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
572 LPVOID format, LONG formatsize)
574 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
577 return AVIERR_BADHANDLE;
579 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
582 /***********************************************************************
583 * AVIStreamRead (AVIFIL32.@)
585 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
586 LPVOID buffer, LONG buffersize,
587 LPLONG bytesread, LPLONG samplesread)
589 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
590 buffersize, bytesread, samplesread);
593 return AVIERR_BADHANDLE;
595 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
596 bytesread, samplesread);
599 /***********************************************************************
600 * AVIStreamWrite (AVIFIL32.@)
602 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
603 LPVOID buffer, LONG buffersize, DWORD flags,
604 LPLONG sampwritten, LPLONG byteswritten)
606 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
607 buffersize, flags, sampwritten, byteswritten);
610 return AVIERR_BADHANDLE;
612 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
613 flags, sampwritten, byteswritten);
616 /***********************************************************************
617 * AVIStreamReadData (AVIFIL32.@)
619 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
622 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
625 return AVIERR_BADHANDLE;
627 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
630 /***********************************************************************
631 * AVIStreamWriteData (AVIFIL32.@)
633 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
636 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
639 return AVIERR_BADHANDLE;
641 return IAVIStream_WriteData(pstream, fcc, lp, size);
644 /***********************************************************************
645 * AVIStreamGetFrameOpen (AVIFIL32.@)
647 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
648 LPBITMAPINFOHEADER lpbiWanted)
652 TRACE("(%p,%p)\n", pstream, lpbiWanted);
654 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
656 pg = AVIFILE_CreateGetFrame(pstream);
661 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
662 IGetFrame_Release(pg);
669 /***********************************************************************
670 * AVIStreamGetFrame (AVIFIL32.@)
672 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
674 TRACE("(%p,%ld)\n", pg, pos);
679 return IGetFrame_GetFrame(pg, pos);
682 /***********************************************************************
683 * AVIStreamGetFrameClose (AVIFIL32.@)
685 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
690 return IGetFrame_Release(pg);
694 /***********************************************************************
695 * AVIMakeCompressedStream (AVIFIL32.@)
697 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
699 LPAVICOMPRESSOPTIONS aco,
700 LPCLSID pclsidHandler)
707 LONG size = sizeof(szValue);
709 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
710 debugstr_guid(pclsidHandler));
712 if (ppsCompressed == NULL)
713 return AVIERR_BADPARAM;
714 if (psSource == NULL)
715 return AVIERR_BADHANDLE;
717 *ppsCompressed = NULL;
719 /* if no handler given get default ones based on streamtype */
720 if (pclsidHandler == NULL) {
721 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
725 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
726 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
727 return AVIERR_UNSUPPORTED;
728 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
729 return AVIERR_UNSUPPORTED;
731 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
733 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
734 &IID_IAVIStream, (LPVOID*)ppsCompressed);
735 if (FAILED(hr) || *ppsCompressed == NULL)
738 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
740 IAVIStream_Release(*ppsCompressed);
741 *ppsCompressed = NULL;
747 /***********************************************************************
748 * AVIStreamOpenFromFile (AVIFILE.103)
749 * AVIStreamOpenFromFileA (AVIFIL32.@)
751 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
752 DWORD fccType, LONG lParam,
753 UINT mode, LPCLSID pclsidHandler)
755 PAVIFILE pfile = NULL;
758 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
759 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
761 if (ppavi == NULL || szFile == NULL)
762 return AVIERR_BADPARAM;
766 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
767 if (FAILED(hr) || pfile == NULL)
770 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
771 IAVIFile_Release(pfile);
776 /***********************************************************************
777 * AVIStreamOpenFromFileW (AVIFIL32.@)
779 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
780 DWORD fccType, LONG lParam,
781 UINT mode, LPCLSID pclsidHandler)
783 PAVIFILE pfile = NULL;
786 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
787 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
789 if (ppavi == NULL || szFile == NULL)
790 return AVIERR_BADPARAM;
794 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
795 if (FAILED(hr) || pfile == NULL)
798 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
799 IAVIFile_Release(pfile);
804 /***********************************************************************
805 * AVIStreamStart (AVIFILE.130)
806 * AVIStreamStart (AVIFIL32.@)
808 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
812 TRACE("(%p)\n", pstream);
817 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
823 /***********************************************************************
824 * AVIStreamLength (AVIFILE.131)
825 * AVIStreamLength (AVIFIL32.@)
827 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
831 TRACE("(%p)\n", pstream);
836 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
839 return asiw.dwLength;
842 /***********************************************************************
843 * AVIStreamSampleToTime (AVIFILE.133)
844 * AVIStreamSampleToTime (AVIFIL32.@)
846 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
850 TRACE("(%p,%ld)\n", pstream, lSample);
855 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
857 if (asiw.dwRate == 0)
860 return (LONG)(((float)lSample * asiw.dwScale * 1000.0) / asiw.dwRate);
863 /***********************************************************************
864 * AVIStreamTimeToSample (AVIFILE.132)
865 * AVIStreamTimeToSample (AVIFIL32.@)
867 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
871 TRACE("(%p,%ld)\n", pstream, lTime);
876 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
878 if (asiw.dwScale == 0)
881 return (LONG)(((float)lTime * asiw.dwRate) / asiw.dwScale / 1000.0);
884 /***********************************************************************
885 * AVIBuildFilterA (AVIFIL32.@)
887 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
892 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
894 /* check parameters */
895 if (szFilter == NULL)
896 return AVIERR_BADPARAM;
898 return AVIERR_BADSIZE;
903 wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter);
904 if (wszFilter == NULL)
905 return AVIERR_MEMORY;
907 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
909 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
910 szFilter, cbFilter, NULL, NULL);
913 GlobalFreePtr(wszFilter);
918 /***********************************************************************
919 * AVIBuildFilterW (AVIFIL32.@)
921 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
923 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
924 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
925 static const WCHAR szAVIFileExtensions[] =
926 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
929 WCHAR szAllFiles[40];
937 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
939 /* check parameters */
940 if (szFilter == NULL)
941 return AVIERR_BADPARAM;
943 return AVIERR_BADSIZE;
945 lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
947 return AVIERR_MEMORY;
950 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
951 * extensions and CLSID's
952 * 2. iterate over collected CLSID's and copy it's description and it's
953 * extensions to szFilter if it fits
955 * First filter is named "All multimedia files" and it's filter is a
956 * collection of all possible extensions except "*.*".
958 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
962 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
963 /* get CLSID to extension */
964 size = sizeof(szValue)/sizeof(szValue[0]);
965 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
968 /* search if the CLSID is already known */
969 for (i = 1; i <= count; i++) {
970 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
971 break; /* a new one */
974 if (count - i == -1) {
975 /* it's a new CLSID */
977 /* FIXME: How do we get info's about read/write capabilities? */
979 if (count >= MAX_FILTERS) {
980 /* try to inform user of our full fixed size table */
981 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
985 lstrcpyW(lp[i].szClsid, szValue);
990 /* append extension to the filter */
991 wsprintfW(szValue, szExtensionFmt, szFileExt);
992 if (lp[i].szExtensions[0] == 0)
993 lstrcatW(lp[i].szExtensions, szValue + 1);
995 lstrcatW(lp[i].szExtensions, szValue);
997 /* also append to the "all multimedia"-filter */
998 if (lp[0].szExtensions[0] == 0)
999 lstrcatW(lp[0].szExtensions, szValue + 1);
1001 lstrcatW(lp[0].szExtensions, szValue);
1005 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1006 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1008 return AVIERR_ERROR;
1010 for (n = 0; n <= count; n++) {
1011 /* first the description */
1013 size = sizeof(szValue)/sizeof(szValue[0]);
1014 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1015 size = lstrlenW(szValue);
1016 lstrcpynW(szFilter, szValue, cbFilter);
1019 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1021 /* check for enough space */
1023 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1028 return AVIERR_BUFFERTOOSMALL;
1033 /* and then the filter */
1034 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1035 size = lstrlenW(lp[n].szExtensions) + 1;
1043 /* add "All files" "*.*" filter if enough space left */
1044 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1045 szAllFiles, sizeof(szAllFiles)) + 1;
1046 if (cbFilter > size) {
1049 /* replace '@' with \000 to seperate description of filter */
1050 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1051 if (szAllFiles[i] == '@') {
1057 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1064 return AVIERR_BUFFERTOOSMALL;
1068 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1070 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1071 AVISTREAMINFOW sInfo;
1073 TRACE("(%p)\n", hWnd);
1075 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1076 ERR(": bad state!\n");
1080 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1081 &sInfo, sizeof(sInfo)))) {
1082 ERR(": AVIStreamInfoW failed!\n");
1086 if (sInfo.fccType == streamtypeVIDEO) {
1090 memset(&cv, 0, sizeof(cv));
1092 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1093 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1094 pOptions->fccType = streamtypeVIDEO;
1095 pOptions->fccHandler = comptypeDIB;
1096 pOptions->dwQuality = ICQUALITY_DEFAULT;
1099 cv.cbSize = sizeof(cv);
1100 cv.dwFlags = ICMF_COMPVARS_VALID;
1101 /*cv.fccType = pOptions->fccType; */
1102 cv.fccHandler = pOptions->fccHandler;
1103 cv.lQ = pOptions->dwQuality;
1104 cv.lpState = pOptions->lpParms;
1105 cv.cbState = pOptions->cbParms;
1106 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1107 cv.lKey = pOptions->dwKeyFrameEvery;
1110 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1111 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1115 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1116 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1119 pOptions->lpParms = cv.lpState;
1120 pOptions->cbParms = cv.cbState;
1121 pOptions->dwQuality = cv.lQ;
1123 pOptions->dwKeyFrameEvery = cv.lKey;
1124 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1126 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1127 if (cv.lDataRate != 0) {
1128 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1129 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1131 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1132 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1134 ICCompressorFree(&cv);
1137 } else if (sInfo.fccType == streamtypeAUDIO) {
1138 ACMFORMATCHOOSEW afmtc;
1142 /* FIXME: check ACM version -- Which version is needed? */
1144 memset(&afmtc, 0, sizeof(afmtc));
1145 afmtc.cbStruct = sizeof(afmtc);
1147 afmtc.hwndOwner = hWnd;
1149 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1150 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1151 pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1152 pOptions->cbFormat = size;
1153 } else if (pOptions->cbFormat < size) {
1154 pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1155 pOptions->cbFormat = size;
1157 if (pOptions->lpFormat == NULL)
1159 afmtc.pwfx = pOptions->lpFormat;
1160 afmtc.cbwfx = pOptions->cbFormat;
1163 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1164 sInfo.dwStart, &size);
1165 if (size < sizeof(PCMWAVEFORMAT))
1166 size = sizeof(PCMWAVEFORMAT);
1167 afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1168 if (afmtc.pwfxEnum != NULL) {
1169 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1170 sInfo.dwStart, afmtc.pwfxEnum, &size);
1171 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1174 ret = acmFormatChooseW(&afmtc);
1176 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1178 if (afmtc.pwfxEnum != NULL)
1179 GlobalFreePtr(afmtc.pwfxEnum);
1181 return (ret == S_OK ? TRUE : FALSE);
1183 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1188 static void AVISaveOptionsUpdate(HWND hWnd)
1190 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1191 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1193 WCHAR szFormat[128];
1194 AVISTREAMINFOW sInfo;
1198 TRACE("(%p)\n", hWnd);
1200 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1201 if (SaveOpts.nCurrent < 0)
1204 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1207 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1211 /* read format to build format descriotion string */
1212 lpFormat = GlobalAllocPtr(GHND, size);
1213 if (lpFormat != NULL) {
1214 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1215 if (sInfo.fccType == streamtypeVIDEO) {
1216 LPBITMAPINFOHEADER lpbi = lpFormat;
1219 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1220 lpbi->biHeight, lpbi->biBitCount);
1222 if (lpbi->biCompression != BI_RGB) {
1225 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1226 NULL, ICMODE_DECOMPRESS);
1228 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1229 lstrcatW(szFormat, icinfo.szDescription);
1233 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1234 icinfo.szDescription, sizeof(icinfo.szDescription));
1235 lstrcatW(szFormat, icinfo.szDescription);
1237 } else if (sInfo.fccType == streamtypeAUDIO) {
1238 ACMFORMATTAGDETAILSW aftd;
1239 ACMFORMATDETAILSW afd;
1241 memset(&aftd, 0, sizeof(aftd));
1242 memset(&afd, 0, sizeof(afd));
1244 aftd.cbStruct = sizeof(aftd);
1245 aftd.dwFormatTag = afd.dwFormatTag =
1246 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1247 aftd.cbFormatSize = afd.cbwfx = size;
1249 afd.cbStruct = sizeof(afd);
1250 afd.pwfx = lpFormat;
1252 if (acmFormatTagDetailsW(NULL, &aftd,
1253 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1254 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1255 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1259 GlobalFreePtr(lpFormat);
1262 /* set text for format description */
1263 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1265 /* Disable option button for unsupported streamtypes */
1266 if (sInfo.fccType == streamtypeVIDEO ||
1267 sInfo.fccType == streamtypeAUDIO)
1268 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1270 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1275 INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1276 WPARAM wParam, LPARAM lParam)
1279 BOOL bIsInterleaved;
1282 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1286 SaveOpts.nCurrent = 0;
1287 if (SaveOpts.nStreams == 1) {
1288 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1293 for (n = 0; n < SaveOpts.nStreams; n++) {
1294 AVISTREAMINFOW sInfo;
1296 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1297 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1298 0L, (LPARAM)sInfo.szName);
1301 /* select first stream */
1302 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1303 SendMessageW(hWnd, WM_COMMAND,
1304 GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1306 /* initialize interleave */
1307 if (SaveOpts.ppOptions[0] != NULL &&
1308 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1309 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1310 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1312 bIsInterleaved = TRUE;
1315 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1316 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1317 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1320 switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
1322 /* get data from controls and save them */
1323 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1324 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1325 for (n = 0; n < SaveOpts.nStreams; n++) {
1326 if (SaveOpts.ppOptions[n] != NULL) {
1327 if (bIsInterleaved) {
1328 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1329 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1331 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1336 EndDialog(hWnd, GET_WM_COMMAND_CMD(wParam, lParam) == IDOK);
1338 case IDC_INTERLEAVE:
1339 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1340 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1343 if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1344 /* update control elements */
1345 AVISaveOptionsUpdate(hWnd);
1349 AVISaveOptionsFmtChoose(hWnd);
1358 /***********************************************************************
1359 * AVISaveOptions (AVIFIL32.@)
1361 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1362 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1364 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1367 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1370 /* check parameters */
1371 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1372 return AVIERR_BADPARAM;
1374 /* save options for case user press cancel */
1375 if (ppOptions != NULL && nStreams > 1) {
1376 pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1377 if (pSavedOptions == NULL)
1380 for (n = 0; n < nStreams; n++) {
1381 if (ppOptions[n] != NULL)
1382 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1386 SaveOpts.uFlags = uFlags;
1387 SaveOpts.nStreams = nStreams;
1388 SaveOpts.ppavis = ppavi;
1389 SaveOpts.ppOptions = ppOptions;
1391 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1392 hWnd, AVISaveOptionsDlgProc);
1397 /* restore options when user pressed cancel */
1398 if (pSavedOptions != NULL && ret == FALSE) {
1399 for (n = 0; n < nStreams; n++) {
1400 if (ppOptions[n] != NULL)
1401 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1403 GlobalFreePtr(pSavedOptions);
1409 /***********************************************************************
1410 * AVISaveOptionsFree (AVIFIL32.@)
1412 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1414 TRACE("(%d,%p)\n", nStreams, ppOptions);
1416 if (nStreams < 0 || ppOptions == NULL)
1417 return AVIERR_BADPARAM;
1419 for (; nStreams > 0; nStreams--) {
1420 if (ppOptions[nStreams] != NULL) {
1421 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1423 if (ppOptions[nStreams]->lpParms != NULL) {
1424 GlobalFreePtr(ppOptions[nStreams]->lpParms);
1425 ppOptions[nStreams]->lpParms = NULL;
1426 ppOptions[nStreams]->cbParms = 0;
1428 if (ppOptions[nStreams]->lpFormat != NULL) {
1429 GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1430 ppOptions[nStreams]->lpFormat = NULL;
1431 ppOptions[nStreams]->cbFormat = 0;