Authors: Tim Ferguson <Tim.Ferguson@infotech.monash.edu.au>, Mike McCormack <mike...
[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 long rgb0, rgb1, rgb2, rgb3;        /* should be a union */
68     unsigned char r[4], g[4], b[4];
69 } cvid_codebook;
70
71 typedef struct {
72     cvid_codebook *v4_codebook[MAX_STRIPS];
73     cvid_codebook *v1_codebook[MAX_STRIPS];
74     int strip_num;
75 } cinepak_info;
76
77 typedef struct _ICCVID_Info
78 {
79     DWORD         dwMagic;
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_32(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->rgb0 = (c->y0 << 16) | (c->y0 << 8) | c->y0;
119         c->rgb1 = (c->y1 << 16) | (c->y1 << 8) | c->y1;
120         c->rgb2 = (c->y2 << 16) | (c->y2 << 8) | c->y2;
121         c->rgb3 = (c->y3 << 16) | (c->y3 << 8) | 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->rgb0 = (uiclp[c->y0 + uvr] << 16) | (uiclp[c->y0 + uvg] << 8) | uiclp[c->y0 + uvb];
137         c->rgb1 = (uiclp[c->y1 + uvr] << 16) | (uiclp[c->y1 + uvg] << 8) | uiclp[c->y1 + uvb];
138         c->rgb2 = (uiclp[c->y2 + uvr] << 16) | (uiclp[c->y2 + uvg] << 8) | uiclp[c->y2 + uvb];
139         c->rgb3 = (uiclp[c->y3 + uvr] << 16) | (uiclp[c->y3 + uvg] << 8) | uiclp[c->y3 + uvb];
140         }
141 }
142
143
144 /* ------------------------------------------------------------------------ */
145 inline void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
146 {
147 unsigned long *vptr = (unsigned long *)frm, rgb;
148 int row_inc = stride/4;
149
150 #ifndef ORIGINAL
151     vptr += row_inc*3;
152 #endif
153     vptr[0] = rgb = cb->rgb0; vptr[1] = rgb;
154     vptr[2] = rgb = cb->rgb1; vptr[3] = rgb;
155 #ifndef ORIGINAL
156     vptr -= row_inc; if(vptr < (unsigned long *)limit) return;
157 #else
158     vptr += row_inc; if(vptr > (unsigned long *)limit) return;
159 #endif
160     vptr[0] = rgb = cb->rgb0; vptr[1] = rgb;
161     vptr[2] = rgb = cb->rgb1; vptr[3] = rgb;
162 #ifndef ORIGINAL
163     vptr -= row_inc; if(vptr < (unsigned long *)limit) return;
164 #else
165     vptr += row_inc; if(vptr > (unsigned long *)limit) return;
166 #endif
167     vptr[0] = rgb = cb->rgb2; vptr[1] = rgb;
168     vptr[2] = rgb = cb->rgb3; vptr[3] = rgb;
169 #ifndef ORIGINAL
170     vptr -= row_inc; if(vptr < (unsigned long *)limit) return;
171 #else
172     vptr += row_inc; if(vptr > (unsigned long *)limit) return;
173 #endif
174     vptr[0] = rgb = cb->rgb2; vptr[1] = rgb;
175     vptr[2] = rgb = cb->rgb3; vptr[3] = rgb;
176 }
177
178
179 /* ------------------------------------------------------------------------ */
180 inline void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
181     cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
182 {
183 unsigned long *vptr = (unsigned long *)frm;
184 int row_inc = stride/4;
185
186 #ifndef ORIGINAL
187     vptr += row_inc*3;
188 #endif
189     vptr[0] = cb0->rgb0;
190     vptr[1] = cb0->rgb1;
191     vptr[2] = cb1->rgb0;
192     vptr[3] = cb1->rgb1;
193 #ifndef ORIGINAL
194     vptr -= row_inc; if(vptr < (unsigned long *)limit) return;
195 #else
196     vptr += row_inc; if(vptr > (unsigned long *)limit) return;
197 #endif
198     vptr[0] = cb0->rgb2;
199     vptr[1] = cb0->rgb3;
200     vptr[2] = cb1->rgb2;
201     vptr[3] = cb1->rgb3;
202 #ifndef ORIGINAL
203     vptr -= row_inc; if(vptr < (unsigned long *)limit) return;
204 #else
205     vptr += row_inc; if(vptr > (unsigned long *)limit) return;
206 #endif
207     vptr[0] = cb2->rgb0;
208     vptr[1] = cb2->rgb1;
209     vptr[2] = cb3->rgb0;
210     vptr[3] = cb3->rgb1;
211 #ifndef ORIGINAL
212     vptr -= row_inc; if(vptr < (unsigned long *)limit) return;
213 #else
214     vptr += row_inc; if(vptr > (unsigned long *)limit) return;
215 #endif
216     vptr[0] = cb2->rgb2;
217     vptr[1] = cb2->rgb3;
218     vptr[2] = cb3->rgb2;
219     vptr[3] = cb3->rgb3;
220 }
221
222
223 /* ---------------------------------------------------------------------- */
224 static inline void read_codebook_24(cvid_codebook *c, int mode)
225 {
226 int uvr, uvg, uvb;
227
228     if(mode)        /* black and white */
229         {
230         c->y0 = get_byte();
231         c->y1 = get_byte();
232         c->y2 = get_byte();
233         c->y3 = get_byte();
234         c->u = c->v = 0;
235
236         c->r[0] = c->g[0] = c->b[0] = c->y0;
237         c->r[1] = c->g[1] = c->b[1] = c->y1;
238         c->r[2] = c->g[2] = c->b[2] = c->y2;
239         c->r[3] = c->g[3] = c->b[3] = c->y3;
240         }
241     else            /* colour */
242         {
243         c->y0 = get_byte();  /* luma */
244         c->y1 = get_byte();
245         c->y2 = get_byte();
246         c->y3 = get_byte();
247         c->u = get_byte(); /* chroma */
248         c->v = get_byte();
249
250         uvr = c->v << 1;
251         uvg = -((c->u+1) >> 1) - c->v;
252         uvb = c->u << 1;
253
254         c->r[0] = uiclp[c->y0 + uvr]; c->g[0] = uiclp[c->y0 + uvg]; c->b[0] = uiclp[c->y0 + uvb];
255         c->r[1] = uiclp[c->y1 + uvr]; c->g[1] = uiclp[c->y1 + uvg]; c->b[1] = uiclp[c->y1 + uvb];
256         c->r[2] = uiclp[c->y2 + uvr]; c->g[2] = uiclp[c->y2 + uvg]; c->b[2] = uiclp[c->y2 + uvb];
257         c->r[3] = uiclp[c->y3 + uvr]; c->g[3] = uiclp[c->y3 + uvg]; c->b[3] = uiclp[c->y3 + uvb];
258         }
259 }
260
261
262 /* ------------------------------------------------------------------------ */
263 void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb)
264 {
265 unsigned char r, g, b;
266 #ifndef ORIGINAL
267 int row_inc = stride+4*3;
268 #else
269 int row_inc = stride-4*3;
270 #endif
271
272 #ifndef ORIGINAL
273     vptr += (3*row_inc);
274 #endif
275     *vptr++ = b = cb->b[0]; *vptr++ = g = cb->g[0]; *vptr++ = r = cb->r[0];
276     *vptr++ = b; *vptr++ = g; *vptr++ = r;
277     *vptr++ = b = cb->b[1]; *vptr++ = g = cb->g[1]; *vptr++ = r = cb->r[1];
278     *vptr++ = b; *vptr++ = g; *vptr++ = r;
279 #ifndef ORIGINAL
280     vptr -= row_inc; if(vptr < limit) return;
281 #else
282     vptr += row_inc; if(vptr > limit) return;
283 #endif
284     *vptr++ = b = cb->b[0]; *vptr++ = g = cb->g[0]; *vptr++ = r = cb->r[0];
285     *vptr++ = b; *vptr++ = g; *vptr++ = r;
286     *vptr++ = b = cb->b[1]; *vptr++ = g = cb->g[1]; *vptr++ = r = cb->r[1];
287     *vptr++ = b; *vptr++ = g; *vptr++ = r;
288 #ifndef ORIGINAL
289     vptr -= row_inc; if(vptr < limit) return;
290 #else
291     vptr += row_inc; if(vptr > limit) return;
292 #endif
293     *vptr++ = b = cb->b[2]; *vptr++ = g = cb->g[2]; *vptr++ = r = cb->r[2];
294     *vptr++ = b; *vptr++ = g; *vptr++ = r;
295     *vptr++ = b = cb->b[3]; *vptr++ = g = cb->g[3]; *vptr++ = r = cb->r[3];
296     *vptr++ = b; *vptr++ = g; *vptr++ = r;
297 #ifndef ORIGINAL
298     vptr -= row_inc; if(vptr < limit) return;
299 #else
300     vptr += row_inc; if(vptr > limit) return;
301 #endif
302     *vptr++ = b = cb->b[2]; *vptr++ = g = cb->g[2]; *vptr++ = r = cb->r[2];
303     *vptr++ = b; *vptr++ = g; *vptr++ = r;
304     *vptr++ = b = cb->b[3]; *vptr++ = g = cb->g[3]; *vptr++ = r = cb->r[3];
305     *vptr++ = b; *vptr++ = g; *vptr++ = r;
306 }
307
308
309 /* ------------------------------------------------------------------------ */
310 void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb0,
311     cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
312 {
313 #ifndef ORIGINAL
314 int row_inc = stride+4*3;
315 #else
316 int row_inc = stride-4*3;
317 #endif
318
319 #ifndef ORIGINAL
320     vptr += (3*row_inc);
321 #endif
322     *vptr++ = cb0->b[0]; *vptr++ = cb0->g[0]; *vptr++ = cb0->r[0];
323     *vptr++ = cb0->b[1]; *vptr++ = cb0->g[1]; *vptr++ = cb0->r[1];
324     *vptr++ = cb1->b[0]; *vptr++ = cb1->g[0]; *vptr++ = cb1->r[0];
325     *vptr++ = cb1->b[1]; *vptr++ = cb1->g[1]; *vptr++ = cb1->r[1];
326 #ifndef ORIGINAL
327     vptr -= row_inc; if(vptr < limit) return;
328 #else
329     vptr += row_inc; if(vptr > limit) return;
330 #endif
331     *vptr++ = cb0->b[2]; *vptr++ = cb0->g[2]; *vptr++ = cb0->r[2];
332     *vptr++ = cb0->b[3]; *vptr++ = cb0->g[3]; *vptr++ = cb0->r[3];
333     *vptr++ = cb1->b[2]; *vptr++ = cb1->g[2]; *vptr++ = cb1->r[2];
334     *vptr++ = cb1->b[3]; *vptr++ = cb1->g[3]; *vptr++ = cb1->r[3];
335 #ifndef ORIGINAL
336     vptr -= row_inc; if(vptr < limit) return;
337 #else
338     vptr += row_inc; if(vptr > limit) return;
339 #endif
340     *vptr++ = cb2->b[0]; *vptr++ = cb2->g[0]; *vptr++ = cb2->r[0];
341     *vptr++ = cb2->b[1]; *vptr++ = cb2->g[1]; *vptr++ = cb2->r[1];
342     *vptr++ = cb3->b[0]; *vptr++ = cb3->g[0]; *vptr++ = cb3->r[0];
343     *vptr++ = cb3->b[1]; *vptr++ = cb3->g[1]; *vptr++ = cb3->r[1];
344 #ifndef ORIGINAL
345     vptr -= row_inc; if(vptr < limit) return;
346 #else
347     vptr += row_inc; if(vptr > limit) return;
348 #endif
349     *vptr++ = cb2->b[2]; *vptr++ = cb2->g[2]; *vptr++ = cb2->r[2];
350     *vptr++ = cb2->b[3]; *vptr++ = cb2->g[3]; *vptr++ = cb2->r[3];
351     *vptr++ = cb3->b[2]; *vptr++ = cb3->g[2]; *vptr++ = cb3->r[2];
352     *vptr++ = cb3->b[3]; *vptr++ = cb3->g[3]; *vptr++ = cb3->r[3];
353 }
354
355
356 /* ------------------------------------------------------------------------
357  * Call this function once at the start of the sequence and save the
358  * returned context for calls to decode_cinepak().
359  */
360 cinepak_info *decode_cinepak_init(void)
361 {
362     cinepak_info *cvinfo;
363     int i;
364
365     cvinfo = ICCVID_Alloc( sizeof (cinepak_info), 1 );
366     if( !cvinfo )
367         return NULL;
368     cvinfo->strip_num = 0;
369
370     if(uiclp == NULL)
371     {
372         uiclp = uiclip+512;
373         for(i = -512; i < 512; i++)
374             uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i));
375     }
376
377     return cvinfo;
378 }
379
380 void free_cvinfo( cinepak_info *cvinfo )
381 {
382     int i;
383
384     for( i=0; i<cvinfo->strip_num; i++ )
385     {
386         ICCVID_Free(cvinfo->v4_codebook[i]);
387         ICCVID_Free(cvinfo->v1_codebook[i]);
388     }
389     ICCVID_Free( cvinfo );
390 }
391
392 typedef void (*fn_read_codebook)(cvid_codebook *c, int mode);
393 typedef void (*fn_cvid_v1)(unsigned char *frm, unsigned char *limit,
394                            int stride, cvid_codebook *cb);
395 typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit, int stride,
396                            cvid_codebook *cb0, cvid_codebook *cb1,
397                            cvid_codebook *cb2, cvid_codebook *cb3);
398
399 /* ------------------------------------------------------------------------
400  * This function decodes a buffer containing a Cinepak encoded frame.
401  *
402  * context - the context created by decode_cinepak_init().
403  * buf - the input buffer to be decoded
404  * size - the size of the input buffer
405  * frame - the output frame buffer (24 or 32 bit per pixel)
406  * width - the width of the output frame
407  * height - the height of the output frame
408  * bit_per_pixel - the number of bits per pixel allocated to the output
409  *   frame (only 24 or 32 bpp are supported)
410  */
411 void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
412            unsigned char *frame, int width, int height, int bit_per_pixel)
413 {
414     cvid_codebook *v4_codebook, *v1_codebook, *codebook = NULL;
415     unsigned long x, y, y_bottom, frame_flags, strips, cv_width, cv_height,
416                   cnum, strip_id, chunk_id, x0, y0, x1, y1, ci, flag, mask;
417     long len, top_size, chunk_size;
418     unsigned char *frm_ptr, *frm_end;
419     int i, cur_strip, d0, d1, d2, d3, frm_stride, bpp = 3;
420     fn_read_codebook read_codebook = read_codebook_24;
421     fn_cvid_v1 cvid_v1 = cvid_v1_24;
422     fn_cvid_v4 cvid_v4 = cvid_v4_24;
423
424     x = y = 0;
425     y_bottom = 0;
426     in_buffer = buf;
427
428     frame_flags = get_byte();
429     len = get_byte() << 16;
430     len |= get_byte() << 8;
431     len |= get_byte();
432
433     switch(bit_per_pixel)
434         {
435         case 24:
436             bpp = 3;
437             read_codebook = read_codebook_24;
438             cvid_v1 = cvid_v1_24;
439             cvid_v4 = cvid_v4_24;
440             break;
441         case 32:
442             bpp = 4;
443             read_codebook = read_codebook_32;
444             cvid_v1 = cvid_v1_32;
445             cvid_v4 = cvid_v4_32;
446             break;
447         }
448
449     frm_stride = width * bpp;
450     frm_ptr = frame;
451     frm_end = frm_ptr + width * height * bpp;
452
453     if(len != size)
454         {
455         if(len & 0x01) len++; /* AVIs tend to have a size mismatch */
456         if(len != size)
457             {
458             ERR("CVID: corruption %d (QT/AVI) != %ld (CV)\n", size, len);
459             /* return; */
460             }
461         }
462
463     cv_width = get_word();
464     cv_height = get_word();
465     strips = get_word();
466
467     if(strips > cvinfo->strip_num)
468         {
469         if(strips >= MAX_STRIPS)
470             {
471             ERR("CVID: strip overflow (more than %d)\n", MAX_STRIPS);
472             return;
473             }
474
475         for(i = cvinfo->strip_num; i < strips; i++)
476             {
477             if((cvinfo->v4_codebook[i] = (cvid_codebook *)ICCVID_Alloc(sizeof(cvid_codebook), 260)) == NULL)
478                 {
479                 ERR("CVID: codebook v4 alloc err\n");
480                 return;
481                 }
482
483             if((cvinfo->v1_codebook[i] = (cvid_codebook *)ICCVID_Alloc(sizeof(cvid_codebook), 260)) == NULL)
484                 {
485                 ERR("CVID: codebook v1 alloc err\n");
486                 return;
487                 }
488             }
489         }
490     cvinfo->strip_num = strips;
491
492     TRACE("CVID: <%ld,%ld> strips %ld\n", cv_width, cv_height, strips);
493
494     for(cur_strip = 0; cur_strip < strips; cur_strip++)
495         {
496         v4_codebook = cvinfo->v4_codebook[cur_strip];
497         v1_codebook = cvinfo->v1_codebook[cur_strip];
498
499         if((cur_strip > 0) && (!(frame_flags & 0x01)))
500             {
501             memcpy(cvinfo->v4_codebook[cur_strip], cvinfo->v4_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
502             memcpy(cvinfo->v1_codebook[cur_strip], cvinfo->v1_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
503             }
504
505         strip_id = get_word();        /* 1000 = key strip, 1100 = iter strip */
506         top_size = get_word();
507         y0 = get_word();        /* FIXME: most of these are ignored at the moment */
508         x0 = get_word();
509         y1 = get_word();
510         x1 = get_word();
511
512         y_bottom += y1;
513         top_size -= 12;
514         x = 0;
515         if(x1 != width)
516             WARN("CVID: Warning x1 (%ld) != width (%d)\n", x1, width);
517
518         TRACE("   %d) %04lx %04ld <%ld,%ld> <%ld,%ld> yt %ld\n",
519               cur_strip, strip_id, top_size, x0, y0, x1, y1, y_bottom);
520
521         while(top_size > 0)
522             {
523             chunk_id  = get_word();
524             chunk_size = get_word();
525
526             TRACE("        %04lx %04ld\n", chunk_id, chunk_size);
527             top_size -= chunk_size;
528             chunk_size -= 4;
529
530             switch(chunk_id)
531                 {
532                     /* -------------------- Codebook Entries -------------------- */
533                 case 0x2000:
534                 case 0x2200:
535                     codebook = (chunk_id == 0x2200 ? v1_codebook : v4_codebook);
536                     cnum = chunk_size/6;
537                     for(i = 0; i < cnum; i++) read_codebook(codebook+i, 0);
538                     break;
539
540                 case 0x2400:
541                 case 0x2600:        /* 8 bit per pixel */
542                     codebook = (chunk_id == 0x2600 ? v1_codebook : v4_codebook);
543                     cnum = chunk_size/4;
544                     for(i = 0; i < cnum; i++) read_codebook(codebook+i, 1);
545                     break;
546
547                 case 0x2100:
548                 case 0x2300:
549                     codebook = (chunk_id == 0x2300 ? v1_codebook : v4_codebook);
550
551                     ci = 0;
552                     while(chunk_size > 0)
553                         {
554                         flag = get_long();
555                         chunk_size -= 4;
556
557                         for(i = 0; i < 32; i++)
558                             {
559                             if(flag & 0x80000000)
560                                 {
561                                 chunk_size -= 6;
562                                 read_codebook(codebook+ci, 0);
563                                 }
564
565                             ci++;
566                             flag <<= 1;
567                             }
568                         }
569                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
570                     break;
571
572                 case 0x2500:
573                 case 0x2700:        /* 8 bit per pixel */
574                     codebook = (chunk_id == 0x2700 ? v1_codebook : v4_codebook);
575
576                     ci = 0;
577                     while(chunk_size > 0)
578                         {
579                         flag = get_long();
580                         chunk_size -= 4;
581
582                         for(i = 0; i < 32; i++)
583                             {
584                             if(flag & 0x80000000)
585                                 {
586                                 chunk_size -= 4;
587                                 read_codebook(codebook+ci, 1);
588                                 }
589
590                             ci++;
591                             flag <<= 1;
592                             }
593                         }
594                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
595                     break;
596
597                     /* -------------------- Frame -------------------- */
598                 case 0x3000:
599                     while((chunk_size > 0) && (y < y_bottom))
600                         {
601                         flag = get_long();
602                         chunk_size -= 4;
603
604                         for(i = 0; i < 32; i++)
605                             {
606                             if(y >= y_bottom) break;
607                             if(flag & 0x80000000)    /* 4 bytes per block */
608                                 {
609                                 d0 = get_byte();
610                                 d1 = get_byte();
611                                 d2 = get_byte();
612                                 d3 = get_byte();
613                                 chunk_size -= 4;
614 #ifdef ORIGINAL
615                                 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);
616 #else
617                                 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);
618 #endif
619                                 }
620                             else        /* 1 byte per block */
621                                 {
622 #ifdef ORIGINAL
623                                 cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
624 #else
625                                 cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte());
626 #endif
627                                 chunk_size--;
628                                 }
629
630                             x += 4;
631                             if(x >= width)
632                                 {
633                                 x = 0;
634                                 y += 4;
635                                 }
636                             flag <<= 1;
637                             }
638                         }
639                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
640                     break;
641
642                 case 0x3100:
643                     while((chunk_size > 0) && (y < y_bottom))
644                         {
645                             /* ---- flag bits: 0 = SKIP, 10 = V1, 11 = V4 ---- */
646                         flag = (unsigned long)get_long();
647                         chunk_size -= 4;
648                         mask = 0x80000000;
649
650                         while((mask) && (y < y_bottom))
651                             {
652                             if(flag & mask)
653                                 {
654                                 if(mask == 1)
655                                     {
656                                     if(chunk_size < 0) break;
657                                     flag = (unsigned long)get_long();
658                                     chunk_size -= 4;
659                                     mask = 0x80000000;
660                                     }
661                                 else mask >>= 1;
662
663                                 if(flag & mask)        /* V4 */
664                                     {
665                                     d0 = get_byte();
666                                     d1 = get_byte();
667                                     d2 = get_byte();
668                                     d3 = get_byte();
669                                     chunk_size -= 4;
670 #ifdef ORIGINAL
671                                     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);
672 #else
673                                     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);
674 #endif
675                                     }
676                                 else        /* V1 */
677                                     {
678                                     chunk_size--;
679 #ifdef ORIGINAL
680                                     cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
681 #else
682                                     cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte());
683 #endif
684                                     }
685                                 }        /* else SKIP */
686
687                             mask >>= 1;
688                             x += 4;
689                             if(x >= width)
690                                 {
691                                 x = 0;
692                                 y += 4;
693                                 }
694                             }
695                         }
696
697                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
698                     break;
699
700                 case 0x3200:        /* each byte is a V1 codebook */
701                     while((chunk_size > 0) && (y < y_bottom))
702                         {
703 #ifdef ORIGINAL
704                         cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
705 #else
706                         cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte());
707 #endif
708                         chunk_size--;
709                         x += 4;
710                         if(x >= width)
711                             {
712                             x = 0;
713                             y += 4;
714                             }
715                         }
716                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
717                     break;
718
719                 default:
720                     ERR("CVID: unknown chunk_id %08lx\n", chunk_id);
721                     while(chunk_size > 0) { skip_byte(); chunk_size--; }
722                     break;
723                 }
724             }
725         }
726
727     if(len != size)
728         {
729         if(len & 0x01) len++; /* AVIs tend to have a size mismatch */
730         if(len != size)
731             {
732             long xlen;
733             skip_byte();
734             xlen = get_byte() << 16;
735             xlen |= get_byte() << 8;
736             xlen |= get_byte(); /* Read Len */
737             WARN("CVID: END INFO chunk size %d cvid size1 %ld cvid size2 %ld\n",
738                   size, len, xlen);
739             }
740         }
741 }
742
743 LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
744 {
745     TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
746
747     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
748         return ICERR_BADPARAM;
749
750     TRACE("planes = %d\n", in->bmiHeader.biPlanes );
751     TRACE("bpp    = %d\n", in->bmiHeader.biBitCount );
752     TRACE("height = %ld\n", in->bmiHeader.biHeight );
753     TRACE("width  = %ld\n", in->bmiHeader.biWidth );
754     TRACE("compr  = %lx\n", in->bmiHeader.biCompression );
755
756     if( in->bmiHeader.biCompression != ICCVID_MAGIC )
757         return ICERR_UNSUPPORTED;
758
759     switch( in->bmiHeader.biBitCount )
760     {
761     case 24:
762     case 32:
763         break;
764     default:
765         TRACE("bitcount = %d\n", in->bmiHeader.biBitCount );
766         return ICERR_UNSUPPORTED;
767     }
768
769     if( out )
770         return ICERR_UNSUPPORTED;
771
772     return ICERR_OK;
773 }
774
775 LRESULT ICCVID_DecompressGetFormat( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
776 {
777     TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
778
779     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
780         return ICERR_BADPARAM;
781
782     if( out )
783     {
784         memcpy( out, in, sizeof (BITMAPINFO) );
785         out->bmiHeader.biCompression = BI_RGB;
786         out->bmiHeader.biSizeImage = in->bmiHeader.biHeight
787                                    * in->bmiHeader.biWidth *4;
788     }
789
790     return sizeof (BITMAPINFO);
791 }
792
793 LRESULT ICCVID_DecompressBegin( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
794 {
795     TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
796
797     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
798         return ICERR_BADPARAM;
799
800     if( info->cvinfo )
801         free_cvinfo( info->cvinfo );
802     info->cvinfo = decode_cinepak_init();
803
804     return ICERR_OK;
805 }
806
807 LRESULT ICCVID_Decompress( ICCVID_Info *info, ICDECOMPRESS *icd, DWORD size )
808 {
809     LONG width, height;
810     WORD bit_per_pixel;
811
812     TRACE("ICM_DECOMPRESS %p %p %ld\n", info, icd, size);
813
814     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
815         return ICERR_BADPARAM;
816
817     width  = icd->lpbiInput->biWidth;
818     height = icd->lpbiInput->biHeight;
819     bit_per_pixel = icd->lpbiInput->biBitCount;
820
821     decode_cinepak(info->cvinfo, icd->lpInput, icd->lpbiInput->biSizeImage,
822                    icd->lpOutput, width, height, bit_per_pixel);
823
824     return ICERR_OK;
825 }
826
827 LRESULT ICCVID_Close( ICCVID_Info *info )
828 {
829     if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
830         return 0;
831     if( info->cvinfo )
832         free_cvinfo( info->cvinfo );
833     ICCVID_Free( info );
834     return 1;
835 }
836
837 LRESULT WINAPI ICCVID_DriverProc( DWORD dwDriverId, HDRVR hdrvr, UINT msg,
838                                   LONG lParam1, LONG lParam2)
839 {
840     ICCVID_Info *info = (ICCVID_Info *) dwDriverId;
841
842     TRACE("%ld %p %d %ld %ld\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
843
844     switch( msg )
845     {
846     case DRV_LOAD:
847         TRACE("Loaded\n");
848         return 1;
849     case DRV_ENABLE:
850         return 0;
851
852     case DRV_OPEN:
853         TRACE("Opened\n");
854         info = ICCVID_Alloc( sizeof (ICCVID_Info), 1 );
855         if( info )
856         {
857             info->dwMagic = ICCVID_MAGIC;
858             info->cvinfo = NULL;
859         }
860         return (LRESULT) info;
861
862     case ICM_DECOMPRESS_QUERY:
863         return ICCVID_DecompressQuery( info, (LPBITMAPINFO) lParam1,
864                                        (LPBITMAPINFO) lParam2 );
865     case ICM_DECOMPRESS_GET_FORMAT:
866         return ICCVID_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
867                                        (LPBITMAPINFO) lParam2 );
868     case ICM_DECOMPRESS_BEGIN:
869         return ICCVID_DecompressBegin( info, (LPBITMAPINFO) lParam1,
870                                        (LPBITMAPINFO) lParam2 );
871     case ICM_DECOMPRESS:
872         return ICCVID_Decompress( info, (ICDECOMPRESS*) lParam1,
873                                   (DWORD) lParam2 );
874     case DRV_CLOSE:
875         return ICCVID_Close( info );
876
877     default:
878         FIXME("Unknown message: %d %ld %ld\n", msg, lParam1, lParam2);
879     }
880     return 0;
881 }