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
20 #define COM_NO_WINDOWS_H
35 #include "avifile_private.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
42 /***********************************************************************
43 * copied from dlls/shell32/undocshell.h
45 HRESULT WINAPI SHCoCreateInstance(LPCSTR lpszClsid,REFCLSID rClsid,
46 LPUNKNOWN pUnkOuter,REFIID riid,LPVOID *ppv);
48 /***********************************************************************
49 * for AVIBuildFilterW -- uses fixed size table
51 #define MAX_FILTERS 30 /* 30 => 7kB */
53 typedef struct _AVIFilter {
55 WCHAR szExtensions[MAX_FILTERS * 7];
58 /***********************************************************************
65 LPAVICOMPRESSOPTIONS *ppOptions;
69 /***********************************************************************
70 * copied from dlls/ole32/compobj.c
72 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
74 BYTE *s = (BYTE*)idstr;
80 memset(s, 0, sizeof(CLSID));
82 } else { /* validate the CLSID string */
83 if (lstrlenA(s) != 38)
84 return CO_E_CLASSSTRING;
86 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
87 (s[24]!='-') || (s[37]!='}'))
88 return CO_E_CLASSSTRING;
90 for (i = 1; i < 37; i++) {
91 if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
93 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
94 ((s[i] >= 'a') && (s[i] <= 'f')) ||
95 ((s[i] >= 'A') && (s[i] <= 'F')))
97 return CO_E_CLASSSTRING;
101 TRACE("%s -> %p\n", s, id);
103 /* quick lookup table */
104 memset(table, 0, 256);
106 for (i = 0; i < 10; i++)
109 for (i = 0; i < 6; i++) {
110 table['A' + i] = i+10;
111 table['a' + i] = i+10;
114 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
117 s++; /* skip leading brace */
118 for (i = 0; i < 4; i++) {
119 p[3 - i] = table[*s]<<4 | table[*(s+1)];
125 for (i = 0; i < 2; i++) {
126 p[1-i] = table[*s]<<4 | table[*(s+1)];
132 for (i = 0; i < 2; i++) {
133 p[1-i] = table[*s]<<4 | table[*(s+1)];
139 /* these are just sequential bytes */
140 for (i = 0; i < 2; i++) {
141 *p++ = table[*s]<<4 | table[*(s+1)];
146 for (i = 0; i < 6; i++) {
147 *p++ = table[*s]<<4 | table[*(s+1)];
154 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
158 LPWSTR szExt = strrchrW(szFile, '.');
159 LONG len = sizeof(szValue) / sizeof(szValue[0]);
166 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
167 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
170 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
173 /***********************************************************************
174 * AVIFileInit (AVIFIL32.@)
175 * AVIFileInit (AVIFILE.100)
177 void WINAPI AVIFileInit(void) {
178 /* need to load ole32.dll if not already done and get some functions */
179 FIXME("(): stub!\n");
182 /***********************************************************************
183 * AVIFileExit (AVIFIL32.@)
184 * AVIFileExit (AVIFILE.101)
186 void WINAPI AVIFileExit(void) {
187 /* need to free ole32.dll if we are the last exit call */
188 FIXME("(): stub!\n");
191 /***********************************************************************
192 * AVIFileOpenA (AVIFIL32.@)
193 * AVIFileOpen (AVIFILE.102)
195 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
198 LPWSTR wszFile = NULL;
202 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
203 debugstr_guid(lpHandler));
205 /* check parameters */
206 if (ppfile == NULL || szFile == NULL)
207 return AVIERR_BADPARAM;
209 /* convert ASCII string to Unicode and call unicode function */
210 len = lstrlenA(szFile);
212 return AVIERR_BADPARAM;
214 wszFile = (LPWSTR)LocalAlloc(LPTR, (len + 1) * sizeof(WCHAR));
216 return AVIERR_MEMORY;
218 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len + 1);
219 wszFile[len + 1] = 0;
221 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
223 LocalFree((HLOCAL)wszFile);
228 /***********************************************************************
229 * AVIFileOpenW (AVIFIL32.@)
231 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
234 IPersistFile *ppersist = NULL;
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;
247 /* if no handler then try guessing it by extension */
248 if (lpHandler == NULL) {
249 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
250 return AVIERR_UNSUPPORTED;
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)
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);
268 hr = IPersistFile_Load(ppersist, szFile, uMode);
269 IPersistFile_Release(ppersist);
271 IAVIFile_Release(*ppfile);
278 /***********************************************************************
279 * AVIFileAddRef (AVIFIL32.@)
280 * AVIFileAddRef (AVIFILE.140)
282 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
284 TRACE("(%p)\n", pfile);
287 ERR(": bad handle passed!\n");
291 return IAVIFile_AddRef(pfile);
294 /***********************************************************************
295 * AVIFileRelease (AVIFIL32.@)
296 * AVIFileRelease (AVIFILE.141)
298 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
300 TRACE("(%p)\n", pfile);
303 ERR(": bad handle passed!\n");
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)
320 TRACE("(%p,%p,%ld)\n", pfile, afi, size);
323 return AVIERR_BADHANDLE;
324 if (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;
337 /***********************************************************************
338 * AVIFileInfoW (AVIFIL32.@)
340 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
342 TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
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);
360 return AVIERR_BADHANDLE;
362 return IAVIFile_GetStream(pfile, avis, fccType, lParam);
365 /***********************************************************************
366 * AVIFileCreateStreamA (AVIFIL32.@)
368 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
369 LPAVISTREAMINFOA psi)
373 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
376 return AVIERR_BADHANDLE;
378 /* Only the szName at the end is different */
379 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
380 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
381 sizeof(psiw.szName) / sizeof(psiw.szName[0]));
383 return IAVIFile_CreateStream(pfile, ppavi, &psiw);
386 /***********************************************************************
387 * AVIFileCreateStreamW (AVIFIL32.@)
389 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
390 LPAVISTREAMINFOW asi)
392 TRACE("(%p,%p,%p)\n", pfile, avis, asi);
394 return IAVIFile_CreateStream(pfile, avis, asi);
397 /***********************************************************************
398 * AVIFileWriteData (AVIFIL32.@)
400 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
402 TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
405 return AVIERR_BADHANDLE;
407 return IAVIFile_WriteData(pfile, fcc, lp, size);
410 /***********************************************************************
411 * AVIFileReadData (AVIFIL32.@)
413 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
415 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
418 return AVIERR_BADHANDLE;
420 return IAVIFile_ReadData(pfile, fcc, lp, size);
423 /***********************************************************************
424 * AVIFileEndRecord (AVIFIL32.@)
425 * AVIFileEndRecord (AVIFILE.148)
427 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
429 TRACE("(%p)\n", pfile);
432 return AVIERR_BADHANDLE;
434 return IAVIFile_EndRecord(pfile);
437 /***********************************************************************
438 * AVIStreamAddRef (AVIFIL32.@)
439 * AVIStreamAddRef (AVIFILE.160)
441 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
443 TRACE("(%p)\n", pstream);
445 if (pstream == NULL) {
446 ERR(": bad handle passed!\n");
450 return IAVIStream_AddRef(pstream);
453 /***********************************************************************
454 * AVIStreamRelease (AVIFIL32.@)
455 * AVIStreamRelease (AVIFILE.161)
457 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
459 TRACE("(%p)\n", pstream);
461 if (pstream == NULL) {
462 ERR(": bad handle passed!\n");
466 return IAVIStream_Release(pstream);
469 /***********************************************************************
470 * AVIStreamCreate (AVIFIL32.@)
471 * AVIStreamCreate (AVIFILE.104)
473 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
474 LPCLSID pclsidHandler)
478 TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
479 debugstr_guid(pclsidHandler));
482 return AVIERR_BADPARAM;
485 if (pclsidHandler == NULL)
486 return AVIERR_UNSUPPORTED;
488 hr = SHCoCreateInstance(NULL, pclsidHandler, NULL,
489 &IID_IAVIStream, (LPVOID*)ppavi);
490 if (FAILED(hr) || *ppavi == NULL)
493 hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
495 IAVIStream_Release(*ppavi);
502 /***********************************************************************
503 * AVIStreamInfoA (AVIFIL32.@)
505 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
511 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
514 return AVIERR_BADHANDLE;
515 if (size < sizeof(AVISTREAMINFOA))
516 return AVIERR_BADSIZE;
518 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
520 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
521 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
522 sizeof(asi->szName), NULL, NULL);
523 asi->szName[sizeof(asi->szName) - 1] = 0;
528 /***********************************************************************
529 * AVIStreamInfoW (AVIFIL32.@)
531 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
534 TRACE("(%p,%p,%ld)\n", pstream, asi, size);
537 return AVIERR_BADHANDLE;
539 return IAVIStream_Info(pstream, asi, size);
542 /***********************************************************************
543 * AVIStreamFindSample (AVIFIL32.@)
545 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
547 TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
552 return IAVIStream_FindSample(pstream, pos, flags);
555 /***********************************************************************
556 * AVIStreamReadFormat (AVIFIL32.@)
558 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
559 LPVOID format, LPLONG formatsize)
561 TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
564 return AVIERR_BADHANDLE;
566 return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
569 /***********************************************************************
570 * AVIStreamSetFormat (AVIFIL32.@)
572 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
573 LPVOID format, LONG formatsize)
575 TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
578 return AVIERR_BADHANDLE;
580 return IAVIStream_SetFormat(pstream, pos, format, formatsize);
583 /***********************************************************************
584 * AVIStreamRead (AVIFIL32.@)
586 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
587 LPVOID buffer, LONG buffersize,
588 LPLONG bytesread, LPLONG samplesread)
590 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
591 buffersize, bytesread, samplesread);
594 return AVIERR_BADHANDLE;
596 return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
597 bytesread, samplesread);
600 /***********************************************************************
601 * AVIStreamWrite (AVIFIL32.@)
603 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
604 LPVOID buffer, LONG buffersize, DWORD flags,
605 LPLONG sampwritten, LPLONG byteswritten)
607 TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
608 buffersize, flags, sampwritten, byteswritten);
611 return AVIERR_BADHANDLE;
613 return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
614 flags, sampwritten, byteswritten);
617 /***********************************************************************
618 * AVIStreamReadData (AVIFIL32.@)
620 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
623 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
626 return AVIERR_BADHANDLE;
628 return IAVIStream_ReadData(pstream, fcc, lp, lpread);
631 /***********************************************************************
632 * AVIStreamWriteData (AVIFIL32.@)
634 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
637 TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
640 return AVIERR_BADHANDLE;
642 return IAVIStream_WriteData(pstream, fcc, lp, size);
645 /***********************************************************************
646 * AVIStreamGetFrameOpen (AVIFIL32.@)
648 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
649 LPBITMAPINFOHEADER lpbiWanted)
653 TRACE("(%p,%p)\n", pstream, lpbiWanted);
655 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
657 pg = AVIFILE_CreateGetFrame(pstream);
662 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
663 IGetFrame_Release(pg);
670 /***********************************************************************
671 * AVIStreamGetFrame (AVIFIL32.@)
673 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
675 TRACE("(%p,%ld)\n", pg, pos);
680 return IGetFrame_GetFrame(pg, pos);
683 /***********************************************************************
684 * AVIStreamGetFrameClose (AVIFIL32.@)
686 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
691 return IGetFrame_Release(pg);
695 /***********************************************************************
696 * AVIMakeCompressedStream (AVIFIL32.@)
698 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
700 LPAVICOMPRESSOPTIONS aco,
701 LPCLSID pclsidHandler)
708 LONG size = sizeof(szValue);
710 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
711 debugstr_guid(pclsidHandler));
713 if (ppsCompressed == NULL)
714 return AVIERR_BADPARAM;
715 if (psSource == NULL)
716 return AVIERR_BADHANDLE;
718 *ppsCompressed = NULL;
720 /* if no handler given get default ones based on streamtype */
721 if (pclsidHandler == NULL) {
722 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
726 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
727 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
728 return AVIERR_UNSUPPORTED;
729 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
730 return AVIERR_UNSUPPORTED;
732 memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
734 hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
735 &IID_IAVIStream, (LPVOID*)ppsCompressed);
736 if (FAILED(hr) || *ppsCompressed == NULL)
739 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
741 IAVIStream_Release(*ppsCompressed);
742 *ppsCompressed = NULL;
748 /***********************************************************************
749 * AVIStreamOpenFromFile (AVIFILE.103)
750 * AVIStreamOpenFromFileA (AVIFIL32.@)
752 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
753 DWORD fccType, LONG lParam,
754 UINT mode, LPCLSID pclsidHandler)
756 PAVIFILE pfile = NULL;
759 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
760 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
762 if (ppavi == NULL || szFile == NULL)
763 return AVIERR_BADPARAM;
767 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
768 if (FAILED(hr) || pfile == NULL)
771 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
772 IAVIFile_Release(pfile);
777 /***********************************************************************
778 * AVIStreamOpenFromFileW (AVIFIL32.@)
780 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
781 DWORD fccType, LONG lParam,
782 UINT mode, LPCLSID pclsidHandler)
784 PAVIFILE pfile = NULL;
787 TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
788 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
790 if (ppavi == NULL || szFile == NULL)
791 return AVIERR_BADPARAM;
795 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
796 if (FAILED(hr) || pfile == NULL)
799 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
800 IAVIFile_Release(pfile);
805 /***********************************************************************
806 * AVIStreamStart (AVIFILE.130)
807 * AVIStreamStart (AVIFIL32.@)
809 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
813 TRACE("(%p)\n", pstream);
818 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
824 /***********************************************************************
825 * AVIStreamLength (AVIFILE.131)
826 * AVIStreamLength (AVIFIL32.@)
828 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
832 TRACE("(%p)\n", pstream);
837 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
840 return asiw.dwLength;
843 /***********************************************************************
844 * AVIStreamSampleToTime (AVIFILE.133)
845 * AVIStreamSampleToTime (AVIFIL32.@)
847 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
851 TRACE("(%p,%ld)\n", pstream, lSample);
856 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
858 if (asiw.dwRate == 0)
861 return (LONG)(((float)lSample * asiw.dwScale * 1000.0) / asiw.dwRate);
864 /***********************************************************************
865 * AVIStreamTimeToSample (AVIFILE.132)
866 * AVIStreamTimeToSample (AVIFIL32.@)
868 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
872 TRACE("(%p,%ld)\n", pstream, lTime);
877 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
879 if (asiw.dwScale == 0)
882 return (LONG)(((float)lTime * asiw.dwRate) / asiw.dwScale / 1000.0);
885 /***********************************************************************
886 * AVIBuildFilterA (AVIFIL32.@)
888 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
893 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
895 /* check parameters */
896 if (szFilter == NULL)
897 return AVIERR_BADPARAM;
899 return AVIERR_BADSIZE;
904 wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter);
905 if (wszFilter == NULL)
906 return AVIERR_MEMORY;
908 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
910 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
911 szFilter, cbFilter, NULL, NULL);
914 GlobalFreePtr(wszFilter);
919 /***********************************************************************
920 * AVIBuildFilterW (AVIFIL32.@)
922 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
924 static const WCHAR szClsid[] = {'C','L','S','I','D',0};
925 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
926 static const WCHAR szAVIFileExtensions[] =
927 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
930 WCHAR szAllFiles[40];
938 TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
940 /* check parameters */
941 if (szFilter == NULL)
942 return AVIERR_BADPARAM;
944 return AVIERR_BADSIZE;
946 lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
948 return AVIERR_MEMORY;
951 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
952 * extensions and CLSID's
953 * 2. iterate over collected CLSID's and copy it's description and it's
954 * extensions to szFilter if it fits
956 * First filter is named "All multimedia files" and it's filter is a
957 * collection of all possible extensions except "*.*".
959 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
963 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
964 /* get CLSID to extension */
965 size = sizeof(szValue)/sizeof(szValue[0]);
966 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
969 /* search if the CLSID is already known */
970 for (i = 1; i <= count; i++) {
971 if (lstrcmpW(lp[i].szClsid, szValue) == 0)
972 break; /* a new one */
975 if (count - i == -1) {
976 /* it's a new CLSID */
978 /* FIXME: How do we get info's about read/write capabilities? */
980 if (count >= MAX_FILTERS) {
981 /* try to inform user of our full fixed size table */
982 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
986 lstrcpyW(lp[i].szClsid, szValue);
991 /* append extension to the filter */
992 wsprintfW(szValue, szExtensionFmt, szFileExt);
993 if (lp[i].szExtensions[0] == 0)
994 lstrcatW(lp[i].szExtensions, szValue + 1);
996 lstrcatW(lp[i].szExtensions, szValue);
998 /* also append to the "all multimedia"-filter */
999 if (lp[0].szExtensions[0] == 0)
1000 lstrcatW(lp[0].szExtensions, szValue + 1);
1002 lstrcatW(lp[0].szExtensions, szValue);
1006 /* 2. get descriptions for the CLSIDs and fill out szFilter */
1007 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1009 return AVIERR_ERROR;
1011 for (n = 0; n <= count; n++) {
1012 /* first the description */
1014 size = sizeof(szValue)/sizeof(szValue[0]);
1015 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1016 size = lstrlenW(szValue);
1017 lstrcpynW(szFilter, szValue, cbFilter);
1020 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1022 /* check for enough space */
1024 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1029 return AVIERR_BUFFERTOOSMALL;
1034 /* and then the filter */
1035 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1036 size = lstrlenW(lp[n].szExtensions) + 1;
1044 /* add "All files" "*.*" filter if enough space left */
1045 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1046 szAllFiles, sizeof(szAllFiles)) + 1;
1047 if (cbFilter > size) {
1050 /* replace '@' with \000 to separate description of filter */
1051 for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1052 if (szAllFiles[i] == '@') {
1058 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1065 return AVIERR_BUFFERTOOSMALL;
1069 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1071 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1072 AVISTREAMINFOW sInfo;
1074 TRACE("(%p)\n", hWnd);
1076 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1077 ERR(": bad state!\n");
1081 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1082 &sInfo, sizeof(sInfo)))) {
1083 ERR(": AVIStreamInfoW failed!\n");
1087 if (sInfo.fccType == streamtypeVIDEO) {
1091 memset(&cv, 0, sizeof(cv));
1093 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1094 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1095 pOptions->fccType = streamtypeVIDEO;
1096 pOptions->fccHandler = comptypeDIB;
1097 pOptions->dwQuality = ICQUALITY_DEFAULT;
1100 cv.cbSize = sizeof(cv);
1101 cv.dwFlags = ICMF_COMPVARS_VALID;
1102 /*cv.fccType = pOptions->fccType; */
1103 cv.fccHandler = pOptions->fccHandler;
1104 cv.lQ = pOptions->dwQuality;
1105 cv.lpState = pOptions->lpParms;
1106 cv.cbState = pOptions->cbParms;
1107 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1108 cv.lKey = pOptions->dwKeyFrameEvery;
1111 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1112 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1116 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1117 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1120 pOptions->lpParms = cv.lpState;
1121 pOptions->cbParms = cv.cbState;
1122 pOptions->dwQuality = cv.lQ;
1124 pOptions->dwKeyFrameEvery = cv.lKey;
1125 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1127 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1128 if (cv.lDataRate != 0) {
1129 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1130 pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1132 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1133 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1135 ICCompressorFree(&cv);
1138 } else if (sInfo.fccType == streamtypeAUDIO) {
1139 ACMFORMATCHOOSEW afmtc;
1143 /* FIXME: check ACM version -- Which version is needed? */
1145 memset(&afmtc, 0, sizeof(afmtc));
1146 afmtc.cbStruct = sizeof(afmtc);
1148 afmtc.hwndOwner = hWnd;
1150 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1151 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1152 pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1153 pOptions->cbFormat = size;
1154 } else if (pOptions->cbFormat < size) {
1155 pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1156 pOptions->cbFormat = size;
1158 if (pOptions->lpFormat == NULL)
1160 afmtc.pwfx = pOptions->lpFormat;
1161 afmtc.cbwfx = pOptions->cbFormat;
1164 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1165 sInfo.dwStart, &size);
1166 if (size < sizeof(PCMWAVEFORMAT))
1167 size = sizeof(PCMWAVEFORMAT);
1168 afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1169 if (afmtc.pwfxEnum != NULL) {
1170 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1171 sInfo.dwStart, afmtc.pwfxEnum, &size);
1172 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1175 ret = acmFormatChooseW(&afmtc);
1177 pOptions->dwFlags |= AVICOMPRESSF_VALID;
1179 if (afmtc.pwfxEnum != NULL)
1180 GlobalFreePtr(afmtc.pwfxEnum);
1182 return (ret == S_OK ? TRUE : FALSE);
1184 ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1189 static void AVISaveOptionsUpdate(HWND hWnd)
1191 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1192 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1194 WCHAR szFormat[128];
1195 AVISTREAMINFOW sInfo;
1199 TRACE("(%p)\n", hWnd);
1201 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1202 if (SaveOpts.nCurrent < 0)
1205 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1208 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1212 /* read format to build format descriotion string */
1213 lpFormat = GlobalAllocPtr(GHND, size);
1214 if (lpFormat != NULL) {
1215 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1216 if (sInfo.fccType == streamtypeVIDEO) {
1217 LPBITMAPINFOHEADER lpbi = lpFormat;
1220 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1221 lpbi->biHeight, lpbi->biBitCount);
1223 if (lpbi->biCompression != BI_RGB) {
1226 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1227 NULL, ICMODE_DECOMPRESS);
1229 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1230 lstrcatW(szFormat, icinfo.szDescription);
1234 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1235 icinfo.szDescription, sizeof(icinfo.szDescription));
1236 lstrcatW(szFormat, icinfo.szDescription);
1238 } else if (sInfo.fccType == streamtypeAUDIO) {
1239 ACMFORMATTAGDETAILSW aftd;
1240 ACMFORMATDETAILSW afd;
1242 memset(&aftd, 0, sizeof(aftd));
1243 memset(&afd, 0, sizeof(afd));
1245 aftd.cbStruct = sizeof(aftd);
1246 aftd.dwFormatTag = afd.dwFormatTag =
1247 ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1248 aftd.cbFormatSize = afd.cbwfx = size;
1250 afd.cbStruct = sizeof(afd);
1251 afd.pwfx = lpFormat;
1253 if (acmFormatTagDetailsW(NULL, &aftd,
1254 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1255 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1256 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1260 GlobalFreePtr(lpFormat);
1263 /* set text for format description */
1264 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1266 /* Disable option button for unsupported streamtypes */
1267 if (sInfo.fccType == streamtypeVIDEO ||
1268 sInfo.fccType == streamtypeAUDIO)
1269 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1271 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1276 INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1277 WPARAM wParam, LPARAM lParam)
1280 BOOL bIsInterleaved;
1283 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1287 SaveOpts.nCurrent = 0;
1288 if (SaveOpts.nStreams == 1) {
1289 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1294 for (n = 0; n < SaveOpts.nStreams; n++) {
1295 AVISTREAMINFOW sInfo;
1297 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1298 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1299 0L, (LPARAM)sInfo.szName);
1302 /* select first stream */
1303 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1304 SendMessageW(hWnd, WM_COMMAND,
1305 GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1307 /* initialize interleave */
1308 if (SaveOpts.ppOptions[0] != NULL &&
1309 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1310 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1311 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1313 bIsInterleaved = TRUE;
1316 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1317 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1318 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1321 switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
1323 /* get data from controls and save them */
1324 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1325 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1326 for (n = 0; n < SaveOpts.nStreams; n++) {
1327 if (SaveOpts.ppOptions[n] != NULL) {
1328 if (bIsInterleaved) {
1329 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1330 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1332 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1337 EndDialog(hWnd, GET_WM_COMMAND_CMD(wParam, lParam) == IDOK);
1339 case IDC_INTERLEAVE:
1340 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1341 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1344 if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1345 /* update control elements */
1346 AVISaveOptionsUpdate(hWnd);
1350 AVISaveOptionsFmtChoose(hWnd);
1359 /***********************************************************************
1360 * AVISaveOptions (AVIFIL32.@)
1362 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1363 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1365 LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1368 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1371 /* check parameters */
1372 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1373 return AVIERR_BADPARAM;
1375 /* save options for case user press cancel */
1376 if (ppOptions != NULL && nStreams > 1) {
1377 pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1378 if (pSavedOptions == NULL)
1381 for (n = 0; n < nStreams; n++) {
1382 if (ppOptions[n] != NULL)
1383 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1387 SaveOpts.uFlags = uFlags;
1388 SaveOpts.nStreams = nStreams;
1389 SaveOpts.ppavis = ppavi;
1390 SaveOpts.ppOptions = ppOptions;
1392 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1393 hWnd, AVISaveOptionsDlgProc);
1398 /* restore options when user pressed cancel */
1399 if (pSavedOptions != NULL && ret == FALSE) {
1400 for (n = 0; n < nStreams; n++) {
1401 if (ppOptions[n] != NULL)
1402 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1404 GlobalFreePtr(pSavedOptions);
1410 /***********************************************************************
1411 * AVISaveOptionsFree (AVIFIL32.@)
1413 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1415 TRACE("(%d,%p)\n", nStreams, ppOptions);
1417 if (nStreams < 0 || ppOptions == NULL)
1418 return AVIERR_BADPARAM;
1420 for (; nStreams > 0; nStreams--) {
1421 if (ppOptions[nStreams] != NULL) {
1422 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1424 if (ppOptions[nStreams]->lpParms != NULL) {
1425 GlobalFreePtr(ppOptions[nStreams]->lpParms);
1426 ppOptions[nStreams]->lpParms = NULL;
1427 ppOptions[nStreams]->cbParms = 0;
1429 if (ppOptions[nStreams]->lpFormat != NULL) {
1430 GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1431 ppOptions[nStreams]->lpFormat = NULL;
1432 ppOptions[nStreams]->cbFormat = 0;