msvideo_main.c 44.3 KB
Newer Older
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 * Copyright 1998 Marcus Meissner
3
 * Copyright 2000 Bradley Baetz
4
 * Copyright 2003 Michael Günnewig
5
 * Copyright 2005 Dmitry Timoshkov
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23
 * FIXME: This all assumes 32 bit codecs
 *		Win95 appears to prefer 32 bit codecs, even from 16 bit code.
 *		There is the ICOpenFunction16 to worry about still, though.
24 25 26
 *      
 * TODO
 *      - no thread safety
Alexandre Julliard's avatar
Alexandre Julliard committed
27
 */
28

29
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
30
#include <stdio.h>
31
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
32

33 34 35
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
36
#include "winnls.h"
37
#include "wingdi.h"
38
#include "winuser.h"
39 40 41
#include "commdlg.h"
#include "vfw.h"
#include "msvideo_private.h"
42
#include "wine/debug.h"
43

44 45 46
/* Drivers32 settings */
#define HKLM_DRIVERS32 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"

47
WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
Alexandre Julliard's avatar
Alexandre Julliard committed
48

49 50 51 52 53 54 55
static inline const char *wine_dbgstr_fcc( DWORD fcc )
{
    return wine_dbg_sprintf("%c%c%c%c", 
                            LOBYTE(LOWORD(fcc)), HIBYTE(LOWORD(fcc)),
                            LOBYTE(HIWORD(fcc)), HIBYTE(HIWORD(fcc)));
}

56 57
static WINE_HIC*        MSVIDEO_FirstHic /* = NULL */;

58
typedef struct _reg_driver reg_driver;
59 60 61 62 63 64 65
struct _reg_driver
{
    DWORD       fccType;
    DWORD       fccHandler;
    DRIVERPROC  proc;
    LPWSTR      name;
    reg_driver* next;
66 67 68 69
};

static reg_driver* reg_driver_list = NULL;

70 71 72 73 74 75 76 77
/* This one is a macro such that it works for both ASCII and Unicode */
#define fourcc_to_string(str, fcc) do { \
	(str)[0] = LOBYTE(LOWORD(fcc)); \
	(str)[1] = HIBYTE(LOWORD(fcc)); \
	(str)[2] = LOBYTE(HIWORD(fcc)); \
	(str)[3] = HIBYTE(HIWORD(fcc)); \
	} while(0)

78 79 80 81
HMODULE MSVFW32_hModule;

BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
82
    TRACE("%p,%x,%p\n", hinst, reason, reserved);
83 84 85 86 87

    switch(reason)
    {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hinst);
88
            MSVFW32_hModule = hinst;
89 90 91 92 93
            break;
    }
    return TRUE;
}

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/******************************************************************
 *		MSVIDEO_SendMessage
 *
 *
 */
static LRESULT MSVIDEO_SendMessage(WINE_HIC* whic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
{
    LRESULT     ret;

#define XX(x) case x: TRACE("(%p,"#x",0x%08lx,0x%08lx)\n",whic,lParam1,lParam2); break

    switch (msg) {
        /* DRV_* */
        XX(DRV_LOAD);
        XX(DRV_ENABLE);
        XX(DRV_OPEN);
        XX(DRV_CLOSE);
        XX(DRV_DISABLE);
        XX(DRV_FREE);
        /* ICM_RESERVED+X */
        XX(ICM_ABOUT);
        XX(ICM_CONFIGURE);
        XX(ICM_GET);
        XX(ICM_GETINFO);
        XX(ICM_GETDEFAULTQUALITY);
        XX(ICM_GETQUALITY);
        XX(ICM_GETSTATE);
        XX(ICM_SETQUALITY);
        XX(ICM_SET);
        XX(ICM_SETSTATE);
        /* ICM_USER+X */
        XX(ICM_COMPRESS_FRAMES_INFO);
        XX(ICM_COMPRESS_GET_FORMAT);
        XX(ICM_COMPRESS_GET_SIZE);
        XX(ICM_COMPRESS_QUERY);
        XX(ICM_COMPRESS_BEGIN);
        XX(ICM_COMPRESS);
        XX(ICM_COMPRESS_END);
        XX(ICM_DECOMPRESS_GET_FORMAT);
        XX(ICM_DECOMPRESS_QUERY);
        XX(ICM_DECOMPRESS_BEGIN);
        XX(ICM_DECOMPRESS);
        XX(ICM_DECOMPRESS_END);
        XX(ICM_DECOMPRESS_SET_PALETTE);
        XX(ICM_DECOMPRESS_GET_PALETTE);
        XX(ICM_DRAW_QUERY);
        XX(ICM_DRAW_BEGIN);
        XX(ICM_DRAW_GET_PALETTE);
        XX(ICM_DRAW_START);
        XX(ICM_DRAW_STOP);
        XX(ICM_DRAW_END);
        XX(ICM_DRAW_GETTIME);
        XX(ICM_DRAW);
        XX(ICM_DRAW_WINDOW);
        XX(ICM_DRAW_SETTIME);
        XX(ICM_DRAW_REALIZE);
        XX(ICM_DRAW_FLUSH);
        XX(ICM_DRAW_RENDERBUFFER);
        XX(ICM_DRAW_START_PLAY);
        XX(ICM_DRAW_STOP_PLAY);
        XX(ICM_DRAW_SUGGESTFORMAT);
        XX(ICM_DRAW_CHANGEPALETTE);
        XX(ICM_GETBUFFERSWANTED);
        XX(ICM_GETDEFAULTKEYFRAMERATE);
        XX(ICM_DECOMPRESSEX_BEGIN);
        XX(ICM_DECOMPRESSEX_QUERY);
        XX(ICM_DECOMPRESSEX);
        XX(ICM_DECOMPRESSEX_END);
        XX(ICM_SET_STATUS_PROC);
    default:
        FIXME("(%p,0x%08x,0x%08lx,0x%08lx) unknown message\n",whic,msg,lParam1,lParam2);
    }

#undef XX

    if (whic->driverproc) {
	/* dwDriverId parameter is the value returned by the DRV_OPEN */
        ret = whic->driverproc(whic->driverId, whic->hdrv, msg, lParam1, lParam2);
    } else {
        ret = SendDriverMessage(whic->hdrv, msg, lParam1, lParam2);
    }

    TRACE("	-> 0x%08lx\n", ret);
    return ret;
}

180 181
static int compare_fourcc(DWORD fcc1, DWORD fcc2)
{
182 183 184 185 186 187 188
  char fcc_str1[4];
  char fcc_str2[4];
  fourcc_to_string(fcc_str1, fcc1);
  fourcc_to_string(fcc_str2, fcc2);
  return strncasecmp(fcc_str1, fcc_str2, 4);
}

189
typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*);
190 191 192 193

static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
{
    CHAR buf[2048], fccTypeStr[5], *s;
194
    DWORD i, cnt = 0, lRet;
195 196 197 198 199 200 201 202 203 204
    BOOL result = FALSE;
    HKEY hKey;

    fourcc_to_string(fccTypeStr, fccType);
    fccTypeStr[4] = '.';

    /* first, go through the registry entries */
    lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey);
    if (lRet == ERROR_SUCCESS) 
    {
205 206 207
        DWORD name, data, type;
        i = 0;
        for (;;)
208
	{
209 210 211 212
	    name = 10;
	    data = sizeof buf - name;
	    lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data);
	    if (lRet == ERROR_NO_MORE_ITEMS) break;
213
	    if (lRet != ERROR_SUCCESS) continue;
214 215
	    if (name != 9 || strncasecmp(buf, fccTypeStr, 5)) continue;
	    buf[name] = '=';
216
	    if ((result = handler(buf, cnt++, param))) break;
217 218 219 220 221 222 223 224
	}
    	RegCloseKey( hKey );
    }
    if (result) return result;

    /* if that didn't work, go through the values in system.ini */
    if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini")) 
    {
225
	for (s = buf; *s; s += strlen(s) + 1)
226
	{
227
            TRACE("got %s\n", s);
228
	    if (strncasecmp(s, fccTypeStr, 5) || s[9] != '=') continue;
229
	    if ((result = handler(s, cnt++, param))) break;
230 231 232 233
	}
    }

    return result;
234 235
}

236 237 238 239 240
/******************************************************************
 *		MSVIDEO_GetHicPtr
 *
 *
 */
241
static WINE_HIC*   MSVIDEO_GetHicPtr(HIC hic)
242 243 244 245 246 247 248
{
    WINE_HIC*   whic;

    for (whic = MSVIDEO_FirstHic; whic && whic->hic != hic; whic = whic->next);
    return whic;
}

249
/***********************************************************************
250 251
 *		VideoForWindowsVersion		[MSVFW32.2]
 *		VideoForWindowsVersion		[MSVIDEO.2]
Alexandre Julliard's avatar
Alexandre Julliard committed
252 253
 * Returns the version in major.minor form.
 * In Windows95 this returns 0x040003b6 (4.950)
Alexandre Julliard's avatar
Alexandre Julliard committed
254
 */
255 256 257
DWORD WINAPI VideoForWindowsVersion(void) 
{
    return 0x040003B6; /* 4.950 */
258 259
}

260
static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
261
{
262
    ICINFO *lpicinfo = param;
263 264 265 266 267 268 269 270 271
    DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0);

    /* exact match of fccHandler or nth driver found */
    if ((lpicinfo->fccHandler != nr) && (lpicinfo->fccHandler != fccHandler))
	return FALSE;

    lpicinfo->fccHandler = fccHandler;
    lpicinfo->dwFlags = 0;
    lpicinfo->dwVersion = 0;
272
    lpicinfo->dwVersionICM = ICVERSION;
273 274 275 276 277 278 279
    lpicinfo->szName[0] = 0;
    lpicinfo->szDescription[0] = 0;
    MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver, 
			sizeof(lpicinfo->szDriver)/sizeof(WCHAR));

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
280

281
/***********************************************************************
282
 *		ICInfo				[MSVFW32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
283 284
 * Get information about an installable compressor. Return TRUE if there
 * is one.
285 286 287 288 289
 *
 * PARAMS
 *   fccType     [I] type of compressor (e.g. 'vidc')
 *   fccHandler  [I] real fcc for handler or <n>th compressor
 *   lpicinfo    [O] information about compressor
Alexandre Julliard's avatar
Alexandre Julliard committed
290
 */
291
BOOL VFWAPI ICInfo( DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo)
292
{
293
    TRACE("(%s,%s/%08x,%p)\n",
294
          wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), fccHandler, lpicinfo);
295

296
    lpicinfo->fccType = fccType;
297 298
    lpicinfo->fccHandler = fccHandler;
    return enum_drivers(fccType, ICInfo_enum_handler, lpicinfo);
Alexandre Julliard's avatar
Alexandre Julliard committed
299 300
}

301 302
static DWORD IC_HandleRef = 1;

303 304 305 306 307 308
/***********************************************************************
 *		ICInstall			[MSVFW32.@]
 */
BOOL VFWAPI ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags) 
{
    reg_driver* driver;
309
    unsigned len;
310 311 312 313

    TRACE("(%s,%s,%p,%p,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), (void*)lParam, szDesc, wFlags);

    /* Check if a driver is already registered */
314 315
    for (driver = reg_driver_list; driver; driver = driver->next)
    {
316 317 318
        if (!compare_fourcc(fccType, driver->fccType) &&
            !compare_fourcc(fccHandler, driver->fccHandler))
            break;
319 320
    }
    if (driver) return FALSE;
321 322 323

    /* Register the driver */
    driver = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(reg_driver));
324
    if (!driver) goto oom;
325 326 327
    driver->fccType = fccType;
    driver->fccHandler = fccHandler;

328 329
    switch(wFlags)
    {
330 331 332 333 334 335
    case ICINSTALL_FUNCTION:
        driver->proc = (DRIVERPROC)lParam;
	driver->name = NULL;
        break;
    case ICINSTALL_DRIVER:
	driver->proc = NULL;
336 337 338 339
        len = MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, NULL, 0);
        driver->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
        if (!driver->name) goto oom;
        MultiByteToWideChar(CP_ACP, 0, (char*)lParam, -1, driver->name, len);
340 341 342 343 344 345 346 347 348 349 350 351
	break;
    default:
	ERR("Invalid flags!\n");
	HeapFree(GetProcessHeap(), 0, driver);
	return FALSE;
   }

   /* Insert our driver in the list*/
   driver->next = reg_driver_list;
   reg_driver_list = driver;
    
   return TRUE;
352
oom:
353
   HeapFree(GetProcessHeap(), 0, driver);
354
   return FALSE;
355 356 357 358 359 360 361
}

/***********************************************************************
 *		ICRemove			[MSVFW32.@]
 */
BOOL VFWAPI ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags) 
{
362
    reg_driver** pdriver;
363 364
    reg_driver*  drv;

365 366 367
    TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wFlags);

    /* Check if a driver is already registered */
368 369 370 371
    for (pdriver = &reg_driver_list; *pdriver; pdriver = &(*pdriver)->next)
    {
        if (!compare_fourcc(fccType, (*pdriver)->fccType) &&
            !compare_fourcc(fccHandler, (*pdriver)->fccHandler))
372
            break;
373 374
    }
    if (!*pdriver)
375 376 377
        return FALSE;

    /* Remove the driver from the list */
378
    drv = *pdriver;
379
    *pdriver = (*pdriver)->next;
380 381
    HeapFree(GetProcessHeap(), 0, drv->name);
    HeapFree(GetProcessHeap(), 0, drv);
382 383 384 385 386
    
    return TRUE;  
}


387
/***********************************************************************
388
 *		ICOpen				[MSVFW32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
389 390
 * Opens an installable compressor. Return special handle.
 */
391 392
HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode) 
{
393
    WCHAR		codecname[10];
394 395 396
    ICOPEN		icopen;
    HDRVR		hdrv;
    WINE_HIC*           whic;
397
    static const WCHAR  drv32W[] = {'d','r','i','v','e','r','s','3','2','\0'};
398
    reg_driver*         driver;
399

400
    TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode);
401

402 403 404 405
    /* Check if there is a registered driver that matches */
    driver = reg_driver_list;
    while(driver)
        if (!compare_fourcc(fccType, driver->fccType) &&
406 407 408
            !compare_fourcc(fccHandler, driver->fccHandler)) {
	    fccType = driver->fccType;
	    fccHandler = driver->fccHandler;
409
	    break;
410
        } else
411 412 413 414
            driver = driver->next;

    if (driver && driver->proc)
	/* The driver has been registered at runtime with its driverproc */
415
        return ICOpenFunction(fccType, fccHandler, wMode, driver->proc);
416
  
417 418 419 420 421 422 423 424 425 426 427 428
    /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
     * same layout as ICOPEN
     */
    icopen.dwSize		= sizeof(ICOPEN);
    icopen.fccType		= fccType;
    icopen.fccHandler	        = fccHandler;
    icopen.dwVersion            = 0x00001000; /* FIXME */
    icopen.dwFlags		= wMode;
    icopen.dwError              = 0;
    icopen.pV1Reserved          = NULL;
    icopen.pV2Reserved          = NULL;
    icopen.dnDevNode            = 0; /* FIXME */
429 430
	
    if (!driver) {
431 432 433 434 435 436 437
        /* normalize to lower case as in 'vidc' */
        ((char*)&fccType)[0] = tolower(((char*)&fccType)[0]);
        ((char*)&fccType)[1] = tolower(((char*)&fccType)[1]);
        ((char*)&fccType)[2] = tolower(((char*)&fccType)[2]);
        ((char*)&fccType)[3] = tolower(((char*)&fccType)[3]);
        icopen.fccType = fccType;
        /* Seek the driver in the registry */
438
	fourcc_to_string(codecname, fccType);
439
        codecname[4] = '.';
440
	fourcc_to_string(codecname + 5, fccHandler);
441 442
        codecname[9] = '\0';

443
        hdrv = OpenDriver(codecname, drv32W, (LPARAM)&icopen);
444
        if (!hdrv) 
445
            return 0;
446 447
    } else {
        /* The driver has been registered at runtime with its name */
448
        hdrv = OpenDriver(driver->name, NULL, (LPARAM)&icopen);
449 450
        if (!hdrv) 
            return 0; 
451 452 453 454 455 456 457 458 459
    }

    whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
    if (!whic)
    {
        CloseDriver(hdrv, 0, 0);
        return FALSE;
    }
    whic->hdrv          = hdrv;
460
    whic->driverproc    = NULL;
461 462
    whic->type          = fccType;
    whic->handler       = fccHandler;
463 464
    while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
    whic->hic           = (HIC)(ULONG_PTR)IC_HandleRef++;
465 466 467 468 469
    whic->next          = MSVIDEO_FirstHic;
    MSVIDEO_FirstHic = whic;

    TRACE("=> %p\n", whic->hic);
    return whic->hic;
Alexandre Julliard's avatar
Alexandre Julliard committed
470
}
471

472
/***********************************************************************
473
 *		ICOpenFunction			[MSVFW32.@]
474
 */
475
HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, DRIVERPROC lpfnHandler)
476
{
477 478 479
    ICOPEN      icopen;
    WINE_HIC*   whic;

480 481
    TRACE("(%s,%s,%d,%p)\n",
          wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode, lpfnHandler);
482 483 484 485

    icopen.dwSize		= sizeof(ICOPEN);
    icopen.fccType		= fccType;
    icopen.fccHandler	        = fccHandler;
486
    icopen.dwVersion            = ICVERSION;
487 488 489 490 491 492 493 494 495 496
    icopen.dwFlags		= wMode;
    icopen.dwError              = 0;
    icopen.pV1Reserved          = NULL;
    icopen.pV2Reserved          = NULL;
    icopen.dnDevNode            = 0; /* FIXME */

    whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
    if (!whic) return 0;

    whic->driverproc   = lpfnHandler;
497 498
    while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
    whic->hic          = (HIC)(ULONG_PTR)IC_HandleRef++;
499 500 501 502 503 504
    whic->next         = MSVIDEO_FirstHic;
    MSVIDEO_FirstHic = whic;

    /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
    /* What if the function is used more than once? */

505
    if (MSVIDEO_SendMessage(whic, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) 
506 507 508 509 510 511 512
    {
        WARN("DRV_LOAD failed for hic %p\n", whic->hic);
        MSVIDEO_FirstHic = whic->next;
        HeapFree(GetProcessHeap(), 0, whic);
        return 0;
    }
    /* return value is not checked */
513
    MSVIDEO_SendMessage(whic, DRV_ENABLE, 0L, 0L);
514

515
    whic->driverId = (DWORD)MSVIDEO_SendMessage(whic, DRV_OPEN, 0, (DWORD_PTR)&icopen);
516
    /* FIXME: What should we put here? */
517
    whic->hdrv = NULL;
518 519
    
    if (whic->driverId == 0) 
520 521 522 523 524 525
    {
        WARN("DRV_OPEN failed for hic %p\n", whic->hic);
        MSVIDEO_FirstHic = whic->next;
        HeapFree(GetProcessHeap(), 0, whic);
        return 0;
    }
526

527 528
    TRACE("=> %p\n", whic->hic);
    return whic->hic;
529 530
}

531
/***********************************************************************
532
 *		ICGetInfo			[MSVFW32.@]
533
 */
534 535 536 537 538
LRESULT VFWAPI ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb) 
{
    LRESULT	ret;
    WINE_HIC*   whic = MSVIDEO_GetHicPtr(hic);

539
    TRACE("(%p,%p,%d)\n", hic, picinfo, cb);
540 541 542 543 544 545 546

    if (!whic) return ICERR_BADHANDLE;
    if (!picinfo) return MMSYSERR_INVALPARAM;

    /* (WS) The field szDriver should be initialized because the driver 
     * is not obliged and often will not do it. Some applications, like
     * VirtualDub, rely on this field and will occasionally crash if it
547
     * goes uninitialized.
548 549 550
     */
    if (cb >= sizeof(ICINFO)) picinfo->szDriver[0] = '\0';

551
    ret = ICSendMessage(hic, ICM_GETINFO, (DWORD_PTR)picinfo, cb);
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568

    /* (WS) When szDriver was not supplied by the driver itself, apparently 
     * Windows will set its value equal to the driver file name. This can
     * be obtained from the registry as we do here.
     */
    if (cb >= sizeof(ICINFO) && picinfo->szDriver[0] == 0)
    {
        ICINFO  ii;

        memset(&ii, 0, sizeof(ii));
        ii.dwSize = sizeof(ii);
        ICInfo(picinfo->fccType, picinfo->fccHandler, &ii);
        lstrcpyW(picinfo->szDriver, ii.szDriver);
    }

    TRACE("	-> 0x%08lx\n", ret);
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
569 570
}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
typedef struct {
    DWORD fccType;
    DWORD fccHandler;
    LPBITMAPINFOHEADER lpbiIn;
    LPBITMAPINFOHEADER lpbiOut;
    WORD wMode;
    DWORD querymsg;
    HIC hic;
} driver_info_t;

static HIC try_driver(driver_info_t *info)
{
    HIC   hic;

    if ((hic = ICOpen(info->fccType, info->fccHandler, info->wMode))) 
    {
587
	if (!ICSendMessage(hic, info->querymsg, (DWORD_PTR)info->lpbiIn, (DWORD_PTR)info->lpbiOut))
588 589 590 591 592 593
	    return hic;
	ICClose(hic);
    }
    return 0;
}

594
static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param)
595
{
596
    driver_info_t *info = param;
597 598 599 600 601
    info->fccHandler = mmioStringToFOURCCA(drv + 5, 0);
    info->hic = try_driver(info);
    return info->hic != 0;
}

602
/***********************************************************************
603
 *		ICLocate			[MSVFW32.@]
604
 */
605 606
HIC VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
                    LPBITMAPINFOHEADER lpbiOut, WORD wMode)
607
{
608
    driver_info_t info;
609

610 611
    TRACE("(%s,%s,%p,%p,0x%04x)\n", 
          wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpbiIn, lpbiOut, wMode);
612

613 614 615 616 617 618
    info.fccType = fccType;
    info.fccHandler = fccHandler;
    info.lpbiIn = lpbiIn;
    info.lpbiOut = lpbiOut;
    info.wMode = wMode;

619 620 621 622
    switch (wMode) 
    {
    case ICMODE_FASTCOMPRESS:
    case ICMODE_COMPRESS:
623
        info.querymsg = ICM_COMPRESS_QUERY;
624 625 626
        break;
    case ICMODE_FASTDECOMPRESS:
    case ICMODE_DECOMPRESS:
627
        info.querymsg = ICM_DECOMPRESS_QUERY;
628 629
        break;
    case ICMODE_DRAW:
630
        info.querymsg = ICM_DRAW_QUERY;
631 632 633 634 635
        break;
    default:
        WARN("Unknown mode (%d)\n", wMode);
        return 0;
    }
636

637
    /* Easy case: handler/type match, we just fire a query and return */
638 639
    info.hic = try_driver(&info);
    /* If it didn't work, try each driver in turn. 32 bit codecs only. */
640
    /* FIXME: Move this to an init routine? */
641
    if (!info.hic) enum_drivers(fccType, ICLocate_enum_handler, &info);
642

643 644 645 646
    if (info.hic) 
    {
        TRACE("=> %p\n", info.hic);
	return info.hic;
647
    }
648

649 650 651
    if (fccType == streamtypeVIDEO) 
        return ICLocate(ICTYPE_VIDEO, fccHandler, lpbiIn, lpbiOut, wMode);
    
652 653
    WARN("(%s,%s,%p,%p,0x%04x) not found!\n",
         wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), lpbiIn, lpbiOut, wMode);
654
    return 0;
655 656
}

657
/***********************************************************************
658
 *		ICGetDisplayFormat			[MSVFW32.@]
659
 */
660 661
HIC VFWAPI ICGetDisplayFormat(
	HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
662 663
	INT depth,INT dx,INT dy)
{
664
	HIC	tmphic = hic;
665

666 667
	TRACE("(%p,%p,%p,%d,%d,%d)!\n",hic,lpbiIn,lpbiOut,depth,dx,dy);

668 669 670 671 672
	if (!tmphic) {
		tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
		if (!tmphic)
			return tmphic;
	}
Eric Pouech's avatar
Eric Pouech committed
673
	if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
674
		dy = dx = 0; /* no resize needed */
Eric Pouech's avatar
Eric Pouech committed
675

676
	/* Can we decompress it ? */
Eric Pouech's avatar
Eric Pouech committed
677
	if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
678
		goto errout; /* no, sorry */
Eric Pouech's avatar
Eric Pouech committed
679

680
	ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)lpbiIn, (DWORD_PTR)lpbiOut);
Eric Pouech's avatar
Eric Pouech committed
681 682

	if (lpbiOut->biCompression != 0) {
683
           FIXME("Ooch, how come decompressor outputs compressed data (%d)??\n",
Eric Pouech's avatar
Eric Pouech committed
684 685 686
			 lpbiOut->biCompression);
	}
	if (lpbiOut->biSize < sizeof(*lpbiOut)) {
687
           FIXME("Ooch, size of output BIH is too small (%d)\n",
Eric Pouech's avatar
Eric Pouech committed
688 689 690
			 lpbiOut->biSize);
	   lpbiOut->biSize = sizeof(*lpbiOut);
	}
691 692 693 694
	if (!depth) {
		HDC	hdc;

		hdc = GetDC(0);
695
		depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
696 697 698 699 700 701
		ReleaseDC(0,hdc);
		if (depth==15)	depth = 16;
		if (depth<8)	depth =  8;
	}
	if (lpbiIn->biBitCount == 8)
		depth = 8;
702

703
	TRACE("=> %p\n", tmphic);
704
	return tmphic;
705 706 707
errout:
	if (hic!=tmphic)
		ICClose(tmphic);
708 709

	TRACE("=> 0\n");
710 711 712
	return 0;
}

713
/***********************************************************************
714
 *		ICCompress			[MSVFW32.@]
715
 */
716
DWORD VFWAPIV
717 718
ICCompress(
	HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
719 720
	LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
	LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
721 722
	LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
{
723 724
	ICCOMPRESS	iccmp;

725
	TRACE("(%p,%d,%p,%p,%p,%p,...)\n",hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
726

727 728 729 730 731 732 733 734 735 736 737 738 739 740
	iccmp.dwFlags		= dwFlags;

	iccmp.lpbiOutput	= lpbiOutput;
	iccmp.lpOutput		= lpData;
	iccmp.lpbiInput		= lpbiInput;
	iccmp.lpInput		= lpBits;

	iccmp.lpckid		= lpckid;
	iccmp.lpdwFlags		= lpdwFlags;
	iccmp.lFrameNum		= lFrameNum;
	iccmp.dwFrameSize	= dwFrameSize;
	iccmp.dwQuality		= dwQuality;
	iccmp.lpbiPrev		= lpbiPrev;
	iccmp.lpPrev		= lpPrev;
741
	return ICSendMessage(hic,ICM_COMPRESS,(DWORD_PTR)&iccmp,sizeof(iccmp));
742 743
}

744
/***********************************************************************
745
 *		ICDecompress			[MSVFW32.@]
746
 */
747 748 749
DWORD VFWAPIV  ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
				LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
{
750
	ICDECOMPRESS	icd;
751 752
	DWORD ret;

753
	TRACE("(%p,%d,%p,%p,%p,%p)\n",hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
754

755 756 757 758 759 760
	icd.dwFlags	= dwFlags;
	icd.lpbiInput	= lpbiFormat;
	icd.lpInput	= lpData;

	icd.lpbiOutput	= lpbi;
	icd.lpOutput	= lpBits;
761
	icd.ckid	= 0;
762
	ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD_PTR)&icd,sizeof(ICDECOMPRESS));
763

764
	TRACE("-> %d\n",ret);
765 766

	return ret;
767
}
Alexandre Julliard's avatar
Alexandre Julliard committed
768

769 770 771 772 773 774 775 776

struct choose_compressor
{
    UINT flags;
    LPCSTR title;
    COMPVARS cv;
};

777 778 779 780 781 782 783
struct codec_info
{
    HIC hic;
    ICINFO icinfo;
};

static BOOL enum_compressors(HWND list, COMPVARS *pcv, BOOL enum_all)
784
{
785
    UINT id, total = 0;
786 787 788 789
    ICINFO icinfo;

    id = 0;

790
    while (ICInfo(pcv->fccType, id, &icinfo))
791
    {
792
        struct codec_info *ic;
793 794 795
        DWORD idx;
        HIC hic;

796 797
        id++;

798 799 800 801 802 803 804 805 806
        hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);

        if (hic)
        {
            /* for unknown reason fccHandler reported by the driver
             * doesn't always work, use the one returned by ICInfo instead.
             */
            DWORD fccHandler = icinfo.fccHandler;

807
            if (!enum_all && pcv->lpbiIn)
808 809 810
            {
                if (ICCompressQuery(hic, pcv->lpbiIn, NULL) != ICERR_OK)
                {
811
                    TRACE("fccHandler %s doesn't support input DIB format %d\n",
812 813 814 815 816 817
                          wine_dbgstr_fcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression);
                    ICClose(hic);
                    continue;
                }
            }

818 819 820 821 822
            ICGetInfo(hic, &icinfo, sizeof(icinfo));
            icinfo.fccHandler = fccHandler;

            idx = SendMessageW(list, CB_ADDSTRING, 0, (LPARAM)icinfo.szDescription);

823
            ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
824
            ic->icinfo = icinfo;
825
            ic->hic = hic;
826 827
            SendMessageW(list, CB_SETITEMDATA, idx, (LPARAM)ic);
        }
828
        total++;
829 830
    }

831
    return total != 0;
832 833 834 835 836 837 838 839
}

static INT_PTR CALLBACK icm_choose_compressor_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg)
    {
    case WM_INITDIALOG:
    {
840
        struct codec_info *ic;
841 842 843
        WCHAR buf[128];
        struct choose_compressor *choose_comp = (struct choose_compressor *)lparam;

844 845 846 847 848
        SetWindowLongPtrW(hdlg, DWLP_USER, lparam);

        /* FIXME */
        choose_comp->flags &= ~(ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME);

849 850 851
        if (choose_comp->title)
            SetWindowTextA(hdlg, choose_comp->title);

852
        if (!(choose_comp->flags & ICMF_CHOOSE_DATARATE))
853 854 855 856 857
        {
            ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_CHECKBOX), SW_HIDE);
            ShowWindow(GetDlgItem(hdlg, IDC_DATARATE), SW_HIDE);
            ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_KB), SW_HIDE);
        }
858 859

        if (!(choose_comp->flags & ICMF_CHOOSE_KEYFRAME))
860 861 862 863 864 865 866 867 868
        {
            ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_CHECKBOX), SW_HIDE);
            ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME), SW_HIDE);
            ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_FRAMES), SW_HIDE);
        }

        /* FIXME */
        EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_SCROLL), FALSE);
        EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_TXT), FALSE);
869 870

        /*if (!(choose_comp->flags & ICMF_CHOOSE_PREVIEW))
871
            ShowWindow(GetDlgItem(hdlg, IDC_PREVIEW), SW_HIDE);*/
872

873
        LoadStringW(MSVFW32_hModule, IDS_FULLFRAMES, buf, 128);
874 875
        SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_ADDSTRING, 0, (LPARAM)buf);

876 877 878 879
        ic = HeapAlloc(GetProcessHeap(), 0, sizeof(struct codec_info));
        ic->icinfo.fccType = streamtypeVIDEO;
        ic->icinfo.fccHandler = comptypeDIB;
        ic->hic = 0;
880 881
        SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETITEMDATA, 0, (LPARAM)ic);

882
        enum_compressors(GetDlgItem(hdlg, IDC_COMP_LIST), &choose_comp->cv, choose_comp->flags & ICMF_CHOOSE_ALLCOMPRESSORS);
883 884 885 886 887 888 889 890 891 892 893

        SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETCURSEL, 0, 0);
        SetFocus(GetDlgItem(hdlg, IDC_COMP_LIST));

        SetWindowLongPtrW(hdlg, DWLP_USER, (ULONG_PTR)choose_comp);
        break;
    }

    case WM_COMMAND:
        switch (LOWORD(wparam))
        {
894 895 896 897
        case IDC_COMP_LIST:
        {
            INT cur_sel;
            struct codec_info *ic;
898 899
            BOOL can_configure = FALSE, can_about = FALSE;
            struct choose_compressor *choose_comp;
900

901
            if (HIWORD(wparam) != CBN_SELCHANGE && HIWORD(wparam) != CBN_SETFOCUS)
902 903
                break;

904 905
            choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);

906 907 908 909 910 911
            cur_sel = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);

            ic = (struct codec_info *)SendMessageW((HWND)lparam, CB_GETITEMDATA, cur_sel, 0);
            if (ic && ic->hic)
            {
                if (ICQueryConfigure(ic->hic) == DRVCNF_OK)
912 913 914
                    can_configure = TRUE;
                if (ICQueryAbout(ic->hic) == DRVCNF_OK)
                    can_about = TRUE;
915
            }
916 917 918 919 920 921 922 923 924 925 926 927
            EnableWindow(GetDlgItem(hdlg, IDC_CONFIGURE), can_configure);
            EnableWindow(GetDlgItem(hdlg, IDC_ABOUT), can_about);

            if (choose_comp->flags & ICMF_CHOOSE_DATARATE)
            {
                /* FIXME */
            }
            if (choose_comp->flags & ICMF_CHOOSE_KEYFRAME)
            {
                /* FIXME */
            }

928 929 930 931
            break;
        }

        case IDC_CONFIGURE:
932
        case IDC_ABOUT:
933 934 935 936 937
        {
            HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
            INT cur_sel;
            struct codec_info *ic;

938
            if (HIWORD(wparam) != BN_CLICKED)
939 940 941 942 943 944
                break;

            cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);

            ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
            if (ic && ic->hic)
945 946 947 948 949 950
            {
                if (LOWORD(wparam) == IDC_CONFIGURE)
                    ICConfigure(ic->hic, hdlg);
                else
                    ICAbout(ic->hic, hdlg);
            }
951 952 953 954

            break;
        }

955 956 957 958
        case IDOK:
        {
            HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
            INT cur_sel;
959
            struct codec_info *ic;
960

961 962 963
            if (HIWORD(wparam) != BN_CLICKED)
                break;

964
            cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
965
            ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
966 967 968 969
            if (ic)
            {
                struct choose_compressor *choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);

970 971 972 973
                choose_comp->cv.hic = ic->hic;
                choose_comp->cv.fccType = ic->icinfo.fccType;
                choose_comp->cv.fccHandler = ic->icinfo.fccHandler;
                /* FIXME: fill everything else */
974

975 976
                /* prevent closing the codec handle below */
                ic->hic = 0;
977 978 979 980 981 982 983 984
            }
        }
        /* fall through */
        case IDCANCEL:
        {
            HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
            INT idx = 0;

985 986 987
            if (HIWORD(wparam) != BN_CLICKED)
                break;

988 989
            while (1)
            {
990 991 992
                struct codec_info *ic;
    
                ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, idx++, 0);
993

994
                if (!ic || (LONG_PTR)ic == CB_ERR) break;
995

996 997
                if (ic->hic) ICClose(ic->hic);
                HeapFree(GetProcessHeap(), 0, ic);
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
            }

            EndDialog(hdlg, LOWORD(wparam) == IDOK);
            break;
        }

        default:
            break;
        }
        break;

    default:
        break;
    }

    return FALSE;
}

1016 1017 1018
/***********************************************************************
 *		ICCompressorChoose   [MSVFW32.@]
 */
1019 1020
BOOL VFWAPI ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn,
                               LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle)
1021
{
1022 1023
    struct choose_compressor choose_comp;
    BOOL ret;
1024

1025
    TRACE("(%p,%08x,%p,%p,%p,%s)\n", hwnd, uiFlags, pvIn, lpData, pc, lpszTitle);
1026

1027 1028 1029 1030 1031 1032 1033 1034
    if (!pc || pc->cbSize != sizeof(COMPVARS))
        return FALSE;

    if (!(pc->dwFlags & ICMF_COMPVARS_VALID))
    {
        pc->dwFlags   = 0;
        pc->fccType   = pc->fccHandler = 0;
        pc->hic       = NULL;
1035
        pc->lpbiIn    = NULL;
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
        pc->lpbiOut   = NULL;
        pc->lpBitsOut = pc->lpBitsPrev = pc->lpState = NULL;
        pc->lQ        = ICQUALITY_DEFAULT;
        pc->lKey      = -1;
        pc->lDataRate = 300; /* kB */
        pc->lpState   = NULL;
        pc->cbState   = 0;
    }
    if (pc->fccType == 0)
        pc->fccType = ICTYPE_VIDEO;

1047
    choose_comp.cv = *pc;
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    choose_comp.flags = uiFlags;
    choose_comp.title = lpszTitle;

    ret = DialogBoxParamW(MSVFW32_hModule, MAKEINTRESOURCEW(ICM_CHOOSE_COMPRESSOR), hwnd,
                          icm_choose_compressor_dlgproc, (LPARAM)&choose_comp);

    if (ret)
    {
        *pc = choose_comp.cv;
        pc->dwFlags |= ICMF_COMPVARS_VALID;
    }

    return ret;
1061 1062 1063 1064 1065 1066 1067 1068
}


/***********************************************************************
 *		ICCompressorFree   [MSVFW32.@]
 */
void VFWAPI ICCompressorFree(PCOMPVARS pc)
{
1069 1070 1071 1072 1073 1074 1075
  TRACE("(%p)\n",pc);

  if (pc != NULL && pc->cbSize == sizeof(COMPVARS)) {
    if (pc->hic != NULL) {
      ICClose(pc->hic);
      pc->hic = NULL;
    }
1076 1077 1078 1079 1080 1081 1082 1083
    HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
    pc->lpbiIn = NULL;
    HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
    pc->lpBitsOut = NULL;
    HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
    pc->lpBitsPrev = NULL;
    HeapFree(GetProcessHeap(), 0, pc->lpState);
    pc->lpState = NULL;
1084 1085
    pc->dwFlags = 0;
  }
1086 1087
}

1088
/***********************************************************************
1089
 *		ICSendMessage			[MSVFW32.@]
1090
 */
1091
LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2) 
1092 1093 1094 1095 1096
{
    WINE_HIC*   whic = MSVIDEO_GetHicPtr(hic);

    if (!whic) return ICERR_BADHANDLE;
    return MSVIDEO_SendMessage(whic, msg, lParam1, lParam2);
1097 1098
}

1099
/***********************************************************************
1100
 *		ICDrawBegin		[MSVFW32.@]
1101
 */
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
DWORD VFWAPIV ICDrawBegin(
	HIC                hic,     /* [in] */
	DWORD              dwFlags, /* [in] flags */
	HPALETTE           hpal,    /* [in] palette to draw with */
	HWND               hwnd,    /* [in] window to draw to */
	HDC                hdc,     /* [in] HDC to draw to */
	INT                xDst,    /* [in] destination rectangle */
	INT                yDst,    /* [in] */
	INT                dxDst,   /* [in] */
	INT                dyDst,   /* [in] */
	LPBITMAPINFOHEADER lpbi,    /* [in] format of frame to draw */
	INT                xSrc,    /* [in] source rectangle */
	INT                ySrc,    /* [in] */
	INT                dxSrc,   /* [in] */
	INT                dySrc,   /* [in] */
	DWORD              dwRate,  /* [in] frames/second = (dwRate/dwScale) */
	DWORD              dwScale) /* [in] */
{
1120

1121 1122
	ICDRAWBEGIN	icdb;

1123
	TRACE("(%p,%d,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%d,%d)\n",
1124
		  hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
1125 1126
		  lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);

1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
	icdb.dwFlags = dwFlags;
	icdb.hpal = hpal;
	icdb.hwnd = hwnd;
	icdb.hdc = hdc;
	icdb.xDst = xDst;
	icdb.yDst = yDst;
	icdb.dxDst = dxDst;
	icdb.dyDst = dyDst;
	icdb.lpbi = lpbi;
	icdb.xSrc = xSrc;
	icdb.ySrc = ySrc;
	icdb.dxSrc = dxSrc;
	icdb.dySrc = dySrc;
	icdb.dwRate = dwRate;
	icdb.dwScale = dwScale;
1142
	return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD_PTR)&icdb,sizeof(icdb));
1143 1144
}

1145
/***********************************************************************
1146
 *		ICDraw			[MSVFW32.@]
1147
 */
1148
DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
1149 1150
	ICDRAW	icd;

1151
	TRACE("(%p,%d,%p,%p,%d,%d)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
1152

1153 1154 1155 1156 1157
	icd.dwFlags = dwFlags;
	icd.lpFormat = lpFormat;
	icd.lpData = lpData;
	icd.cbData = cbData;
	icd.lTime = lTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1158

1159
	return ICSendMessage(hic,ICM_DRAW,(DWORD_PTR)&icd,sizeof(icd));
1160 1161
}

1162
/***********************************************************************
1163
 *		ICClose			[MSVFW32.@]
1164
 */
1165 1166 1167 1168
LRESULT WINAPI ICClose(HIC hic)
{
    WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
    WINE_HIC** p;
1169

1170 1171 1172 1173 1174 1175
    TRACE("(%p)\n",hic);

    if (!whic) return ICERR_BADHANDLE;

    if (whic->driverproc) 
    {
1176 1177 1178
        MSVIDEO_SendMessage(whic, DRV_CLOSE, 0, 0);
        MSVIDEO_SendMessage(whic, DRV_DISABLE, 0, 0);
        MSVIDEO_SendMessage(whic, DRV_FREE, 0, 0);
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
    }
    else
    {
        CloseDriver(whic->hdrv, 0, 0);
    }

    /* remove whic from list */
    for (p = &MSVIDEO_FirstHic; *p != NULL; p = &((*p)->next))
    {
        if ((*p) == whic)
        {
            *p = whic->next;
            break;
        }
    }

    HeapFree(GetProcessHeap(), 0, whic);
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
}
1198

1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209


/***********************************************************************
 *		ICImageCompress	[MSVFW32.@]
 */
HANDLE VFWAPI ICImageCompress(
	HIC hic, UINT uiFlags,
	LPBITMAPINFO lpbiIn, LPVOID lpBits,
	LPBITMAPINFO lpbiOut, LONG lQuality,
	LONG* plSize)
{
1210
	FIXME("(%p,%08x,%p,%p,%p,%d,%p)\n",
1211 1212
		hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);

1213
	return NULL;
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
}

/***********************************************************************
 *		ICImageDecompress	[MSVFW32.@]
 */

HANDLE VFWAPI ICImageDecompress(
	HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
	LPVOID lpBits, LPBITMAPINFO lpbiOut)
{
1224
	HGLOBAL	hMem = NULL;
1225 1226 1227
	BYTE*	pMem = NULL;
	BOOL	bReleaseIC = FALSE;
	BYTE*	pHdr = NULL;
1228
	ULONG	cbHdr = 0;
1229 1230 1231 1232
	BOOL	bSucceeded = FALSE;
	BOOL	bInDecompress = FALSE;
	DWORD	biSizeImage;

1233
	TRACE("(%p,%08x,%p,%p,%p)\n",
1234 1235
		hic, uiFlags, lpbiIn, lpBits, lpbiOut);

1236
	if ( hic == NULL )
1237
	{
1238
		hic = ICDecompressOpen( ICTYPE_VIDEO, 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
1239
		if ( hic == NULL )
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
		{
			WARN("no handler\n" );
			goto err;
		}
		bReleaseIC = TRUE;
	}
	if ( uiFlags != 0 )
	{
		FIXME( "unknown flag %08x\n", uiFlags );
		goto err;
	}
	if ( lpbiIn == NULL || lpBits == NULL )
	{
		WARN("invalid argument\n");
		goto err;
	}

	if ( lpbiOut != NULL )
	{
		if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
			goto err;
		cbHdr = sizeof(BITMAPINFOHEADER);
		if ( lpbiOut->bmiHeader.biCompression == 3 )
			cbHdr += sizeof(DWORD)*3;
		else
		if ( lpbiOut->bmiHeader.biBitCount <= 8 )
		{
			if ( lpbiOut->bmiHeader.biClrUsed == 0 )
				cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
			else
				cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
		}
	}
	else
	{
		TRACE( "get format\n" );

		cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
		if ( cbHdr < sizeof(BITMAPINFOHEADER) )
			goto err;
1280
		pHdr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,cbHdr+sizeof(RGBQUAD)*256);
1281 1282
		if ( pHdr == NULL )
			goto err;
1283
		if ( ICDecompressGetFormat( hic, lpbiIn, pHdr ) != ICERR_OK )
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
			goto err;
		lpbiOut = (BITMAPINFO*)pHdr;
		if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
			 ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
			 lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
		{
			if ( lpbiIn->bmiHeader.biClrUsed == 0 )
				memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
			else
				memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
		}
		if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
			 lpbiOut->bmiHeader.biClrUsed == 0 )
			lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;

		lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
	}

	biSizeImage = lpbiOut->bmiHeader.biSizeImage;
	if ( biSizeImage == 0 )
		biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);

	TRACE( "call ICDecompressBegin\n" );

	if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
		goto err;
	bInDecompress = TRUE;

1313
	TRACE( "cbHdr %d, biSizeImage %d\n", cbHdr, biSizeImage );
1314 1315

	hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
1316
	if ( hMem == NULL )
1317 1318 1319 1320
	{
		WARN( "out of memory\n" );
		goto err;
	}
1321
	pMem = GlobalLock( hMem );
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
	if ( pMem == NULL )
		goto err;
	memcpy( pMem, lpbiOut, cbHdr );

	TRACE( "call ICDecompress\n" );
	if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
		goto err;

	bSucceeded = TRUE;
err:
	if ( bInDecompress )
		ICDecompressEnd( hic );
	if ( bReleaseIC )
		ICClose(hic);
1336
        HeapFree(GetProcessHeap(),0,pHdr);
1337 1338
	if ( pMem != NULL )
		GlobalUnlock( hMem );
1339
	if ( !bSucceeded && hMem != NULL )
1340
	{
1341
		GlobalFree(hMem); hMem = NULL;
1342 1343
	}

1344
	return hMem;
1345
}
1346

1347 1348 1349 1350 1351
/***********************************************************************
 *      ICSeqCompressFrame   [MSVFW32.@]
 */
LPVOID VFWAPI ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL *pfKey, LONG *plSize)
{
1352
    ICCOMPRESS* icComp = pc->lpState;
1353 1354 1355 1356 1357
    DWORD ret;
    TRACE("(%p, 0x%08x, %p, %p, %p)\n", pc, uiFlags, lpBits, pfKey, plSize);

    if (pc->cbState != sizeof(ICCOMPRESS))
    {
1358
       ERR("Invalid cbState %i\n", pc->cbState);
1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
       return NULL;
    }

    if (!pc->lKeyCount++)
       icComp->dwFlags = ICCOMPRESS_KEYFRAME;
    else
    {
        if (pc->lKey && pc->lKeyCount == (pc->lKey - 1))
        /* No key frames if pc->lKey == 0 */
           pc->lKeyCount = 0;
	icComp->dwFlags = 0;
    }

    icComp->lpInput = lpBits;
    icComp->lFrameNum = pc->lFrame++;
    icComp->lpOutput = pc->lpBitsOut;
    icComp->lpPrev = pc->lpBitsPrev;
    ret = ICSendMessage(pc->hic, ICM_COMPRESS, (DWORD_PTR)icComp, sizeof(icComp));

    if (icComp->dwFlags & AVIIF_KEYFRAME)
    {
       pc->lKeyCount = 1;
       *pfKey = TRUE;
       TRACE("Key frame\n");
    }
    else
       *pfKey = FALSE;

    *plSize = icComp->lpbiOutput->biSizeImage;
1388
    TRACE(" -- 0x%08x\n", ret);
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
    if (ret == ICERR_OK)
    {
       LPVOID oldprev, oldout;
/* We shift Prev and Out, so we don't have to allocate and release memory */
       oldprev = pc->lpBitsPrev;
       oldout = pc->lpBitsOut;
       pc->lpBitsPrev = oldout;
       pc->lpBitsOut = oldprev;

       TRACE("returning: %p\n", icComp->lpOutput);
       return icComp->lpOutput;
    }
1401 1402 1403 1404 1405 1406 1407 1408
    return NULL;
}

/***********************************************************************
 *      ICSeqCompressFrameEnd   [MSVFW32.@]
 */
void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
{
1409 1410 1411
    DWORD ret;
    TRACE("(%p)\n", pc);
    ret = ICSendMessage(pc->hic, ICM_COMPRESS_END, 0, 0);
1412
    TRACE(" -- %x\n", ret);
1413 1414 1415 1416
    HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
    HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
    HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
    HeapFree(GetProcessHeap(), 0, pc->lpState);
1417
    pc->lpbiIn = pc->lpBitsPrev = pc->lpBitsOut = pc->lpState = NULL;
1418 1419 1420
}

/***********************************************************************
1421
 *      ICSeqCompressFrameStart [MSVFW32.@]
1422 1423 1424
 */
BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
{
1425 1426 1427 1428 1429 1430 1431 1432
    /* I'm ignoring bmiColors as I don't know what to do with it,
     * it doesn't appear to be used though
     */
    DWORD ret;
    pc->lpbiIn = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFO));
    if (!pc->lpbiIn)
        return FALSE;

1433
    *pc->lpbiIn = *lpbiIn;
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
    pc->lpBitsPrev = HeapAlloc(GetProcessHeap(), 0, pc->lpbiIn->bmiHeader.biSizeImage);
    if (!pc->lpBitsPrev)
    {
        HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
	return FALSE;
    }

    pc->lpState = HeapAlloc(GetProcessHeap(), 0, sizeof(ICCOMPRESS));
    if (!pc->lpState)
    {
       HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
       HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
       return FALSE;
    }
    pc->cbState = sizeof(ICCOMPRESS);

    pc->lpBitsOut = HeapAlloc(GetProcessHeap(), 0, pc->lpbiOut->bmiHeader.biSizeImage);
    if (!pc->lpBitsOut)
    {
       HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
       HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
       HeapFree(GetProcessHeap(), 0, pc->lpState);
       return FALSE;
    }
    TRACE("Compvars:\n"
1459 1460 1461 1462 1463 1464 1465 1466
          "\tpc:\n"
          "\tsize: %i\n"
          "\tflags: %i\n"
          "\thic: %p\n"
          "\ttype: %x\n"
          "\thandler: %x\n"
          "\tin/out: %p/%p\n"
          "key/data/quality: %i/%i/%i\n",
1467 1468 1469
	     pc->cbSize, pc->dwFlags, pc->hic, pc->fccType, pc->fccHandler,
	     pc->lpbiIn, pc->lpbiOut, pc->lKey, pc->lDataRate, pc->lQ);

1470
    ret = ICSendMessage(pc->hic, ICM_COMPRESS_BEGIN, (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1471
    TRACE(" -- %x\n", ret);
1472 1473
    if (ret == ICERR_OK)
    {
1474
       ICCOMPRESS* icComp = pc->lpState;
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
       /* Initialise some variables */
       pc->lFrame = 0; pc->lKeyCount = 0;

       icComp->lpbiOutput = &pc->lpbiOut->bmiHeader;
       icComp->lpbiInput = &pc->lpbiIn->bmiHeader;
       icComp->lpckid = NULL;
       icComp->dwFrameSize = 0;
       icComp->dwQuality = pc->lQ;
       icComp->lpbiPrev = &pc->lpbiIn->bmiHeader;
       return TRUE;
    }
    HeapFree(GetProcessHeap(), 0, pc->lpbiIn);
    HeapFree(GetProcessHeap(), 0, pc->lpBitsPrev);
    HeapFree(GetProcessHeap(), 0, pc->lpState);
    HeapFree(GetProcessHeap(), 0, pc->lpBitsOut);
    pc->lpBitsPrev = pc->lpbiIn = pc->lpState = pc->lpBitsOut = NULL;
    return FALSE;
1492 1493 1494 1495 1496
}

/***********************************************************************
 *      GetFileNamePreview   [MSVFW32.@]
 */
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
static BOOL GetFileNamePreview(LPVOID lpofn,BOOL bSave,BOOL bUnicode)
{
  CHAR    szFunctionName[20];
  BOOL    (*fnGetFileName)(LPVOID);
  HMODULE hComdlg32;
  BOOL    ret;

  FIXME("(%p,%d,%d), semi-stub!\n",lpofn,bSave,bUnicode);

  lstrcpyA(szFunctionName, (bSave ? "GetSaveFileName" : "GetOpenFileName"));
  lstrcatA(szFunctionName, (bUnicode ? "W" : "A"));

  hComdlg32 = LoadLibraryA("COMDLG32.DLL");
  if (hComdlg32 == NULL)
    return FALSE;

  fnGetFileName = (LPVOID)GetProcAddress(hComdlg32, szFunctionName);
  if (fnGetFileName == NULL)
    return FALSE;

  /* FIXME: need to add OFN_ENABLEHOOK and our own handler */
  ret = fnGetFileName(lpofn);

  FreeLibrary(hComdlg32);
  return ret;
}

1524 1525 1526 1527 1528
/***********************************************************************
 *		GetOpenFileNamePreviewA	[MSVFW32.@]
 */
BOOL WINAPI GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn)
{
1529
  FIXME("(%p), semi-stub!\n", lpofn);
1530

1531
  return GetFileNamePreview(lpofn, FALSE, FALSE);
1532 1533 1534 1535 1536 1537 1538
}

/***********************************************************************
 *		GetOpenFileNamePreviewW	[MSVFW32.@]
 */
BOOL WINAPI GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn)
{
1539
  FIXME("(%p), semi-stub!\n", lpofn);
1540

1541
  return GetFileNamePreview(lpofn, FALSE, TRUE);
1542 1543 1544 1545 1546 1547 1548
}

/***********************************************************************
 *		GetSaveFileNamePreviewA	[MSVFW32.@]
 */
BOOL WINAPI GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn)
{
1549
  FIXME("(%p), semi-stub!\n", lpofn);
1550

1551
  return GetFileNamePreview(lpofn, TRUE, FALSE);
1552 1553 1554 1555 1556 1557 1558
}

/***********************************************************************
 *		GetSaveFileNamePreviewW	[MSVFW32.@]
 */
BOOL WINAPI GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn)
{
1559
  FIXME("(%p), semi-stub!\n", lpofn);
1560

1561
  return GetFileNamePreview(lpofn, TRUE, TRUE);
1562
}