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