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