Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / dll / win32 / msvfw32 / msvideo_main.c
1 /*
2 * Copyright 1998 Marcus Meissner
3 * Copyright 2000 Bradley Baetz
4 * Copyright 2003 Michael Günnewig
5 * Copyright 2005 Dmitry Timoshkov
6 *
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.
11 *
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.
16 *
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
20 *
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.
24 *
25 * TODO
26 * - no thread safety
27 */
28
29 #define WIN32_NO_STATUS
30 #define _INC_WINDOWS
31 #define COM_NO_WINDOWS_H
32
33 #include <stdarg.h>
34 //#include <stdio.h>
35 //#include <string.h>
36
37 #include <windef.h>
38 #include <winbase.h>
39 #include <winreg.h>
40 #include <winnls.h>
41 #include <wingdi.h>
42 #include <winuser.h>
43 #include <commdlg.h>
44 #include <vfw.h>
45 #include "msvideo_private.h"
46 #include <wine/debug.h>
47
48 /* Drivers32 settings */
49 #define HKLM_DRIVERS32 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
52
53 static inline const char *wine_dbgstr_fcc( DWORD fcc )
54 {
55 return wine_dbg_sprintf("%c%c%c%c",
56 LOBYTE(LOWORD(fcc)), HIBYTE(LOWORD(fcc)),
57 LOBYTE(HIWORD(fcc)), HIBYTE(HIWORD(fcc)));
58 }
59
60 static WINE_HIC* MSVIDEO_FirstHic /* = NULL */;
61
62 typedef struct _reg_driver reg_driver;
63 struct _reg_driver
64 {
65 DWORD fccType;
66 DWORD fccHandler;
67 DRIVERPROC proc;
68 LPWSTR name;
69 reg_driver* next;
70 };
71
72 static reg_driver* reg_driver_list = NULL;
73
74 /* This one is a macro such that it works for both ASCII and Unicode */
75 #define fourcc_to_string(str, fcc) do { \
76 (str)[0] = LOBYTE(LOWORD(fcc)); \
77 (str)[1] = HIBYTE(LOWORD(fcc)); \
78 (str)[2] = LOBYTE(HIWORD(fcc)); \
79 (str)[3] = HIBYTE(HIWORD(fcc)); \
80 } while(0)
81
82 HMODULE MSVFW32_hModule;
83
84 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
85 {
86 TRACE("%p,%x,%p\n", hinst, reason, reserved);
87
88 switch(reason)
89 {
90 case DLL_PROCESS_ATTACH:
91 DisableThreadLibraryCalls(hinst);
92 MSVFW32_hModule = hinst;
93 break;
94 }
95 return TRUE;
96 }
97
98 /******************************************************************
99 * MSVIDEO_SendMessage
100 *
101 *
102 */
103 static LRESULT MSVIDEO_SendMessage(WINE_HIC* whic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
104 {
105 LRESULT ret;
106
107 #define XX(x) case x: TRACE("(%p,"#x",0x%08lx,0x%08lx)\n",whic,lParam1,lParam2); break
108
109 switch (msg) {
110 /* DRV_* */
111 XX(DRV_LOAD);
112 XX(DRV_ENABLE);
113 XX(DRV_OPEN);
114 XX(DRV_CLOSE);
115 XX(DRV_DISABLE);
116 XX(DRV_FREE);
117 /* ICM_RESERVED+X */
118 XX(ICM_ABOUT);
119 XX(ICM_CONFIGURE);
120 XX(ICM_GET);
121 XX(ICM_GETINFO);
122 XX(ICM_GETDEFAULTQUALITY);
123 XX(ICM_GETQUALITY);
124 XX(ICM_GETSTATE);
125 XX(ICM_SETQUALITY);
126 XX(ICM_SET);
127 XX(ICM_SETSTATE);
128 /* ICM_USER+X */
129 XX(ICM_COMPRESS_FRAMES_INFO);
130 XX(ICM_COMPRESS_GET_FORMAT);
131 XX(ICM_COMPRESS_GET_SIZE);
132 XX(ICM_COMPRESS_QUERY);
133 XX(ICM_COMPRESS_BEGIN);
134 XX(ICM_COMPRESS);
135 XX(ICM_COMPRESS_END);
136 XX(ICM_DECOMPRESS_GET_FORMAT);
137 XX(ICM_DECOMPRESS_QUERY);
138 XX(ICM_DECOMPRESS_BEGIN);
139 XX(ICM_DECOMPRESS);
140 XX(ICM_DECOMPRESS_END);
141 XX(ICM_DECOMPRESS_SET_PALETTE);
142 XX(ICM_DECOMPRESS_GET_PALETTE);
143 XX(ICM_DRAW_QUERY);
144 XX(ICM_DRAW_BEGIN);
145 XX(ICM_DRAW_GET_PALETTE);
146 XX(ICM_DRAW_START);
147 XX(ICM_DRAW_STOP);
148 XX(ICM_DRAW_END);
149 XX(ICM_DRAW_GETTIME);
150 XX(ICM_DRAW);
151 XX(ICM_DRAW_WINDOW);
152 XX(ICM_DRAW_SETTIME);
153 XX(ICM_DRAW_REALIZE);
154 XX(ICM_DRAW_FLUSH);
155 XX(ICM_DRAW_RENDERBUFFER);
156 XX(ICM_DRAW_START_PLAY);
157 XX(ICM_DRAW_STOP_PLAY);
158 XX(ICM_DRAW_SUGGESTFORMAT);
159 XX(ICM_DRAW_CHANGEPALETTE);
160 XX(ICM_GETBUFFERSWANTED);
161 XX(ICM_GETDEFAULTKEYFRAMERATE);
162 XX(ICM_DECOMPRESSEX_BEGIN);
163 XX(ICM_DECOMPRESSEX_QUERY);
164 XX(ICM_DECOMPRESSEX);
165 XX(ICM_DECOMPRESSEX_END);
166 XX(ICM_SET_STATUS_PROC);
167 default:
168 FIXME("(%p,0x%08x,0x%08lx,0x%08lx) unknown message\n",whic,msg,lParam1,lParam2);
169 }
170
171 #undef XX
172
173 if (whic->driverproc) {
174 /* dwDriverId parameter is the value returned by the DRV_OPEN */
175 ret = whic->driverproc(whic->driverId, whic->hdrv, msg, lParam1, lParam2);
176 } else {
177 ret = SendDriverMessage(whic->hdrv, msg, lParam1, lParam2);
178 }
179
180 TRACE(" -> 0x%08lx\n", ret);
181 return ret;
182 }
183
184 static int compare_fourcc(DWORD fcc1, DWORD fcc2)
185 {
186 char fcc_str1[4];
187 char fcc_str2[4];
188 fourcc_to_string(fcc_str1, fcc1);
189 fourcc_to_string(fcc_str2, fcc2);
190 return strncasecmp(fcc_str1, fcc_str2, 4);
191 }
192
193 typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*);
194
195 static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
196 {
197 CHAR buf[2048], fccTypeStr[5], *s;
198 DWORD i, cnt = 0, lRet;
199 BOOL result = FALSE;
200 HKEY hKey;
201
202 fourcc_to_string(fccTypeStr, fccType);
203 fccTypeStr[4] = '.';
204
205 /* first, go through the registry entries */
206 lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey);
207 if (lRet == ERROR_SUCCESS)
208 {
209 DWORD name, data, type;
210 i = 0;
211 for (;;)
212 {
213 name = 10;
214 data = sizeof buf - name;
215 lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data);
216 if (lRet == ERROR_NO_MORE_ITEMS) break;
217 if (lRet != ERROR_SUCCESS) continue;
218 if (name != 9 || strncasecmp(buf, fccTypeStr, 5)) continue;
219 buf[name] = '=';
220 if ((result = handler(buf, cnt++, param))) break;
221 }
222 RegCloseKey( hKey );
223 }
224 if (result) return result;
225
226 /* if that didn't work, go through the values in system.ini */
227 if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini"))
228 {
229 for (s = buf; *s; s += strlen(s) + 1)
230 {
231 TRACE("got %s\n", s);
232 if (strncasecmp(s, fccTypeStr, 5) || s[9] != '=') continue;
233 if ((result = handler(s, cnt++, param))) break;
234 }
235 }
236
237 return result;
238 }
239
240 /******************************************************************
241 * MSVIDEO_GetHicPtr
242 *
243 *
244 */
245 static WINE_HIC* MSVIDEO_GetHicPtr(HIC hic)
246 {
247 WINE_HIC* whic;
248
249 for (whic = MSVIDEO_FirstHic; whic && whic->hic != hic; whic = whic->next);
250 return whic;
251 }
252
253 /***********************************************************************
254 * VideoForWindowsVersion [MSVFW32.2]
255 * VideoForWindowsVersion [MSVIDEO.2]
256 * Returns the version in major.minor form.
257 * In Windows95 this returns 0x040003b6 (4.950)
258 */
259 DWORD WINAPI VideoForWindowsVersion(void)
260 {
261 return 0x040003B6; /* 4.950 */
262 }
263
264 static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
265 {
266 ICINFO *lpicinfo = param;
267 DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0);
268
269 /* exact match of fccHandler or nth driver found */
270 if ((lpicinfo->fccHandler != nr) && (lpicinfo->fccHandler != fccHandler))
271 return FALSE;
272
273 lpicinfo->fccHandler = fccHandler;
274 lpicinfo->dwFlags = 0;
275 lpicinfo->dwVersion = 0;
276 lpicinfo->dwVersionICM = ICVERSION;
277 lpicinfo->szName[0] = 0;
278 lpicinfo->szDescription[0] = 0;
279 MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver,
280 sizeof(lpicinfo->szDriver)/sizeof(WCHAR));
281
282 return TRUE;
283 }
284
285 /***********************************************************************
286 * ICInfo [MSVFW32.@]
287 * Get information about an installable compressor. Return TRUE if there
288 * is one.
289 *
290 * PARAMS
291 * fccType [I] type of compressor (e.g. 'vidc')
292 * fccHandler [I] real fcc for handler or <n>th compressor
293 * lpicinfo [O] information about compressor
294 */
295 BOOL VFWAPI ICInfo( DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo)
296 {
297 TRACE("(%s,%s/%08x,%p)\n",
298 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), fccHandler, lpicinfo);
299
300 lpicinfo->fccType = fccType;
301 lpicinfo->fccHandler = fccHandler;
302 return enum_drivers(fccType, ICInfo_enum_handler, lpicinfo);
303 }
304
305 static DWORD IC_HandleRef = 1;
306
307 /***********************************************************************
308 * ICInstall [MSVFW32.@]
309 */
310 BOOL VFWAPI ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags)
311 {
312 reg_driver* driver;
313 unsigned len;
314
315 TRACE("(%s,%s,%p,%p,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), (void*)lParam, szDesc, wFlags);
316
317 /* Check if a driver is already registered */
318 for (driver = reg_driver_list; driver; driver = driver->next)
319 {
320 if (!compare_fourcc(fccType, driver->fccType) &&
321 !compare_fourcc(fccHandler, driver->fccHandler))
322 break;
323 }
324 if (driver) return FALSE;
325
326 /* Register the driver */
327 driver = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(reg_driver));
328 if (!driver) goto oom;
329 driver->fccType = fccType;
330 driver->fccHandler = fccHandler;
331
332 switch(wFlags)
333 {
334 case ICINSTALL_FUNCTION:
335 driver->proc = (DRIVERPROC)lParam;
336 driver->name = NULL;
337 break;
338 case ICINSTALL_DRIVER:
339 driver->proc = NULL;
340 len = MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, NULL, 0);
341 driver->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
342 if (!driver->name) goto oom;
343 MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, driver->name, len);
344 break;
345 default:
346 ERR("Invalid flags!\n");
347 HeapFree(GetProcessHeap(), 0, driver);
348 return FALSE;
349 }
350
351 /* Insert our driver in the list*/
352 driver->next = reg_driver_list;
353 reg_driver_list = driver;
354
355 return TRUE;
356 oom:
357 HeapFree(GetProcessHeap(), 0, driver);
358 return FALSE;
359 }
360
361 /***********************************************************************
362 * ICRemove [MSVFW32.@]
363 */
364 BOOL VFWAPI ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags)
365 {
366 reg_driver** pdriver;
367 reg_driver* drv;
368
369 TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wFlags);
370
371 /* Check if a driver is already registered */
372 for (pdriver = &reg_driver_list; *pdriver; pdriver = &(*pdriver)->next)
373 {
374 if (!compare_fourcc(fccType, (*pdriver)->fccType) &&
375 !compare_fourcc(fccHandler, (*pdriver)->fccHandler))
376 break;
377 }
378 if (!*pdriver)
379 return FALSE;
380
381 /* Remove the driver from the list */
382 drv = *pdriver;
383 *pdriver = (*pdriver)->next;
384 HeapFree(GetProcessHeap(), 0, drv->name);
385 HeapFree(GetProcessHeap(), 0, drv);
386
387 return TRUE;
388 }
389
390
391 /***********************************************************************
392 * ICOpen [MSVFW32.@]
393 * Opens an installable compressor. Return special handle.
394 */
395 HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode)
396 {
397 WCHAR codecname[10];
398 ICOPEN icopen;
399 HDRVR hdrv;
400 WINE_HIC* whic;
401 static const WCHAR drv32W[] = {'d','r','i','v','e','r','s','3','2','\0'};
402 reg_driver* driver;
403
404 TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode);
405
406 /* Check if there is a registered driver that matches */
407 driver = reg_driver_list;
408 while(driver)
409 if (!compare_fourcc(fccType, driver->fccType) &&
410 !compare_fourcc(fccHandler, driver->fccHandler))
411 break;
412 else
413 driver = driver->next;
414
415 if (driver && driver->proc)
416 /* The driver has been registered at runtime with its driverproc */
417 return ICOpenFunction(fccType, fccHandler, wMode, driver->proc);
418
419 /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
420 * same layout as ICOPEN
421 */
422 icopen.dwSize = sizeof(ICOPEN);
423 icopen.fccType = fccType;
424 icopen.fccHandler = fccHandler;
425 icopen.dwVersion = 0x00001000; /* FIXME */
426 icopen.dwFlags = wMode;
427 icopen.dwError = 0;
428 icopen.pV1Reserved = NULL;
429 icopen.pV2Reserved = NULL;
430 icopen.dnDevNode = 0; /* FIXME */
431
432 if (!driver) {
433 /* The driver is registered in the registry */
434 fourcc_to_string(codecname, fccType);
435 codecname[4] = '.';
436 fourcc_to_string(codecname + 5, fccHandler);
437 codecname[9] = '\0';
438
439 hdrv = OpenDriver(codecname, drv32W, (LPARAM)&icopen);
440 if (!hdrv)
441 return 0;
442 } else {
443 /* The driver has been registered at runtime with its name */
444 hdrv = OpenDriver(driver->name, NULL, (LPARAM)&icopen);
445 if (!hdrv)
446 return 0;
447 }
448
449 whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
450 if (!whic)
451 {
452 CloseDriver(hdrv, 0, 0);
453 return FALSE;
454 }
455 whic->hdrv = hdrv;
456 whic->driverproc = NULL;
457 whic->type = fccType;
458 whic->handler = fccHandler;
459 while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
460 whic->hic = (HIC)(ULONG_PTR)IC_HandleRef++;
461 whic->next = MSVIDEO_FirstHic;
462 MSVIDEO_FirstHic = whic;
463
464 TRACE("=> %p\n", whic->hic);
465 return whic->hic;
466 }
467
468 /***********************************************************************
469 * ICOpenFunction [MSVFW32.@]
470 */
471 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, DRIVERPROC lpfnHandler)
472 {
473 ICOPEN icopen;
474 WINE_HIC* whic;
475
476 TRACE("(%s,%s,%d,%p)\n",
477 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode, lpfnHandler);
478
479 icopen.dwSize = sizeof(ICOPEN);
480 icopen.fccType = fccType;
481 icopen.fccHandler = fccHandler;
482 icopen.dwVersion = ICVERSION;
483 icopen.dwFlags = wMode;
484 icopen.dwError = 0;
485 icopen.pV1Reserved = NULL;
486 icopen.pV2Reserved = NULL;
487 icopen.dnDevNode = 0; /* FIXME */
488
489 whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
490 if (!whic) return 0;
491
492 whic->driverproc = lpfnHandler;
493 while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
494 whic->hic = (HIC)(ULONG_PTR)IC_HandleRef++;
495 whic->next = MSVIDEO_FirstHic;
496 MSVIDEO_FirstHic = whic;
497
498 /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
499 /* What if the function is used more than once? */
500
501 if (MSVIDEO_SendMessage(whic, DRV_LOAD, 0L, 0L) != DRV_SUCCESS)
502 {
503 WARN("DRV_LOAD failed for hic %p\n", whic->hic);
504 MSVIDEO_FirstHic = whic->next;
505 HeapFree(GetProcessHeap(), 0, whic);
506 return 0;
507 }
508 /* return value is not checked */
509 MSVIDEO_SendMessage(whic, DRV_ENABLE, 0L, 0L);
510
511 whic->driverId = (DWORD)MSVIDEO_SendMessage(whic, DRV_OPEN, 0, (DWORD_PTR)&icopen);
512 /* FIXME: What should we put here? */
513 whic->hdrv = NULL;
514
515 if (whic->driverId == 0)
516 {
517 WARN("DRV_OPEN failed for hic %p\n", whic->hic);
518 MSVIDEO_FirstHic = whic->next;
519 HeapFree(GetProcessHeap(), 0, whic);
520 return 0;
521 }
522
523 TRACE("=> %p\n", whic->hic);
524 return whic->hic;
525 }
526
527 /***********************************************************************
528 * ICGetInfo [MSVFW32.@]
529 */
530 LRESULT VFWAPI ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb)
531 {
532 LRESULT ret;
533 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
534
535 TRACE("(%p,%p,%d)\n", hic, picinfo, cb);
536
537 whic = MSVIDEO_GetHicPtr(hic);
538 if (!whic) return ICERR_BADHANDLE;
539 if (!picinfo) return MMSYSERR_INVALPARAM;
540
541 /* (WS) The field szDriver should be initialized because the driver
542 * is not obliged and often will not do it. Some applications, like
543 * VirtualDub, rely on this field and will occasionally crash if it
544 * goes uninitialized.
545 */
546 if (cb >= sizeof(ICINFO)) picinfo->szDriver[0] = '\0';
547
548 ret = ICSendMessage(hic, ICM_GETINFO, (DWORD_PTR)picinfo, cb);
549
550 /* (WS) When szDriver was not supplied by the driver itself, apparently
551 * Windows will set its value equal to the driver file name. This can
552 * be obtained from the registry as we do here.
553 */
554 if (cb >= sizeof(ICINFO) && picinfo->szDriver[0] == 0)
555 {
556 ICINFO ii;
557
558 memset(&ii, 0, sizeof(ii));
559 ii.dwSize = sizeof(ii);
560 ICInfo(picinfo->fccType, picinfo->fccHandler, &ii);
561 lstrcpyW(picinfo->szDriver, ii.szDriver);
562 }
563
564 TRACE(" -> 0x%08lx\n", ret);
565 return ret;
566 }
567
568 typedef struct {
569 DWORD fccType;
570 DWORD fccHandler;
571 LPBITMAPINFOHEADER lpbiIn;
572 LPBITMAPINFOHEADER lpbiOut;
573 WORD wMode;
574 DWORD querymsg;
575 HIC hic;
576 } driver_info_t;
577
578 static HIC try_driver(driver_info_t *info)
579 {
580 HIC hic;
581
582 if ((hic = ICOpen(info->fccType, info->fccHandler, info->wMode)))
583 {
584 if (!ICSendMessage(hic, info->querymsg, (DWORD_PTR)info->lpbiIn, (DWORD_PTR)info->lpbiOut))
585 return hic;
586 ICClose(hic);
587 }
588 return 0;
589 }
590
591 static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param)
592 {
593 driver_info_t *info = param;
594 info->fccHandler = mmioStringToFOURCCA(drv + 5, 0);
595 info->hic = try_driver(info);
596 return info->hic != 0;
597 }
598
599 /***********************************************************************
600 * ICLocate [MSVFW32.@]
601 */
602 HIC VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
603 LPBITMAPINFOHEADER lpbiOut, WORD wMode)
604 {
605 driver_info_t info;
606
607 TRACE("(%s,%s,%p,%p,0x%04x)\n",
608 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpbiIn, lpbiOut, wMode);
609
610 info.fccType = fccType;
611 info.fccHandler = fccHandler;
612 info.lpbiIn = lpbiIn;
613 info.lpbiOut = lpbiOut;
614 info.wMode = wMode;
615
616 switch (wMode)
617 {
618 case ICMODE_FASTCOMPRESS:
619 case ICMODE_COMPRESS:
620 info.querymsg = ICM_COMPRESS_QUERY;
621 break;
622 case ICMODE_FASTDECOMPRESS:
623 case ICMODE_DECOMPRESS:
624 info.querymsg = ICM_DECOMPRESS_QUERY;
625 break;
626 case ICMODE_DRAW:
627 info.querymsg = ICM_DRAW_QUERY;
628 break;
629 default:
630 WARN("Unknown mode (%d)\n", wMode);
631 return 0;
632 }
633
634 /* Easy case: handler/type match, we just fire a query and return */
635 info.hic = try_driver(&info);
636 /* If it didn't work, try each driver in turn. 32 bit codecs only. */
637 /* FIXME: Move this to an init routine? */
638 if (!info.hic) enum_drivers(fccType, ICLocate_enum_handler, &info);
639
640 if (info.hic)
641 {
642 TRACE("=> %p\n", info.hic);
643 return info.hic;
644 }
645
646 if (fccType == streamtypeVIDEO)
647 return ICLocate(ICTYPE_VIDEO, fccHandler, lpbiIn, lpbiOut, wMode);
648
649 WARN("(%s,%s,%p,%p,0x%04x) not found!\n",
650 wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpbiIn, lpbiOut, wMode);
651 return 0;
652 }
653
654 /***********************************************************************
655 * ICGetDisplayFormat [MSVFW32.@]
656 */
657 HIC VFWAPI ICGetDisplayFormat(
658 HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
659 INT depth,INT dx,INT dy)
660 {
661 HIC tmphic = hic;
662
663 TRACE("(%p,%p,%p,%d,%d,%d)!\n",hic,lpbiIn,lpbiOut,depth,dx,dy);
664
665 if (!tmphic) {
666 tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
667 if (!tmphic)
668 return tmphic;
669 }
670 if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
671 dy = dx = 0; /* no resize needed */
672
673 /* Can we decompress it ? */
674 if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
675 goto errout; /* no, sorry */
676
677 ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)lpbiIn, (DWORD_PTR)lpbiOut);
678
679 if (lpbiOut->biCompression != 0) {
680 FIXME("Ooch, how come decompressor outputs compressed data (%d)??\n",
681 lpbiOut->biCompression);
682 }
683 if (lpbiOut->biSize < sizeof(*lpbiOut)) {
684 FIXME("Ooch, size of output BIH is too small (%d)\n",
685 lpbiOut->biSize);
686 lpbiOut->biSize = sizeof(*lpbiOut);
687 }
688 if (!depth) {
689 HDC hdc;
690
691 hdc = GetDC(0);
692 depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
693 ReleaseDC(0,hdc);
694 if (depth==15) depth = 16;
695 if (depth<8) depth = 8;
696 }
697 if (lpbiIn->biBitCount == 8)
698 depth = 8;
699
700 TRACE("=> %p\n", tmphic);
701 return tmphic;
702 errout:
703 if (hic!=tmphic)
704 ICClose(tmphic);
705
706 TRACE("=> 0\n");
707 return 0;
708 }
709
710 /***********************************************************************
711 * ICCompress [MSVFW32.@]
712 */
713 DWORD VFWAPIV
714 ICCompress(
715 HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
716 LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
717 LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
718 LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
719 {
720 ICCOMPRESS iccmp;
721
722 TRACE("(%p,%d,%p,%p,%p,%p,...)\n",hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
723
724 iccmp.dwFlags = dwFlags;
725
726 iccmp.lpbiOutput = lpbiOutput;
727 iccmp.lpOutput = lpData;
728 iccmp.lpbiInput = lpbiInput;
729 iccmp.lpInput = lpBits;
730
731 iccmp.lpckid = lpckid;
732 iccmp.lpdwFlags = lpdwFlags;
733 iccmp.lFrameNum = lFrameNum;
734 iccmp.dwFrameSize = dwFrameSize;
735 iccmp.dwQuality = dwQuality;
736 iccmp.lpbiPrev = lpbiPrev;
737 iccmp.lpPrev = lpPrev;
738 return ICSendMessage(hic,ICM_COMPRESS,(DWORD_PTR)&iccmp,sizeof(iccmp));
739 }
740
741 /***********************************************************************
742 * ICDecompress [MSVFW32.@]
743 */
744 DWORD VFWAPIV ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
745 LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
746 {
747 ICDECOMPRESS icd;
748 DWORD ret;
749
750 TRACE("(%p,%d,%p,%p,%p,%p)\n",hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
751
752 icd.dwFlags = dwFlags;
753 icd.lpbiInput = lpbiFormat;
754 icd.lpInput = lpData;
755
756 icd.lpbiOutput = lpbi;
757 icd.lpOutput = lpBits;
758 icd.ckid = 0;
759 ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD_PTR)&icd,sizeof(ICDECOMPRESS));
760
761 TRACE("-> %d\n",ret);
762
763 return ret;
764 }
765
766
767 struct choose_compressor
768 {
769 UINT flags;
770 LPCSTR title;
771 COMPVARS cv;
772 };
773
774 struct codec_info
775 {
776 HIC hic;
777 ICINFO icinfo;
778 };
779
780 static BOOL enum_compressors(HWND list, COMPVARS *pcv, BOOL enum_all)
781 {
782 UINT id, total = 0;
783 ICINFO icinfo;
784
785 id = 0;
786
787 while (ICInfo(pcv->fccType, id, &icinfo))
788 {
789 struct codec_info *ic;
790 DWORD idx;
791 HIC hic;
792
793 id++;
794
795 hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
796
797 if (hic)
798 {
799 /* for unknown reason fccHandler reported by the driver
800 * doesn't always work, use the one returned by ICInfo instead.
801 */
802 DWORD fccHandler = icinfo.fccHandler;
803
804 if (!enum_all && pcv->lpbiIn)
805 {
806 if (ICCompressQuery(hic, pcv->lpbiIn, NULL) != ICERR_OK)
807 {
808 TRACE("fccHandler %s doesn't support input DIB format %d\n",
809 wine_dbgstr_fcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression);
810 ICClose(hic);
811 continue;
812 }
813 }
814
815 ICGetInfo(hic, &icinfo, sizeof(icinfo));
816 icinfo.fccHandler = fccHandler;
817
818 idx = SendMessageW(list, CB_ADDSTRING, 0, (LPARAM)icinfo.szDescription);
819
820 ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
821 ic->icinfo = icinfo;
822 ic->hic = hic;
823 SendMessageW(list, CB_SETITEMDATA, idx, (LPARAM)ic);
824 }
825 total++;
826 }
827
828 return total != 0;
829 }
830
831 static INT_PTR CALLBACK icm_choose_compressor_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
832 {
833 switch (msg)
834 {
835 case WM_INITDIALOG:
836 {
837 struct codec_info *ic;
838 WCHAR buf[128];
839 struct choose_compressor *choose_comp = (struct choose_compressor *)lparam;
840
841 SetWindowLongPtrW(hdlg, DWLP_USER, lparam);
842
843 /* FIXME */
844 choose_comp->flags &= ~(ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME);
845
846 if (choose_comp->title)
847 SetWindowTextA(hdlg, choose_comp->title);
848
849 if (!(choose_comp->flags & ICMF_CHOOSE_DATARATE))
850 {
851 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_CHECKBOX), SW_HIDE);
852 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE), SW_HIDE);
853 ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_KB), SW_HIDE);
854 }
855
856 if (!(choose_comp->flags & ICMF_CHOOSE_KEYFRAME))
857 {
858 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_CHECKBOX), SW_HIDE);
859 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME), SW_HIDE);
860 ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_FRAMES), SW_HIDE);
861 }
862
863 /* FIXME */
864 EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_SCROLL), FALSE);
865 EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_TXT), FALSE);
866
867 /*if (!(choose_comp->flags & ICMF_CHOOSE_PREVIEW))
868 ShowWindow(GetDlgItem(hdlg, IDC_PREVIEW), SW_HIDE);*/
869
870 LoadStringW(MSVFW32_hModule, IDS_FULLFRAMES, buf, 128);
871 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_ADDSTRING, 0, (LPARAM)buf);
872
873 ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
874 ic->icinfo.fccType = streamtypeVIDEO;
875 ic->icinfo.fccHandler = comptypeDIB;
876 ic->hic = 0;
877 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETITEMDATA, 0, (LPARAM)ic);
878
879 enum_compressors(GetDlgItem(hdlg, IDC_COMP_LIST), &choose_comp->cv, choose_comp->flags & ICMF_CHOOSE_ALLCOMPRESSORS);
880
881 SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETCURSEL, 0, 0);
882 SetFocus(GetDlgItem(hdlg, IDC_COMP_LIST));
883
884 SetWindowLongPtrW(hdlg, DWLP_USER, (ULONG_PTR)choose_comp);
885 break;
886 }
887
888 case WM_COMMAND:
889 switch (LOWORD(wparam))
890 {
891 case IDC_COMP_LIST:
892 {
893 INT cur_sel;
894 struct codec_info *ic;
895 BOOL can_configure = FALSE, can_about = FALSE;
896 struct choose_compressor *choose_comp;
897
898 if (HIWORD(wparam) != CBN_SELCHANGE && HIWORD(wparam) != CBN_SETFOCUS)
899 break;
900
901 choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
902
903 cur_sel = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
904
905 ic = (struct codec_info *)SendMessageW((HWND)lparam, CB_GETITEMDATA, cur_sel, 0);
906 if (ic && ic->hic)
907 {
908 if (ICQueryConfigure(ic->hic) == DRVCNF_OK)
909 can_configure = TRUE;
910 if (ICQueryAbout(ic->hic) == DRVCNF_OK)
911 can_about = TRUE;
912 }
913 EnableWindow(GetDlgItem(hdlg, IDC_CONFIGURE), can_configure);
914 EnableWindow(GetDlgItem(hdlg, IDC_ABOUT), can_about);
915
916 if (choose_comp->flags & ICMF_CHOOSE_DATARATE)
917 {
918 /* FIXME */
919 }
920 if (choose_comp->flags & ICMF_CHOOSE_KEYFRAME)
921 {
922 /* FIXME */
923 }
924
925 break;
926 }
927
928 case IDC_CONFIGURE:
929 case IDC_ABOUT:
930 {
931 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
932 INT cur_sel;
933 struct codec_info *ic;
934
935 if (HIWORD(wparam) != BN_CLICKED)
936 break;
937
938 cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
939
940 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
941 if (ic && ic->hic)
942 {
943 if (LOWORD(wparam) == IDC_CONFIGURE)
944 ICConfigure(ic->hic, hdlg);
945 else
946 ICAbout(ic->hic, hdlg);
947 }
948
949 break;
950 }
951
952 case IDOK:
953 {
954 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
955 INT cur_sel;
956 struct codec_info *ic;
957
958 if (HIWORD(wparam) != BN_CLICKED)
959 break;
960
961 cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
962 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
963 if (ic)
964 {
965 struct choose_compressor *choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
966
967 choose_comp->cv.hic = ic->hic;
968 choose_comp->cv.fccType = ic->icinfo.fccType;
969 choose_comp->cv.fccHandler = ic->icinfo.fccHandler;
970 /* FIXME: fill everything else */
971
972 /* prevent closing the codec handle below */
973 ic->hic = 0;
974 }
975 }
976 /* fall through */
977 case IDCANCEL:
978 {
979 HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
980 INT idx = 0;
981
982 if (HIWORD(wparam) != BN_CLICKED)
983 break;
984
985 while (1)
986 {
987 struct codec_info *ic;
988
989 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, idx++, 0);
990
991 if (!ic || (LONG_PTR)ic == CB_ERR) break;
992
993 if (ic->hic) ICClose(ic->hic);
994 HeapFree(GetProcessHeap(), 0, ic);
995 }
996
997 EndDialog(hdlg, LOWORD(wparam) == IDOK);
998 break;
999 }
1000
1001 default:
1002 break;
1003 }
1004 break;
1005
1006 default:
1007 break;
1008 }
1009
1010 return FALSE;
1011 }
1012
1013 /***********************************************************************
1014 * ICCompressorChoose [MSVFW32.@]
1015 */
1016 BOOL VFWAPI ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn,
1017 LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle)
1018 {
1019 struct choose_compressor choose_comp;
1020 BOOL ret;
1021
1022 TRACE("(%p,%08x,%p,%p,%p,%s)\n", hwnd, uiFlags, pvIn, lpData, pc, lpszTitle);
1023
1024 if (!pc || pc->cbSize != sizeof(COMPVARS))
1025 return FALSE;
1026
1027 if (!(pc->dwFlags & ICMF_COMPVARS_VALID))
1028 {
1029 pc->dwFlags = 0;
1030 pc->fccType = pc->fccHandler = 0;
1031 pc->hic = NULL;
1032 pc->lpbiIn = NULL;
1033 pc->lpbiOut = NULL;
1034 pc->lpBitsOut = pc->lpBitsPrev = pc->lpState = NULL;
1035 pc->lQ = ICQUALITY_DEFAULT;
1036 pc->lKey = -1;
1037 pc->lDataRate = 300; /* kB */
1038 pc->lpState = NULL;
1039 pc->cbState = 0;
1040 }
1041 if (pc->fccType == 0)
1042 pc->fccType = ICTYPE_VIDEO;
1043
1044 choose_comp.cv = *pc;
1045 choose_comp.flags = uiFlags;
1046 choose_comp.title = lpszTitle;
1047
1048 ret = DialogBoxParamW(MSVFW32_hModule, MAKEINTRESOURCEW(ICM_CHOOSE_COMPRESSOR), hwnd,
1049 icm_choose_compressor_dlgproc, (LPARAM)&choose_comp);
1050
1051 if (ret)
1052 {
1053 *pc = choose_comp.cv;
1054 pc->dwFlags |= ICMF_COMPVARS_VALID;
1055 }
1056
1057 return ret;
1058 }
1059
1060
1061 /***********************************************************************
1062 * ICCompressorFree [MSVFW32.@]
1063 */
1064 void VFWAPI ICCompressorFree(PCOMPVARS pc)
1065 {
1066 TRACE("(%p)\n",pc);
1067
1068 if (pc != NULL && pc->cbSize == sizeof(COMPVARS)) {
1069 if (pc->hic != NULL) {
1070 ICClose(pc->hic);
1071 pc->hic = NULL;
1072 }
1073 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1074 pc->lpbiIn = NULL;
1075 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1076 pc->lpBitsOut = NULL;
1077 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1078 pc->lpBitsPrev = NULL;
1079 HeapFree(GetProcessHeap(), 0, pc->lpState);
1080 pc->lpState = NULL;
1081 pc->dwFlags = 0;
1082 }
1083 }
1084
1085 /***********************************************************************
1086 * ICSendMessage [MSVFW32.@]
1087 */
1088 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
1089 {
1090 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1091
1092 if (!whic) return ICERR_BADHANDLE;
1093 return MSVIDEO_SendMessage(whic, msg, lParam1, lParam2);
1094 }
1095
1096 /***********************************************************************
1097 * ICDrawBegin [MSVFW32.@]
1098 */
1099 DWORD VFWAPIV ICDrawBegin(
1100 HIC hic, /* [in] */
1101 DWORD dwFlags, /* [in] flags */
1102 HPALETTE hpal, /* [in] palette to draw with */
1103 HWND hwnd, /* [in] window to draw to */
1104 HDC hdc, /* [in] HDC to draw to */
1105 INT xDst, /* [in] destination rectangle */
1106 INT yDst, /* [in] */
1107 INT dxDst, /* [in] */
1108 INT dyDst, /* [in] */
1109 LPBITMAPINFOHEADER lpbi, /* [in] format of frame to draw */
1110 INT xSrc, /* [in] source rectangle */
1111 INT ySrc, /* [in] */
1112 INT dxSrc, /* [in] */
1113 INT dySrc, /* [in] */
1114 DWORD dwRate, /* [in] frames/second = (dwRate/dwScale) */
1115 DWORD dwScale) /* [in] */
1116 {
1117
1118 ICDRAWBEGIN icdb;
1119
1120 TRACE("(%p,%d,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%d,%d)\n",
1121 hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
1122 lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
1123
1124 icdb.dwFlags = dwFlags;
1125 icdb.hpal = hpal;
1126 icdb.hwnd = hwnd;
1127 icdb.hdc = hdc;
1128 icdb.xDst = xDst;
1129 icdb.yDst = yDst;
1130 icdb.dxDst = dxDst;
1131 icdb.dyDst = dyDst;
1132 icdb.lpbi = lpbi;
1133 icdb.xSrc = xSrc;
1134 icdb.ySrc = ySrc;
1135 icdb.dxSrc = dxSrc;
1136 icdb.dySrc = dySrc;
1137 icdb.dwRate = dwRate;
1138 icdb.dwScale = dwScale;
1139 return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD_PTR)&icdb,sizeof(icdb));
1140 }
1141
1142 /***********************************************************************
1143 * ICDraw [MSVFW32.@]
1144 */
1145 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
1146 ICDRAW icd;
1147
1148 TRACE("(%p,%d,%p,%p,%d,%d)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
1149
1150 icd.dwFlags = dwFlags;
1151 icd.lpFormat = lpFormat;
1152 icd.lpData = lpData;
1153 icd.cbData = cbData;
1154 icd.lTime = lTime;
1155
1156 return ICSendMessage(hic,ICM_DRAW,(DWORD_PTR)&icd,sizeof(icd));
1157 }
1158
1159 /***********************************************************************
1160 * ICClose [MSVFW32.@]
1161 */
1162 LRESULT WINAPI ICClose(HIC hic)
1163 {
1164 WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1165 WINE_HIC** p;
1166
1167 TRACE("(%p)\n",hic);
1168
1169 if (!whic) return ICERR_BADHANDLE;
1170
1171 if (whic->driverproc)
1172 {
1173 MSVIDEO_SendMessage(whic, DRV_CLOSE, 0, 0);
1174 MSVIDEO_SendMessage(whic, DRV_DISABLE, 0, 0);
1175 MSVIDEO_SendMessage(whic, DRV_FREE, 0, 0);
1176 }
1177 else
1178 {
1179 CloseDriver(whic->hdrv, 0, 0);
1180 }
1181
1182 /* remove whic from list */
1183 for (p = &MSVIDEO_FirstHic; *p != NULL; p = &((*p)->next))
1184 {
1185 if ((*p) == whic)
1186 {
1187 *p = whic->next;
1188 break;
1189 }
1190 }
1191
1192 HeapFree(GetProcessHeap(), 0, whic);
1193 return 0;
1194 }
1195
1196
1197
1198 /***********************************************************************
1199 * ICImageCompress [MSVFW32.@]
1200 */
1201 HANDLE VFWAPI ICImageCompress(
1202 HIC hic, UINT uiFlags,
1203 LPBITMAPINFO lpbiIn, LPVOID lpBits,
1204 LPBITMAPINFO lpbiOut, LONG lQuality,
1205 LONG* plSize)
1206 {
1207 FIXME("(%p,%08x,%p,%p,%p,%d,%p)\n",
1208 hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
1209
1210 return NULL;
1211 }
1212
1213 /***********************************************************************
1214 * ICImageDecompress [MSVFW32.@]
1215 */
1216
1217 HANDLE VFWAPI ICImageDecompress(
1218 HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
1219 LPVOID lpBits, LPBITMAPINFO lpbiOut)
1220 {
1221 HGLOBAL hMem = NULL;
1222 BYTE* pMem = NULL;
1223 BOOL bReleaseIC = FALSE;
1224 BYTE* pHdr = NULL;
1225 ULONG cbHdr = 0;
1226 BOOL bSucceeded = FALSE;
1227 BOOL bInDecompress = FALSE;
1228 DWORD biSizeImage;
1229
1230 TRACE("(%p,%08x,%p,%p,%p)\n",
1231 hic, uiFlags, lpbiIn, lpBits, lpbiOut);
1232
1233 if ( hic == NULL )
1234 {
1235 hic = ICDecompressOpen( ICTYPE_VIDEO, 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
1236 if ( hic == NULL )
1237 {
1238 WARN("no handler\n" );
1239 goto err;
1240 }
1241 bReleaseIC = TRUE;
1242 }
1243 if ( uiFlags != 0 )
1244 {
1245 FIXME( "unknown flag %08x\n", uiFlags );
1246 goto err;
1247 }
1248 if ( lpbiIn == NULL || lpBits == NULL )
1249 {
1250 WARN("invalid argument\n");
1251 goto err;
1252 }
1253
1254 if ( lpbiOut != NULL )
1255 {
1256 if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
1257 goto err;
1258 cbHdr = sizeof(BITMAPINFOHEADER);
1259 if ( lpbiOut->bmiHeader.biCompression == 3 )
1260 cbHdr += sizeof(DWORD)*3;
1261 else
1262 if ( lpbiOut->bmiHeader.biBitCount <= 8 )
1263 {
1264 if ( lpbiOut->bmiHeader.biClrUsed == 0 )
1265 cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
1266 else
1267 cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
1268 }
1269 }
1270 else
1271 {
1272 TRACE( "get format\n" );
1273
1274 cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
1275 if ( cbHdr < sizeof(BITMAPINFOHEADER) )
1276 goto err;
1277 pHdr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,cbHdr+sizeof(RGBQUAD)*256);
1278 if ( pHdr == NULL )
1279 goto err;
1280 if ( ICDecompressGetFormat( hic, lpbiIn, pHdr ) != ICERR_OK )
1281 goto err;
1282 lpbiOut = (BITMAPINFO*)pHdr;
1283 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1284 ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
1285 lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
1286 {
1287 if ( lpbiIn->bmiHeader.biClrUsed == 0 )
1288 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
1289 else
1290 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
1291 }
1292 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1293 lpbiOut->bmiHeader.biClrUsed == 0 )
1294 lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
1295
1296 lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1297 cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
1298 }
1299
1300 biSizeImage = lpbiOut->bmiHeader.biSizeImage;
1301 if ( biSizeImage == 0 )
1302 biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
1303
1304 TRACE( "call ICDecompressBegin\n" );
1305
1306 if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
1307 goto err;
1308 bInDecompress = TRUE;
1309
1310 TRACE( "cbHdr %d, biSizeImage %d\n", cbHdr, biSizeImage );
1311
1312 hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
1313 if ( hMem == NULL )
1314 {
1315 WARN( "out of memory\n" );
1316 goto err;
1317 }
1318 pMem = GlobalLock( hMem );
1319 if ( pMem == NULL )
1320 goto err;
1321 memcpy( pMem, lpbiOut, cbHdr );
1322
1323 TRACE( "call ICDecompress\n" );
1324 if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
1325 goto err;
1326
1327 bSucceeded = TRUE;
1328 err:
1329 if ( bInDecompress )
1330 ICDecompressEnd( hic );
1331 if ( bReleaseIC )
1332 ICClose(hic);
1333 HeapFree(GetProcessHeap(),0,pHdr);
1334 if ( pMem != NULL )
1335 GlobalUnlock( hMem );
1336 if ( !bSucceeded && hMem != NULL )
1337 {
1338 GlobalFree(hMem); hMem = NULL;
1339 }
1340
1341 return hMem;
1342 }
1343
1344 /***********************************************************************
1345 * ICSeqCompressFrame [MSVFW32.@]
1346 */
1347 LPVOID VFWAPI ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL *pfKey, LONG *plSize)
1348 {
1349 ICCOMPRESS* icComp = pc->lpState;
1350 DWORD ret;
1351 TRACE("(%p, 0x%08x, %p, %p, %p)\n", pc, uiFlags, lpBits, pfKey, plSize);
1352
1353 if (pc->cbState != sizeof(ICCOMPRESS))
1354 {
1355 ERR("Invalid cbState %i\n", pc->cbState);
1356 return NULL;
1357 }
1358
1359 if (!pc->lKeyCount++)
1360 icComp->dwFlags = ICCOMPRESS_KEYFRAME;
1361 else
1362 {
1363 if (pc->lKey && pc->lKeyCount == (pc->lKey - 1))
1364 /* No key frames if pc->lKey == 0 */
1365 pc->lKeyCount = 0;
1366 icComp->dwFlags = 0;
1367 }
1368
1369 icComp->lpInput = lpBits;
1370 icComp->lFrameNum = pc->lFrame++;
1371 icComp->lpOutput = pc->lpBitsOut;
1372 icComp->lpPrev = pc->lpBitsPrev;
1373 ret = ICSendMessage(pc->hic, ICM_COMPRESS, (DWORD_PTR)icComp, sizeof(icComp));
1374
1375 if (icComp->dwFlags & AVIIF_KEYFRAME)
1376 {
1377 pc->lKeyCount = 1;
1378 *pfKey = TRUE;
1379 TRACE("Key frame\n");
1380 }
1381 else
1382 *pfKey = FALSE;
1383
1384 *plSize = icComp->lpbiOutput->biSizeImage;
1385 TRACE(" -- 0x%08x\n", ret);
1386 if (ret == ICERR_OK)
1387 {
1388 LPVOID oldprev, oldout;
1389 /* We shift Prev and Out, so we don't have to allocate and release memory */
1390 oldprev = pc->lpBitsPrev;
1391 oldout = pc->lpBitsOut;
1392 pc->lpBitsPrev = oldout;
1393 pc->lpBitsOut = oldprev;
1394
1395 TRACE("returning: %p\n", icComp->lpOutput);
1396 return icComp->lpOutput;
1397 }
1398 return NULL;
1399 }
1400
1401 /***********************************************************************
1402 * ICSeqCompressFrameEnd [MSVFW32.@]
1403 */
1404 void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
1405 {
1406 DWORD ret;
1407 TRACE("(%p)\n", pc);
1408 ret = ICSendMessage(pc->hic, ICM_COMPRESS_END, 0, 0);
1409 TRACE(" -- %x\n", ret);
1410 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1411 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1412 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1413 HeapFree(GetProcessHeap(), 0, pc->lpState);
1414 pc->lpbiIn = pc->lpBitsPrev = pc->lpBitsOut = pc->lpState = NULL;
1415 }
1416
1417 /***********************************************************************
1418 * ICSeqCompressFrameStart [MSVFW32.@]
1419 */
1420 BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
1421 {
1422 /* I'm ignoring bmiColors as I don't know what to do with it,
1423 * it doesn't appear to be used though
1424 */
1425 DWORD ret;
1426 pc->lpbiIn = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFO));
1427 if (!pc->lpbiIn)
1428 return FALSE;
1429
1430 *pc->lpbiIn = *lpbiIn;
1431 pc->lpBitsPrev = HeapAlloc(GetProcessHeap(), 0, pc->lpbiIn->bmiHeader.biSizeImage);
1432 if (!pc->lpBitsPrev)
1433 {
1434 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1435 return FALSE;
1436 }
1437
1438 pc->lpState = HeapAlloc(GetProcessHeap(), 0, sizeof(ICCOMPRESS));
1439 if (!pc->lpState)
1440 {
1441 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1442 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1443 return FALSE;
1444 }
1445 pc->cbState = sizeof(ICCOMPRESS);
1446
1447 pc->lpBitsOut = HeapAlloc(GetProcessHeap(), 0, pc->lpbiOut->bmiHeader.biSizeImage);
1448 if (!pc->lpBitsOut)
1449 {
1450 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1451 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1452 HeapFree(GetProcessHeap(), 0, pc->lpState);
1453 return FALSE;
1454 }
1455 TRACE("Compvars:\n"
1456 "\tpc:\n"
1457 "\tsize: %i\n"
1458 "\tflags: %i\n"
1459 "\thic: %p\n"
1460 "\ttype: %x\n"
1461 "\thandler: %x\n"
1462 "\tin/out: %p/%p\n"
1463 "key/data/quality: %i/%i/%i\n",
1464 pc->cbSize, pc->dwFlags, pc->hic, pc->fccType, pc->fccHandler,
1465 pc->lpbiIn, pc->lpbiOut, pc->lKey, pc->lDataRate, pc->lQ);
1466
1467 ret = ICSendMessage(pc->hic, ICM_COMPRESS_BEGIN, (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1468 TRACE(" -- %x\n", ret);
1469 if (ret == ICERR_OK)
1470 {
1471 ICCOMPRESS* icComp = pc->lpState;
1472 /* Initialise some variables */
1473 pc->lFrame = 0; pc->lKeyCount = 0;
1474
1475 icComp->lpbiOutput = &pc->lpbiOut->bmiHeader;
1476 icComp->lpbiInput = &pc->lpbiIn->bmiHeader;
1477 icComp->lpckid = NULL;
1478 icComp->dwFrameSize = 0;
1479 icComp->dwQuality = pc->lQ;
1480 icComp->lpbiPrev = &pc->lpbiIn->bmiHeader;
1481 return TRUE;
1482 }
1483 HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
1484 HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
1485 HeapFree(GetProcessHeap(), 0, pc->lpState);
1486 HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
1487 pc->lpBitsPrev = pc->lpbiIn = pc->lpState = pc->lpBitsOut = NULL;
1488 return FALSE;
1489 }
1490
1491 /***********************************************************************
1492 * GetFileNamePreview [MSVFW32.@]
1493 */
1494 static BOOL GetFileNamePreview(LPVOID lpofn,BOOL bSave,BOOL bUnicode)
1495 {
1496 CHAR szFunctionName[20];
1497 BOOL (*fnGetFileName)(LPVOID);
1498 HMODULE hComdlg32;
1499 BOOL ret;
1500
1501 FIXME("(%p,%d,%d), semi-stub!\n",lpofn,bSave,bUnicode);
1502
1503 lstrcpyA(szFunctionName, (bSave ? "GetSaveFileName" : "GetOpenFileName"));
1504 lstrcatA(szFunctionName, (bUnicode ? "W" : "A"));
1505
1506 hComdlg32 = LoadLibraryA("COMDLG32.DLL");
1507 if (hComdlg32 == NULL)
1508 return FALSE;
1509
1510 fnGetFileName = (LPVOID)GetProcAddress(hComdlg32, szFunctionName);
1511 if (fnGetFileName == NULL)
1512 return FALSE;
1513
1514 /* FIXME: need to add OFN_ENABLEHOOK and our own handler */
1515 ret = fnGetFileName(lpofn);
1516
1517 FreeLibrary(hComdlg32);
1518 return ret;
1519 }
1520
1521 /***********************************************************************
1522 * GetOpenFileNamePreviewA [MSVFW32.@]
1523 */
1524 BOOL WINAPI GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn)
1525 {
1526 FIXME("(%p), semi-stub!\n", lpofn);
1527
1528 return GetFileNamePreview(lpofn, FALSE, FALSE);
1529 }
1530
1531 /***********************************************************************
1532 * GetOpenFileNamePreviewW [MSVFW32.@]
1533 */
1534 BOOL WINAPI GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn)
1535 {
1536 FIXME("(%p), semi-stub!\n", lpofn);
1537
1538 return GetFileNamePreview(lpofn, FALSE, TRUE);
1539 }
1540
1541 /***********************************************************************
1542 * GetSaveFileNamePreviewA [MSVFW32.@]
1543 */
1544 BOOL WINAPI GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn)
1545 {
1546 FIXME("(%p), semi-stub!\n", lpofn);
1547
1548 return GetFileNamePreview(lpofn, TRUE, FALSE);
1549 }
1550
1551 /***********************************************************************
1552 * GetSaveFileNamePreviewW [MSVFW32.@]
1553 */
1554 BOOL WINAPI GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn)
1555 {
1556 FIXME("(%p), semi-stub!\n", lpofn);
1557
1558 return GetFileNamePreview(lpofn, TRUE, TRUE);
1559 }