d3d10core/tests: Remove dead code.
[wine.git] / dlls / msvfw32 / msvideo_main.c
blob4f1a2bf9bcae8e3a10e065306adc27695387d814
1 /*
2 * Copyright 1998 Marcus Meissner
3 * Copyright 2000 Bradley Baetz
4 * Copyright 2003 Michael Günnewig
5 * Copyright 2005 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: This all assumes 32 bit codecs
22 * Win95 appears to prefer 32 bit codecs, even from 16 bit code.
23 * There is the ICOpenFunction16 to worry about still, though.
25 * TODO
26 * - no thread safety
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "winnls.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "commdlg.h"
40 #include "vfw.h"
41 #include "msvideo_private.h"
42 #include "wine/debug.h"
44 /* Drivers32 settings */
45 #define HKLM_DRIVERS32 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"
47 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
49 /* This one is a macro in order to work for both ASCII and Unicode */
50 #define fourcc_to_string(str, fcc) do { \
51 (str)[0] = LOBYTE(LOWORD(fcc)); \
52 (str)[1] = HIBYTE(LOWORD(fcc)); \
53 (str)[2] = LOBYTE(HIWORD(fcc)); \
54 (str)[3] = HIBYTE(HIWORD(fcc)); \
55 } while(0)
57 static inline const char *wine_dbgstr_fcc( DWORD fcc )
59 char fcc_str[5];
60 fourcc_to_string(fcc_str, fcc);
61 fcc_str[4] = '\0';
62 /* Last byte may be ' ' in some cases like "DIB " */
63 if (isalnum(fcc_str[0]) && isalnum(fcc_str[1]) && isalnum(fcc_str[2])
64 && (isalnum(fcc_str[3]) || isspace(fcc_str[3])))
65 return wine_dbg_sprintf("%s", fcc_str);
66 return wine_dbg_sprintf("0x%08x", fcc);
69 static const char *wine_dbgstr_icerr( int ret )
71 const char *str;
72 if (ret <= ICERR_CUSTOM)
73 return wine_dbg_sprintf("ICERR_CUSTOM (%d)", ret);
74 #define XX(x) case (x): str = #x; break
75 switch (ret)
77 XX(ICERR_OK);
78 XX(ICERR_DONTDRAW);
79 XX(ICERR_NEWPALETTE);
80 XX(ICERR_GOTOKEYFRAME);
81 XX(ICERR_STOPDRAWING);
82 XX(ICERR_UNSUPPORTED);
83 XX(ICERR_BADFORMAT);
84 XX(ICERR_MEMORY);
85 XX(ICERR_INTERNAL);
86 XX(ICERR_BADFLAGS);
87 XX(ICERR_BADPARAM);
88 XX(ICERR_BADSIZE);
89 XX(ICERR_BADHANDLE);
90 XX(ICERR_CANTUPDATE);
91 XX(ICERR_ABORT);
92 XX(ICERR_ERROR);
93 XX(ICERR_BADBITDEPTH);
94 XX(ICERR_BADIMAGESIZE);
95 default: str = wine_dbg_sprintf("UNKNOWN (%d)", ret);
97 #undef XX
98 return str;
101 static WINE_HIC* MSVIDEO_FirstHic /* = NULL */;
103 typedef struct _reg_driver reg_driver;
104 struct _reg_driver
106 DWORD fccType;
107 DWORD fccHandler;
108 DRIVERPROC proc;
109 LPWSTR name;
110 reg_driver* next;
113 static reg_driver* reg_driver_list = NULL;
115 HMODULE MSVFW32_hModule;
117 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
119 TRACE("%p,%x,%p\n", hinst, reason, reserved);
121 switch(reason)
123 case DLL_PROCESS_ATTACH:
124 DisableThreadLibraryCalls(hinst);
125 MSVFW32_hModule = hinst;
126 break;
128 return TRUE;
131 /******************************************************************
132 * MSVIDEO_SendMessage
136 static LRESULT MSVIDEO_SendMessage(WINE_HIC* whic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
138 LRESULT ret;
140 #define XX(x) case x: TRACE("(%p,"#x",0x%08lx,0x%08lx)\n",whic,lParam1,lParam2); break
142 switch (msg) {
143 /* DRV_* */
144 XX(DRV_LOAD);
145 XX(DRV_ENABLE);
146 XX(DRV_OPEN);
147 XX(DRV_CLOSE);
148 XX(DRV_DISABLE);
149 XX(DRV_FREE);
150 /* ICM_RESERVED+X */
151 XX(ICM_ABOUT);
152 XX(ICM_CONFIGURE);
153 XX(ICM_GET);
154 XX(ICM_GETINFO);
155 XX(ICM_GETDEFAULTQUALITY);
156 XX(ICM_GETQUALITY);
157 XX(ICM_GETSTATE);
158 XX(ICM_SETQUALITY);
159 XX(ICM_SET);
160 XX(ICM_SETSTATE);
161 /* ICM_USER+X */
162 XX(ICM_COMPRESS_FRAMES_INFO);
163 XX(ICM_COMPRESS_GET_FORMAT);
164 XX(ICM_COMPRESS_GET_SIZE);
165 XX(ICM_COMPRESS_QUERY);
166 XX(ICM_COMPRESS_BEGIN);
167 XX(ICM_COMPRESS);
168 XX(ICM_COMPRESS_END);
169 XX(ICM_DECOMPRESS_GET_FORMAT);
170 XX(ICM_DECOMPRESS_QUERY);
171 XX(ICM_DECOMPRESS_BEGIN);
172 XX(ICM_DECOMPRESS);
173 XX(ICM_DECOMPRESS_END);
174 XX(ICM_DECOMPRESS_SET_PALETTE);
175 XX(ICM_DECOMPRESS_GET_PALETTE);
176 XX(ICM_DRAW_QUERY);
177 XX(ICM_DRAW_BEGIN);
178 XX(ICM_DRAW_GET_PALETTE);
179 XX(ICM_DRAW_START);
180 XX(ICM_DRAW_STOP);
181 XX(ICM_DRAW_END);
182 XX(ICM_DRAW_GETTIME);
183 XX(ICM_DRAW);
184 XX(ICM_DRAW_WINDOW);
185 XX(ICM_DRAW_SETTIME);
186 XX(ICM_DRAW_REALIZE);
187 XX(ICM_DRAW_FLUSH);
188 XX(ICM_DRAW_RENDERBUFFER);
189 XX(ICM_DRAW_START_PLAY);
190 XX(ICM_DRAW_STOP_PLAY);
191 XX(ICM_DRAW_SUGGESTFORMAT);
192 XX(ICM_DRAW_CHANGEPALETTE);
193 XX(ICM_GETBUFFERSWANTED);
194 XX(ICM_GETDEFAULTKEYFRAMERATE);
195 XX(ICM_DECOMPRESSEX_BEGIN);
196 XX(ICM_DECOMPRESSEX_QUERY);
197 XX(ICM_DECOMPRESSEX);
198 XX(ICM_DECOMPRESSEX_END);
199 XX(ICM_SET_STATUS_PROC);
200 default:
201 FIXME("(%p,0x%08x,0x%08lx,0x%08lx) unknown message\n",whic,msg,lParam1,lParam2);
204 #undef XX
206 if (whic->driverproc) {
207 /* dwDriverId parameter is the value returned by the DRV_OPEN */
208 ret = whic->driverproc(whic->driverId, whic->hdrv, msg, lParam1, lParam2);
209 } else {
210 ret = SendDriverMessage(whic->hdrv, msg, lParam1, lParam2);
213 TRACE(" -> %s\n", wine_dbgstr_icerr(ret));
214 return ret;
217 static int compare_fourcc(DWORD fcc1, DWORD fcc2)
219 char fcc_str1[4];
220 char fcc_str2[4];
221 fourcc_to_string(fcc_str1, fcc1);
222 fourcc_to_string(fcc_str2, fcc2);
223 return strncasecmp(fcc_str1, fcc_str2, 4);
226 typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*);
228 static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
230 CHAR buf[2048], fccTypeStr[5], *s;
231 DWORD i, cnt = 0, lRet;
232 BOOL result = FALSE;
233 HKEY hKey;
235 fourcc_to_string(fccTypeStr, fccType);
236 fccTypeStr[4] = '.';
238 /* first, go through the registry entries */
239 lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey);
240 if (lRet == ERROR_SUCCESS)
242 DWORD name, data, type;
243 i = 0;
244 for (;;)
246 name = 10;
247 data = sizeof buf - name;
248 lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data);
249 if (lRet == ERROR_NO_MORE_ITEMS) break;
250 if (lRet != ERROR_SUCCESS) continue;
251 if (name != 9 || strncasecmp(buf, fccTypeStr, 5)) continue;
252 buf[name] = '=';
253 if ((result = handler(buf, cnt++, param))) break;
255 RegCloseKey( hKey );
257 if (result) return result;
259 /* if that didn't work, go through the values in system.ini */
260 if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini"))
262 for (s = buf; *s; s += strlen(s) + 1)
264 TRACE("got %s\n", s);
265 if (strncasecmp(s, fccTypeStr, 5) || s[9] != '=') continue;
266 if ((result = handler(s, cnt++, param))) break;
270 return result;
273 /******************************************************************
274 * MSVIDEO_GetHicPtr
278 static WINE_HIC* MSVIDEO_GetHicPtr(HIC hic)
280 WINE_HIC* whic;
282 for (whic = MSVIDEO_FirstHic; whic && whic->hic != hic; whic = whic->next);
283 return whic;
286 /***********************************************************************
287 * VideoForWindowsVersion [MSVFW32.2]
288 * VideoForWindowsVersion [MSVIDEO.2]
289 * Returns the version in major.minor form.
290 * In Windows95 this returns 0x040003b6 (4.950)
292 DWORD WINAPI VideoForWindowsVersion(void)
294 return 0x040003B6; /* 4.950 */
297 static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
299 ICINFO *lpicinfo = param;
300 DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0);
302 /* exact match of fccHandler or nth driver found */
303 if ((lpicinfo->fccHandler != nr) && (lpicinfo->fccHandler != fccHandler))
304 return FALSE;
306 lpicinfo->fccHandler = fccHandler;
307 lpicinfo->dwFlags = 0;
308 lpicinfo->dwVersion = 0;
309 lpicinfo->dwVersionICM = ICVERSION;
310 lpicinfo->szName[0] = 0;
311 lpicinfo->szDescription[0] = 0;
312 MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver,
313 sizeof(lpicinfo->szDriver)/sizeof(WCHAR));
315 return TRUE;
318 /***********************************************************************
319 * ICInfo [MSVFW32.@]
320 * Get information about an installable compressor. Return TRUE if there
321 * is one.
323 * PARAMS
324 * fccType [I] type of compressor (e.g. 'vidc')
325 * fccHandler [I] real fcc for handler or <n>th compressor
326 * lpicinfo [O] information about compressor
328 BOOL VFWAPI ICInfo( DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo)
330 TRACE("(%s,%s,%p)\n",
331 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpicinfo);
333 lpicinfo->fccType = fccType;
334 lpicinfo->fccHandler = fccHandler;
335 return enum_drivers(fccType, ICInfo_enum_handler, lpicinfo);
338 static DWORD IC_HandleRef = 1;
340 /***********************************************************************
341 * ICInstall [MSVFW32.@]
343 BOOL VFWAPI ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags)
345 reg_driver* driver;
346 unsigned len;
348 TRACE("(%s,%s,%p,%p,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), (void*)lParam, szDesc, wFlags);
350 /* Check if a driver is already registered */
351 for (driver = reg_driver_list; driver; driver = driver->next)
353 if (!compare_fourcc(fccType, driver->fccType) &&
354 !compare_fourcc(fccHandler, driver->fccHandler))
355 break;
357 if (driver) return FALSE;
359 /* Register the driver */
360 driver = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(reg_driver));
361 if (!driver) goto oom;
362 driver->fccType = fccType;
363 driver->fccHandler = fccHandler;
365 switch(wFlags)
367 case ICINSTALL_FUNCTION:
368 driver->proc = (DRIVERPROC)lParam;
369 driver->name = NULL;
370 break;
371 case ICINSTALL_DRIVER:
372 driver->proc = NULL;
373 len = MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, NULL, 0);
374 driver->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
375 if (!driver->name) goto oom;
376 MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, driver->name, len);
377 break;
378 default:
379 ERR("Invalid flags!\n");
380 HeapFree(GetProcessHeap(), 0, driver);
381 return FALSE;
384 /* Insert our driver in the list*/
385 driver->next = reg_driver_list;
386 reg_driver_list = driver;
388 return TRUE;
389 oom:
390 HeapFree(GetProcessHeap(), 0, driver);
391 return FALSE;
394 /***********************************************************************
395 * ICRemove [MSVFW32.@]
397 BOOL VFWAPI ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags)
399 reg_driver** pdriver;
400 reg_driver* drv;
402 TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wFlags);
404 /* Check if a driver is already registered */
405 for (pdriver = &reg_driver_list; *pdriver; pdriver = &(*pdriver)->next)
407 if (!compare_fourcc(fccType, (*pdriver)->fccType) &&
408 !compare_fourcc(fccHandler, (*pdriver)->fccHandler))
409 break;
411 if (!*pdriver)
412 return FALSE;
414 /* Remove the driver from the list */
415 drv = *pdriver;
416 *pdriver = (*pdriver)->next;
417 HeapFree(GetProcessHeap(), 0, drv->name);
418 HeapFree(GetProcessHeap(), 0, drv);
420 return TRUE;
424 /***********************************************************************
425 * ICOpen [MSVFW32.@]
426 * Opens an installable compressor. Return special handle.
428 HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode)
430 WCHAR codecname[10];
431 ICOPEN icopen;
432 HDRVR hdrv;
433 WINE_HIC* whic;
434 static const WCHAR drv32W[] = {'d','r','i','v','e','r','s','3','2','\0'};
435 reg_driver* driver;
437 TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode);
439 if (!fccHandler) /* No specific handler, return the first valid for wMode */
441 HIC local;
442 ICINFO info;
443 DWORD loop = 0;
444 info.dwSize = sizeof(info);
445 while(ICInfo(fccType, loop++, &info))
447 /* Ensure fccHandler is not 0x0 because we will recurse on ICOpen */
448 if(!info.fccHandler)
449 continue;
450 local = ICOpen(fccType, info.fccHandler, wMode);
451 if (local != 0)
453 TRACE("Returning %s as defult handler for %s\n",
454 wine_dbgstr_fcc(info.fccHandler), wine_dbgstr_fcc(fccType));
455 return local;
460 /* Check if there is a registered driver that matches */
461 driver = reg_driver_list;
462 while(driver)
463 if (!compare_fourcc(fccType, driver->fccType) &&
464 !compare_fourcc(fccHandler, driver->fccHandler)) {
465 fccType = driver->fccType;
466 fccHandler = driver->fccHandler;
467 break;
468 } else
469 driver = driver->next;
471 if (driver && driver->proc)
472 /* The driver has been registered at runtime with its driverproc */
473 return ICOpenFunction(fccType, fccHandler, wMode, driver->proc);
475 /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
476 * same layout as ICOPEN
478 icopen.dwSize = sizeof(ICOPEN);
479 icopen.fccType = fccType;
480 icopen.fccHandler = fccHandler;
481 icopen.dwVersion = 0x00001000; /* FIXME */
482 icopen.dwFlags = wMode;
483 icopen.dwError = 0;
484 icopen.pV1Reserved = NULL;
485 icopen.pV2Reserved = NULL;
486 icopen.dnDevNode = 0; /* FIXME */
488 if (!driver) {
489 /* normalize to lower case as in 'vidc' */
490 ((char*)&fccType)[0] = tolower(((char*)&fccType)[0]);
491 ((char*)&fccType)[1] = tolower(((char*)&fccType)[1]);
492 ((char*)&fccType)[2] = tolower(((char*)&fccType)[2]);
493 ((char*)&fccType)[3] = tolower(((char*)&fccType)[3]);
494 icopen.fccType = fccType;
495 /* Seek the driver in the registry */
496 fourcc_to_string(codecname, fccType);
497 codecname[4] = '.';
498 fourcc_to_string(codecname + 5, fccHandler);
499 codecname[9] = '\0';
501 hdrv = OpenDriver(codecname, drv32W, (LPARAM)&icopen);
502 if (!hdrv)
503 return 0;
504 } else {
505 /* The driver has been registered at runtime with its name */
506 hdrv = OpenDriver(driver->name, NULL, (LPARAM)&icopen);
507 if (!hdrv)
508 return 0;
511 whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
512 if (!whic)
514 CloseDriver(hdrv, 0, 0);
515 return FALSE;
517 whic->hdrv = hdrv;
518 whic->driverproc = NULL;
519 whic->type = fccType;
520 whic->handler = fccHandler;
521 while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
522 whic->hic = (HIC)(ULONG_PTR)IC_HandleRef++;
523 whic->next = MSVIDEO_FirstHic;
524 MSVIDEO_FirstHic = whic;
526 TRACE("=> %p\n", whic->hic);
527 return whic->hic;
530 /***********************************************************************
531 * ICOpenFunction [MSVFW32.@]
533 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, DRIVERPROC lpfnHandler)
535 ICOPEN icopen;
536 WINE_HIC* whic;
538 TRACE("(%s,%s,%d,%p)\n",
539 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode, lpfnHandler);
541 icopen.dwSize = sizeof(ICOPEN);
542 icopen.fccType = fccType;
543 icopen.fccHandler = fccHandler;
544 icopen.dwVersion = ICVERSION;
545 icopen.dwFlags = wMode;
546 icopen.dwError = 0;
547 icopen.pV1Reserved = NULL;
548 icopen.pV2Reserved = NULL;
549 icopen.dnDevNode = 0; /* FIXME */
551 whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
552 if (!whic) return 0;
554 whic->driverproc = lpfnHandler;
555 while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
556 whic->hic = (HIC)(ULONG_PTR)IC_HandleRef++;
557 whic->next = MSVIDEO_FirstHic;
558 MSVIDEO_FirstHic = whic;
560 /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
561 /* What if the function is used more than once? */
563 if (MSVIDEO_SendMessage(whic, DRV_LOAD, 0L, 0L) != DRV_SUCCESS)
565 WARN("DRV_LOAD failed for hic %p\n", whic->hic);
566 MSVIDEO_FirstHic = whic->next;
567 HeapFree(GetProcessHeap(), 0, whic);
568 return 0;
570 /* return value is not checked */
571 MSVIDEO_SendMessage(whic, DRV_ENABLE, 0L, 0L);
573 whic->driverId = (DWORD)MSVIDEO_SendMessage(whic, DRV_OPEN, 0, (DWORD_PTR)&icopen);
574 /* FIXME: What should we put here? */
575 whic->hdrv = NULL;
577 if (whic->driverId == 0)
579 WARN("DRV_OPEN failed for hic %p\n", whic->hic);
580 MSVIDEO_FirstHic = whic->next;
581 HeapFree(GetProcessHeap(), 0, whic);
582 return 0;
585 TRACE("=> %p\n", whic->hic);
586 return whic->hic;
589 /***********************************************************************
590 * ICGetInfo [MSVFW32.@]
592 LRESULT VFWAPI ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb)
594 LRESULT ret;
595 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
597 TRACE("(%p,%p,%d)\n", hic, picinfo, cb);
599 if (!whic) return ICERR_BADHANDLE;
600 if (!picinfo) return MMSYSERR_INVALPARAM;
602 /* (WS) The field szDriver should be initialized because the driver
603 * is not obliged and often will not do it. Some applications, like
604 * VirtualDub, rely on this field and will occasionally crash if it
605 * goes uninitialized.
607 if (cb >= sizeof(ICINFO)) picinfo->szDriver[0] = '\0';
609 ret = ICSendMessage(hic, ICM_GETINFO, (DWORD_PTR)picinfo, cb);
611 /* (WS) When szDriver was not supplied by the driver itself, apparently
612 * Windows will set its value equal to the driver file name. This can
613 * be obtained from the registry as we do here.
615 if (cb >= sizeof(ICINFO) && picinfo->szDriver[0] == 0)
617 ICINFO ii;
619 memset(&ii, 0, sizeof(ii));
620 ii.dwSize = sizeof(ii);
621 ICInfo(picinfo->fccType, picinfo->fccHandler, &ii);
622 lstrcpyW(picinfo->szDriver, ii.szDriver);
625 TRACE(" -> %s\n", wine_dbgstr_icerr(ret));
626 return ret;
629 typedef struct {
630 DWORD fccType;
631 DWORD fccHandler;
632 LPBITMAPINFOHEADER lpbiIn;
633 LPBITMAPINFOHEADER lpbiOut;
634 WORD wMode;
635 DWORD querymsg;
636 HIC hic;
637 } driver_info_t;
639 static HIC try_driver(driver_info_t *info)
641 HIC hic;
643 if ((hic = ICOpen(info->fccType, info->fccHandler, info->wMode)))
645 if (!ICSendMessage(hic, info->querymsg, (DWORD_PTR)info->lpbiIn, (DWORD_PTR)info->lpbiOut))
646 return hic;
647 ICClose(hic);
649 return 0;
652 static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param)
654 driver_info_t *info = param;
655 info->fccHandler = mmioStringToFOURCCA(drv + 5, 0);
656 info->hic = try_driver(info);
657 return info->hic != 0;
660 /***********************************************************************
661 * ICLocate [MSVFW32.@]
663 HIC VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
664 LPBITMAPINFOHEADER lpbiOut, WORD wMode)
666 driver_info_t info;
668 TRACE("(%s,%s,%p,%p,0x%04x)\n",
669 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpbiIn, lpbiOut, wMode);
671 info.fccType = fccType;
672 info.fccHandler = fccHandler;
673 info.lpbiIn = lpbiIn;
674 info.lpbiOut = lpbiOut;
675 info.wMode = wMode;
677 switch (wMode)
679 case ICMODE_FASTCOMPRESS:
680 case ICMODE_COMPRESS:
681 info.querymsg = ICM_COMPRESS_QUERY;
682 break;
683 case ICMODE_FASTDECOMPRESS:
684 case ICMODE_DECOMPRESS:
685 info.querymsg = ICM_DECOMPRESS_QUERY;
686 break;
687 case ICMODE_DRAW:
688 info.querymsg = ICM_DRAW_QUERY;
689 break;
690 default:
691 WARN("Unknown mode (%d)\n", wMode);
692 return 0;
695 /* Easy case: handler/type match, we just fire a query and return */
696 info.hic = try_driver(&info);
697 /* If it didn't work, try each driver in turn. 32 bit codecs only. */
698 /* FIXME: Move this to an init routine? */
699 if (!info.hic) enum_drivers(fccType, ICLocate_enum_handler, &info);
701 if (info.hic)
703 TRACE("=> %p\n", info.hic);
704 return info.hic;
707 if (fccType == streamtypeVIDEO)
708 return ICLocate(ICTYPE_VIDEO, fccHandler, lpbiIn, lpbiOut, wMode);
710 ERR("Required media codec '%s %s' not found!\n",
711 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler));
712 return 0;
715 /***********************************************************************
716 * ICGetDisplayFormat [MSVFW32.@]
718 HIC VFWAPI ICGetDisplayFormat(
719 HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
720 INT depth,INT dx,INT dy)
722 HIC tmphic = hic;
724 TRACE("(%p,%p,%p,%d,%d,%d)!\n",hic,lpbiIn,lpbiOut,depth,dx,dy);
726 if (!tmphic) {
727 tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
728 if (!tmphic)
729 return tmphic;
731 if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
732 dy = dx = 0; /* no resize needed */
734 /* Can we decompress it ? */
735 if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
736 goto errout; /* no, sorry */
738 ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)lpbiIn, (DWORD_PTR)lpbiOut);
740 if (lpbiOut->biCompression != 0) {
741 FIXME("Ooch, how come decompressor outputs compressed data (%d)??\n",
742 lpbiOut->biCompression);
744 if (lpbiOut->biSize < sizeof(*lpbiOut)) {
745 FIXME("Ooch, size of output BIH is too small (%d)\n",
746 lpbiOut->biSize);
747 lpbiOut->biSize = sizeof(*lpbiOut);
749 if (!depth) {
750 HDC hdc;
752 hdc = GetDC(0);
753 depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
754 ReleaseDC(0,hdc);
755 if (depth==15) depth = 16;
756 if (depth<8) depth = 8;
758 if (lpbiIn->biBitCount == 8)
759 depth = 8;
761 TRACE("=> %p\n", tmphic);
762 return tmphic;
763 errout:
764 if (hic!=tmphic)
765 ICClose(tmphic);
767 TRACE("=> 0\n");
768 return 0;
771 /***********************************************************************
772 * ICCompress [MSVFW32.@]
774 DWORD VFWAPIV
775 ICCompress(
776 HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
777 LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
778 LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
779 LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
781 ICCOMPRESS iccmp;
783 TRACE("(%p,%d,%p,%p,%p,%p,...)\n",hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
785 iccmp.dwFlags = dwFlags;
787 iccmp.lpbiOutput = lpbiOutput;
788 iccmp.lpOutput = lpData;
789 iccmp.lpbiInput = lpbiInput;
790 iccmp.lpInput = lpBits;
792 iccmp.lpckid = lpckid;
793 iccmp.lpdwFlags = lpdwFlags;
794 iccmp.lFrameNum = lFrameNum;
795 iccmp.dwFrameSize = dwFrameSize;
796 iccmp.dwQuality = dwQuality;
797 iccmp.lpbiPrev = lpbiPrev;
798 iccmp.lpPrev = lpPrev;
799 return ICSendMessage(hic,ICM_COMPRESS,(DWORD_PTR)&iccmp,sizeof(iccmp));
802 /***********************************************************************
803 * ICDecompress [MSVFW32.@]
805 DWORD VFWAPIV ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
806 LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
808 ICDECOMPRESS icd;
809 DWORD ret;
811 TRACE("(%p,%d,%p,%p,%p,%p)\n",hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
813 icd.dwFlags = dwFlags;
814 icd.lpbiInput = lpbiFormat;
815 icd.lpInput = lpData;
817 icd.lpbiOutput = lpbi;
818 icd.lpOutput = lpBits;
819 icd.ckid = 0;
820 ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD_PTR)&icd,sizeof(ICDECOMPRESS));
822 TRACE("-> %s\n",wine_dbgstr_icerr(ret));
824 return ret;
828 struct choose_compressor
830 UINT flags;
831 LPCSTR title;
832 COMPVARS cv;
835 struct codec_info
837 HIC hic;
838 ICINFO icinfo;
841 static BOOL enum_compressors(HWND list, COMPVARS *pcv, BOOL enum_all)
843 UINT id, total = 0;
844 ICINFO icinfo;
846 id = 0;
848 while (ICInfo(pcv->fccType, id, &icinfo))
850 struct codec_info *ic;
851 DWORD idx;
852 HIC hic;
854 id++;
856 hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
858 if (hic)
860 /* for unknown reason fccHandler reported by the driver
861 * doesn't always work, use the one returned by ICInfo instead.
863 DWORD fccHandler = icinfo.fccHandler;
865 if (!enum_all && pcv->lpbiIn)
867 if (ICCompressQuery(hic, pcv->lpbiIn, NULL) != ICERR_OK)
869 TRACE("fccHandler %s doesn't support input DIB format %d\n",
870 wine_dbgstr_fcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression);
871 ICClose(hic);
872 continue;
876 ICGetInfo(hic, &icinfo, sizeof(icinfo));
877 icinfo.fccHandler = fccHandler;
879 idx = SendMessageW(list, CB_ADDSTRING, 0, (LPARAM)icinfo.szDescription);
881 ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
882 ic->icinfo = icinfo;
883 ic->hic = hic;
884 SendMessageW(list, CB_SETITEMDATA, idx, (LPARAM)ic);
886 total++;
889 return total != 0;
892 static INT_PTR CALLBACK icm_choose_compressor_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
894 switch (msg)
896 case WM_INITDIALOG:
898 struct codec_info *ic;
899 WCHAR buf[128];
900 struct choose_compressor *choose_comp = (struct choose_compressor *)lparam;
902 SetWindowLongPtrW(hdlg, DWLP_USER, lparam);
904 /* FIXME */
905 choose_comp->flags &= ~(ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME);
907 if (choose_comp->title)
908 SetWindowTextA(hdlg, choose_comp->title);
910 if (!(choose_comp->flags & ICMF_CHOOSE_DATARATE))
912 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_CHECKBOX), SW_HIDE);
913 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE), SW_HIDE);
914 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_KB), SW_HIDE);
917 if (!(choose_comp->flags & ICMF_CHOOSE_KEYFRAME))
919 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_CHECKBOX), SW_HIDE);
920 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME), SW_HIDE);
921 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_FRAMES), SW_HIDE);
924 /* FIXME */
925 EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_SCROLL), FALSE);
926 EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_TXT), FALSE);
928 /*if (!(choose_comp->flags & ICMF_CHOOSE_PREVIEW))
929 ShowWindow(GetDlgItem(hdlg, IDC_PREVIEW), SW_HIDE);*/
931 LoadStringW(MSVFW32_hModule, IDS_FULLFRAMES, buf, 128);
932 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_ADDSTRING, 0, (LPARAM)buf);
934 ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
935 ic->icinfo.fccType = streamtypeVIDEO;
936 ic->icinfo.fccHandler = comptypeDIB;
937 ic->hic = 0;
938 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETITEMDATA, 0, (LPARAM)ic);
940 enum_compressors(GetDlgItem(hdlg, IDC_COMP_LIST), &choose_comp->cv, choose_comp->flags & ICMF_CHOOSE_ALLCOMPRESSORS);
942 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETCURSEL, 0, 0);
943 SetFocus(GetDlgItem(hdlg, IDC_COMP_LIST));
945 SetWindowLongPtrW(hdlg, DWLP_USER, (ULONG_PTR)choose_comp);
946 break;
949 case WM_COMMAND:
950 switch (LOWORD(wparam))
952 case IDC_COMP_LIST:
954 INT cur_sel;
955 struct codec_info *ic;
956 BOOL can_configure = FALSE, can_about = FALSE;
957 struct choose_compressor *choose_comp;
959 if (HIWORD(wparam) != CBN_SELCHANGE && HIWORD(wparam) != CBN_SETFOCUS)
960 break;
962 choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
964 cur_sel = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
966 ic = (struct codec_info *)SendMessageW((HWND)lparam, CB_GETITEMDATA, cur_sel, 0);
967 if (ic && ic->hic)
969 if (ICQueryConfigure(ic->hic) == DRVCNF_OK)
970 can_configure = TRUE;
971 if (ICQueryAbout(ic->hic) == DRVCNF_OK)
972 can_about = TRUE;
974 EnableWindow(GetDlgItem(hdlg, IDC_CONFIGURE), can_configure);
975 EnableWindow(GetDlgItem(hdlg, IDC_ABOUT), can_about);
977 if (choose_comp->flags & ICMF_CHOOSE_DATARATE)
979 /* FIXME */
981 if (choose_comp->flags & ICMF_CHOOSE_KEYFRAME)
983 /* FIXME */
986 break;
989 case IDC_CONFIGURE:
990 case IDC_ABOUT:
992 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
993 INT cur_sel;
994 struct codec_info *ic;
996 if (HIWORD(wparam) != BN_CLICKED)
997 break;
999 cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
1001 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
1002 if (ic && ic->hic)
1004 if (LOWORD(wparam) == IDC_CONFIGURE)
1005 ICConfigure(ic->hic, hdlg);
1006 else
1007 ICAbout(ic->hic, hdlg);
1010 break;
1013 case IDOK:
1015 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1016 INT cur_sel;
1017 struct codec_info *ic;
1019 if (HIWORD(wparam) != BN_CLICKED)
1020 break;
1022 cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
1023 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
1024 if (ic)
1026 struct choose_compressor *choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
1028 choose_comp->cv.hic = ic->hic;
1029 choose_comp->cv.fccType = ic->icinfo.fccType;
1030 choose_comp->cv.fccHandler = ic->icinfo.fccHandler;
1031 /* FIXME: fill everything else */
1033 /* prevent closing the codec handle below */
1034 ic->hic = 0;
1037 /* fall through */
1038 case IDCANCEL:
1040 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1041 INT idx = 0;
1043 if (HIWORD(wparam) != BN_CLICKED)
1044 break;
1046 while (1)
1048 struct codec_info *ic;
1050 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, idx++, 0);
1052 if (!ic || (LONG_PTR)ic == CB_ERR) break;
1054 if (ic->hic) ICClose(ic->hic);
1055 HeapFree(GetProcessHeap(), 0, ic);
1058 EndDialog(hdlg, LOWORD(wparam) == IDOK);
1059 break;
1062 default:
1063 break;
1065 break;
1067 default:
1068 break;
1071 return FALSE;
1074 /***********************************************************************
1075 * ICCompressorChoose [MSVFW32.@]
1077 BOOL VFWAPI ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn,
1078 LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle)
1080 struct choose_compressor choose_comp;
1081 BOOL ret;
1083 TRACE("(%p,%08x,%p,%p,%p,%s)\n", hwnd, uiFlags, pvIn, lpData, pc, lpszTitle);
1085 if (!pc || pc->cbSize != sizeof(COMPVARS))
1086 return FALSE;
1088 if (!(pc->dwFlags & ICMF_COMPVARS_VALID))
1090 pc->dwFlags = 0;
1091 pc->fccType = pc->fccHandler = 0;
1092 pc->hic = NULL;
1093 pc->lpbiIn = NULL;
1094 pc->lpbiOut = NULL;
1095 pc->lpBitsOut = pc->lpBitsPrev = pc->lpState = NULL;
1096 pc->lQ = ICQUALITY_DEFAULT;
1097 pc->lKey = -1;
1098 pc->lDataRate = 300; /* kB */
1099 pc->lpState = NULL;
1100 pc->cbState = 0;
1102 if (pc->fccType == 0)
1103 pc->fccType = ICTYPE_VIDEO;
1105 choose_comp.cv = *pc;
1106 choose_comp.flags = uiFlags;
1107 choose_comp.title = lpszTitle;
1109 ret = DialogBoxParamW(MSVFW32_hModule, MAKEINTRESOURCEW(ICM_CHOOSE_COMPRESSOR), hwnd,
1110 icm_choose_compressor_dlgproc, (LPARAM)&choose_comp);
1112 if (ret)
1114 *pc = choose_comp.cv;
1115 pc->dwFlags |= ICMF_COMPVARS_VALID;
1118 return ret;
1122 /***********************************************************************
1123 * ICCompressorFree [MSVFW32.@]
1125 void VFWAPI ICCompressorFree(PCOMPVARS pc)
1127 TRACE("(%p)\n",pc);
1129 if (pc != NULL && pc->cbSize == sizeof(COMPVARS)) {
1130 if (pc->hic != NULL) {
1131 ICClose(pc->hic);
1132 pc->hic = NULL;
1134 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1135 pc->lpbiIn = NULL;
1136 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1137 pc->lpBitsOut = NULL;
1138 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1139 pc->lpBitsPrev = NULL;
1140 HeapFree(GetProcessHeap(), 0, pc->lpState);
1141 pc->lpState = NULL;
1142 pc->dwFlags = 0;
1146 /***********************************************************************
1147 * ICSendMessage [MSVFW32.@]
1149 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
1151 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1153 if (!whic) return ICERR_BADHANDLE;
1154 return MSVIDEO_SendMessage(whic, msg, lParam1, lParam2);
1157 /***********************************************************************
1158 * ICDrawBegin [MSVFW32.@]
1160 DWORD VFWAPIV ICDrawBegin(
1161 HIC hic, /* [in] */
1162 DWORD dwFlags, /* [in] flags */
1163 HPALETTE hpal, /* [in] palette to draw with */
1164 HWND hwnd, /* [in] window to draw to */
1165 HDC hdc, /* [in] HDC to draw to */
1166 INT xDst, /* [in] destination rectangle */
1167 INT yDst, /* [in] */
1168 INT dxDst, /* [in] */
1169 INT dyDst, /* [in] */
1170 LPBITMAPINFOHEADER lpbi, /* [in] format of frame to draw */
1171 INT xSrc, /* [in] source rectangle */
1172 INT ySrc, /* [in] */
1173 INT dxSrc, /* [in] */
1174 INT dySrc, /* [in] */
1175 DWORD dwRate, /* [in] frames/second = (dwRate/dwScale) */
1176 DWORD dwScale) /* [in] */
1179 ICDRAWBEGIN icdb;
1181 TRACE("(%p,%d,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%d,%d)\n",
1182 hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
1183 lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
1185 icdb.dwFlags = dwFlags;
1186 icdb.hpal = hpal;
1187 icdb.hwnd = hwnd;
1188 icdb.hdc = hdc;
1189 icdb.xDst = xDst;
1190 icdb.yDst = yDst;
1191 icdb.dxDst = dxDst;
1192 icdb.dyDst = dyDst;
1193 icdb.lpbi = lpbi;
1194 icdb.xSrc = xSrc;
1195 icdb.ySrc = ySrc;
1196 icdb.dxSrc = dxSrc;
1197 icdb.dySrc = dySrc;
1198 icdb.dwRate = dwRate;
1199 icdb.dwScale = dwScale;
1200 return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD_PTR)&icdb,sizeof(icdb));
1203 /***********************************************************************
1204 * ICDraw [MSVFW32.@]
1206 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
1207 ICDRAW icd;
1209 TRACE("(%p,%d,%p,%p,%d,%d)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
1211 icd.dwFlags = dwFlags;
1212 icd.lpFormat = lpFormat;
1213 icd.lpData = lpData;
1214 icd.cbData = cbData;
1215 icd.lTime = lTime;
1217 return ICSendMessage(hic,ICM_DRAW,(DWORD_PTR)&icd,sizeof(icd));
1220 /***********************************************************************
1221 * ICClose [MSVFW32.@]
1223 LRESULT WINAPI ICClose(HIC hic)
1225 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1226 WINE_HIC** p;
1228 TRACE("(%p)\n",hic);
1230 if (!whic) return ICERR_BADHANDLE;
1232 if (whic->driverproc)
1234 MSVIDEO_SendMessage(whic, DRV_CLOSE, 0, 0);
1235 MSVIDEO_SendMessage(whic, DRV_DISABLE, 0, 0);
1236 MSVIDEO_SendMessage(whic, DRV_FREE, 0, 0);
1238 else
1240 CloseDriver(whic->hdrv, 0, 0);
1243 /* remove whic from list */
1244 for (p = &MSVIDEO_FirstHic; *p != NULL; p = &((*p)->next))
1246 if ((*p) == whic)
1248 *p = whic->next;
1249 break;
1253 HeapFree(GetProcessHeap(), 0, whic);
1254 return 0;
1259 /***********************************************************************
1260 * ICImageCompress [MSVFW32.@]
1262 HANDLE VFWAPI ICImageCompress(
1263 HIC hic, UINT uiFlags,
1264 LPBITMAPINFO lpbiIn, LPVOID lpBits,
1265 LPBITMAPINFO lpbiOut, LONG lQuality,
1266 LONG* plSize)
1268 FIXME("(%p,%08x,%p,%p,%p,%d,%p)\n",
1269 hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
1271 return NULL;
1274 /***********************************************************************
1275 * ICImageDecompress [MSVFW32.@]
1278 HANDLE VFWAPI ICImageDecompress(
1279 HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
1280 LPVOID lpBits, LPBITMAPINFO lpbiOut)
1282 HGLOBAL hMem = NULL;
1283 BYTE* pMem = NULL;
1284 BOOL bReleaseIC = FALSE;
1285 BYTE* pHdr = NULL;
1286 ULONG cbHdr = 0;
1287 BOOL bSucceeded = FALSE;
1288 BOOL bInDecompress = FALSE;
1289 DWORD biSizeImage;
1291 TRACE("(%p,%08x,%p,%p,%p)\n",
1292 hic, uiFlags, lpbiIn, lpBits, lpbiOut);
1294 if ( hic == NULL )
1296 hic = ICDecompressOpen( ICTYPE_VIDEO, 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
1297 if ( hic == NULL )
1299 WARN("no handler\n" );
1300 goto err;
1302 bReleaseIC = TRUE;
1304 if ( uiFlags != 0 )
1306 FIXME( "unknown flag %08x\n", uiFlags );
1307 goto err;
1309 if ( lpbiIn == NULL || lpBits == NULL )
1311 WARN("invalid argument\n");
1312 goto err;
1315 if ( lpbiOut != NULL )
1317 if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
1318 goto err;
1319 cbHdr = sizeof(BITMAPINFOHEADER);
1320 if ( lpbiOut->bmiHeader.biCompression == 3 )
1321 cbHdr += sizeof(DWORD)*3;
1322 else
1323 if ( lpbiOut->bmiHeader.biBitCount <= 8 )
1325 if ( lpbiOut->bmiHeader.biClrUsed == 0 )
1326 cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
1327 else
1328 cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
1331 else
1333 TRACE( "get format\n" );
1335 cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
1336 if ( cbHdr < sizeof(BITMAPINFOHEADER) )
1337 goto err;
1338 pHdr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,cbHdr+sizeof(RGBQUAD)*256);
1339 if ( pHdr == NULL )
1340 goto err;
1341 if ( ICDecompressGetFormat( hic, lpbiIn, pHdr ) != ICERR_OK )
1342 goto err;
1343 lpbiOut = (BITMAPINFO*)pHdr;
1344 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1345 ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
1346 lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
1348 if ( lpbiIn->bmiHeader.biClrUsed == 0 )
1349 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
1350 else
1351 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
1353 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1354 lpbiOut->bmiHeader.biClrUsed == 0 )
1355 lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
1357 lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1358 cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
1361 biSizeImage = lpbiOut->bmiHeader.biSizeImage;
1362 if ( biSizeImage == 0 )
1363 biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
1365 TRACE( "call ICDecompressBegin\n" );
1367 if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
1368 goto err;
1369 bInDecompress = TRUE;
1371 TRACE( "cbHdr %d, biSizeImage %d\n", cbHdr, biSizeImage );
1373 hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
1374 if ( hMem == NULL )
1376 WARN( "out of memory\n" );
1377 goto err;
1379 pMem = GlobalLock( hMem );
1380 if ( pMem == NULL )
1381 goto err;
1382 memcpy( pMem, lpbiOut, cbHdr );
1384 TRACE( "call ICDecompress\n" );
1385 if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
1386 goto err;
1388 bSucceeded = TRUE;
1389 err:
1390 if ( bInDecompress )
1391 ICDecompressEnd( hic );
1392 if ( bReleaseIC )
1393 ICClose(hic);
1394 HeapFree(GetProcessHeap(),0,pHdr);
1395 if ( pMem != NULL )
1396 GlobalUnlock( hMem );
1397 if ( !bSucceeded && hMem != NULL )
1399 GlobalFree(hMem); hMem = NULL;
1402 return hMem;
1405 /***********************************************************************
1406 * ICSeqCompressFrame [MSVFW32.@]
1408 LPVOID VFWAPI ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL *pfKey, LONG *plSize)
1410 ICCOMPRESS* icComp = pc->lpState;
1411 DWORD ret;
1412 TRACE("(%p, 0x%08x, %p, %p, %p)\n", pc, uiFlags, lpBits, pfKey, plSize);
1414 if (pc->cbState != sizeof(ICCOMPRESS))
1416 ERR("Invalid cbState %i\n", pc->cbState);
1417 return NULL;
1420 if (!pc->lKeyCount++)
1421 icComp->dwFlags = ICCOMPRESS_KEYFRAME;
1422 else
1424 if (pc->lKey && pc->lKeyCount == (pc->lKey - 1))
1425 /* No key frames if pc->lKey == 0 */
1426 pc->lKeyCount = 0;
1427 icComp->dwFlags = 0;
1430 icComp->lpInput = lpBits;
1431 icComp->lFrameNum = pc->lFrame++;
1432 icComp->lpOutput = pc->lpBitsOut;
1433 icComp->lpPrev = pc->lpBitsPrev;
1434 ret = ICSendMessage(pc->hic, ICM_COMPRESS, (DWORD_PTR)icComp, sizeof(*icComp));
1436 if (ret == ICERR_OK)
1438 LPVOID oldprev, oldout;
1440 if (icComp->dwFlags & AVIIF_KEYFRAME)
1442 pc->lKeyCount = 1;
1443 *pfKey = TRUE;
1444 TRACE("Key frame\n");
1446 else
1447 *pfKey = FALSE;
1449 *plSize = icComp->lpbiOutput->biSizeImage;
1451 /* We shift Prev and Out, so we don't have to allocate and release memory */
1452 oldprev = pc->lpBitsPrev;
1453 oldout = pc->lpBitsOut;
1454 pc->lpBitsPrev = oldout;
1455 pc->lpBitsOut = oldprev;
1457 TRACE("returning: %p, compressed frame size %u\n", icComp->lpOutput, *plSize);
1458 return icComp->lpOutput;
1460 return NULL;
1463 static void clear_compvars(PCOMPVARS pc)
1465 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1466 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1467 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1468 HeapFree(GetProcessHeap(), 0, pc->lpState);
1469 pc->lpbiIn = pc->lpBitsPrev = pc->lpBitsOut = pc->lpState = NULL;
1470 if (pc->dwFlags & 0x80000000)
1472 HeapFree(GetProcessHeap(), 0, pc->lpbiOut);
1473 pc->lpbiOut = NULL;
1474 pc->dwFlags &= ~0x80000000;
1478 /***********************************************************************
1479 * ICSeqCompressFrameEnd [MSVFW32.@]
1481 void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
1483 TRACE("(%p)\n", pc);
1484 ICSendMessage(pc->hic, ICM_COMPRESS_END, 0, 0);
1485 clear_compvars(pc);
1488 /***********************************************************************
1489 * ICSeqCompressFrameStart [MSVFW32.@]
1491 BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
1493 /* I'm ignoring bmiColors as I don't know what to do with it,
1494 * it doesn't appear to be used though
1496 DWORD ret;
1497 ICCOMPRESS* icComp;
1498 pc->lpbiIn = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFO));
1499 if (!pc->lpbiIn)
1500 return FALSE;
1502 *pc->lpbiIn = *lpbiIn;
1504 pc->lpState = HeapAlloc(GetProcessHeap(), 0, sizeof(ICCOMPRESS)
1505 + sizeof(*icComp->lpckid) + sizeof(*icComp->lpdwFlags));
1506 if (!pc->lpState)
1507 goto error;
1509 pc->cbState = sizeof(ICCOMPRESS);
1511 if (!pc->lpbiOut)
1513 /* Ask compressor for needed header size */
1514 int size = ICSendMessage(pc->hic, ICM_COMPRESS_GET_FORMAT,
1515 (DWORD_PTR)pc->lpbiIn, 0);
1516 if (size <= 0)
1517 goto error;
1519 pc->lpbiOut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1520 if (!pc->lpbiOut)
1521 goto error;
1522 /* Flag to show that we allocated lpbiOut for proper cleanup */
1523 pc->dwFlags |= 0x80000000;
1525 ret = ICSendMessage(pc->hic, ICM_COMPRESS_GET_FORMAT,
1526 (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1527 if (ret != ICERR_OK)
1529 ERR("Could not get output format from compressor\n");
1530 goto error;
1532 if (!pc->lpbiOut->bmiHeader.biSizeImage)
1534 /* If we can't know the output frame size for sure at least allocate
1535 * the same size of the input frame and also at least 8Kb to be sure
1536 * that poor compressors will have enough memory to work if the input
1537 * frame is too small.
1539 pc->lpbiOut->bmiHeader.biSizeImage = max(8192, pc->lpbiIn->bmiHeader.biSizeImage);
1540 ERR("Bad codec! Invalid output frame size, guessing from input\n");
1544 TRACE("Input: %ux%u, fcc %s, bpp %u, size %u\n",
1545 pc->lpbiIn->bmiHeader.biWidth, pc->lpbiIn->bmiHeader.biHeight,
1546 wine_dbgstr_fcc(pc->lpbiIn->bmiHeader.biCompression),
1547 pc->lpbiIn->bmiHeader.biBitCount,
1548 pc->lpbiIn->bmiHeader.biSizeImage);
1549 TRACE("Output: %ux%u, fcc %s, bpp %u, size %u\n",
1550 pc->lpbiOut->bmiHeader.biWidth, pc->lpbiOut->bmiHeader.biHeight,
1551 wine_dbgstr_fcc(pc->lpbiOut->bmiHeader.biCompression),
1552 pc->lpbiOut->bmiHeader.biBitCount,
1553 pc->lpbiOut->bmiHeader.biSizeImage);
1555 /* Buffer for compressed frame data */
1556 pc->lpBitsOut = HeapAlloc(GetProcessHeap(), 0, pc->lpbiOut->bmiHeader.biSizeImage);
1557 if (!pc->lpBitsOut)
1558 goto error;
1560 /* Buffer for previous compressed frame data */
1561 pc->lpBitsPrev = HeapAlloc(GetProcessHeap(), 0, pc->lpbiOut->bmiHeader.biSizeImage);
1562 if (!pc->lpBitsPrev)
1563 goto error;
1565 TRACE("Compvars:\n"
1566 "\tsize: %i\n"
1567 "\tflags: 0x%x\n"
1568 "\thic: %p\n"
1569 "\ttype: %s\n"
1570 "\thandler: %s\n"
1571 "\tin/out: %p/%p\n"
1572 "\tkey/data/quality: %i/%i/%i\n",
1573 pc->cbSize, pc->dwFlags, pc->hic, wine_dbgstr_fcc(pc->fccType),
1574 wine_dbgstr_fcc(pc->fccHandler), pc->lpbiIn, pc->lpbiOut, pc->lKey,
1575 pc->lDataRate, pc->lQ);
1577 ret = ICSendMessage(pc->hic, ICM_COMPRESS_BEGIN, (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1578 if (ret == ICERR_OK)
1580 icComp = pc->lpState;
1581 /* Initialise some variables */
1582 pc->lFrame = 0; pc->lKeyCount = 0;
1584 icComp->lpbiOutput = &pc->lpbiOut->bmiHeader;
1585 icComp->lpbiInput = &pc->lpbiIn->bmiHeader;
1586 icComp->lpckid = (DWORD *)(icComp + 1);
1587 *icComp->lpckid = 0;
1588 icComp->lpdwFlags = (DWORD *)((char *)(icComp + 1) + sizeof(*icComp->lpckid));
1589 *icComp->lpdwFlags = 0;
1590 icComp->dwFrameSize = 0;
1591 icComp->dwQuality = pc->lQ;
1592 icComp->lpbiPrev = &pc->lpbiIn->bmiHeader;
1593 return TRUE;
1595 error:
1596 clear_compvars(pc);
1597 return FALSE;
1600 /***********************************************************************
1601 * GetFileNamePreview [MSVFW32.@]
1603 static BOOL GetFileNamePreview(LPVOID lpofn,BOOL bSave,BOOL bUnicode)
1605 CHAR szFunctionName[20];
1606 BOOL (*fnGetFileName)(LPVOID);
1607 HMODULE hComdlg32;
1608 BOOL ret;
1610 FIXME("(%p,%d,%d), semi-stub!\n",lpofn,bSave,bUnicode);
1612 lstrcpyA(szFunctionName, (bSave ? "GetSaveFileName" : "GetOpenFileName"));
1613 lstrcatA(szFunctionName, (bUnicode ? "W" : "A"));
1615 hComdlg32 = LoadLibraryA("COMDLG32.DLL");
1616 if (hComdlg32 == NULL)
1617 return FALSE;
1619 fnGetFileName = (LPVOID)GetProcAddress(hComdlg32, szFunctionName);
1620 if (fnGetFileName == NULL)
1622 FreeLibrary(hComdlg32);
1623 return FALSE;
1626 /* FIXME: need to add OFN_ENABLEHOOK and our own handler */
1627 ret = fnGetFileName(lpofn);
1629 FreeLibrary(hComdlg32);
1630 return ret;
1633 /***********************************************************************
1634 * GetOpenFileNamePreviewA [MSVFW32.@]
1636 BOOL WINAPI GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn)
1638 FIXME("(%p), semi-stub!\n", lpofn);
1640 return GetFileNamePreview(lpofn, FALSE, FALSE);
1643 /***********************************************************************
1644 * GetOpenFileNamePreviewW [MSVFW32.@]
1646 BOOL WINAPI GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn)
1648 FIXME("(%p), semi-stub!\n", lpofn);
1650 return GetFileNamePreview(lpofn, FALSE, TRUE);
1653 /***********************************************************************
1654 * GetSaveFileNamePreviewA [MSVFW32.@]
1656 BOOL WINAPI GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn)
1658 FIXME("(%p), semi-stub!\n", lpofn);
1660 return GetFileNamePreview(lpofn, TRUE, FALSE);
1663 /***********************************************************************
1664 * GetSaveFileNamePreviewW [MSVFW32.@]
1666 BOOL WINAPI GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn)
1668 FIXME("(%p), semi-stub!\n", lpofn);
1670 return GetFileNamePreview(lpofn, TRUE, TRUE);