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