mstask: Implement ITask::DeleteTrigger().
[wine.git] / dlls / msvfw32 / msvideo_main.c
blob5dc99a42dadae314d1c03d072c2adf7c4ccf73ab
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 *name, const char *driver, unsigned int index, void *param);
228 static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
230 char fccTypeStr[4];
231 char name_buf[10];
232 char buf[2048];
234 DWORD i, cnt = 0, lRet;
235 BOOL result = FALSE;
236 HKEY hKey;
238 fourcc_to_string(fccTypeStr, fccType);
240 /* first, go through the registry entries */
241 lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey);
242 if (lRet == ERROR_SUCCESS)
244 i = 0;
245 for (;;)
247 DWORD name_len = 10, driver_len = 128;
248 lRet = RegEnumValueA(hKey, i++, name_buf, &name_len, 0, 0, (BYTE *)buf, &driver_len);
249 if (lRet == ERROR_NO_MORE_ITEMS) break;
250 if (name_len != 9 || name_buf[4] != '.') continue;
251 if (fccType && strncasecmp(name_buf, fccTypeStr, 4)) continue;
252 if ((result = handler(name_buf, buf, cnt++, param))) break;
254 RegCloseKey( hKey );
256 if (result) return result;
258 /* if that didn't work, go through the values in system.ini */
259 if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini"))
261 char *s;
262 for (s = buf; *s; s += strlen(s) + 1)
264 if (s[4] != '.' || s[9] != '=') continue;
265 if (fccType && strncasecmp(s, fccTypeStr, 4)) continue;
266 if ((result = handler(s, s + 10, 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 *name, const char *driver, unsigned int nr, void *param)
299 ICINFO *lpicinfo = param;
300 DWORD fccType = mmioStringToFOURCCA(name, 0);
301 DWORD fccHandler = mmioStringToFOURCCA(name + 5, 0);
303 if (lpicinfo->fccHandler != nr && compare_fourcc(lpicinfo->fccHandler, fccHandler))
304 return FALSE;
306 lpicinfo->fccType = fccType;
307 lpicinfo->fccHandler = fccHandler;
308 lpicinfo->dwFlags = 0;
309 lpicinfo->dwVersion = 0;
310 lpicinfo->dwVersionICM = ICVERSION;
311 lpicinfo->szName[0] = 0;
312 lpicinfo->szDescription[0] = 0;
313 MultiByteToWideChar(CP_ACP, 0, driver, -1, lpicinfo->szDriver,
314 sizeof(lpicinfo->szDriver)/sizeof(WCHAR));
316 return TRUE;
319 /***********************************************************************
320 * ICInfo [MSVFW32.@]
321 * Get information about an installable compressor. Return TRUE if there
322 * is one.
324 * PARAMS
325 * fccType [I] type of compressor (e.g. 'vidc')
326 * fccHandler [I] real fcc for handler or <n>th compressor
327 * lpicinfo [O] information about compressor
329 BOOL VFWAPI ICInfo( DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo)
331 TRACE("(%s,%s,%p)\n",
332 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpicinfo);
334 lpicinfo->fccType = fccType;
335 lpicinfo->fccHandler = fccHandler;
336 return enum_drivers(fccType, ICInfo_enum_handler, lpicinfo);
339 static DWORD IC_HandleRef = 1;
341 /***********************************************************************
342 * ICInstall [MSVFW32.@]
344 BOOL VFWAPI ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags)
346 reg_driver* driver;
347 unsigned len;
349 TRACE("(%s,%s,%p,%p,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), (void*)lParam, szDesc, wFlags);
351 /* Check if a driver is already registered */
352 for (driver = reg_driver_list; driver; driver = driver->next)
354 if (!compare_fourcc(fccType, driver->fccType) &&
355 !compare_fourcc(fccHandler, driver->fccHandler))
356 break;
358 if (driver) return FALSE;
360 /* Register the driver */
361 driver = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(reg_driver));
362 if (!driver) goto oom;
363 driver->fccType = fccType;
364 driver->fccHandler = fccHandler;
366 switch(wFlags)
368 case ICINSTALL_FUNCTION:
369 driver->proc = (DRIVERPROC)lParam;
370 driver->name = NULL;
371 break;
372 case ICINSTALL_DRIVER:
373 driver->proc = NULL;
374 len = MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, NULL, 0);
375 driver->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
376 if (!driver->name) goto oom;
377 MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, driver->name, len);
378 break;
379 default:
380 ERR("Invalid flags!\n");
381 HeapFree(GetProcessHeap(), 0, driver);
382 return FALSE;
385 /* Insert our driver in the list*/
386 driver->next = reg_driver_list;
387 reg_driver_list = driver;
389 return TRUE;
390 oom:
391 HeapFree(GetProcessHeap(), 0, driver);
392 return FALSE;
395 /***********************************************************************
396 * ICRemove [MSVFW32.@]
398 BOOL VFWAPI ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags)
400 reg_driver** pdriver;
401 reg_driver* drv;
403 TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wFlags);
405 /* Check if a driver is already registered */
406 for (pdriver = &reg_driver_list; *pdriver; pdriver = &(*pdriver)->next)
408 if (!compare_fourcc(fccType, (*pdriver)->fccType) &&
409 !compare_fourcc(fccHandler, (*pdriver)->fccHandler))
410 break;
412 if (!*pdriver)
413 return FALSE;
415 /* Remove the driver from the list */
416 drv = *pdriver;
417 *pdriver = (*pdriver)->next;
418 HeapFree(GetProcessHeap(), 0, drv->name);
419 HeapFree(GetProcessHeap(), 0, drv);
421 return TRUE;
425 /***********************************************************************
426 * ICOpen [MSVFW32.@]
427 * Opens an installable compressor. Return special handle.
429 HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode)
431 WCHAR codecname[10];
432 ICOPEN icopen;
433 HDRVR hdrv;
434 WINE_HIC* whic;
435 static const WCHAR drv32W[] = {'d','r','i','v','e','r','s','3','2','\0'};
436 reg_driver* driver;
438 TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode);
440 if (!fccHandler) /* No specific handler, return the first valid for wMode */
442 HIC local;
443 ICINFO info;
444 DWORD loop = 0;
445 info.dwSize = sizeof(info);
446 while(ICInfo(fccType, loop++, &info))
448 /* Ensure fccHandler is not 0x0 because we will recurse on ICOpen */
449 if(!info.fccHandler)
450 continue;
451 local = ICOpen(fccType, info.fccHandler, wMode);
452 if (local != 0)
454 TRACE("Returning %s as default handler for %s\n",
455 wine_dbgstr_fcc(info.fccHandler), wine_dbgstr_fcc(fccType));
456 return local;
461 /* Check if there is a registered driver that matches */
462 driver = reg_driver_list;
463 while(driver)
464 if (!compare_fourcc(fccType, driver->fccType) &&
465 !compare_fourcc(fccHandler, driver->fccHandler)) {
466 fccType = driver->fccType;
467 fccHandler = driver->fccHandler;
468 break;
469 } else
470 driver = driver->next;
472 if (driver && driver->proc)
473 /* The driver has been registered at runtime with its driverproc */
474 return ICOpenFunction(fccType, fccHandler, wMode, driver->proc);
476 /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
477 * same layout as ICOPEN
479 icopen.dwSize = sizeof(ICOPEN);
480 icopen.fccType = fccType;
481 icopen.fccHandler = fccHandler;
482 icopen.dwVersion = 0x00001000; /* FIXME */
483 icopen.dwFlags = wMode;
484 icopen.dwError = 0;
485 icopen.pV1Reserved = NULL;
486 icopen.pV2Reserved = NULL;
487 icopen.dnDevNode = 0; /* FIXME */
489 if (!driver) {
490 /* normalize to lower case as in 'vidc' */
491 ((char*)&fccType)[0] = tolower(((char*)&fccType)[0]);
492 ((char*)&fccType)[1] = tolower(((char*)&fccType)[1]);
493 ((char*)&fccType)[2] = tolower(((char*)&fccType)[2]);
494 ((char*)&fccType)[3] = tolower(((char*)&fccType)[3]);
495 icopen.fccType = fccType;
496 /* Seek the driver in the registry */
497 fourcc_to_string(codecname, fccType);
498 codecname[4] = '.';
499 fourcc_to_string(codecname + 5, fccHandler);
500 codecname[9] = '\0';
502 hdrv = OpenDriver(codecname, drv32W, (LPARAM)&icopen);
503 if (!hdrv)
504 return 0;
505 } else {
506 /* The driver has been registered at runtime with its name */
507 hdrv = OpenDriver(driver->name, NULL, (LPARAM)&icopen);
508 if (!hdrv)
509 return 0;
512 whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
513 if (!whic)
515 CloseDriver(hdrv, 0, 0);
516 return FALSE;
518 whic->hdrv = hdrv;
519 whic->driverproc = NULL;
520 whic->type = fccType;
521 whic->handler = fccHandler;
522 while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
523 whic->hic = (HIC)(ULONG_PTR)IC_HandleRef++;
524 whic->next = MSVIDEO_FirstHic;
525 MSVIDEO_FirstHic = whic;
527 TRACE("=> %p\n", whic->hic);
528 return whic->hic;
531 /***********************************************************************
532 * ICOpenFunction [MSVFW32.@]
534 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, DRIVERPROC lpfnHandler)
536 ICOPEN icopen;
537 WINE_HIC* whic;
539 TRACE("(%s,%s,%d,%p)\n",
540 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode, lpfnHandler);
542 icopen.dwSize = sizeof(ICOPEN);
543 icopen.fccType = fccType;
544 icopen.fccHandler = fccHandler;
545 icopen.dwVersion = ICVERSION;
546 icopen.dwFlags = wMode;
547 icopen.dwError = 0;
548 icopen.pV1Reserved = NULL;
549 icopen.pV2Reserved = NULL;
550 icopen.dnDevNode = 0; /* FIXME */
552 whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
553 if (!whic) return 0;
555 whic->driverproc = lpfnHandler;
556 while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
557 whic->hic = (HIC)(ULONG_PTR)IC_HandleRef++;
558 whic->next = MSVIDEO_FirstHic;
559 MSVIDEO_FirstHic = whic;
561 /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
562 /* What if the function is used more than once? */
564 if (MSVIDEO_SendMessage(whic, DRV_LOAD, 0L, 0L) != DRV_SUCCESS)
566 WARN("DRV_LOAD failed for hic %p\n", whic->hic);
567 MSVIDEO_FirstHic = whic->next;
568 HeapFree(GetProcessHeap(), 0, whic);
569 return 0;
571 /* return value is not checked */
572 MSVIDEO_SendMessage(whic, DRV_ENABLE, 0L, 0L);
574 whic->driverId = (DWORD)MSVIDEO_SendMessage(whic, DRV_OPEN, 0, (DWORD_PTR)&icopen);
575 /* FIXME: What should we put here? */
576 whic->hdrv = NULL;
578 if (whic->driverId == 0)
580 WARN("DRV_OPEN failed for hic %p\n", whic->hic);
581 MSVIDEO_FirstHic = whic->next;
582 HeapFree(GetProcessHeap(), 0, whic);
583 return 0;
586 TRACE("=> %p\n", whic->hic);
587 return whic->hic;
590 /***********************************************************************
591 * ICGetInfo [MSVFW32.@]
593 LRESULT VFWAPI ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb)
595 LRESULT ret;
596 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
598 TRACE("(%p,%p,%d)\n", hic, picinfo, cb);
600 if (!whic) return ICERR_BADHANDLE;
601 if (!picinfo) return MMSYSERR_INVALPARAM;
603 /* (WS) The field szDriver should be initialized because the driver
604 * is not obliged and often will not do it. Some applications, like
605 * VirtualDub, rely on this field and will occasionally crash if it
606 * goes uninitialized.
608 if (cb >= sizeof(ICINFO)) picinfo->szDriver[0] = '\0';
610 ret = ICSendMessage(hic, ICM_GETINFO, (DWORD_PTR)picinfo, cb);
612 /* (WS) When szDriver was not supplied by the driver itself, apparently
613 * Windows will set its value equal to the driver file name. This can
614 * be obtained from the registry as we do here.
616 if (cb >= sizeof(ICINFO) && picinfo->szDriver[0] == 0)
618 ICINFO ii;
620 memset(&ii, 0, sizeof(ii));
621 ii.dwSize = sizeof(ii);
622 ICInfo(picinfo->fccType, picinfo->fccHandler, &ii);
623 lstrcpyW(picinfo->szDriver, ii.szDriver);
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 *name, const char *driver, unsigned int nr, void *param)
654 driver_info_t *info = param;
655 info->fccHandler = mmioStringToFOURCCA(name + 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 return ret;
826 struct choose_compressor
828 UINT flags;
829 LPCSTR title;
830 COMPVARS cv;
833 struct codec_info
835 HIC hic;
836 ICINFO icinfo;
839 static BOOL enum_compressors(HWND list, COMPVARS *pcv, BOOL enum_all)
841 UINT id, total = 0;
842 ICINFO icinfo;
844 id = 0;
846 while (ICInfo(pcv->fccType, id, &icinfo))
848 struct codec_info *ic;
849 DWORD idx;
850 HIC hic;
852 id++;
854 hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
856 if (hic)
858 /* for unknown reason fccHandler reported by the driver
859 * doesn't always work, use the one returned by ICInfo instead.
861 DWORD fccHandler = icinfo.fccHandler;
863 if (!enum_all && pcv->lpbiIn)
865 if (ICCompressQuery(hic, pcv->lpbiIn, NULL) != ICERR_OK)
867 TRACE("fccHandler %s doesn't support input DIB format %d\n",
868 wine_dbgstr_fcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression);
869 ICClose(hic);
870 continue;
874 ICGetInfo(hic, &icinfo, sizeof(icinfo));
875 icinfo.fccHandler = fccHandler;
877 idx = SendMessageW(list, CB_ADDSTRING, 0, (LPARAM)icinfo.szDescription);
879 ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
880 ic->icinfo = icinfo;
881 ic->hic = hic;
882 SendMessageW(list, CB_SETITEMDATA, idx, (LPARAM)ic);
884 total++;
887 return total != 0;
890 static INT_PTR CALLBACK icm_choose_compressor_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
892 switch (msg)
894 case WM_INITDIALOG:
896 struct codec_info *ic;
897 WCHAR buf[128];
898 struct choose_compressor *choose_comp = (struct choose_compressor *)lparam;
900 SetWindowLongPtrW(hdlg, DWLP_USER, lparam);
902 /* FIXME */
903 choose_comp->flags &= ~(ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME);
905 if (choose_comp->title)
906 SetWindowTextA(hdlg, choose_comp->title);
908 if (!(choose_comp->flags & ICMF_CHOOSE_DATARATE))
910 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_CHECKBOX), SW_HIDE);
911 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE), SW_HIDE);
912 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_KB), SW_HIDE);
915 if (!(choose_comp->flags & ICMF_CHOOSE_KEYFRAME))
917 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_CHECKBOX), SW_HIDE);
918 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME), SW_HIDE);
919 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_FRAMES), SW_HIDE);
922 /* FIXME */
923 EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_SCROLL), FALSE);
924 EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_TXT), FALSE);
926 /*if (!(choose_comp->flags & ICMF_CHOOSE_PREVIEW))
927 ShowWindow(GetDlgItem(hdlg, IDC_PREVIEW), SW_HIDE);*/
929 LoadStringW(MSVFW32_hModule, IDS_FULLFRAMES, buf, 128);
930 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_ADDSTRING, 0, (LPARAM)buf);
932 ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
933 ic->icinfo.fccType = streamtypeVIDEO;
934 ic->icinfo.fccHandler = comptypeDIB;
935 ic->hic = 0;
936 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETITEMDATA, 0, (LPARAM)ic);
938 enum_compressors(GetDlgItem(hdlg, IDC_COMP_LIST), &choose_comp->cv, choose_comp->flags & ICMF_CHOOSE_ALLCOMPRESSORS);
940 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETCURSEL, 0, 0);
941 SetFocus(GetDlgItem(hdlg, IDC_COMP_LIST));
943 SetWindowLongPtrW(hdlg, DWLP_USER, (ULONG_PTR)choose_comp);
944 break;
947 case WM_COMMAND:
948 switch (LOWORD(wparam))
950 case IDC_COMP_LIST:
952 INT cur_sel;
953 struct codec_info *ic;
954 BOOL can_configure = FALSE, can_about = FALSE;
955 struct choose_compressor *choose_comp;
957 if (HIWORD(wparam) != CBN_SELCHANGE && HIWORD(wparam) != CBN_SETFOCUS)
958 break;
960 choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
962 cur_sel = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
964 ic = (struct codec_info *)SendMessageW((HWND)lparam, CB_GETITEMDATA, cur_sel, 0);
965 if (ic && ic->hic)
967 if (ICQueryConfigure(ic->hic) == DRVCNF_OK)
968 can_configure = TRUE;
969 if (ICQueryAbout(ic->hic) == DRVCNF_OK)
970 can_about = TRUE;
972 EnableWindow(GetDlgItem(hdlg, IDC_CONFIGURE), can_configure);
973 EnableWindow(GetDlgItem(hdlg, IDC_ABOUT), can_about);
975 if (choose_comp->flags & ICMF_CHOOSE_DATARATE)
977 /* FIXME */
979 if (choose_comp->flags & ICMF_CHOOSE_KEYFRAME)
981 /* FIXME */
984 break;
987 case IDC_CONFIGURE:
988 case IDC_ABOUT:
990 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
991 INT cur_sel;
992 struct codec_info *ic;
994 if (HIWORD(wparam) != BN_CLICKED)
995 break;
997 cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
999 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
1000 if (ic && ic->hic)
1002 if (LOWORD(wparam) == IDC_CONFIGURE)
1003 ICConfigure(ic->hic, hdlg);
1004 else
1005 ICAbout(ic->hic, hdlg);
1008 break;
1011 case IDOK:
1013 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1014 INT cur_sel;
1015 struct codec_info *ic;
1017 if (HIWORD(wparam) != BN_CLICKED)
1018 break;
1020 cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
1021 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
1022 if (ic)
1024 struct choose_compressor *choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
1026 choose_comp->cv.hic = ic->hic;
1027 choose_comp->cv.fccType = ic->icinfo.fccType;
1028 choose_comp->cv.fccHandler = ic->icinfo.fccHandler;
1029 /* FIXME: fill everything else */
1031 /* prevent closing the codec handle below */
1032 ic->hic = 0;
1035 /* fall through */
1036 case IDCANCEL:
1038 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1039 INT idx = 0;
1041 if (HIWORD(wparam) != BN_CLICKED)
1042 break;
1044 while (1)
1046 struct codec_info *ic;
1048 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, idx++, 0);
1050 if (!ic || (LONG_PTR)ic == CB_ERR) break;
1052 if (ic->hic) ICClose(ic->hic);
1053 HeapFree(GetProcessHeap(), 0, ic);
1056 EndDialog(hdlg, LOWORD(wparam) == IDOK);
1057 break;
1060 default:
1061 break;
1063 break;
1065 default:
1066 break;
1069 return FALSE;
1072 /***********************************************************************
1073 * ICCompressorChoose [MSVFW32.@]
1075 BOOL VFWAPI ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn,
1076 LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle)
1078 struct choose_compressor choose_comp;
1079 BOOL ret;
1081 TRACE("(%p,%08x,%p,%p,%p,%s)\n", hwnd, uiFlags, pvIn, lpData, pc, lpszTitle);
1083 if (!pc || pc->cbSize != sizeof(COMPVARS))
1084 return FALSE;
1086 if (!(pc->dwFlags & ICMF_COMPVARS_VALID))
1088 pc->dwFlags = 0;
1089 pc->fccType = pc->fccHandler = 0;
1090 pc->hic = NULL;
1091 pc->lpbiIn = NULL;
1092 pc->lpbiOut = NULL;
1093 pc->lpBitsOut = pc->lpBitsPrev = pc->lpState = NULL;
1094 pc->lQ = ICQUALITY_DEFAULT;
1095 pc->lKey = -1;
1096 pc->lDataRate = 300; /* kB */
1097 pc->lpState = NULL;
1098 pc->cbState = 0;
1100 if (pc->fccType == 0)
1101 pc->fccType = ICTYPE_VIDEO;
1103 choose_comp.cv = *pc;
1104 choose_comp.flags = uiFlags;
1105 choose_comp.title = lpszTitle;
1107 ret = DialogBoxParamW(MSVFW32_hModule, MAKEINTRESOURCEW(ICM_CHOOSE_COMPRESSOR), hwnd,
1108 icm_choose_compressor_dlgproc, (LPARAM)&choose_comp);
1110 if (ret)
1112 *pc = choose_comp.cv;
1113 pc->dwFlags |= ICMF_COMPVARS_VALID;
1116 return ret;
1120 /***********************************************************************
1121 * ICCompressorFree [MSVFW32.@]
1123 void VFWAPI ICCompressorFree(PCOMPVARS pc)
1125 TRACE("(%p)\n",pc);
1127 if (pc != NULL && pc->cbSize == sizeof(COMPVARS)) {
1128 if (pc->hic != NULL) {
1129 ICClose(pc->hic);
1130 pc->hic = NULL;
1132 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1133 pc->lpbiIn = NULL;
1134 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1135 pc->lpBitsOut = NULL;
1136 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1137 pc->lpBitsPrev = NULL;
1138 HeapFree(GetProcessHeap(), 0, pc->lpState);
1139 pc->lpState = NULL;
1140 pc->dwFlags = 0;
1144 /***********************************************************************
1145 * ICSendMessage [MSVFW32.@]
1147 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
1149 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1151 if (!whic) return ICERR_BADHANDLE;
1152 return MSVIDEO_SendMessage(whic, msg, lParam1, lParam2);
1155 /***********************************************************************
1156 * ICDrawBegin [MSVFW32.@]
1158 DWORD VFWAPIV ICDrawBegin(
1159 HIC hic, /* [in] */
1160 DWORD dwFlags, /* [in] flags */
1161 HPALETTE hpal, /* [in] palette to draw with */
1162 HWND hwnd, /* [in] window to draw to */
1163 HDC hdc, /* [in] HDC to draw to */
1164 INT xDst, /* [in] destination rectangle */
1165 INT yDst, /* [in] */
1166 INT dxDst, /* [in] */
1167 INT dyDst, /* [in] */
1168 LPBITMAPINFOHEADER lpbi, /* [in] format of frame to draw */
1169 INT xSrc, /* [in] source rectangle */
1170 INT ySrc, /* [in] */
1171 INT dxSrc, /* [in] */
1172 INT dySrc, /* [in] */
1173 DWORD dwRate, /* [in] frames/second = (dwRate/dwScale) */
1174 DWORD dwScale) /* [in] */
1177 ICDRAWBEGIN icdb;
1179 TRACE("(%p,%d,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%d,%d)\n",
1180 hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
1181 lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
1183 icdb.dwFlags = dwFlags;
1184 icdb.hpal = hpal;
1185 icdb.hwnd = hwnd;
1186 icdb.hdc = hdc;
1187 icdb.xDst = xDst;
1188 icdb.yDst = yDst;
1189 icdb.dxDst = dxDst;
1190 icdb.dyDst = dyDst;
1191 icdb.lpbi = lpbi;
1192 icdb.xSrc = xSrc;
1193 icdb.ySrc = ySrc;
1194 icdb.dxSrc = dxSrc;
1195 icdb.dySrc = dySrc;
1196 icdb.dwRate = dwRate;
1197 icdb.dwScale = dwScale;
1198 return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD_PTR)&icdb,sizeof(icdb));
1201 /***********************************************************************
1202 * ICDraw [MSVFW32.@]
1204 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
1205 ICDRAW icd;
1207 TRACE("(%p,%d,%p,%p,%d,%d)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
1209 icd.dwFlags = dwFlags;
1210 icd.lpFormat = lpFormat;
1211 icd.lpData = lpData;
1212 icd.cbData = cbData;
1213 icd.lTime = lTime;
1215 return ICSendMessage(hic,ICM_DRAW,(DWORD_PTR)&icd,sizeof(icd));
1218 /***********************************************************************
1219 * ICClose [MSVFW32.@]
1221 LRESULT WINAPI ICClose(HIC hic)
1223 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1224 WINE_HIC** p;
1226 TRACE("(%p)\n",hic);
1228 if (!whic) return ICERR_BADHANDLE;
1230 if (whic->driverproc)
1232 MSVIDEO_SendMessage(whic, DRV_CLOSE, 0, 0);
1233 MSVIDEO_SendMessage(whic, DRV_DISABLE, 0, 0);
1234 MSVIDEO_SendMessage(whic, DRV_FREE, 0, 0);
1236 else
1238 CloseDriver(whic->hdrv, 0, 0);
1241 /* remove whic from list */
1242 for (p = &MSVIDEO_FirstHic; *p != NULL; p = &((*p)->next))
1244 if ((*p) == whic)
1246 *p = whic->next;
1247 break;
1251 HeapFree(GetProcessHeap(), 0, whic);
1252 return 0;
1257 /***********************************************************************
1258 * ICImageCompress [MSVFW32.@]
1260 HANDLE VFWAPI ICImageCompress(
1261 HIC hic, UINT uiFlags,
1262 LPBITMAPINFO lpbiIn, LPVOID lpBits,
1263 LPBITMAPINFO lpbiOut, LONG lQuality,
1264 LONG* plSize)
1266 FIXME("(%p,%08x,%p,%p,%p,%d,%p)\n",
1267 hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
1269 return NULL;
1272 /***********************************************************************
1273 * ICImageDecompress [MSVFW32.@]
1276 HANDLE VFWAPI ICImageDecompress(
1277 HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
1278 LPVOID lpBits, LPBITMAPINFO lpbiOut)
1280 HGLOBAL hMem = NULL;
1281 BYTE* pMem = NULL;
1282 BOOL bReleaseIC = FALSE;
1283 BYTE* pHdr = NULL;
1284 ULONG cbHdr = 0;
1285 BOOL bSucceeded = FALSE;
1286 BOOL bInDecompress = FALSE;
1287 DWORD biSizeImage;
1289 TRACE("(%p,%08x,%p,%p,%p)\n",
1290 hic, uiFlags, lpbiIn, lpBits, lpbiOut);
1292 if ( hic == NULL )
1294 hic = ICDecompressOpen( ICTYPE_VIDEO, 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
1295 if ( hic == NULL )
1297 WARN("no handler\n" );
1298 goto err;
1300 bReleaseIC = TRUE;
1302 if ( uiFlags != 0 )
1304 FIXME( "unknown flag %08x\n", uiFlags );
1305 goto err;
1307 if ( lpbiIn == NULL || lpBits == NULL )
1309 WARN("invalid argument\n");
1310 goto err;
1313 if ( lpbiOut != NULL )
1315 if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
1316 goto err;
1317 cbHdr = sizeof(BITMAPINFOHEADER);
1318 if ( lpbiOut->bmiHeader.biCompression == 3 )
1319 cbHdr += sizeof(DWORD)*3;
1320 else
1321 if ( lpbiOut->bmiHeader.biBitCount <= 8 )
1323 if ( lpbiOut->bmiHeader.biClrUsed == 0 )
1324 cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
1325 else
1326 cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
1329 else
1331 TRACE( "get format\n" );
1333 cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
1334 if ( cbHdr < sizeof(BITMAPINFOHEADER) )
1335 goto err;
1336 pHdr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,cbHdr+sizeof(RGBQUAD)*256);
1337 if ( pHdr == NULL )
1338 goto err;
1339 if ( ICDecompressGetFormat( hic, lpbiIn, pHdr ) != ICERR_OK )
1340 goto err;
1341 lpbiOut = (BITMAPINFO*)pHdr;
1342 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1343 ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
1344 lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
1346 if ( lpbiIn->bmiHeader.biClrUsed == 0 )
1347 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
1348 else
1349 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
1351 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1352 lpbiOut->bmiHeader.biClrUsed == 0 )
1353 lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
1355 lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1356 cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
1359 biSizeImage = lpbiOut->bmiHeader.biSizeImage;
1360 if ( biSizeImage == 0 )
1361 biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
1363 TRACE( "call ICDecompressBegin\n" );
1365 if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
1366 goto err;
1367 bInDecompress = TRUE;
1369 TRACE( "cbHdr %d, biSizeImage %d\n", cbHdr, biSizeImage );
1371 hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
1372 if ( hMem == NULL )
1374 WARN( "out of memory\n" );
1375 goto err;
1377 pMem = GlobalLock( hMem );
1378 if ( pMem == NULL )
1379 goto err;
1380 memcpy( pMem, lpbiOut, cbHdr );
1382 TRACE( "call ICDecompress\n" );
1383 if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
1384 goto err;
1386 bSucceeded = TRUE;
1387 err:
1388 if ( bInDecompress )
1389 ICDecompressEnd( hic );
1390 if ( bReleaseIC )
1391 ICClose(hic);
1392 HeapFree(GetProcessHeap(),0,pHdr);
1393 if ( pMem != NULL )
1394 GlobalUnlock( hMem );
1395 if ( !bSucceeded && hMem != NULL )
1397 GlobalFree(hMem); hMem = NULL;
1400 return hMem;
1403 /***********************************************************************
1404 * ICSeqCompressFrame [MSVFW32.@]
1406 LPVOID VFWAPI ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL *pfKey, LONG *plSize)
1408 ICCOMPRESS* icComp = pc->lpState;
1409 DWORD ret;
1410 TRACE("(%p, 0x%08x, %p, %p, %p)\n", pc, uiFlags, lpBits, pfKey, plSize);
1412 if (pc->cbState != sizeof(ICCOMPRESS))
1414 ERR("Invalid cbState %i\n", pc->cbState);
1415 return NULL;
1418 if (!pc->lKeyCount++)
1419 icComp->dwFlags = ICCOMPRESS_KEYFRAME;
1420 else
1422 if (pc->lKey && pc->lKeyCount == (pc->lKey - 1))
1423 /* No key frames if pc->lKey == 0 */
1424 pc->lKeyCount = 0;
1425 icComp->dwFlags = 0;
1428 icComp->lpInput = lpBits;
1429 icComp->lFrameNum = pc->lFrame++;
1430 icComp->lpOutput = pc->lpBitsOut;
1431 icComp->lpPrev = pc->lpBitsPrev;
1432 ret = ICSendMessage(pc->hic, ICM_COMPRESS, (DWORD_PTR)icComp, sizeof(*icComp));
1434 if (ret == ICERR_OK)
1436 LPVOID oldprev, oldout;
1438 if (icComp->dwFlags & AVIIF_KEYFRAME)
1440 pc->lKeyCount = 1;
1441 *pfKey = TRUE;
1442 TRACE("Key frame\n");
1444 else
1445 *pfKey = FALSE;
1447 *plSize = icComp->lpbiOutput->biSizeImage;
1449 /* We shift Prev and Out, so we don't have to allocate and release memory */
1450 oldprev = pc->lpBitsPrev;
1451 oldout = pc->lpBitsOut;
1452 pc->lpBitsPrev = oldout;
1453 pc->lpBitsOut = oldprev;
1455 TRACE("returning: %p, compressed frame size %u\n", icComp->lpOutput, *plSize);
1456 return icComp->lpOutput;
1458 return NULL;
1461 static void clear_compvars(PCOMPVARS pc)
1463 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1464 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1465 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1466 HeapFree(GetProcessHeap(), 0, pc->lpState);
1467 pc->lpbiIn = pc->lpBitsPrev = pc->lpBitsOut = pc->lpState = NULL;
1468 if (pc->dwFlags & 0x80000000)
1470 HeapFree(GetProcessHeap(), 0, pc->lpbiOut);
1471 pc->lpbiOut = NULL;
1472 pc->dwFlags &= ~0x80000000;
1476 /***********************************************************************
1477 * ICSeqCompressFrameEnd [MSVFW32.@]
1479 void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
1481 TRACE("(%p)\n", pc);
1482 ICSendMessage(pc->hic, ICM_COMPRESS_END, 0, 0);
1483 clear_compvars(pc);
1486 /***********************************************************************
1487 * ICSeqCompressFrameStart [MSVFW32.@]
1489 BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
1491 /* I'm ignoring bmiColors as I don't know what to do with it,
1492 * it doesn't appear to be used though
1494 DWORD ret;
1495 ICCOMPRESS* icComp;
1496 pc->lpbiIn = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFO));
1497 if (!pc->lpbiIn)
1498 return FALSE;
1500 *pc->lpbiIn = *lpbiIn;
1502 pc->lpState = HeapAlloc(GetProcessHeap(), 0, sizeof(ICCOMPRESS)
1503 + sizeof(*icComp->lpckid) + sizeof(*icComp->lpdwFlags));
1504 if (!pc->lpState)
1505 goto error;
1507 pc->cbState = sizeof(ICCOMPRESS);
1509 if (!pc->lpbiOut)
1511 /* Ask compressor for needed header size */
1512 int size = ICSendMessage(pc->hic, ICM_COMPRESS_GET_FORMAT,
1513 (DWORD_PTR)pc->lpbiIn, 0);
1514 if (size <= 0)
1515 goto error;
1517 pc->lpbiOut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1518 if (!pc->lpbiOut)
1519 goto error;
1520 /* Flag to show that we allocated lpbiOut for proper cleanup */
1521 pc->dwFlags |= 0x80000000;
1523 ret = ICSendMessage(pc->hic, ICM_COMPRESS_GET_FORMAT,
1524 (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1525 if (ret != ICERR_OK)
1527 ERR("Could not get output format from compressor\n");
1528 goto error;
1530 if (!pc->lpbiOut->bmiHeader.biSizeImage)
1532 /* If we can't know the output frame size for sure at least allocate
1533 * the same size of the input frame and also at least 8Kb to be sure
1534 * that poor compressors will have enough memory to work if the input
1535 * frame is too small.
1537 pc->lpbiOut->bmiHeader.biSizeImage = max(8192, pc->lpbiIn->bmiHeader.biSizeImage);
1538 ERR("Bad codec! Invalid output frame size, guessing from input\n");
1542 TRACE("Input: %ux%u, fcc %s, bpp %u, size %u\n",
1543 pc->lpbiIn->bmiHeader.biWidth, pc->lpbiIn->bmiHeader.biHeight,
1544 wine_dbgstr_fcc(pc->lpbiIn->bmiHeader.biCompression),
1545 pc->lpbiIn->bmiHeader.biBitCount,
1546 pc->lpbiIn->bmiHeader.biSizeImage);
1547 TRACE("Output: %ux%u, fcc %s, bpp %u, size %u\n",
1548 pc->lpbiOut->bmiHeader.biWidth, pc->lpbiOut->bmiHeader.biHeight,
1549 wine_dbgstr_fcc(pc->lpbiOut->bmiHeader.biCompression),
1550 pc->lpbiOut->bmiHeader.biBitCount,
1551 pc->lpbiOut->bmiHeader.biSizeImage);
1553 /* Buffer for compressed frame data */
1554 pc->lpBitsOut = HeapAlloc(GetProcessHeap(), 0, pc->lpbiOut->bmiHeader.biSizeImage);
1555 if (!pc->lpBitsOut)
1556 goto error;
1558 /* Buffer for previous compressed frame data */
1559 pc->lpBitsPrev = HeapAlloc(GetProcessHeap(), 0, pc->lpbiOut->bmiHeader.biSizeImage);
1560 if (!pc->lpBitsPrev)
1561 goto error;
1563 TRACE("Compvars:\n"
1564 "\tsize: %i\n"
1565 "\tflags: 0x%x\n"
1566 "\thic: %p\n"
1567 "\ttype: %s\n"
1568 "\thandler: %s\n"
1569 "\tin/out: %p/%p\n"
1570 "\tkey/data/quality: %i/%i/%i\n",
1571 pc->cbSize, pc->dwFlags, pc->hic, wine_dbgstr_fcc(pc->fccType),
1572 wine_dbgstr_fcc(pc->fccHandler), pc->lpbiIn, pc->lpbiOut, pc->lKey,
1573 pc->lDataRate, pc->lQ);
1575 ret = ICSendMessage(pc->hic, ICM_COMPRESS_BEGIN, (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1576 if (ret == ICERR_OK)
1578 icComp = pc->lpState;
1579 /* Initialise some variables */
1580 pc->lFrame = 0; pc->lKeyCount = 0;
1582 icComp->lpbiOutput = &pc->lpbiOut->bmiHeader;
1583 icComp->lpbiInput = &pc->lpbiIn->bmiHeader;
1584 icComp->lpckid = (DWORD *)(icComp + 1);
1585 *icComp->lpckid = 0;
1586 icComp->lpdwFlags = (DWORD *)((char *)(icComp + 1) + sizeof(*icComp->lpckid));
1587 *icComp->lpdwFlags = 0;
1588 icComp->dwFrameSize = 0;
1589 icComp->dwQuality = pc->lQ;
1590 icComp->lpbiPrev = &pc->lpbiIn->bmiHeader;
1591 return TRUE;
1593 error:
1594 clear_compvars(pc);
1595 return FALSE;
1598 /***********************************************************************
1599 * GetFileNamePreview [MSVFW32.@]
1601 static BOOL GetFileNamePreview(LPVOID lpofn,BOOL bSave,BOOL bUnicode)
1603 CHAR szFunctionName[20];
1604 BOOL (*fnGetFileName)(LPVOID);
1605 HMODULE hComdlg32;
1606 BOOL ret;
1608 FIXME("(%p,%d,%d), semi-stub!\n",lpofn,bSave,bUnicode);
1610 lstrcpyA(szFunctionName, (bSave ? "GetSaveFileName" : "GetOpenFileName"));
1611 lstrcatA(szFunctionName, (bUnicode ? "W" : "A"));
1613 hComdlg32 = LoadLibraryA("COMDLG32.DLL");
1614 if (hComdlg32 == NULL)
1615 return FALSE;
1617 fnGetFileName = (LPVOID)GetProcAddress(hComdlg32, szFunctionName);
1618 if (fnGetFileName == NULL)
1620 FreeLibrary(hComdlg32);
1621 return FALSE;
1624 /* FIXME: need to add OFN_ENABLEHOOK and our own handler */
1625 ret = fnGetFileName(lpofn);
1627 FreeLibrary(hComdlg32);
1628 return ret;
1631 /***********************************************************************
1632 * GetOpenFileNamePreviewA [MSVFW32.@]
1634 BOOL WINAPI GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn)
1636 FIXME("(%p), semi-stub!\n", lpofn);
1638 return GetFileNamePreview(lpofn, FALSE, FALSE);
1641 /***********************************************************************
1642 * GetOpenFileNamePreviewW [MSVFW32.@]
1644 BOOL WINAPI GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn)
1646 FIXME("(%p), semi-stub!\n", lpofn);
1648 return GetFileNamePreview(lpofn, FALSE, TRUE);
1651 /***********************************************************************
1652 * GetSaveFileNamePreviewA [MSVFW32.@]
1654 BOOL WINAPI GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn)
1656 FIXME("(%p), semi-stub!\n", lpofn);
1658 return GetFileNamePreview(lpofn, TRUE, FALSE);
1661 /***********************************************************************
1662 * GetSaveFileNamePreviewW [MSVFW32.@]
1664 BOOL WINAPI GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn)
1666 FIXME("(%p), semi-stub!\n", lpofn);
1668 return GetFileNamePreview(lpofn, TRUE, TRUE);