Add stub implementation for NtAccessCheckAndAuditAlarm.
[wine] / dlls / iccvid / iccvid.c
1 /*
2  * Radius Cinepak Video Decoder
3  *
4  * Copyright 2001 Dr. Tim Ferguson (see below)
5  * Portions Copyright 2003 Mike McCormack for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* Copyright notice from original source:
23  * ------------------------------------------------------------------------
24  * Radius Cinepak Video Decoder
25  *
26  * Dr. Tim Ferguson, 2001.
27  * For more details on the algorithm:
28  *         http://www.csse.monash.edu.au/~timf/videocodec.html
29  *
30  * This is basically a vector quantiser with adaptive vector density.  The
31  * frame is segmented into 4x4 pixel blocks, and each block is coded using
32  * either 1 or 4 vectors.
33  *
34  * There are still some issues with this code yet to be resolved.  In
35  * particular with decoding in the strip boundaries.  However, I have not
36  * yet found a sequence it doesn't work on.  Ill keep trying :)
37  *
38  * You may freely use this source code.  I only ask that you reference its
39  * source in your projects documentation:
40  *       Tim Ferguson: http://www.csse.monash.edu.au/~timf/
41  * ------------------------------------------------------------------------ */
42
43 #include <stdarg.h>
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wingdi.h"
47 #include "winuser.h"
48 #include "commdlg.h"
49 #include "vfw.h"
50
51 #include "mmsystem.h"
52
53 #include "wine/debug.h"
54
55 WINE_DEFAULT_DEBUG_CHANNEL(iccvid);
56
57 #define ICCVID_MAGIC mmioFOURCC('c', 'v', 'i', 'd')
58
59 #define DBUG    0
60 #define MAX_STRIPS 32
61
62 /* ------------------------------------------------------------------------ */
63 typedef struct
64 {
65     unsigned char y0, y1, y2, y3;
66     char u, v;
67     unsigned char r[4], g[4], b[4];
68 } cvid_codebook;
69
70 typedef struct {
71     cvid_codebook *v4_codebook[MAX_STRIPS];
72     cvid_codebook *v1_codebook[MAX_STRIPS];
73     unsigned int strip_num;
74 } cinepak_info;
75
76 typedef struct _ICCVID_Info
77 {
78     DWORD         dwMagic;
79     int           bits_per_pixel;
80     cinepak_info *cvinfo;
81 } ICCVID_Info;
82
83 static inline LPVOID ICCVID_Alloc( size_t size, size_t count )
84 {
85     return HeapAlloc( GetProcessHeap(), 0, size*count );
86 }
87
88 static inline BOOL ICCVID_Free( LPVOID ptr )
89 {
90     return HeapFree( GetProcessHeap(), 0, ptr );
91 }
92
93
94 /* ------------------------------------------------------------------------ */
95 static unsigned char *in_buffer, uiclip[1024], *uiclp = NULL;
96
97 #define get_byte() *(in_buffer++)
98 #define skip_byte() in_buffer++
99 #define get_word() ((unsigned short)(in_buffer += 2, \
100     (in_buffer[-2] << 8 | in_buffer[-1])))
101 #define get_long() ((unsigned long)(in_buffer += 4, \
102     (in_buffer[-4] << 24 | in_buffer[-3] << 16 | in_buffer[-2] << 8 | in_buffer[-1])))
103
104
105 /* ---------------------------------------------------------------------- */
106 static inline void read_codebook(cvid_codebook *c, int mode)
107 {
108 int uvr, uvg, uvb;
109
110     if(mode)        /* black and white */
111         {
112         c->y0 = get_byte();
113         c->y1 = get_byte();
114         c->y2 = get_byte();
115         c->y3 = get_byte();
116         c->u = c->v = 0;
117
118         c->r[0] = c->g[0] = c->b[0] = c->y0;
119         c->r[1] = c->g[1] = c->b[1] = c->y1;
120         c->r[2] = c->g[2] = c->b[2] = c->y2;
121         c->r[3] = c->g[3] = c->b[3] = c->y3;
122         }
123     else            /* colour */
124         {
125         c->y0 = get_byte();  /* luma */
126         c->y1 = get_byte();
127         c->y2 = get_byte();
128         c->y3 = get_byte();
129         c->u = get_byte(); /* chroma */
130         c->v = get_byte();
131
132         uvr = c->v << 1;
133         uvg = -((c->u+1) >> 1) - c->v;
134         uvb = c->u << 1;
135
136         c->r[0] = uiclp[c->y0 + uvr]; c->g[0] = uiclp[c->y0 + uvg]; c->b[0] = uiclp[c->y0 + uvb];
137         c->r[1] = uiclp[c->y1 + uvr]; c->g[1] = uiclp[c->y1 + uvg]; c->b[1] = uiclp[c->y1 + uvb];
138         c->r[2] = uiclp[c->y2 + uvr]; c->g[2] = uiclp[c->y2 + uvg]; c->b[2] = uiclp[c->y2 + uvb];
139         c->r[3] = uiclp[c->y3 + uvr]; c->g[3] = uiclp[c->y3 + uvg]; c->b[3] = uiclp[c->y3 + uvb];
140         }
141 }
142
143
144 #define MAKECOLOUR32(r,g,b) (((r) << 16) | ((g) << 8) | (b))
145 /*#define MAKECOLOUR24(r,g,b) (((r) << 16) | ((g) << 8) | (b))*/
146 #define MAKECOLOUR16(r,g,b) (((r) >> 3) << 11)| (((g) >> 2) << 5)| (((b) >> 3) << 0)
147 #define MAKECOLOUR15(r,g,b) (((r) >> 3) << 10)| (((g) >> 3) << 5)| (((b) >> 3) << 0)
148
149 /* ------------------------------------------------------------------------ */
150 static void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
151 {
152 unsigned long *vptr = (unsigned long *)frm;
153 #ifndef ORIGINAL
154 int row_inc = -stride/4;
155 #else
156 int row_inc = stride/4;
157 #endif
158 int x, y;
159
160     /* fill 4x4 block of pixels with colour values from codebook */
161     for (y = 0; y < 4; y++)
162     {
163         if (&vptr[y*row_inc] < (unsigned long *)limit) return;
164         for (x = 0; x < 4; x++)
165             vptr[y*row_inc + x] = MAKECOLOUR32(cb->r[x/2+(y/2)*2], cb->g[x/2+(y/2)*2], cb->b[x/2+(y/2)*2]);
166     }
167 }
168
169
170 /* ------------------------------------------------------------------------ */
171 static void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
172     cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
173 {
174 unsigned long *vptr = (unsigned long *)frm;
175 #ifndef ORIGINAL
176 int row_inc = -stride/4;
177 #else
178 int row_inc = stride/4;
179 #endif
180 int x, y;
181 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
182
183     /* fill 4x4 block of pixels with colour values from codebooks */
184     for (y = 0; y < 4; y++)
185     {
186         if (&vptr[y*row_inc] < (unsigned long *)limit) return;
187         for (x = 0; x < 4; x++)
188             vptr[y*row_inc + x] = MAKECOLOUR32(cb[x/2+(y/2)*2]->r[x%2+(y%2)*2], cb[x/2+(y/2)*2]->g[x%2+(y%2)*2], cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]);
189     }
190 }
191
192
193 /* ------------------------------------------------------------------------ */
194 static void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb)
195 {
196 #ifndef ORIGINAL
197 int row_inc = -stride;
198 #else
199 int row_inc = stride;
200 #endif
201 int x, y;
202
203     /* fill 4x4 block of pixels with colour values from codebook */
204     for (y = 0; y < 4; y++)
205     {
206         if (&vptr[y*row_inc] < limit) return;
207         for (x = 0; x < 4; x++)
208         {
209             vptr[y*row_inc + x*3 + 0] = cb->b[x/2+(y/2)*2];
210             vptr[y*row_inc + x*3 + 1] = cb->g[x/2+(y/2)*2];
211             vptr[y*row_inc + x*3 + 2] = cb->r[x/2+(y/2)*2];
212         }
213     }
214 }
215
216
217 /* ------------------------------------------------------------------------ */
218 static void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb0,
219     cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
220 {
221 #ifndef ORIGINAL
222 int row_inc = -stride;
223 #else
224 int row_inc = stride;
225 #endif
226 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
227 int x, y;
228
229     /* fill 4x4 block of pixels with colour values from codebooks */
230     for (y = 0; y < 4; y++)
231     {
232         if (&vptr[y*row_inc] < limit) return;
233         for (x = 0; x < 4; x++)
234         {
235             vptr[y*row_inc + x*3 + 0] = cb[x/2+(y/2)*2]->b[x%2+(y%2)*2];
236             vptr[y*row_inc + x*3 + 1] = cb[x/2+(y/2)*2]->g[x%2+(y%2)*2];
237             vptr[y*row_inc + x*3 + 2] = cb[x/2+(y/2)*2]->r[x%2+(y%2)*2];
238         }
239     }
240 }
241
242
243 /* ------------------------------------------------------------------------ */
244 static void cvid_v1_16(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
245 {
246 unsigned short *vptr = (unsigned short *)frm;
247 #ifndef ORIGINAL
248 int row_inc = -stride/2;
249 #else
250 int row_inc = stride/2;
251 #endif
252 int x, y;
253
254     /* fill 4x4 block of pixels with colour values from codebook */
255     for (y = 0; y < 4; y++)
256     {
257         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
258         for (x = 0; x < 4; x++)
259             vptr[y*row_inc + x] = MAKECOLOUR16(cb->r[x/2+(y/2)*2], cb->g[x/2+(y/2)*2], cb->b[x/2+(y/2)*2]);
260     }
261 }
262
263
264 /* ------------------------------------------------------------------------ */
265 static void cvid_v4_16(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
266     cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
267 {
268 unsigned short *vptr = (unsigned short *)frm;
269 #ifndef ORIGINAL
270 int row_inc = -stride/2;
271 #else
272 int row_inc = stride/2;
273 #endif
274 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
275 int x, y;
276
277     /* fill 4x4 block of pixels with colour values from codebooks */
278     for (y = 0; y < 4; y++)
279     {
280         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
281         for (x = 0; x < 4; x++)
282             vptr[y*row_inc + x] = MAKECOLOUR16(cb[x/2+(y/2)*2]->r[x%2+(y%2)*2], cb[x/2+(y/2)*2]->g[x%2+(y%2)*2], cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]);
283     }
284 }
285
286 /* ------------------------------------------------------------------------ */
287 static void cvid_v1_15(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
288 {
289 unsigned short *vptr = (unsigned short *)frm;
290 #ifndef ORIGINAL
291 int row_inc = -stride/2;
292 #else
293 int row_inc = stride/2;
294 #endif
295 int x, y;
296
297     /* fill 4x4 block of pixels with colour values from codebook */
298     for (y = 0; y < 4; y++)
299     {
300         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
301         for (x = 0; x < 4; x++)
302             vptr[y*row_inc + x] = MAKECOLOUR15(cb->r[x/2+(y/2)*2], cb->g[x/2+(y/2)*2], cb->b[x/2+(y/2)*2]);
303     }
304 }
305
306
307 /* ------------------------------------------------------------------------ */
308 static void cvid_v4_15(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
309     cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
310 {
311 unsigned short *vptr = (unsigned short *)frm;
312 #ifndef ORIGINAL
313 int row_inc = -stride/2;
314 #else
315 int row_inc = stride/2;
316 #endif
317 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
318 int x, y;
319
320     /* fill 4x4 block of pixels with colour values from codebooks */
321     for (y = 0; y < 4; y++)
322     {
323         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
324         for (x = 0; x < 4; x++)
325             vptr[y*row_inc + x] = MAKECOLOUR15(cb[x/2+(y/2)*2]->r[x%2+(y%2)*2], cb[x/2+(y/2)*2]->g[x%2+(y%2)*2], cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]);
326     }
327 }
328
329
330 /* ------------------------------------------------------------------------
331  * Call this function once at the start of the sequence and save the
332  * returned context for calls to decode_cinepak().
333  */
334 static cinepak_info *decode_cinepak_init(void)
335 {
336     cinepak_info *cvinfo;
337     int i;
338
339     cvinfo = ICCVID_Alloc( sizeof (cinepak_info), 1 );
340     if( !cvinfo )
341         return NULL;
342     cvinfo->strip_num = 0;
343
344     if(uiclp == NULL)
345     {
346         uiclp = uiclip+512;
347         for(i = -512; i < 512; i++)
348             uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i));
349     }
350
351     return cvinfo;
352 }
353
354 static void free_cvinfo( cinepak_info *cvinfo )
355 {
356     unsigned int i;
357
358     for( i=0; i<cvinfo->strip_num; i++ )
359     {
360         ICCVID_Free(cvinfo->v4_codebook[i]);
361         ICCVID_Free(cvinfo->v1_codebook[i]);
362     }
363     ICCVID_Free( cvinfo );
364 }
365
366 typedef void (*fn_cvid_v1)(unsigned char *frm, unsigned char *limit,
367                            int stride, cvid_codebook *cb);
368 typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit, int stride,
369                            cvid_codebook *cb0, cvid_codebook *cb1,
370                            cvid_codebook *cb2, cvid_codebook *cb3);
371
372 /* ------------------------------------------------------------------------
373  * This function decodes a buffer containing a Cinepak encoded frame.
374  *
375  * context - the context created by decode_cinepak_init().
376  * buf - the input buffer to be decoded
377  * size - the size of the input buffer
378  * frame - the output frame buffer (24 or 32 bit per pixel)
379  * width - the width of the output frame
380  * height - the height of the output frame
381  * bit_per_pixel - the number of bits per pixel allocated to the output
382  *   frame (only 24 or 32 bpp are supported)
383  */
384 static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
385            unsigned char *frame, unsigned int width, unsigned int height, int bit_per_pixel)
386 {
387     cvid_codebook *v4_codebook, *v1_codebook, *codebook = NULL;
388     unsigned long x, y, y_bottom, frame_flags, strips, cv_width, cv_height,
389                   cnum, strip_id, chunk_id, x0, y0, x1, y1, ci, flag, mask;
390     long len, top_size, chunk_size;
391     unsigned char *frm_ptr, *frm_end;
392     unsigned int i, cur_strip;
393     int d0, d1, d2, d3, frm_stride, bpp = 3;
394     fn_cvid_v1 cvid_v1 = cvid_v1_24;
395     fn_cvid_v4 cvid_v4 = cvid_v4_24;
396
397     x = y = 0;
398     y_bottom = 0;
399     in_buffer = buf;
400
401     frame_flags = get_byte();
402     len = get_byte() << 16;
403     len |= get_byte() << 8;
404     len |= get_byte();
405
406     switch(bit_per_pixel)
407         {
408         case 15:
409             bpp = 2;
410             cvid_v1 = cvid_v1_15;
411             cvid_v4 = cvid_v4_15;
412             break;
413         case 16:
414             bpp = 2;
415             cvid_v1 = cvid_v1_16;
416             cvid_v4 = cvid_v4_16;
417             break;
418         case 24:
419             bpp = 3;
420             cvid_v1 = cvid_v1_24;
421             cvid_v4 = cvid_v4_24;
422             break;
423         case 32:
424             bpp = 4;
425             cvid_v1 = cvid_v1_32;
426             cvid_v4 = cvid_v4_32;
427             break;
428         }
429
430     frm_stride = width * bpp;
431     frm_ptr = frame;
432     frm_end = frm_ptr + width * height * bpp;
433
434     if(len != size)
435         {
436         if(len & 0x01) len++; /* AVIs tend to have a size mismatch */
437         if(len != size)
438             {
439             ERR("CVID: corruption %d (QT/AVI) != %ld (CV)\n", size, len);
440             /* return; */
441             }
442         }
443
444     cv_width = get_word();
445     cv_height = get_word();
446     strips = get_word();
447
448     if(strips > cvinfo->strip_num)
449         {
450         if(strips >= MAX_STRIPS)
451             {
452             ERR("CVID: strip overflow (more than %d)\n", MAX_STRIPS);
453             return;
454             }
455
456         for(i = cvinfo->strip_num; i < strips; i++)
457             {
458             if((cvinfo->v4_codebook[i] = (cvid_codebook *)ICCVID_Alloc(sizeof(cvid_codebook), 260)) == NULL)
459                 {
460                 ERR("CVID: codebook v4 alloc err\n");
461                 return;
462                 }
463
464             if((cvinfo->v1_codebook[i] = (cvid_codebook *)ICCVID_Alloc(sizeof(cvid_codebook), 260)) == NULL)
465                 {
466                 ERR("CVID: codebook v1 alloc err\n");
467                 return;
468                 }
469             }
470         }
471     cvinfo->strip_num = strips;
472
473     TRACE("CVID: <%ld,%ld> strips %ld\n", cv_width, cv_height, strips);
474
475     for(cur_strip = 0; cur_strip < strips; cur_strip++)
476         {
477         v4_codebook = cvinfo->v4_codebook[cur_strip];
478         v1_codebook = cvinfo->v1_codebook[cur_strip];
479
480         if((cur_strip > 0) && (!(frame_flags & 0x01)))
481             {
482             memcpy(cvinfo->v4_codebook[cur_strip], cvinfo->v4_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
483             memcpy(cvinfo->v1_codebook[cur_strip], cvinfo->v1_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
484             }
485
486         strip_id = get_word();        /* 1000 = key strip, 1100 = iter strip */
487         top_size = get_word();
488         y0 = get_word();        /* FIXME: most of these are ignored at the moment */
489         x0 = get_word();
490         y1 = get_word();
491         x1 = get_word();
492
493         y_bottom += y1;
494         top_size -= 12;
495         x = 0;
496         if(x1 != width)
497             WARN("CVID: Warning x1 (%ld) != width (%d)\n", x1, width);
498
499         TRACE("   %d) %04lx %04ld <%ld,%ld> <%ld,%ld> yt %ld\n",
500               cur_strip, strip_id, top_size, x0, y0, x1, y1, y_bottom);
501
502         while(top_size > 0)
503             {
504             chunk_id  = get_word();
505             chunk_size = get_word();
506
507             TRACE("        %04lx %04ld\n", chunk_id, chunk_size);
508             top_size -= chunk_size;
509             chunk_size -= 4;
510
511             switch(chunk_id)
512                 {
513                     /* -------------------- Codebook Entries -------------------- */
514                 case 0x2000:
515                 case 0x2200:
516                     codebook = (chunk_id == 0x2200 ? v1_codebook : v4_codebook);
517                     cnum = chunk_size/6;
518                     for(i = 0; i < cnum; i++) read_codebook(codebook+i, 0);
519                     break;
520
521                 case 0x2400:
522                 case 0x2600:        /* 8 bit per pixel */
523                     codebook = (chunk_id == 0x2600 ? v1_codebook : v4_codebook);
524                     cnum = chunk_size/4;
525                     for(i = 0; i < cnum; i++) read_codebook(codebook+i, 1);
526                     break;
527
528                 case 0x2100:
529                 case 0x2300:
530                     codebook = (chunk_id == 0x2300 ? v1_codebook : v4_codebook);
531
532                     ci = 0;
533                     while(chunk_size > 0)
534                         {
535                         flag = get_long();
536                         chunk_size -= 4;
537
538                         for(i = 0; i < 32; i++)
539                             {
540                             if(flag & 0x80000000)
541                                 {
542                                 chunk_size -= 6;
543                                 read_codebook(codebook+ci, 0);
544                                 }
545
546                             ci++;
547                             flag <<= 1;
548                             }
549                         }
550                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
551                     break;
552
553                 case 0x2500:
554                 case 0x2700:        /* 8 bit per pixel */
555                     codebook = (chunk_id == 0x2700 ? v1_codebook : v4_codebook);
556
557                     ci = 0;
558                     while(chunk_size > 0)
559                         {
560                         flag = get_long();
561                         chunk_size -= 4;
562
563                         for(i = 0; i < 32; i++)
564                             {
565                             if(flag & 0x80000000)
566                                 {
567                                 chunk_size -= 4;
568                                 read_codebook(codebook+ci, 1);
569                                 }
570
571                             ci++;
572                             flag <<= 1;
573                             }
574                         }
575                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
576                     break;
577
578                     /* -------------------- Frame -------------------- */
579                 case 0x3000:
580                     while((chunk_size > 0) && (y < y_bottom))
581                         {
582                         flag = get_long();
583                         chunk_size -= 4;
584
585                         for(i = 0; i < 32; i++)
586                             {
587                             if(y >= y_bottom) break;
588                             if(flag & 0x80000000)    /* 4 bytes per block */
589                                 {
590                                 d0 = get_byte();
591                                 d1 = get_byte();
592                                 d2 = get_byte();
593                                 d3 = get_byte();
594                                 chunk_size -= 4;
595 #ifdef ORIGINAL
596                                 cvid_v4(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
597 #else
598                                 cvid_v4(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
599 #endif
600                                 }
601                             else        /* 1 byte per block */
602                                 {
603 #ifdef ORIGINAL
604                                 cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
605 #else
606                                 cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte());
607 #endif
608                                 chunk_size--;
609                                 }
610
611                             x += 4;
612                             if(x >= width)
613                                 {
614                                 x = 0;
615                                 y += 4;
616                                 }
617                             flag <<= 1;
618                             }
619                         }
620                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
621                     break;
622
623                 case 0x3100:
624                     while((chunk_size > 0) && (y < y_bottom))
625                         {
626                             /* ---- flag bits: 0 = SKIP, 10 = V1, 11 = V4 ---- */
627                         flag = (unsigned long)get_long();
628                         chunk_size -= 4;
629                         mask = 0x80000000;
630
631                         while((mask) && (y < y_bottom))
632                             {
633                             if(flag & mask)
634                                 {
635                                 if(mask == 1)
636                                     {
637                                     if(chunk_size < 0) break;
638                                     flag = (unsigned long)get_long();
639                                     chunk_size -= 4;
640                                     mask = 0x80000000;
641                                     }
642                                 else mask >>= 1;
643
644                                 if(flag & mask)        /* V4 */
645                                     {
646                                     d0 = get_byte();
647                                     d1 = get_byte();
648                                     d2 = get_byte();
649                                     d3 = get_byte();
650                                     chunk_size -= 4;
651 #ifdef ORIGINAL
652                                     cvid_v4(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
653 #else
654                                     cvid_v4(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
655 #endif
656                                     }
657                                 else        /* V1 */
658                                     {
659                                     chunk_size--;
660 #ifdef ORIGINAL
661                                     cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
662 #else
663                                     cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte());
664 #endif
665                                     }
666                                 }        /* else SKIP */
667
668                             mask >>= 1;
669                             x += 4;
670                             if(x >= width)
671                                 {
672                                 x = 0;
673                                 y += 4;
674                                 }
675                             }
676                         }
677
678                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
679                     break;
680
681                 case 0x3200:        /* each byte is a V1 codebook */
682                     while((chunk_size > 0) && (y < y_bottom))
683                         {
684 #ifdef ORIGINAL
685                         cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
686 #else
687                         cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte());
688 #endif
689                         chunk_size--;
690                         x += 4;
691                         if(x >= width)
692                             {
693                             x = 0;
694                             y += 4;
695                             }
696                         }
697                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
698                     break;
699
700                 default:
701                     ERR("CVID: unknown chunk_id %08lx\n", chunk_id);
702                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
703                     break;
704                 }
705             }
706         }
707
708     if(len != size)
709         {
710         if(len & 0x01) len++; /* AVIs tend to have a size mismatch */
711         if(len != size)
712             {
713             long xlen;
714             skip_byte();
715             xlen = get_byte() << 16;
716             xlen |= get_byte() << 8;
717             xlen |= get_byte(); /* Read Len */
718             WARN("CVID: END INFO chunk size %d cvid size1 %ld cvid size2 %ld\n",
719                   size, len, xlen);
720             }
721         }
722 }
723
724 static void ICCVID_dump_BITMAPINFO(const BITMAPINFO * bmi)
725 {
726     TRACE(
727         "planes = %d\n"
728         "bpp    = %d\n"
729         "height = %ld\n"
730         "width  = %ld\n"
731         "compr  = %s\n",
732         bmi->bmiHeader.biPlanes,
733         bmi->bmiHeader.biBitCount,
734         bmi->bmiHeader.biHeight,
735         bmi->bmiHeader.biWidth,
736         debugstr_an( (const char *)&bmi->bmiHeader.biCompression, 4 ) );
737 }
738
739 static inline int ICCVID_CheckMask(RGBQUAD bmiColors[3], COLORREF redMask, COLORREF blueMask, COLORREF greenMask)
740 {
741     COLORREF realRedMask = MAKECOLOUR32(bmiColors[0].rgbRed, bmiColors[0].rgbGreen, bmiColors[0].rgbBlue);
742     COLORREF realBlueMask = MAKECOLOUR32(bmiColors[1].rgbRed, bmiColors[1].rgbGreen, bmiColors[1].rgbBlue);
743     COLORREF realGreenMask = MAKECOLOUR32(bmiColors[2].rgbRed, bmiColors[2].rgbGreen, bmiColors[2].rgbBlue);
744
745     TRACE("\nbmiColors[0] = 0x%08lx\nbmiColors[1] = 0x%08lx\nbmiColors[2] = 0x%08lx\n",
746         realRedMask, realBlueMask, realGreenMask);
747         
748     if ((realRedMask == redMask) &&
749         (realBlueMask == blueMask) &&
750         (realGreenMask == greenMask))
751         return TRUE;
752     return FALSE;
753 }
754
755 static LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
756 {
757     TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
758
759     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
760         return ICERR_BADPARAM;
761
762     TRACE("in: ");
763     ICCVID_dump_BITMAPINFO(in);
764
765     if( in->bmiHeader.biCompression != ICCVID_MAGIC )
766         return ICERR_UNSUPPORTED;
767
768     if( out )
769     {
770         TRACE("out: ");
771         ICCVID_dump_BITMAPINFO(out);
772
773         if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes )
774             return ICERR_UNSUPPORTED;
775         if( in->bmiHeader.biHeight != out->bmiHeader.biHeight )
776             return ICERR_UNSUPPORTED;
777         if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
778             return ICERR_UNSUPPORTED;
779
780         switch( out->bmiHeader.biBitCount )
781         {
782         case 16:
783             if ( out->bmiHeader.biCompression == BI_BITFIELDS )
784             {
785                 if ( !ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) &&
786                      !ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
787                 {
788                     TRACE("unsupported output bit field(s) for 16-bit colors\n");
789                     return ICERR_UNSUPPORTED;
790                 }
791             }
792             break;
793         case 24:
794         case 32:
795             break;
796         default:
797             TRACE("unsupported output bitcount = %d\n", out->bmiHeader.biBitCount );
798             return ICERR_UNSUPPORTED;
799         }
800     }
801
802     return ICERR_OK;
803 }
804
805 static LRESULT ICCVID_DecompressGetFormat( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
806 {
807     DWORD size;
808
809     TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
810
811     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
812         return ICERR_BADPARAM;
813
814     size = in->bmiHeader.biSize;
815     if (in->bmiHeader.biBitCount <= 8)
816         size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD);
817
818     if( out )
819     {
820         memcpy( out, in, size );
821         out->bmiHeader.biCompression = BI_RGB;
822         out->bmiHeader.biSizeImage = in->bmiHeader.biHeight
823                                    * in->bmiHeader.biWidth *4;
824         return ICERR_OK;
825     }
826     return size;
827 }
828
829 static LRESULT ICCVID_DecompressBegin( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
830 {
831     TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
832
833     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
834         return ICERR_BADPARAM;
835
836     info->bits_per_pixel = out->bmiHeader.biBitCount;
837
838     if (info->bits_per_pixel == 16)
839     {
840         if ( out->bmiHeader.biCompression == BI_BITFIELDS )
841         {
842             if ( ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) )
843                 info->bits_per_pixel = 15;
844             else if ( ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
845                 info->bits_per_pixel = 16;
846             else
847             {
848                 TRACE("unsupported output bit field(s) for 16-bit colors\n");
849                 return ICERR_UNSUPPORTED;
850             }
851         }
852         else
853             info->bits_per_pixel = 15;
854     }
855
856     TRACE("bit_per_pixel = %d\n", info->bits_per_pixel);
857
858     if( info->cvinfo )
859         free_cvinfo( info->cvinfo );
860     info->cvinfo = decode_cinepak_init();
861
862     return ICERR_OK;
863 }
864
865 static LRESULT ICCVID_Decompress( ICCVID_Info *info, ICDECOMPRESS *icd, DWORD size )
866 {
867     LONG width, height;
868
869     TRACE("ICM_DECOMPRESS %p %p %ld\n", info, icd, size);
870
871     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
872         return ICERR_BADPARAM;
873
874     width  = icd->lpbiInput->biWidth;
875     height = icd->lpbiInput->biHeight;
876
877     decode_cinepak(info->cvinfo, icd->lpInput, icd->lpbiInput->biSizeImage,
878                    icd->lpOutput, width, height, info->bits_per_pixel);
879
880     return ICERR_OK;
881 }
882
883 static LRESULT ICCVID_DecompressEx( ICCVID_Info *info, ICDECOMPRESSEX *icd, DWORD size )
884 {
885     LONG width, height;
886
887     TRACE("ICM_DECOMPRESSEX %p %p %ld\n", info, icd, size);
888
889     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
890         return ICERR_BADPARAM;
891
892     /* FIXME: flags are ignored */
893
894     width  = icd->lpbiSrc->biWidth;
895     height = icd->lpbiSrc->biHeight;
896
897     decode_cinepak(info->cvinfo, icd->lpSrc, icd->lpbiSrc->biSizeImage,
898                    icd->lpDst, width, height, info->bits_per_pixel);
899
900     return ICERR_OK;
901 }
902
903 static LRESULT ICCVID_Close( ICCVID_Info *info )
904 {
905     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
906         return 0;
907     if( info->cvinfo )
908         free_cvinfo( info->cvinfo );
909     ICCVID_Free( info );
910     return 1;
911 }
912
913 LRESULT WINAPI ICCVID_DriverProc( DWORD dwDriverId, HDRVR hdrvr, UINT msg,
914                                   LONG lParam1, LONG lParam2)
915 {
916     ICCVID_Info *info = (ICCVID_Info *) dwDriverId;
917
918     TRACE("%ld %p %d %ld %ld\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
919
920     switch( msg )
921     {
922     case DRV_LOAD:
923         TRACE("Loaded\n");
924         return 1;
925     case DRV_ENABLE:
926         return 0;
927     case DRV_DISABLE:
928         return 0;
929     case DRV_FREE:
930         return 0;
931
932     case DRV_OPEN:
933         TRACE("Opened\n");
934         info = ICCVID_Alloc( sizeof (ICCVID_Info), 1 );
935         if( info )
936         {
937             info->dwMagic = ICCVID_MAGIC;
938             info->cvinfo = NULL;
939         }
940         return (LRESULT) info;
941
942     case ICM_DECOMPRESS_QUERY:
943         return ICCVID_DecompressQuery( info, (LPBITMAPINFO) lParam1,
944                                        (LPBITMAPINFO) lParam2 );
945     case ICM_DECOMPRESS_GET_FORMAT:
946         return ICCVID_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
947                                        (LPBITMAPINFO) lParam2 );
948     case ICM_DECOMPRESS_BEGIN:
949         return ICCVID_DecompressBegin( info, (LPBITMAPINFO) lParam1,
950                                        (LPBITMAPINFO) lParam2 );
951     case ICM_DECOMPRESS:
952         return ICCVID_Decompress( info, (ICDECOMPRESS*) lParam1,
953                                   (DWORD) lParam2 );
954     case ICM_DECOMPRESSEX:
955         return ICCVID_DecompressEx( info, (ICDECOMPRESSEX*) lParam1, 
956                                   (DWORD) lParam2 );
957
958     case DRV_CLOSE:
959         return ICCVID_Close( info );
960
961     default:
962         FIXME("Unknown message: %04x %ld %ld\n", msg, lParam1, lParam2);
963     }
964     return 0;
965 }