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 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 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 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 1702 BOOL WINAPI GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn) 1703 { 1704 FIXME("(%p), semi-stub!\n", lpofn); 1705 1706 return GetFileNamePreview(lpofn, TRUE, TRUE); 1707 } 1708