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