xref: /reactos/dll/win32/iccvid/iccvid.c (revision 84ccccab)
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #define WIN32_NO_STATUS
44 #define _INC_WINDOWS
45 #define COM_NO_WINDOWS_H
46 
47 #include <stdarg.h>
48 #include <windef.h>
49 #include <winbase.h>
50 #include <wingdi.h>
51 //#include "winuser.h"
52 //#include "commdlg.h"
53 #include <vfw.h>
54 //#include "mmsystem.h"
55 #include "iccvid_private.h"
56 
57 #include <wine/debug.h>
58 
59 WINE_DEFAULT_DEBUG_CHANNEL(iccvid);
60 
61 static HINSTANCE ICCVID_hModule;
62 
63 #define ICCVID_MAGIC mmioFOURCC('c', 'v', 'i', 'd')
64 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
65 #define MAX_STRIPS 32
66 
67 /* ------------------------------------------------------------------------ */
68 typedef struct
69 {
70     unsigned char y0, y1, y2, y3;
71     char u, v;
72     unsigned char r[4], g[4], b[4];
73 } cvid_codebook;
74 
75 typedef struct {
76     cvid_codebook *v4_codebook[MAX_STRIPS];
77     cvid_codebook *v1_codebook[MAX_STRIPS];
78     unsigned int strip_num;
79 } cinepak_info;
80 
81 typedef struct _ICCVID_Info
82 {
83     DWORD         dwMagic;
84     int           bits_per_pixel;
85     cinepak_info *cvinfo;
86 } ICCVID_Info;
87 
88 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
89 {
90     return HeapAlloc(GetProcessHeap(), 0, size);
91 }
92 
93 static inline BOOL heap_free(void *mem)
94 {
95     return HeapFree(GetProcessHeap(), 0, mem);
96 }
97 
98 static inline int get_stride(int width, int depth)
99 {
100     return ((depth * width + 31) >> 3) & ~3;
101 }
102 
103 /* ------------------------------------------------------------------------ */
104 static unsigned char *in_buffer, uiclip[1024], *uiclp = NULL;
105 
106 #define get_byte() *(in_buffer++)
107 #define skip_byte() in_buffer++
108 #define get_word() ((unsigned short)(in_buffer += 2, \
109     (in_buffer[-2] << 8 | in_buffer[-1])))
110 #define get_long() ((unsigned long)(in_buffer += 4, \
111     (in_buffer[-4] << 24 | in_buffer[-3] << 16 | in_buffer[-2] << 8 | in_buffer[-1])))
112 
113 
114 /* ---------------------------------------------------------------------- */
115 static inline void read_codebook(cvid_codebook *c, int mode)
116 {
117 int uvr, uvg, uvb;
118 
119     if(mode)        /* black and white */
120         {
121         c->y0 = get_byte();
122         c->y1 = get_byte();
123         c->y2 = get_byte();
124         c->y3 = get_byte();
125         c->u = c->v = 0;
126 
127         c->r[0] = c->g[0] = c->b[0] = c->y0;
128         c->r[1] = c->g[1] = c->b[1] = c->y1;
129         c->r[2] = c->g[2] = c->b[2] = c->y2;
130         c->r[3] = c->g[3] = c->b[3] = c->y3;
131         }
132     else            /* colour */
133         {
134         c->y0 = get_byte();  /* luma */
135         c->y1 = get_byte();
136         c->y2 = get_byte();
137         c->y3 = get_byte();
138         c->u = get_byte(); /* chroma */
139         c->v = get_byte();
140 
141         uvr = c->v << 1;
142         uvg = -((c->u+1) >> 1) - c->v;
143         uvb = c->u << 1;
144 
145         c->r[0] = uiclp[c->y0 + uvr]; c->g[0] = uiclp[c->y0 + uvg]; c->b[0] = uiclp[c->y0 + uvb];
146         c->r[1] = uiclp[c->y1 + uvr]; c->g[1] = uiclp[c->y1 + uvg]; c->b[1] = uiclp[c->y1 + uvb];
147         c->r[2] = uiclp[c->y2 + uvr]; c->g[2] = uiclp[c->y2 + uvg]; c->b[2] = uiclp[c->y2 + uvb];
148         c->r[3] = uiclp[c->y3 + uvr]; c->g[3] = uiclp[c->y3 + uvg]; c->b[3] = uiclp[c->y3 + uvb];
149         }
150 }
151 
152 static inline long get_addr(BOOL inverted, unsigned long x, unsigned long y,
153                        int frm_stride, int bpp, unsigned int out_height)
154 {
155     /* Returns the starting position of a line from top-down or bottom-up */
156     if (inverted)
157         return y * frm_stride + x * bpp;
158     else
159         return (out_height - 1 - y) * frm_stride + x * bpp;
160 }
161 
162 #define MAKECOLOUR32(r,g,b) (((r) << 16) | ((g) << 8) | (b))
163 /*#define MAKECOLOUR24(r,g,b) (((r) << 16) | ((g) << 8) | (b))*/
164 #define MAKECOLOUR16(r,g,b) (((r) >> 3) << 11)| (((g) >> 2) << 5)| (((b) >> 3) << 0)
165 #define MAKECOLOUR15(r,g,b) (((r) >> 3) << 10)| (((g) >> 3) << 5)| (((b) >> 3) << 0)
166 
167 /* ------------------------------------------------------------------------ */
168 static void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
169     cvid_codebook *cb)
170 {
171 unsigned long *vptr = (unsigned long *)frm;
172 int row_inc;
173 int x, y;
174 
175     if (!inverted)
176         row_inc = -stride/4;
177     else
178         row_inc = stride/4;
179 
180     /* fill 4x4 block of pixels with colour values from codebook */
181     for (y = 0; y < 4; y++)
182     {
183         if (&vptr[y*row_inc] < (unsigned long *)limit) return;
184         for (x = 0; x < 4; x++)
185             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]);
186     }
187 }
188 
189 
190 /* ------------------------------------------------------------------------ */
191 static void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
192     cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
193 {
194 unsigned long *vptr = (unsigned long *)frm;
195 int row_inc;
196 int x, y;
197 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
198 
199     if (!inverted)
200         row_inc = -stride/4;
201     else
202         row_inc = stride/4;
203 
204     /* fill 4x4 block of pixels with colour values from codebooks */
205     for (y = 0; y < 4; y++)
206     {
207         if (&vptr[y*row_inc] < (unsigned long *)limit) return;
208         for (x = 0; x < 4; x++)
209             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]);
210     }
211 }
212 
213 
214 /* ------------------------------------------------------------------------ */
215 static void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, BOOL inverted,
216     cvid_codebook *cb)
217 {
218 int row_inc;
219 int x, y;
220 
221     if (!inverted)
222         row_inc = -stride;
223     else
224         row_inc = stride;
225 
226     /* fill 4x4 block of pixels with colour values from codebook */
227     for (y = 0; y < 4; y++)
228     {
229         if (&vptr[y*row_inc] < limit) return;
230         for (x = 0; x < 4; x++)
231         {
232             vptr[y*row_inc + x*3 + 0] = cb->b[x/2+(y/2)*2];
233             vptr[y*row_inc + x*3 + 1] = cb->g[x/2+(y/2)*2];
234             vptr[y*row_inc + x*3 + 2] = cb->r[x/2+(y/2)*2];
235         }
236     }
237 }
238 
239 
240 /* ------------------------------------------------------------------------ */
241 static void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, BOOL inverted,
242     cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
243 {
244 int row_inc;
245 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
246 int x, y;
247 
248     if (!inverted)
249         row_inc = -stride;
250     else
251         row_inc = stride;
252 
253     /* fill 4x4 block of pixels with colour values from codebooks */
254     for (y = 0; y < 4; y++)
255     {
256         if (&vptr[y*row_inc] < limit) return;
257         for (x = 0; x < 4; x++)
258         {
259             vptr[y*row_inc + x*3 + 0] = cb[x/2+(y/2)*2]->b[x%2+(y%2)*2];
260             vptr[y*row_inc + x*3 + 1] = cb[x/2+(y/2)*2]->g[x%2+(y%2)*2];
261             vptr[y*row_inc + x*3 + 2] = cb[x/2+(y/2)*2]->r[x%2+(y%2)*2];
262         }
263     }
264 }
265 
266 
267 /* ------------------------------------------------------------------------ */
268 static void cvid_v1_16(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
269     cvid_codebook *cb)
270 {
271 unsigned short *vptr = (unsigned short *)frm;
272 int row_inc;
273 int x, y;
274 
275     if (!inverted)
276         row_inc = -stride/2;
277     else
278         row_inc = stride/2;
279 
280     /* fill 4x4 block of pixels with colour values from codebook */
281     for (y = 0; y < 4; y++)
282     {
283         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
284         for (x = 0; x < 4; x++)
285             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]);
286     }
287 }
288 
289 
290 /* ------------------------------------------------------------------------ */
291 static void cvid_v4_16(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
292     cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
293 {
294 unsigned short *vptr = (unsigned short *)frm;
295 int row_inc;
296 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
297 int x, y;
298 
299     if (!inverted)
300         row_inc = -stride/2;
301     else
302         row_inc = stride/2;
303 
304     /* fill 4x4 block of pixels with colour values from codebooks */
305     for (y = 0; y < 4; y++)
306     {
307         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
308         for (x = 0; x < 4; x++)
309             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]);
310     }
311 }
312 
313 /* ------------------------------------------------------------------------ */
314 static void cvid_v1_15(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
315     cvid_codebook *cb)
316 {
317 unsigned short *vptr = (unsigned short *)frm;
318 int row_inc;
319 int x, y;
320 
321     if (!inverted)
322         row_inc = -stride/2;
323     else
324         row_inc = stride/2;
325 
326     /* fill 4x4 block of pixels with colour values from codebook */
327     for (y = 0; y < 4; y++)
328     {
329         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
330         for (x = 0; x < 4; x++)
331             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]);
332     }
333 }
334 
335 
336 /* ------------------------------------------------------------------------ */
337 static void cvid_v4_15(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
338     cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
339 {
340 unsigned short *vptr = (unsigned short *)frm;
341 int row_inc;
342 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
343 int x, y;
344 
345     if (!inverted)
346         row_inc = -stride/2;
347     else
348         row_inc = stride/2;
349 
350     /* fill 4x4 block of pixels with colour values from codebooks */
351     for (y = 0; y < 4; y++)
352     {
353         if (&vptr[y*row_inc] < (unsigned short *)limit) return;
354         for (x = 0; x < 4; x++)
355             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]);
356     }
357 }
358 
359 
360 /* ------------------------------------------------------------------------
361  * Call this function once at the start of the sequence and save the
362  * returned context for calls to decode_cinepak().
363  */
364 static cinepak_info *decode_cinepak_init(void)
365 {
366     cinepak_info *cvinfo;
367     int i;
368 
369     cvinfo = heap_alloc( sizeof (cinepak_info) );
370     if( !cvinfo )
371         return NULL;
372     cvinfo->strip_num = 0;
373 
374     if(uiclp == NULL)
375     {
376         uiclp = uiclip+512;
377         for(i = -512; i < 512; i++)
378             uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i));
379     }
380 
381     return cvinfo;
382 }
383 
384 static void free_cvinfo( cinepak_info *cvinfo )
385 {
386     unsigned int i;
387 
388     for( i=0; i<cvinfo->strip_num; i++ )
389     {
390         heap_free(cvinfo->v4_codebook[i]);
391         heap_free(cvinfo->v1_codebook[i]);
392     }
393     heap_free( cvinfo );
394 }
395 
396 typedef void (*fn_cvid_v1)(unsigned char *frm, unsigned char *limit,
397                            int stride, BOOL inverted, cvid_codebook *cb);
398 typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit,
399                            int stride, BOOL inverted,
400                            cvid_codebook *cb0, cvid_codebook *cb1,
401                            cvid_codebook *cb2, cvid_codebook *cb3);
402 
403 /* ------------------------------------------------------------------------
404  * This function decodes a buffer containing a Cinepak encoded frame.
405  *
406  * context - the context created by decode_cinepak_init().
407  * buf - the input buffer to be decoded
408  * size - the size of the input buffer
409  * output - the output frame buffer (24 or 32 bit per pixel)
410  * out_width - the width of the output frame
411  * out_height - the height of the output frame
412  * bit_per_pixel - the number of bits per pixel allocated to the output
413  *   frame (only 24 or 32 bpp are supported)
414  * inverted - if true the output frame is written top-down
415  */
416 static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
417            unsigned char *output, unsigned int out_width, unsigned int out_height, int bit_per_pixel, BOOL inverted)
418 {
419     cvid_codebook *v4_codebook, *v1_codebook, *codebook = NULL;
420     unsigned long x, y, y_bottom, cnum, strip_id, chunk_id,
421                   x0, y0, x1, y1, ci, flag, mask;
422     long top_size, chunk_size;
423     unsigned char *frm_ptr;
424     unsigned int i, cur_strip, addr;
425     int d0, d1, d2, d3, frm_stride, bpp = 3;
426     fn_cvid_v1 cvid_v1 = cvid_v1_24;
427     fn_cvid_v4 cvid_v4 = cvid_v4_24;
428     struct frame_header
429     {
430       unsigned char flags;
431       unsigned long length;
432       unsigned short width;
433       unsigned short height;
434       unsigned short strips;
435     } frame;
436 
437     y = 0;
438     y_bottom = 0;
439     in_buffer = buf;
440 
441     frame.flags = get_byte();
442     frame.length = get_byte() << 16;
443     frame.length |= get_byte() << 8;
444     frame.length |= get_byte();
445 
446     switch(bit_per_pixel)
447         {
448         case 15:
449             bpp = 2;
450             cvid_v1 = cvid_v1_15;
451             cvid_v4 = cvid_v4_15;
452             break;
453         case 16:
454             bpp = 2;
455             cvid_v1 = cvid_v1_16;
456             cvid_v4 = cvid_v4_16;
457             break;
458         case 24:
459             bpp = 3;
460             cvid_v1 = cvid_v1_24;
461             cvid_v4 = cvid_v4_24;
462             break;
463         case 32:
464             bpp = 4;
465             cvid_v1 = cvid_v1_32;
466             cvid_v4 = cvid_v4_32;
467             break;
468         }
469 
470     frm_stride = get_stride(out_width, bpp * 8);
471     frm_ptr = output;
472 
473     if(frame.length != size)
474         {
475         if(frame.length & 0x01) frame.length++; /* AVIs tend to have a size mismatch */
476         if(frame.length != size)
477             {
478             ERR("CVID: corruption %d (QT/AVI) != %ld (CV)\n", size, frame.length);
479             /* return; */
480             }
481         }
482 
483     frame.width = get_word();
484     frame.height = get_word();
485     frame.strips = get_word();
486 
487     if(frame.strips > cvinfo->strip_num)
488         {
489         if(frame.strips >= MAX_STRIPS)
490             {
491             ERR("CVID: strip overflow (more than %d)\n", MAX_STRIPS);
492             return;
493             }
494 
495         for(i = cvinfo->strip_num; i < frame.strips; i++)
496             {
497             if((cvinfo->v4_codebook[i] = heap_alloc(sizeof(cvid_codebook) * 260)) == NULL)
498                 {
499                 ERR("CVID: codebook v4 alloc err\n");
500                 return;
501                 }
502 
503             if((cvinfo->v1_codebook[i] = heap_alloc(sizeof(cvid_codebook) * 260)) == NULL)
504                 {
505                 ERR("CVID: codebook v1 alloc err\n");
506                 return;
507                 }
508             }
509         }
510     cvinfo->strip_num = frame.strips;
511 
512     TRACE("CVID: %ux%u, strips %u, length %lu\n",
513           frame.width, frame.height, frame.strips, frame.length);
514 
515     for(cur_strip = 0; cur_strip < frame.strips; cur_strip++)
516         {
517         v4_codebook = cvinfo->v4_codebook[cur_strip];
518         v1_codebook = cvinfo->v1_codebook[cur_strip];
519 
520         if((cur_strip > 0) && (!(frame.flags & 0x01)))
521             {
522             memcpy(cvinfo->v4_codebook[cur_strip], cvinfo->v4_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
523             memcpy(cvinfo->v1_codebook[cur_strip], cvinfo->v1_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
524             }
525 
526         strip_id = get_word();        /* 1000 = key strip, 1100 = iter strip */
527         top_size = get_word();
528         y0 = get_word();        /* FIXME: most of these are ignored at the moment */
529         x0 = get_word();
530         y1 = get_word();
531         x1 = get_word();
532 
533         y_bottom += y1;
534         top_size -= 12;
535         x = 0;
536         if(x1 != out_width)
537             WARN("CVID: Warning x1 (%ld) != width (%d)\n", x1, out_width);
538 
539         TRACE("   %d) %04lx %04ld <%ld,%ld> <%ld,%ld> yt %ld\n",
540               cur_strip, strip_id, top_size, x0, y0, x1, y1, y_bottom);
541 
542         while(top_size > 0)
543             {
544             chunk_id  = get_word();
545             chunk_size = get_word();
546 
547             TRACE("        %04lx %04ld\n", chunk_id, chunk_size);
548             top_size -= chunk_size;
549             chunk_size -= 4;
550 
551             switch(chunk_id)
552                 {
553                     /* -------------------- Codebook Entries -------------------- */
554                 case 0x2000:
555                 case 0x2200:
556                     codebook = (chunk_id == 0x2200 ? v1_codebook : v4_codebook);
557                     cnum = chunk_size/6;
558                     for(i = 0; i < cnum; i++) read_codebook(codebook+i, 0);
559                     break;
560 
561                 case 0x2400:
562                 case 0x2600:        /* 8 bit per pixel */
563                     codebook = (chunk_id == 0x2600 ? v1_codebook : v4_codebook);
564                     cnum = chunk_size/4;
565                     for(i = 0; i < cnum; i++) read_codebook(codebook+i, 1);
566                     break;
567 
568                 case 0x2100:
569                 case 0x2300:
570                     codebook = (chunk_id == 0x2300 ? v1_codebook : v4_codebook);
571 
572                     ci = 0;
573                     while(chunk_size > 0)
574                         {
575                         flag = get_long();
576                         chunk_size -= 4;
577 
578                         for(i = 0; i < 32; i++)
579                             {
580                             if(flag & 0x80000000)
581                                 {
582                                 chunk_size -= 6;
583                                 read_codebook(codebook+ci, 0);
584                                 }
585 
586                             ci++;
587                             flag <<= 1;
588                             }
589                         }
590                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
591                     break;
592 
593                 case 0x2500:
594                 case 0x2700:        /* 8 bit per pixel */
595                     codebook = (chunk_id == 0x2700 ? v1_codebook : v4_codebook);
596 
597                     ci = 0;
598                     while(chunk_size > 0)
599                         {
600                         flag = get_long();
601                         chunk_size -= 4;
602 
603                         for(i = 0; i < 32; i++)
604                             {
605                             if(flag & 0x80000000)
606                                 {
607                                 chunk_size -= 4;
608                                 read_codebook(codebook+ci, 1);
609                                 }
610 
611                             ci++;
612                             flag <<= 1;
613                             }
614                         }
615                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
616                     break;
617 
618                     /* -------------------- Frame -------------------- */
619                 case 0x3000:
620                     while((chunk_size > 0) && (y < y_bottom))
621                         {
622                         flag = get_long();
623                         chunk_size -= 4;
624 
625                         for(i = 0; i < 32; i++)
626                             {
627                             if(y >= y_bottom) break;
628                             if(flag & 0x80000000)    /* 4 bytes per block */
629                                 {
630                                 d0 = get_byte();
631                                 d1 = get_byte();
632                                 d2 = get_byte();
633                                 d3 = get_byte();
634                                 chunk_size -= 4;
635 
636                                 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
637                                 cvid_v4(frm_ptr + addr, output, frm_stride, inverted, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
638                                 }
639                             else        /* 1 byte per block */
640                                 {
641                                 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
642                                 cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
643 
644                                 chunk_size--;
645                                 }
646 
647                             x += 4;
648                             if(x >= out_width)
649                                 {
650                                 x = 0;
651                                 y += 4;
652                                 }
653                             flag <<= 1;
654                             }
655                         }
656                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
657                     break;
658 
659                 case 0x3100:
660                     while((chunk_size > 0) && (y < y_bottom))
661                         {
662                             /* ---- flag bits: 0 = SKIP, 10 = V1, 11 = V4 ---- */
663                         flag = get_long();
664                         chunk_size -= 4;
665                         mask = 0x80000000;
666 
667                         while((mask) && (y < y_bottom))
668                             {
669                             if(flag & mask)
670                                 {
671                                 if(mask == 1)
672                                     {
673                                     if(chunk_size < 0) break;
674                                     flag = get_long();
675                                     chunk_size -= 4;
676                                     mask = 0x80000000;
677                                     }
678                                 else mask >>= 1;
679 
680                                 if(flag & mask)        /* V4 */
681                                     {
682                                     d0 = get_byte();
683                                     d1 = get_byte();
684                                     d2 = get_byte();
685                                     d3 = get_byte();
686                                     chunk_size -= 4;
687 
688                                     addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
689                                     cvid_v4(frm_ptr + addr, output, frm_stride, inverted, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
690                                     }
691                                 else        /* V1 */
692                                     {
693                                     chunk_size--;
694 
695                                     addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
696                                     cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
697                                     }
698                                 }        /* else SKIP */
699 
700                             mask >>= 1;
701                             x += 4;
702                             if(x >= out_width)
703                                 {
704                                 x = 0;
705                                 y += 4;
706                                 }
707                             }
708                         }
709 
710                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
711                     break;
712 
713                 case 0x3200:        /* each byte is a V1 codebook */
714                     while((chunk_size > 0) && (y < y_bottom))
715                         {
716                         addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
717                         cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
718 
719                         chunk_size--;
720                         x += 4;
721                         if(x >= out_width)
722                             {
723                             x = 0;
724                             y += 4;
725                             }
726                         }
727                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
728                     break;
729 
730                 default:
731                     ERR("CVID: unknown chunk_id %08lx\n", chunk_id);
732                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
733                     break;
734                 }
735             }
736         }
737 
738     if(frame.length != size)
739         {
740         if(frame.length & 0x01) frame.length++; /* AVIs tend to have a size mismatch */
741         if(frame.length != size)
742             {
743             long xlen;
744             skip_byte();
745             xlen = get_byte() << 16;
746             xlen |= get_byte() << 8;
747             xlen |= get_byte(); /* Read Len */
748             WARN("CVID: END INFO chunk size %d cvid size1 %ld cvid size2 %ld\n",
749                   size, frame.length, xlen);
750             }
751         }
752 }
753 
754 static void ICCVID_dump_BITMAPINFO(const BITMAPINFO * bmi)
755 {
756     TRACE(
757         "planes = %d\n"
758         "bpp    = %d\n"
759         "height = %d\n"
760         "width  = %d\n"
761         "compr  = %s\n",
762         bmi->bmiHeader.biPlanes,
763         bmi->bmiHeader.biBitCount,
764         bmi->bmiHeader.biHeight,
765         bmi->bmiHeader.biWidth,
766         debugstr_an( (const char *)&bmi->bmiHeader.biCompression, 4 ) );
767 }
768 
769 static inline int ICCVID_CheckMask(RGBQUAD bmiColors[3], COLORREF redMask, COLORREF blueMask, COLORREF greenMask)
770 {
771     COLORREF realRedMask = MAKECOLOUR32(bmiColors[0].rgbRed, bmiColors[0].rgbGreen, bmiColors[0].rgbBlue);
772     COLORREF realBlueMask = MAKECOLOUR32(bmiColors[1].rgbRed, bmiColors[1].rgbGreen, bmiColors[1].rgbBlue);
773     COLORREF realGreenMask = MAKECOLOUR32(bmiColors[2].rgbRed, bmiColors[2].rgbGreen, bmiColors[2].rgbBlue);
774 
775     TRACE("\nbmiColors[0] = 0x%08x\nbmiColors[1] = 0x%08x\nbmiColors[2] = 0x%08x\n",
776         realRedMask, realBlueMask, realGreenMask);
777 
778     if ((realRedMask == redMask) &&
779         (realBlueMask == blueMask) &&
780         (realGreenMask == greenMask))
781         return TRUE;
782     return FALSE;
783 }
784 
785 static LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
786 {
787     TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
788 
789     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
790         return ICERR_BADPARAM;
791 
792     TRACE("in: ");
793     ICCVID_dump_BITMAPINFO(in);
794 
795     if( in->bmiHeader.biCompression != ICCVID_MAGIC )
796         return ICERR_BADFORMAT;
797 
798     if( out )
799     {
800         TRACE("out: ");
801         ICCVID_dump_BITMAPINFO(out);
802 
803         if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes )
804             return ICERR_BADFORMAT;
805         if( in->bmiHeader.biHeight != out->bmiHeader.biHeight )
806         {
807             if( in->bmiHeader.biHeight != -out->bmiHeader.biHeight )
808                 return ICERR_BADFORMAT;
809             TRACE("Detected inverted height for video output\n");
810         }
811         if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
812             return ICERR_BADFORMAT;
813 
814         switch( out->bmiHeader.biBitCount )
815         {
816         case 16:
817             if ( out->bmiHeader.biCompression == BI_BITFIELDS )
818             {
819                 if ( !ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) &&
820                      !ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
821                 {
822                     TRACE("unsupported output bit field(s) for 16-bit colors\n");
823                     return ICERR_BADFORMAT;
824                 }
825             }
826             break;
827         case 24:
828         case 32:
829             break;
830         default:
831             TRACE("unsupported output bitcount = %d\n", out->bmiHeader.biBitCount );
832             return ICERR_BADFORMAT;
833         }
834     }
835 
836     return ICERR_OK;
837 }
838 
839 static LRESULT ICCVID_DecompressGetFormat( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
840 {
841     DWORD size;
842 
843     TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
844 
845     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
846         return ICERR_BADPARAM;
847 
848     size = in->bmiHeader.biSize;
849     if (in->bmiHeader.biBitCount <= 8)
850         size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD);
851 
852     if( out )
853     {
854         memcpy( out, in, size );
855         out->bmiHeader.biBitCount = 24;
856         out->bmiHeader.biCompression = BI_RGB;
857         out->bmiHeader.biSizeImage = get_stride(in->bmiHeader.biWidth, 24) * in->bmiHeader.biHeight;
858         return ICERR_OK;
859     }
860     return size;
861 }
862 
863 static LRESULT ICCVID_DecompressBegin( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
864 {
865     TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
866 
867     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
868         return ICERR_BADPARAM;
869 
870     info->bits_per_pixel = out->bmiHeader.biBitCount;
871 
872     if (info->bits_per_pixel == 16)
873     {
874         if ( out->bmiHeader.biCompression == BI_BITFIELDS )
875         {
876             if ( ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) )
877                 info->bits_per_pixel = 15;
878             else if ( ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
879                 info->bits_per_pixel = 16;
880             else
881             {
882                 TRACE("unsupported output bit field(s) for 16-bit colors\n");
883                 return ICERR_UNSUPPORTED;
884             }
885         }
886         else
887             info->bits_per_pixel = 15;
888     }
889 
890     TRACE("bit_per_pixel = %d\n", info->bits_per_pixel);
891 
892     if( info->cvinfo )
893         free_cvinfo( info->cvinfo );
894     info->cvinfo = decode_cinepak_init();
895 
896     return ICERR_OK;
897 }
898 
899 static LRESULT ICCVID_Decompress( ICCVID_Info *info, ICDECOMPRESS *icd, DWORD size )
900 {
901     LONG width, height;
902     BOOL inverted;
903 
904     TRACE("ICM_DECOMPRESS %p %p %d\n", info, icd, size);
905 
906     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
907         return ICERR_BADPARAM;
908     if (info->cvinfo==NULL)
909     {
910         ERR("ICM_DECOMPRESS sent after ICM_DECOMPRESS_END\n");
911         return ICERR_BADPARAM;
912     }
913 
914     width  = icd->lpbiInput->biWidth;
915     height = icd->lpbiInput->biHeight;
916     inverted = -icd->lpbiOutput->biHeight == height;
917 
918     decode_cinepak(info->cvinfo, icd->lpInput, icd->lpbiInput->biSizeImage,
919                    icd->lpOutput, width, height, info->bits_per_pixel, inverted);
920 
921     return ICERR_OK;
922 }
923 
924 static LRESULT ICCVID_DecompressEx( ICCVID_Info *info, ICDECOMPRESSEX *icd, DWORD size )
925 {
926     LONG width, height;
927     BOOL inverted;
928 
929     TRACE("ICM_DECOMPRESSEX %p %p %d\n", info, icd, size);
930 
931     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
932         return ICERR_BADPARAM;
933     if (info->cvinfo==NULL)
934     {
935         ERR("ICM_DECOMPRESSEX sent after ICM_DECOMPRESS_END\n");
936         return ICERR_BADPARAM;
937     }
938 
939     /* FIXME: flags are ignored */
940 
941     width  = icd->lpbiSrc->biWidth;
942     height = icd->lpbiSrc->biHeight;
943     inverted = -icd->lpbiDst->biHeight == height;
944 
945     decode_cinepak(info->cvinfo, icd->lpSrc, icd->lpbiSrc->biSizeImage,
946                    icd->lpDst, width, height, info->bits_per_pixel, inverted);
947 
948     return ICERR_OK;
949 }
950 
951 static LRESULT ICCVID_Close( ICCVID_Info *info )
952 {
953     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
954         return 0;
955     if( info->cvinfo )
956         free_cvinfo( info->cvinfo );
957     heap_free( info );
958     return 1;
959 }
960 
961 static LRESULT ICCVID_GetInfo( ICCVID_Info *info, ICINFO *icinfo, DWORD dwSize )
962 {
963     if (!icinfo) return sizeof(ICINFO);
964     if (dwSize < sizeof(ICINFO)) return 0;
965 
966     icinfo->dwSize = sizeof(ICINFO);
967     icinfo->fccType = ICTYPE_VIDEO;
968     icinfo->fccHandler = info ? info->dwMagic : ICCVID_MAGIC;
969     icinfo->dwFlags = 0;
970     icinfo->dwVersion = ICVERSION;
971     icinfo->dwVersionICM = ICVERSION;
972 
973     LoadStringW(ICCVID_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
974     LoadStringW(ICCVID_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
975     /* msvfw32 will fill icinfo->szDriver for us */
976 
977     return sizeof(ICINFO);
978 }
979 
980 static LRESULT ICCVID_DecompressEnd( ICCVID_Info *info )
981 {
982     if( info->cvinfo )
983     {
984         free_cvinfo( info->cvinfo );
985         info->cvinfo = NULL;
986     }
987     return ICERR_OK;
988 }
989 
990 LRESULT WINAPI ICCVID_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg,
991                                   LPARAM lParam1, LPARAM lParam2)
992 {
993     ICCVID_Info *info = (ICCVID_Info *) dwDriverId;
994 
995     TRACE("%ld %p %d %ld %ld\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
996 
997     switch( msg )
998     {
999     case DRV_LOAD:
1000         TRACE("Loaded\n");
1001         return 1;
1002     case DRV_ENABLE:
1003         return 0;
1004     case DRV_DISABLE:
1005         return 0;
1006     case DRV_FREE:
1007         return 0;
1008 
1009     case DRV_OPEN:
1010     {
1011         ICINFO *icinfo = (ICINFO *)lParam2;
1012 
1013         TRACE("Opened\n");
1014 
1015         if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return 0;
1016 
1017         info = heap_alloc( sizeof (ICCVID_Info) );
1018         if( info )
1019         {
1020             info->dwMagic = ICCVID_MAGIC;
1021             info->cvinfo = NULL;
1022         }
1023         return (LRESULT) info;
1024     }
1025 
1026     case DRV_CLOSE:
1027         return ICCVID_Close( info );
1028 
1029     case ICM_GETINFO:
1030         return ICCVID_GetInfo( info, (ICINFO *)lParam1, (DWORD)lParam2 );
1031 
1032     case ICM_DECOMPRESS_QUERY:
1033         return ICCVID_DecompressQuery( info, (LPBITMAPINFO) lParam1,
1034                                        (LPBITMAPINFO) lParam2 );
1035     case ICM_DECOMPRESS_GET_FORMAT:
1036         return ICCVID_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
1037                                        (LPBITMAPINFO) lParam2 );
1038     case ICM_DECOMPRESS_BEGIN:
1039         return ICCVID_DecompressBegin( info, (LPBITMAPINFO) lParam1,
1040                                        (LPBITMAPINFO) lParam2 );
1041     case ICM_DECOMPRESS:
1042         return ICCVID_Decompress( info, (ICDECOMPRESS*) lParam1,
1043                                   (DWORD) lParam2 );
1044     case ICM_DECOMPRESSEX:
1045         return ICCVID_DecompressEx( info, (ICDECOMPRESSEX*) lParam1,
1046                                   (DWORD) lParam2 );
1047 
1048     case ICM_DECOMPRESS_END:
1049         return ICCVID_DecompressEnd( info );
1050 
1051     case ICM_COMPRESS_QUERY:
1052         FIXME("compression not implemented\n");
1053         return ICERR_BADFORMAT;
1054 
1055     case ICM_CONFIGURE:
1056         return ICERR_UNSUPPORTED;
1057 
1058     default:
1059         FIXME("Unknown message: %04x %ld %ld\n", msg, lParam1, lParam2);
1060     }
1061     return ICERR_UNSUPPORTED;
1062 }
1063 
1064 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1065 {
1066     TRACE("(%p,%d,%p)\n", hModule, dwReason, lpReserved);
1067 
1068     switch (dwReason)
1069     {
1070     case DLL_PROCESS_ATTACH:
1071         DisableThreadLibraryCalls(hModule);
1072         ICCVID_hModule = hModule;
1073         break;
1074     }
1075     return TRUE;
1076 }
1077