ok() does not support '%S'. Store the Ansi version, convert to Unicode
[wine] / dlls / msvideo / msvideo_main.c
1 /*
2  * Copyright 1998 Marcus Meissner
3  * Copyright 2000 Bradley Baetz
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * FIXME: This all assumes 32 bit codecs
20  *              Win95 appears to prefer 32 bit codecs, even from 16 bit code.
21  *              There is the ICOpenFunction16 to worry about still, though.
22  *      
23  * TODO
24  *      - no thread safety
25  *      - the four CC comparisons are wrong on big endian machines
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "msvideo_private.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
38
39 LRESULT (CALLBACK *pFnCallTo16)(HDRVR, HIC, UINT, LPARAM, LPARAM) = NULL;
40
41 static WINE_HIC*        MSVIDEO_FirstHic /* = NULL */;
42
43 /******************************************************************
44  *              MSVIDEO_GetHicPtr
45  *
46  *
47  */
48 WINE_HIC*   MSVIDEO_GetHicPtr(HIC hic)
49 {
50     WINE_HIC*   whic;
51
52     for (whic = MSVIDEO_FirstHic; whic && whic->hic != hic; whic = whic->next);
53     return whic;
54 }
55
56 /***********************************************************************
57  *              VideoForWindowsVersion          [MSVFW32.2]
58  *              VideoForWindowsVersion          [MSVIDEO.2]
59  * Returns the version in major.minor form.
60  * In Windows95 this returns 0x040003b6 (4.950)
61  */
62 DWORD WINAPI VideoForWindowsVersion(void) 
63 {
64     return 0x040003B6; /* 4.950 */
65 }
66
67 /* system.ini: [drivers] */
68
69 /***********************************************************************
70  *              ICInfo                          [MSVFW32.@]
71  * Get information about an installable compressor. Return TRUE if there
72  * is one.
73  */
74 BOOL VFWAPI ICInfo(
75         DWORD fccType,          /* [in] type of compressor ('vidc') */
76         DWORD fccHandler,       /* [in] <n>th compressor */
77         ICINFO *lpicinfo)       /* [out] information about compressor */
78 {
79     char        buf[2000];
80
81     TRACE("(%.4s,%.4s,%p)\n", (char*)&fccType, (char*)&fccHandler, lpicinfo);
82
83     if (GetPrivateProfileStringA("drivers32", NULL, NULL, buf, sizeof(buf), "system.ini")) 
84     {
85         char *s = buf;
86         while (*s) 
87         {
88             if (!strncasecmp((char*)&fccType, s, 4) && s[4] == '.' && s[9] == '=')
89             {
90                 if (!fccHandler--) 
91                 {
92                     HIC hic;
93
94                     lpicinfo->fccHandler = mmioStringToFOURCCA(s + 5, 0);
95                     hic = ICOpen(fccType, lpicinfo->fccHandler, ICMODE_QUERY);
96                     if (hic)
97                     {
98                         ICGetInfo(hic, lpicinfo, lpicinfo->dwSize);
99                         ICClose(hic);
100                         return TRUE;
101                     }
102                     return FALSE;
103                 }
104             }
105             s += strlen(s) + 1; /* either next char or \0 */
106         }
107     }
108     return FALSE;
109 }
110
111 static DWORD IC_HandleRef = 1;
112
113 /***********************************************************************
114  *              ICOpen                          [MSVFW32.@]
115  * Opens an installable compressor. Return special handle.
116  */
117 HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode) 
118 {
119     char                codecname[20];
120     ICOPEN              icopen;
121     HDRVR               hdrv;
122     WINE_HIC*           whic;
123     BOOL                bIs16;
124
125     TRACE("(%.4s,%.4s,0x%08lx)\n", (char*)&fccType, (char*)&fccHandler, (DWORD)wMode);
126
127     sprintf(codecname, "%.4s.%.4s", (char*)&fccType, (char*)&fccHandler);
128
129     /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
130      * same layout as ICOPEN
131      */
132     icopen.dwSize               = sizeof(ICOPEN);
133     icopen.fccType              = fccType;
134     icopen.fccHandler           = fccHandler;
135     icopen.dwVersion            = 0x00001000; /* FIXME */
136     icopen.dwFlags              = wMode;
137     icopen.dwError              = 0;
138     icopen.pV1Reserved          = NULL;
139     icopen.pV2Reserved          = NULL;
140     icopen.dnDevNode            = 0; /* FIXME */
141         
142     hdrv = OpenDriverA(codecname, "drivers32", (LPARAM)&icopen);
143     if (!hdrv) 
144     {
145         if (fccType == streamtypeVIDEO) 
146         {
147             sprintf(codecname, "vidc.%.4s", (char*)&fccHandler);
148             fccType = ICTYPE_VIDEO;
149             hdrv = OpenDriverA(codecname, "drivers32", (LPARAM)&icopen);
150         }
151         if (!hdrv)
152             return 0;
153     }
154     bIs16 = GetDriverFlags(hdrv) & WINE_GDF_16BIT;
155
156     if (bIs16 && !pFnCallTo16)
157     {
158         FIXME("Got a 16 bit driver, but no 16 bit support in msvfw\n");
159         return 0;
160     }
161     whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
162     if (!whic)
163     {
164         CloseDriver(hdrv, 0, 0);
165         return FALSE;
166     }
167     whic->hdrv          = hdrv;
168     /* FIXME: is the signature the real one ? */
169     whic->driverproc    = bIs16 ? (DRIVERPROC)pFnCallTo16 : NULL;
170     whic->driverproc16  = 0;
171     whic->type          = fccType;
172     whic->handler       = fccHandler;
173     while (MSVIDEO_GetHicPtr(HIC_32(IC_HandleRef)) != NULL) IC_HandleRef++;
174     whic->hic           = HIC_32(IC_HandleRef++);
175     whic->next          = MSVIDEO_FirstHic;
176     MSVIDEO_FirstHic = whic;
177
178     TRACE("=> %p\n", whic->hic);
179     return whic->hic;
180 }
181
182 /***********************************************************************
183  *              MSVIDEO_OpenFunction
184  */
185 HIC MSVIDEO_OpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, 
186                          DRIVERPROC lpfnHandler, DWORD lpfnHandler16) 
187 {
188     ICOPEN      icopen;
189     WINE_HIC*   whic;
190
191     TRACE("(%.4s,%.4s,%d,%p,%08lx)\n", 
192           (char*)&fccType, (char*)&fccHandler, wMode, lpfnHandler, lpfnHandler16);
193
194     icopen.dwSize               = sizeof(ICOPEN);
195     icopen.fccType              = fccType;
196     icopen.fccHandler           = fccHandler;
197     icopen.dwVersion            = 0x00001000; /* FIXME */
198     icopen.dwFlags              = wMode;
199     icopen.dwError              = 0;
200     icopen.pV1Reserved          = NULL;
201     icopen.pV2Reserved          = NULL;
202     icopen.dnDevNode            = 0; /* FIXME */
203
204     whic = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HIC));
205     if (!whic) return 0;
206
207     whic->driverproc   = lpfnHandler;
208     whic->driverproc16 = lpfnHandler16;
209     while (MSVIDEO_GetHicPtr(HIC_32(IC_HandleRef)) != NULL) IC_HandleRef++;
210     whic->hic          = HIC_32(IC_HandleRef++);
211     whic->next         = MSVIDEO_FirstHic;
212     MSVIDEO_FirstHic = whic;
213
214     /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
215     /* What if the function is used more than once? */
216
217     if (MSVIDEO_SendMessage(whic->hic, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) 
218     {
219         WARN("DRV_LOAD failed for hic %p\n", whic->hic);
220         MSVIDEO_FirstHic = whic->next;
221         HeapFree(GetProcessHeap(), 0, whic);
222         return 0;
223     }
224     /* return value is not checked */
225     MSVIDEO_SendMessage(whic->hic, DRV_ENABLE, 0L, 0L);
226
227     whic->hdrv = (HDRVR)MSVIDEO_SendMessage(whic->hic, DRV_OPEN, 0, (DWORD)&icopen);
228
229     if (whic->hdrv == 0) 
230     {
231         WARN("DRV_OPEN failed for hic %p\n", whic->hic);
232         MSVIDEO_FirstHic = whic->next;
233         HeapFree(GetProcessHeap(), 0, whic);
234         return 0;
235     }
236
237     TRACE("=> %p\n", whic->hic);
238     return whic->hic;
239 }
240
241 /***********************************************************************
242  *              ICOpenFunction                  [MSVFW32.@]
243  */
244 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler) 
245 {
246     return MSVIDEO_OpenFunction(fccType, fccHandler, wMode, (DRIVERPROC)lpfnHandler, 0);
247 }
248
249 /***********************************************************************
250  *              ICGetInfo                       [MSVFW32.@]
251  */
252 LRESULT VFWAPI ICGetInfo(HIC hic,ICINFO *picinfo,DWORD cb) {
253         LRESULT         ret;
254
255         TRACE("(%p,%p,%ld)\n",hic,picinfo,cb);
256         ret = ICSendMessage(hic,ICM_GETINFO,(DWORD)picinfo,cb);
257         TRACE(" -> 0x%08lx\n",ret);
258         return ret;
259 }
260
261 /***********************************************************************
262  *              ICLocate                        [MSVFW32.@]
263  */
264 HIC VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
265                     LPBITMAPINFOHEADER lpbiOut, WORD wMode)
266 {
267     HIC         hic;
268     DWORD       querymsg;
269     LPSTR       pszBuffer;
270
271     TRACE("(%.4s,%.4s,%p,%p,0x%04x)\n", 
272           (char*)&fccType, (char*)&fccHandler, lpbiIn, lpbiOut, wMode);
273
274     switch (wMode) 
275     {
276     case ICMODE_FASTCOMPRESS:
277     case ICMODE_COMPRESS:
278         querymsg = ICM_COMPRESS_QUERY;
279         break;
280     case ICMODE_FASTDECOMPRESS:
281     case ICMODE_DECOMPRESS:
282         querymsg = ICM_DECOMPRESS_QUERY;
283         break;
284     case ICMODE_DRAW:
285         querymsg = ICM_DRAW_QUERY;
286         break;
287     default:
288         WARN("Unknown mode (%d)\n", wMode);
289         return 0;
290     }
291
292     /* Easy case: handler/type match, we just fire a query and return */
293     hic = ICOpen(fccType, fccHandler, wMode);
294     if (hic) 
295     {
296         if (!ICSendMessage(hic, querymsg, (DWORD)lpbiIn, (DWORD)lpbiOut))
297         {
298             TRACE("=> %p\n", hic);
299             return hic;
300         }
301         ICClose(hic);
302     }
303
304     /* Now try each driver in turn. 32 bit codecs only. */
305     /* FIXME: Move this to an init routine? */
306     
307     pszBuffer = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 1024);
308     if (GetPrivateProfileSectionA("drivers32", pszBuffer, 1024, "system.ini")) 
309     {
310         char* s = pszBuffer;
311         while (*s) 
312         {
313             if (!strncasecmp((char*)&fccType, s, 4) && s[4] == '.' && s[9] == '=')
314             {
315                 char *s2 = s;
316                 while (*s2 != '\0' && *s2 != '.') s2++;
317                 if (*s2++) 
318                 {
319                     hic = ICOpen(fccType, *(DWORD*)s2, wMode);
320                     if (hic) 
321                     {
322                         if (!ICSendMessage(hic, querymsg, (DWORD)lpbiIn, (DWORD)lpbiOut))
323                         {
324                             HeapFree(GetProcessHeap(), 0, pszBuffer);
325                             TRACE("=> %p\n", hic);
326                             return hic;
327                         }
328                         ICClose(hic);
329                     }
330                 }
331             }
332             s += strlen(s) + 1;
333         }
334     }
335     HeapFree(GetProcessHeap(), 0, pszBuffer);
336
337     if (fccType == streamtypeVIDEO) 
338         return ICLocate(ICTYPE_VIDEO, fccHandler, lpbiIn, lpbiOut, wMode);
339     
340     WARN("(%.4s,%.4s,%p,%p,0x%04x) not found!\n",
341          (char*)&fccType, (char*)&fccHandler, lpbiIn, lpbiOut, wMode);
342     return 0;
343 }
344
345 /***********************************************************************
346  *              ICGetDisplayFormat                      [MSVFW32.@]
347  */
348 HIC VFWAPI ICGetDisplayFormat(
349         HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
350         INT depth,INT dx,INT dy)
351 {
352         HIC     tmphic = hic;
353
354         FIXME("(%p,%p,%p,%d,%d,%d),stub!\n",hic,lpbiIn,lpbiOut,depth,dx,dy);
355         if (!tmphic) {
356                 tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
357                 if (!tmphic)
358                         return tmphic;
359         }
360         if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
361                 dy = dx = 0; /* no resize needed */
362
363         /* Can we decompress it ? */
364         if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
365                 goto errout; /* no, sorry */
366
367         ICDecompressGetFormat(tmphic,lpbiIn,lpbiOut);
368
369         if (lpbiOut->biCompression != 0) {
370            FIXME("Ooch, how come decompressor outputs compressed data (%ld)??\n",
371                          lpbiOut->biCompression);
372         }
373         if (lpbiOut->biSize < sizeof(*lpbiOut)) {
374            FIXME("Ooch, size of output BIH is too small (%ld)\n",
375                          lpbiOut->biSize);
376            lpbiOut->biSize = sizeof(*lpbiOut);
377         }
378         if (!depth) {
379                 HDC     hdc;
380
381                 hdc = GetDC(0);
382                 depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
383                 ReleaseDC(0,hdc);
384                 if (depth==15)  depth = 16;
385                 if (depth<8)    depth =  8;
386         }
387         if (lpbiIn->biBitCount == 8)
388                 depth = 8;
389
390         TRACE("=> %p\n", tmphic);
391         return tmphic;
392 errout:
393         if (hic!=tmphic)
394                 ICClose(tmphic);
395
396         TRACE("=> 0\n");
397         return 0;
398 }
399
400 /***********************************************************************
401  *              ICCompress                      [MSVFW32.@]
402  */
403 DWORD VFWAPIV
404 ICCompress(
405         HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
406         LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
407         LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
408         LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
409 {
410         ICCOMPRESS      iccmp;
411
412         TRACE("(%p,%ld,%p,%p,%p,%p,...)\n",hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
413
414         iccmp.dwFlags           = dwFlags;
415
416         iccmp.lpbiOutput        = lpbiOutput;
417         iccmp.lpOutput          = lpData;
418         iccmp.lpbiInput         = lpbiInput;
419         iccmp.lpInput           = lpBits;
420
421         iccmp.lpckid            = lpckid;
422         iccmp.lpdwFlags         = lpdwFlags;
423         iccmp.lFrameNum         = lFrameNum;
424         iccmp.dwFrameSize       = dwFrameSize;
425         iccmp.dwQuality         = dwQuality;
426         iccmp.lpbiPrev          = lpbiPrev;
427         iccmp.lpPrev            = lpPrev;
428         return ICSendMessage(hic,ICM_COMPRESS,(DWORD)&iccmp,sizeof(iccmp));
429 }
430
431 /***********************************************************************
432  *              ICDecompress                    [MSVFW32.@]
433  */
434 DWORD VFWAPIV  ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
435                                 LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
436 {
437         ICDECOMPRESS    icd;
438         DWORD ret;
439
440         TRACE("(%p,%ld,%p,%p,%p,%p)\n",hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
441
442         TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
443
444         icd.dwFlags     = dwFlags;
445         icd.lpbiInput   = lpbiFormat;
446         icd.lpInput     = lpData;
447
448         icd.lpbiOutput  = lpbi;
449         icd.lpOutput    = lpBits;
450         icd.ckid        = 0;
451         ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD)&icd,sizeof(ICDECOMPRESS));
452
453         TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
454
455         TRACE("-> %ld\n",ret);
456
457         return ret;
458 }
459
460
461 /***********************************************************************
462  *              ICCompressorChoose   [MSVFW32.@]
463  */
464 BOOL VFWAPI ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn, LPVOID lpData,
465                                PCOMPVARS pc, LPSTR lpszTitle)
466 {
467     FIXME("stub\n");
468     return FALSE;
469 }
470
471
472 /***********************************************************************
473  *              ICCompressorFree   [MSVFW32.@]
474  */
475 void VFWAPI ICCompressorFree(PCOMPVARS pc)
476 {
477     FIXME("stub\n");
478 }
479
480
481 /******************************************************************
482  *              MSVIDEO_SendMessage
483  *
484  *
485  */
486 LRESULT MSVIDEO_SendMessage(HIC hic,UINT msg,DWORD lParam1,DWORD lParam2)
487 {
488     LRESULT     ret;
489     WINE_HIC*   whic = MSVIDEO_GetHicPtr(hic);
490     
491 #define XX(x) case x: TRACE("(%p,"#x",0x%08lx,0x%08lx)\n",hic,lParam1,lParam2);break;
492     
493     switch (msg) {
494         /* DRV_* */
495         XX(DRV_LOAD);
496         XX(DRV_ENABLE);
497         XX(DRV_OPEN);
498         XX(DRV_CLOSE);
499         XX(DRV_DISABLE);
500         XX(DRV_FREE);
501         /* ICM_RESERVED+X */
502         XX(ICM_ABOUT);
503         XX(ICM_CONFIGURE);
504         XX(ICM_GET);
505         XX(ICM_GETINFO);
506         XX(ICM_GETDEFAULTQUALITY);
507         XX(ICM_GETQUALITY);
508         XX(ICM_GETSTATE);
509         XX(ICM_SETQUALITY);
510         XX(ICM_SET);
511         XX(ICM_SETSTATE);
512         /* ICM_USER+X */
513         XX(ICM_COMPRESS_FRAMES_INFO);
514         XX(ICM_COMPRESS_GET_FORMAT);
515         XX(ICM_COMPRESS_GET_SIZE);
516         XX(ICM_COMPRESS_QUERY);
517         XX(ICM_COMPRESS_BEGIN);
518         XX(ICM_COMPRESS);
519         XX(ICM_COMPRESS_END);
520         XX(ICM_DECOMPRESS_GET_FORMAT);
521         XX(ICM_DECOMPRESS_QUERY);
522         XX(ICM_DECOMPRESS_BEGIN);
523         XX(ICM_DECOMPRESS);
524         XX(ICM_DECOMPRESS_END);
525         XX(ICM_DECOMPRESS_SET_PALETTE);
526         XX(ICM_DECOMPRESS_GET_PALETTE);
527         XX(ICM_DRAW_QUERY);
528         XX(ICM_DRAW_BEGIN);
529         XX(ICM_DRAW_GET_PALETTE);
530         XX(ICM_DRAW_START);
531         XX(ICM_DRAW_STOP);
532         XX(ICM_DRAW_END);
533         XX(ICM_DRAW_GETTIME);
534         XX(ICM_DRAW);
535         XX(ICM_DRAW_WINDOW);
536         XX(ICM_DRAW_SETTIME);
537         XX(ICM_DRAW_REALIZE);
538         XX(ICM_DRAW_FLUSH);
539         XX(ICM_DRAW_RENDERBUFFER);
540         XX(ICM_DRAW_START_PLAY);
541         XX(ICM_DRAW_STOP_PLAY);
542         XX(ICM_DRAW_SUGGESTFORMAT);
543         XX(ICM_DRAW_CHANGEPALETTE);
544         XX(ICM_GETBUFFERSWANTED);
545         XX(ICM_GETDEFAULTKEYFRAMERATE);
546         XX(ICM_DECOMPRESSEX_BEGIN);
547         XX(ICM_DECOMPRESSEX_QUERY);
548         XX(ICM_DECOMPRESSEX);
549         XX(ICM_DECOMPRESSEX_END);
550         XX(ICM_SET_STATUS_PROC);
551     default:
552         FIXME("(%p,0x%08lx,0x%08lx,0x%08lx) unknown message\n",hic,(DWORD)msg,lParam1,lParam2);
553     }
554     
555 #undef XX
556     
557     if (!whic) return ICERR_BADHANDLE;
558     
559     if (whic->driverproc) {
560         ret = whic->driverproc((DWORD)hic, whic->hdrv, msg, lParam1, lParam2);
561     } else {
562         ret = SendDriverMessage(whic->hdrv, msg, lParam1, lParam2);
563     }
564
565     TRACE("     -> 0x%08lx\n", ret);
566     return ret;
567 }
568
569 /***********************************************************************
570  *              ICSendMessage                   [MSVFW32.@]
571  */
572 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD lParam1, DWORD lParam2) {
573         return MSVIDEO_SendMessage(hic,msg,lParam1,lParam2);
574 }
575
576 /***********************************************************************
577  *              ICDrawBegin             [MSVFW32.@]
578  */
579 DWORD VFWAPIV ICDrawBegin(
580         HIC                hic,     /* [in] */
581         DWORD              dwFlags, /* [in] flags */
582         HPALETTE           hpal,    /* [in] palette to draw with */
583         HWND               hwnd,    /* [in] window to draw to */
584         HDC                hdc,     /* [in] HDC to draw to */
585         INT                xDst,    /* [in] destination rectangle */
586         INT                yDst,    /* [in] */
587         INT                dxDst,   /* [in] */
588         INT                dyDst,   /* [in] */
589         LPBITMAPINFOHEADER lpbi,    /* [in] format of frame to draw */
590         INT                xSrc,    /* [in] source rectangle */
591         INT                ySrc,    /* [in] */
592         INT                dxSrc,   /* [in] */
593         INT                dySrc,   /* [in] */
594         DWORD              dwRate,  /* [in] frames/second = (dwRate/dwScale) */
595         DWORD              dwScale) /* [in] */
596 {
597
598         ICDRAWBEGIN     icdb;
599
600         TRACE("(%p,%ld,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%ld,%ld)\n",
601                   hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
602                   lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
603
604         icdb.dwFlags = dwFlags;
605         icdb.hpal = hpal;
606         icdb.hwnd = hwnd;
607         icdb.hdc = hdc;
608         icdb.xDst = xDst;
609         icdb.yDst = yDst;
610         icdb.dxDst = dxDst;
611         icdb.dyDst = dyDst;
612         icdb.lpbi = lpbi;
613         icdb.xSrc = xSrc;
614         icdb.ySrc = ySrc;
615         icdb.dxSrc = dxSrc;
616         icdb.dySrc = dySrc;
617         icdb.dwRate = dwRate;
618         icdb.dwScale = dwScale;
619         return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD)&icdb,sizeof(icdb));
620 }
621
622 /***********************************************************************
623  *              ICDraw                  [MSVFW32.@]
624  */
625 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
626         ICDRAW  icd;
627
628         TRACE("(%p,%ld,%p,%p,%ld,%ld)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
629
630         icd.dwFlags = dwFlags;
631         icd.lpFormat = lpFormat;
632         icd.lpData = lpData;
633         icd.cbData = cbData;
634         icd.lTime = lTime;
635
636         return ICSendMessage(hic,ICM_DRAW,(DWORD)&icd,sizeof(icd));
637 }
638
639 /***********************************************************************
640  *              ICClose                 [MSVFW32.@]
641  */
642 LRESULT WINAPI ICClose(HIC hic)
643 {
644     WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
645     WINE_HIC** p;
646
647     TRACE("(%p)\n",hic);
648
649     if (!whic) return ICERR_BADHANDLE;
650
651     if (whic->driverproc) 
652     {
653         MSVIDEO_SendMessage(hic, DRV_CLOSE, 0, 0);
654         MSVIDEO_SendMessage(hic, DRV_DISABLE, 0, 0);
655         MSVIDEO_SendMessage(hic, DRV_FREE, 0, 0);
656     }
657     else
658     {
659         CloseDriver(whic->hdrv, 0, 0);
660     }
661
662     /* remove whic from list */
663     for (p = &MSVIDEO_FirstHic; *p != NULL; p = &((*p)->next))
664     {
665         if ((*p) == whic)
666         {
667             *p = whic->next;
668             break;
669         }
670     }
671
672     HeapFree(GetProcessHeap(), 0, whic);
673     return 0;
674 }
675
676
677
678 /***********************************************************************
679  *              ICImageCompress [MSVFW32.@]
680  */
681 HANDLE VFWAPI ICImageCompress(
682         HIC hic, UINT uiFlags,
683         LPBITMAPINFO lpbiIn, LPVOID lpBits,
684         LPBITMAPINFO lpbiOut, LONG lQuality,
685         LONG* plSize)
686 {
687         FIXME("(%p,%08x,%p,%p,%p,%ld,%p)\n",
688                 hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
689
690         return NULL;
691 }
692
693 /***********************************************************************
694  *              ICImageDecompress       [MSVFW32.@]
695  */
696
697 HANDLE VFWAPI ICImageDecompress(
698         HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
699         LPVOID lpBits, LPBITMAPINFO lpbiOut)
700 {
701         HGLOBAL hMem = NULL;
702         BYTE*   pMem = NULL;
703         BOOL    bReleaseIC = FALSE;
704         BYTE*   pHdr = NULL;
705         LONG    cbHdr = 0;
706         BOOL    bSucceeded = FALSE;
707         BOOL    bInDecompress = FALSE;
708         DWORD   biSizeImage;
709
710         TRACE("(%p,%08x,%p,%p,%p)\n",
711                 hic, uiFlags, lpbiIn, lpBits, lpbiOut);
712
713         if ( hic == NULL )
714         {
715                 hic = ICDecompressOpen( mmioFOURCC('V','I','D','C'), 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
716                 if ( hic == NULL )
717                 {
718                         WARN("no handler\n" );
719                         goto err;
720                 }
721                 bReleaseIC = TRUE;
722         }
723         if ( uiFlags != 0 )
724         {
725                 FIXME( "unknown flag %08x\n", uiFlags );
726                 goto err;
727         }
728         if ( lpbiIn == NULL || lpBits == NULL )
729         {
730                 WARN("invalid argument\n");
731                 goto err;
732         }
733
734         if ( lpbiOut != NULL )
735         {
736                 if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
737                         goto err;
738                 cbHdr = sizeof(BITMAPINFOHEADER);
739                 if ( lpbiOut->bmiHeader.biCompression == 3 )
740                         cbHdr += sizeof(DWORD)*3;
741                 else
742                 if ( lpbiOut->bmiHeader.biBitCount <= 8 )
743                 {
744                         if ( lpbiOut->bmiHeader.biClrUsed == 0 )
745                                 cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
746                         else
747                                 cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
748                 }
749         }
750         else
751         {
752                 TRACE( "get format\n" );
753
754                 cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
755                 if ( cbHdr < sizeof(BITMAPINFOHEADER) )
756                         goto err;
757                 pHdr = (BYTE*)HeapAlloc(GetProcessHeap(),0,cbHdr+sizeof(RGBQUAD)*256);
758                 if ( pHdr == NULL )
759                         goto err;
760                 ZeroMemory( pHdr, cbHdr+sizeof(RGBQUAD)*256 );
761                 if ( ICDecompressGetFormat( hic, lpbiIn, (BITMAPINFO*)pHdr ) != ICERR_OK )
762                         goto err;
763                 lpbiOut = (BITMAPINFO*)pHdr;
764                 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
765                          ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
766                          lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
767                 {
768                         if ( lpbiIn->bmiHeader.biClrUsed == 0 )
769                                 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
770                         else
771                                 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
772                 }
773                 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
774                          lpbiOut->bmiHeader.biClrUsed == 0 )
775                         lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
776
777                 lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
778                 cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
779         }
780
781         biSizeImage = lpbiOut->bmiHeader.biSizeImage;
782         if ( biSizeImage == 0 )
783                 biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
784
785         TRACE( "call ICDecompressBegin\n" );
786
787         if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
788                 goto err;
789         bInDecompress = TRUE;
790
791         TRACE( "cbHdr %ld, biSizeImage %ld\n", cbHdr, biSizeImage );
792
793         hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
794         if ( hMem == NULL )
795         {
796                 WARN( "out of memory\n" );
797                 goto err;
798         }
799         pMem = (BYTE*)GlobalLock( hMem );
800         if ( pMem == NULL )
801                 goto err;
802         memcpy( pMem, lpbiOut, cbHdr );
803
804         TRACE( "call ICDecompress\n" );
805         if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
806                 goto err;
807
808         bSucceeded = TRUE;
809 err:
810         if ( bInDecompress )
811                 ICDecompressEnd( hic );
812         if ( bReleaseIC )
813                 ICClose(hic);
814         if ( pHdr != NULL )
815                 HeapFree(GetProcessHeap(),0,pHdr);
816         if ( pMem != NULL )
817                 GlobalUnlock( hMem );
818         if ( !bSucceeded && hMem != NULL )
819         {
820                 GlobalFree(hMem); hMem = NULL;
821         }
822
823         return (HANDLE)hMem;
824 }