include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / iccvid / iccvid.c
blob56a882af65939647b4012b3e8dc78a5db0ca229d
1 /*
2 * Radius Cinepak Video Decoder
4 * Copyright 2001 Dr. Tim Ferguson (see below)
5 * Portions Copyright 2003 Mike McCormack for CodeWeavers
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.
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.
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
22 /* Copyright notice from original source:
23 * ------------------------------------------------------------------------
24 * Radius Cinepak Video Decoder
26 * Dr. Tim Ferguson, 2001.
27 * For more details on the algorithm:
28 * http://www.csse.monash.edu.au/~timf/videocodec.html
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.
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 :)
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 * ------------------------------------------------------------------------ */
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 #include "mmsystem.h"
51 #include "iccvid_private.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(iccvid);
57 static HINSTANCE ICCVID_hModule;
59 #define ICCVID_MAGIC mmioFOURCC('c', 'v', 'i', 'd')
60 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
61 #define MAX_STRIPS 32
63 /* ------------------------------------------------------------------------ */
64 typedef struct
66 unsigned char y0, y1, y2, y3;
67 char u, v;
68 unsigned char r[4], g[4], b[4];
69 } cvid_codebook;
71 typedef struct {
72 cvid_codebook *v4_codebook[MAX_STRIPS];
73 cvid_codebook *v1_codebook[MAX_STRIPS];
74 unsigned int strip_num;
75 } cinepak_info;
77 typedef struct _ICCVID_Info
79 DWORD dwMagic;
80 int bits_per_pixel;
81 cinepak_info *cvinfo;
82 } ICCVID_Info;
85 /* ------------------------------------------------------------------------ */
86 static unsigned char *in_buffer, uiclip[1024], *uiclp = NULL;
88 #define get_byte() *(in_buffer++)
89 #define skip_byte() in_buffer++
90 #define get_word() ((unsigned short)(in_buffer += 2, \
91 (in_buffer[-2] << 8 | in_buffer[-1])))
92 #define get_long() ((unsigned long)(in_buffer += 4, \
93 (in_buffer[-4] << 24 | in_buffer[-3] << 16 | in_buffer[-2] << 8 | in_buffer[-1])))
96 /* ---------------------------------------------------------------------- */
97 static inline void read_codebook(cvid_codebook *c, int mode)
99 int uvr, uvg, uvb;
101 if(mode) /* black and white */
103 c->y0 = get_byte();
104 c->y1 = get_byte();
105 c->y2 = get_byte();
106 c->y3 = get_byte();
107 c->u = c->v = 0;
109 c->r[0] = c->g[0] = c->b[0] = c->y0;
110 c->r[1] = c->g[1] = c->b[1] = c->y1;
111 c->r[2] = c->g[2] = c->b[2] = c->y2;
112 c->r[3] = c->g[3] = c->b[3] = c->y3;
114 else /* colour */
116 c->y0 = get_byte(); /* luma */
117 c->y1 = get_byte();
118 c->y2 = get_byte();
119 c->y3 = get_byte();
120 c->u = get_byte(); /* chroma */
121 c->v = get_byte();
123 uvr = c->v << 1;
124 uvg = -((c->u+1) >> 1) - c->v;
125 uvb = c->u << 1;
127 c->r[0] = uiclp[c->y0 + uvr]; c->g[0] = uiclp[c->y0 + uvg]; c->b[0] = uiclp[c->y0 + uvb];
128 c->r[1] = uiclp[c->y1 + uvr]; c->g[1] = uiclp[c->y1 + uvg]; c->b[1] = uiclp[c->y1 + uvb];
129 c->r[2] = uiclp[c->y2 + uvr]; c->g[2] = uiclp[c->y2 + uvg]; c->b[2] = uiclp[c->y2 + uvb];
130 c->r[3] = uiclp[c->y3 + uvr]; c->g[3] = uiclp[c->y3 + uvg]; c->b[3] = uiclp[c->y3 + uvb];
134 static inline long get_addr(BOOL inverted, unsigned long x, unsigned long y,
135 int frm_stride, int bpp, unsigned int out_height)
137 /* Returns the starting position of a line from top-down or bottom-up */
138 if (inverted)
139 return y * frm_stride + x * bpp;
140 else
141 return (out_height - 1 - y) * frm_stride + x * bpp;
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)
149 /* ------------------------------------------------------------------------ */
150 static void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
151 cvid_codebook *cb)
153 unsigned long *vptr = (unsigned long *)frm;
154 int row_inc;
155 int x, y;
157 if (!inverted)
158 row_inc = -stride/4;
159 else
160 row_inc = stride/4;
162 /* fill 4x4 block of pixels with colour values from codebook */
163 for (y = 0; y < 4; y++)
165 if (&vptr[y*row_inc] < (unsigned long *)limit) return;
166 for (x = 0; x < 4; x++)
167 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]);
171 static inline int get_stride(int width, int depth)
173 return ((depth * width + 31) >> 3) & ~3;
176 /* ------------------------------------------------------------------------ */
177 static void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
178 cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
180 unsigned long *vptr = (unsigned long *)frm;
181 int row_inc;
182 int x, y;
183 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
185 if (!inverted)
186 row_inc = -stride/4;
187 else
188 row_inc = stride/4;
190 /* fill 4x4 block of pixels with colour values from codebooks */
191 for (y = 0; y < 4; y++)
193 if (&vptr[y*row_inc] < (unsigned long *)limit) return;
194 for (x = 0; x < 4; x++)
195 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]);
200 /* ------------------------------------------------------------------------ */
201 static void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, BOOL inverted,
202 cvid_codebook *cb)
204 int row_inc;
205 int x, y;
207 if (!inverted)
208 row_inc = -stride;
209 else
210 row_inc = stride;
212 /* fill 4x4 block of pixels with colour values from codebook */
213 for (y = 0; y < 4; y++)
215 if (&vptr[y*row_inc] < limit) return;
216 for (x = 0; x < 4; x++)
218 vptr[y*row_inc + x*3 + 0] = cb->b[x/2+(y/2)*2];
219 vptr[y*row_inc + x*3 + 1] = cb->g[x/2+(y/2)*2];
220 vptr[y*row_inc + x*3 + 2] = cb->r[x/2+(y/2)*2];
226 /* ------------------------------------------------------------------------ */
227 static void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, BOOL inverted,
228 cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
230 int row_inc;
231 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
232 int x, y;
234 if (!inverted)
235 row_inc = -stride;
236 else
237 row_inc = stride;
239 /* fill 4x4 block of pixels with colour values from codebooks */
240 for (y = 0; y < 4; y++)
242 if (&vptr[y*row_inc] < limit) return;
243 for (x = 0; x < 4; x++)
245 vptr[y*row_inc + x*3 + 0] = cb[x/2+(y/2)*2]->b[x%2+(y%2)*2];
246 vptr[y*row_inc + x*3 + 1] = cb[x/2+(y/2)*2]->g[x%2+(y%2)*2];
247 vptr[y*row_inc + x*3 + 2] = cb[x/2+(y/2)*2]->r[x%2+(y%2)*2];
253 /* ------------------------------------------------------------------------ */
254 static void cvid_v1_16(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
255 cvid_codebook *cb)
257 unsigned short *vptr = (unsigned short *)frm;
258 int row_inc;
259 int x, y;
261 if (!inverted)
262 row_inc = -stride/2;
263 else
264 row_inc = stride/2;
266 /* fill 4x4 block of pixels with colour values from codebook */
267 for (y = 0; y < 4; y++)
269 if (&vptr[y*row_inc] < (unsigned short *)limit) return;
270 for (x = 0; x < 4; x++)
271 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]);
276 /* ------------------------------------------------------------------------ */
277 static void cvid_v4_16(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
278 cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
280 unsigned short *vptr = (unsigned short *)frm;
281 int row_inc;
282 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
283 int x, y;
285 if (!inverted)
286 row_inc = -stride/2;
287 else
288 row_inc = stride/2;
290 /* fill 4x4 block of pixels with colour values from codebooks */
291 for (y = 0; y < 4; y++)
293 if (&vptr[y*row_inc] < (unsigned short *)limit) return;
294 for (x = 0; x < 4; x++)
295 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]);
299 /* ------------------------------------------------------------------------ */
300 static void cvid_v1_15(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
301 cvid_codebook *cb)
303 unsigned short *vptr = (unsigned short *)frm;
304 int row_inc;
305 int x, y;
307 if (!inverted)
308 row_inc = -stride/2;
309 else
310 row_inc = stride/2;
312 /* fill 4x4 block of pixels with colour values from codebook */
313 for (y = 0; y < 4; y++)
315 if (&vptr[y*row_inc] < (unsigned short *)limit) return;
316 for (x = 0; x < 4; x++)
317 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]);
322 /* ------------------------------------------------------------------------ */
323 static void cvid_v4_15(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
324 cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
326 unsigned short *vptr = (unsigned short *)frm;
327 int row_inc;
328 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
329 int x, y;
331 if (!inverted)
332 row_inc = -stride/2;
333 else
334 row_inc = stride/2;
336 /* fill 4x4 block of pixels with colour values from codebooks */
337 for (y = 0; y < 4; y++)
339 if (&vptr[y*row_inc] < (unsigned short *)limit) return;
340 for (x = 0; x < 4; x++)
341 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]);
346 /* ------------------------------------------------------------------------
347 * Call this function once at the start of the sequence and save the
348 * returned context for calls to decode_cinepak().
350 static cinepak_info *decode_cinepak_init(void)
352 cinepak_info *cvinfo;
353 int i;
355 cvinfo = malloc(sizeof(cinepak_info));
356 if( !cvinfo )
357 return NULL;
358 cvinfo->strip_num = 0;
360 if(uiclp == NULL)
362 uiclp = uiclip+512;
363 for(i = -512; i < 512; i++)
364 uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i));
367 return cvinfo;
370 static void free_cvinfo( cinepak_info *cvinfo )
372 unsigned int i;
374 for( i=0; i<cvinfo->strip_num; i++ )
376 free(cvinfo->v4_codebook[i]);
377 free(cvinfo->v1_codebook[i]);
379 free( cvinfo );
382 typedef void (*fn_cvid_v1)(unsigned char *frm, unsigned char *limit,
383 int stride, BOOL inverted, cvid_codebook *cb);
384 typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit,
385 int stride, BOOL inverted,
386 cvid_codebook *cb0, cvid_codebook *cb1,
387 cvid_codebook *cb2, cvid_codebook *cb3);
389 /* ------------------------------------------------------------------------
390 * This function decodes a buffer containing a Cinepak encoded frame.
392 * context - the context created by decode_cinepak_init().
393 * buf - the input buffer to be decoded
394 * size - the size of the input buffer
395 * output - the output frame buffer (24 or 32 bit per pixel)
396 * out_width - the width of the output frame
397 * out_height - the height of the output frame
398 * bit_per_pixel - the number of bits per pixel allocated to the output
399 * frame (only 24 or 32 bpp are supported)
400 * inverted - if true the output frame is written top-down
402 static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
403 unsigned char *output, unsigned int out_width, unsigned int out_height, int bit_per_pixel, BOOL inverted)
405 cvid_codebook *v4_codebook, *v1_codebook, *codebook = NULL;
406 unsigned long x, y, y_bottom, cnum, strip_id, chunk_id,
407 x0, y0, x1, y1, ci, flag, mask;
408 long top_size, chunk_size;
409 unsigned char *frm_ptr;
410 unsigned int i, cur_strip, addr;
411 int d0, d1, d2, d3, frm_stride, bpp = 3;
412 fn_cvid_v1 cvid_v1 = cvid_v1_24;
413 fn_cvid_v4 cvid_v4 = cvid_v4_24;
414 struct frame_header
416 unsigned char flags;
417 unsigned long length;
418 unsigned short width;
419 unsigned short height;
420 unsigned short strips;
421 } frame;
423 y = 0;
424 y_bottom = 0;
425 in_buffer = buf;
427 frame.flags = get_byte();
428 frame.length = get_byte() << 16;
429 frame.length |= get_byte() << 8;
430 frame.length |= get_byte();
432 switch(bit_per_pixel)
434 case 15:
435 bpp = 2;
436 cvid_v1 = cvid_v1_15;
437 cvid_v4 = cvid_v4_15;
438 break;
439 case 16:
440 bpp = 2;
441 cvid_v1 = cvid_v1_16;
442 cvid_v4 = cvid_v4_16;
443 break;
444 case 24:
445 bpp = 3;
446 cvid_v1 = cvid_v1_24;
447 cvid_v4 = cvid_v4_24;
448 break;
449 case 32:
450 bpp = 4;
451 cvid_v1 = cvid_v1_32;
452 cvid_v4 = cvid_v4_32;
453 break;
456 frm_stride = get_stride(out_width, bpp * 8);
457 frm_ptr = output;
459 if(frame.length != size)
461 if(frame.length & 0x01) frame.length++; /* AVIs tend to have a size mismatch */
462 if(frame.length != size)
464 ERR("CVID: corruption %d (QT/AVI) != %ld (CV)\n", size, frame.length);
465 /* return; */
469 frame.width = get_word();
470 frame.height = get_word();
471 frame.strips = get_word();
473 if(frame.strips > cvinfo->strip_num)
475 if(frame.strips >= MAX_STRIPS)
477 ERR("CVID: strip overflow (more than %d)\n", MAX_STRIPS);
478 return;
481 for(i = cvinfo->strip_num; i < frame.strips; i++)
483 if((cvinfo->v4_codebook[i] = malloc(sizeof(cvid_codebook) * 260)) == NULL)
485 ERR("CVID: codebook v4 alloc err\n");
486 return;
489 if((cvinfo->v1_codebook[i] = malloc(sizeof(cvid_codebook) * 260)) == NULL)
491 ERR("CVID: codebook v1 alloc err\n");
492 return;
496 cvinfo->strip_num = frame.strips;
498 TRACE("CVID: %ux%u, strips %u, length %lu\n",
499 frame.width, frame.height, frame.strips, frame.length);
501 for(cur_strip = 0; cur_strip < frame.strips; cur_strip++)
503 v4_codebook = cvinfo->v4_codebook[cur_strip];
504 v1_codebook = cvinfo->v1_codebook[cur_strip];
506 if((cur_strip > 0) && (!(frame.flags & 0x01)))
508 memcpy(cvinfo->v4_codebook[cur_strip], cvinfo->v4_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
509 memcpy(cvinfo->v1_codebook[cur_strip], cvinfo->v1_codebook[cur_strip-1], 260 * sizeof(cvid_codebook));
512 strip_id = get_word(); /* 1000 = key strip, 1100 = iter strip */
513 top_size = get_word();
514 y0 = get_word(); /* FIXME: most of these are ignored at the moment */
515 x0 = get_word();
516 y1 = get_word();
517 x1 = get_word();
519 y_bottom += y1;
520 top_size -= 12;
521 x = 0;
522 if(x1 != out_width)
523 WARN("CVID: Warning x1 (%ld) != width (%d)\n", x1, out_width);
525 TRACE(" %d) %04lx %04ld <%ld,%ld> <%ld,%ld> yt %ld\n",
526 cur_strip, strip_id, top_size, x0, y0, x1, y1, y_bottom);
528 while(top_size > 0)
530 chunk_id = get_word();
531 chunk_size = get_word();
533 TRACE(" %04lx %04ld\n", chunk_id, chunk_size);
534 top_size -= chunk_size;
535 chunk_size -= 4;
537 switch(chunk_id)
539 /* -------------------- Codebook Entries -------------------- */
540 case 0x2000:
541 case 0x2200:
542 codebook = (chunk_id == 0x2200 ? v1_codebook : v4_codebook);
543 cnum = chunk_size/6;
544 for(i = 0; i < cnum; i++) read_codebook(codebook+i, 0);
545 break;
547 case 0x2400:
548 case 0x2600: /* 8 bit per pixel */
549 codebook = (chunk_id == 0x2600 ? v1_codebook : v4_codebook);
550 cnum = chunk_size/4;
551 for(i = 0; i < cnum; i++) read_codebook(codebook+i, 1);
552 break;
554 case 0x2100:
555 case 0x2300:
556 codebook = (chunk_id == 0x2300 ? v1_codebook : v4_codebook);
558 ci = 0;
559 while(chunk_size > 0)
561 flag = get_long();
562 chunk_size -= 4;
564 for(i = 0; i < 32; i++)
566 if(flag & 0x80000000)
568 chunk_size -= 6;
569 read_codebook(codebook+ci, 0);
572 ci++;
573 flag <<= 1;
576 while(chunk_size > 0) { skip_byte(); chunk_size--; }
577 break;
579 case 0x2500:
580 case 0x2700: /* 8 bit per pixel */
581 codebook = (chunk_id == 0x2700 ? v1_codebook : v4_codebook);
583 ci = 0;
584 while(chunk_size > 0)
586 flag = get_long();
587 chunk_size -= 4;
589 for(i = 0; i < 32; i++)
591 if(flag & 0x80000000)
593 chunk_size -= 4;
594 read_codebook(codebook+ci, 1);
597 ci++;
598 flag <<= 1;
601 while(chunk_size > 0) { skip_byte(); chunk_size--; }
602 break;
604 /* -------------------- Frame -------------------- */
605 case 0x3000:
606 while((chunk_size > 0) && (y < y_bottom))
608 flag = get_long();
609 chunk_size -= 4;
611 for(i = 0; i < 32; i++)
613 if(y >= y_bottom) break;
614 if(flag & 0x80000000) /* 4 bytes per block */
616 d0 = get_byte();
617 d1 = get_byte();
618 d2 = get_byte();
619 d3 = get_byte();
620 chunk_size -= 4;
622 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
623 cvid_v4(frm_ptr + addr, output, frm_stride, inverted, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
625 else /* 1 byte per block */
627 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
628 cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
630 chunk_size--;
633 x += 4;
634 if(x >= out_width)
636 x = 0;
637 y += 4;
639 flag <<= 1;
642 while(chunk_size > 0) { skip_byte(); chunk_size--; }
643 break;
645 case 0x3100:
646 while((chunk_size > 0) && (y < y_bottom))
648 /* ---- flag bits: 0 = SKIP, 10 = V1, 11 = V4 ---- */
649 flag = get_long();
650 chunk_size -= 4;
651 mask = 0x80000000;
653 while((mask) && (y < y_bottom))
655 if(flag & mask)
657 if(mask == 1)
659 if(chunk_size < 0) break;
660 flag = get_long();
661 chunk_size -= 4;
662 mask = 0x80000000;
664 else mask >>= 1;
666 if(flag & mask) /* V4 */
668 d0 = get_byte();
669 d1 = get_byte();
670 d2 = get_byte();
671 d3 = get_byte();
672 chunk_size -= 4;
674 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
675 cvid_v4(frm_ptr + addr, output, frm_stride, inverted, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
677 else /* V1 */
679 chunk_size--;
681 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
682 cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
684 } /* else SKIP */
686 mask >>= 1;
687 x += 4;
688 if(x >= out_width)
690 x = 0;
691 y += 4;
696 while(chunk_size > 0) { skip_byte(); chunk_size--; }
697 break;
699 case 0x3200: /* each byte is a V1 codebook */
700 while((chunk_size > 0) && (y < y_bottom))
702 addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
703 cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
705 chunk_size--;
706 x += 4;
707 if(x >= out_width)
709 x = 0;
710 y += 4;
713 while(chunk_size > 0) { skip_byte(); chunk_size--; }
714 break;
716 default:
717 ERR("CVID: unknown chunk_id %08lx\n", chunk_id);
718 while(chunk_size > 0) { skip_byte(); chunk_size--; }
719 break;
724 if(frame.length != size)
726 if(frame.length & 0x01) frame.length++; /* AVIs tend to have a size mismatch */
727 if(frame.length != size)
729 long xlen;
730 skip_byte();
731 xlen = get_byte() << 16;
732 xlen |= get_byte() << 8;
733 xlen |= get_byte(); /* Read Len */
734 WARN("CVID: END INFO chunk size %d cvid size1 %ld cvid size2 %ld\n",
735 size, frame.length, xlen);
740 static void ICCVID_dump_BITMAPINFO(const BITMAPINFO * bmi)
742 TRACE(
743 "planes = %d\n"
744 "bpp = %d\n"
745 "height = %ld\n"
746 "width = %ld\n"
747 "compr = %s\n",
748 bmi->bmiHeader.biPlanes,
749 bmi->bmiHeader.biBitCount,
750 bmi->bmiHeader.biHeight,
751 bmi->bmiHeader.biWidth,
752 debugstr_fourcc(bmi->bmiHeader.biCompression));
755 static inline int ICCVID_CheckMask(RGBQUAD bmiColors[3], COLORREF redMask, COLORREF blueMask, COLORREF greenMask)
757 COLORREF realRedMask = MAKECOLOUR32(bmiColors[0].rgbRed, bmiColors[0].rgbGreen, bmiColors[0].rgbBlue);
758 COLORREF realBlueMask = MAKECOLOUR32(bmiColors[1].rgbRed, bmiColors[1].rgbGreen, bmiColors[1].rgbBlue);
759 COLORREF realGreenMask = MAKECOLOUR32(bmiColors[2].rgbRed, bmiColors[2].rgbGreen, bmiColors[2].rgbBlue);
761 TRACE("\nbmiColors[0] = 0x%08lx\nbmiColors[1] = 0x%08lx\nbmiColors[2] = 0x%08lx\n",
762 realRedMask, realBlueMask, realGreenMask);
764 if ((realRedMask == redMask) &&
765 (realBlueMask == blueMask) &&
766 (realGreenMask == greenMask))
767 return TRUE;
768 return FALSE;
771 static LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
773 TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
775 if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
776 return ICERR_BADPARAM;
778 TRACE("in: ");
779 ICCVID_dump_BITMAPINFO(in);
781 if( in->bmiHeader.biCompression != ICCVID_MAGIC )
782 return ICERR_BADFORMAT;
784 if( out )
786 TRACE("out: ");
787 ICCVID_dump_BITMAPINFO(out);
789 if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes )
790 return ICERR_BADFORMAT;
791 if( in->bmiHeader.biHeight != out->bmiHeader.biHeight )
793 if( in->bmiHeader.biHeight != -out->bmiHeader.biHeight )
794 return ICERR_BADFORMAT;
795 TRACE("Detected inverted height for video output\n");
797 if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
798 return ICERR_BADFORMAT;
800 switch( out->bmiHeader.biCompression )
802 case BI_RGB:
803 if ( out->bmiHeader.biBitCount == 16 || out->bmiHeader.biBitCount == 24 || out->bmiHeader.biBitCount == 32 )
804 return ICERR_OK;
805 break;
806 case BI_BITFIELDS:
807 if ( out->bmiHeader.biBitCount == 16 && ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) )
808 return ICERR_OK;
809 if ( out->bmiHeader.biBitCount == 16 && ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
810 return ICERR_OK;
811 break;
813 TRACE("unsupported output format\n");
814 return ICERR_BADFORMAT;
817 return ICERR_OK;
820 static LRESULT ICCVID_DecompressGetFormat( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
822 DWORD size;
824 TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
826 if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
827 return ICERR_BADPARAM;
829 size = in->bmiHeader.biSize;
830 if (in->bmiHeader.biBitCount <= 8)
831 size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD);
833 if( out )
835 memcpy( out, in, size );
836 out->bmiHeader.biBitCount = 24;
837 out->bmiHeader.biCompression = BI_RGB;
838 out->bmiHeader.biSizeImage = get_stride(in->bmiHeader.biWidth, 24) * in->bmiHeader.biHeight;
839 return ICERR_OK;
841 return size;
844 static LRESULT ICCVID_DecompressBegin( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out )
846 TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
848 if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
849 return ICERR_BADPARAM;
851 info->bits_per_pixel = out->bmiHeader.biBitCount;
853 if (info->bits_per_pixel == 16)
855 if ( out->bmiHeader.biCompression == BI_BITFIELDS )
857 if ( ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) )
858 info->bits_per_pixel = 15;
859 else if ( ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
860 info->bits_per_pixel = 16;
861 else
863 TRACE("unsupported output bit field(s) for 16-bit colors\n");
864 return ICERR_UNSUPPORTED;
867 else
868 info->bits_per_pixel = 15;
871 TRACE("bit_per_pixel = %d\n", info->bits_per_pixel);
873 if( info->cvinfo )
874 free_cvinfo( info->cvinfo );
875 info->cvinfo = decode_cinepak_init();
877 return ICERR_OK;
880 static LRESULT ICCVID_Decompress( ICCVID_Info *info, ICDECOMPRESS *icd, DWORD size )
882 LONG width, height;
883 BOOL inverted;
885 TRACE("ICM_DECOMPRESS %p %p %ld\n", info, icd, size);
887 if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
888 return ICERR_BADPARAM;
889 if (info->cvinfo==NULL)
891 ERR("ICM_DECOMPRESS sent after ICM_DECOMPRESS_END\n");
892 return ICERR_BADPARAM;
895 width = icd->lpbiInput->biWidth;
896 height = icd->lpbiInput->biHeight;
897 inverted = -icd->lpbiOutput->biHeight == height;
899 decode_cinepak(info->cvinfo, icd->lpInput, icd->lpbiInput->biSizeImage,
900 icd->lpOutput, width, height, info->bits_per_pixel, inverted);
902 return ICERR_OK;
905 static LRESULT ICCVID_DecompressEx( ICCVID_Info *info, ICDECOMPRESSEX *icd, DWORD size )
907 LONG width, height;
908 BOOL inverted;
910 TRACE("ICM_DECOMPRESSEX %p %p %ld\n", info, icd, size);
912 if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
913 return ICERR_BADPARAM;
914 if (info->cvinfo==NULL)
916 ERR("ICM_DECOMPRESSEX sent after ICM_DECOMPRESS_END\n");
917 return ICERR_BADPARAM;
920 /* FIXME: flags are ignored */
922 width = icd->lpbiSrc->biWidth;
923 height = icd->lpbiSrc->biHeight;
924 inverted = -icd->lpbiDst->biHeight == height;
926 decode_cinepak(info->cvinfo, icd->lpSrc, icd->lpbiSrc->biSizeImage,
927 icd->lpDst, width, height, info->bits_per_pixel, inverted);
929 return ICERR_OK;
932 static LRESULT ICCVID_Close( ICCVID_Info *info )
934 if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) )
935 return 0;
936 if( info->cvinfo )
937 free_cvinfo( info->cvinfo );
938 free( info );
939 return 1;
942 static LRESULT ICCVID_GetInfo( ICCVID_Info *info, ICINFO *icinfo, DWORD dwSize )
944 if (!icinfo) return sizeof(ICINFO);
945 if (dwSize < sizeof(ICINFO)) return 0;
947 icinfo->dwSize = sizeof(ICINFO);
948 icinfo->fccType = ICTYPE_VIDEO;
949 icinfo->fccHandler = info ? info->dwMagic : ICCVID_MAGIC;
950 icinfo->dwFlags = 0;
951 icinfo->dwVersion = ICVERSION;
952 icinfo->dwVersionICM = ICVERSION;
954 LoadStringW(ICCVID_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName));
955 LoadStringW(ICCVID_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription));
956 /* msvfw32 will fill icinfo->szDriver for us */
958 return sizeof(ICINFO);
961 static LRESULT ICCVID_DecompressEnd( ICCVID_Info *info )
963 if( info->cvinfo )
965 free_cvinfo( info->cvinfo );
966 info->cvinfo = NULL;
968 return ICERR_OK;
971 LRESULT WINAPI ICCVID_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg,
972 LPARAM lParam1, LPARAM lParam2)
974 ICCVID_Info *info = (ICCVID_Info *) dwDriverId;
976 TRACE("%Id %p %d %Id %Id\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
978 switch( msg )
980 case DRV_LOAD:
981 TRACE("Loaded\n");
982 return 1;
983 case DRV_ENABLE:
984 return 0;
985 case DRV_DISABLE:
986 return 0;
987 case DRV_FREE:
988 return 0;
990 case DRV_OPEN:
992 ICINFO *icinfo = (ICINFO *)lParam2;
994 TRACE("Opened\n");
996 if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return 0;
998 info = malloc(sizeof(ICCVID_Info));
999 if( info )
1001 info->dwMagic = ICCVID_MAGIC;
1002 info->cvinfo = NULL;
1004 return (LRESULT) info;
1007 case DRV_CLOSE:
1008 return ICCVID_Close( info );
1010 case ICM_GETINFO:
1011 return ICCVID_GetInfo( info, (ICINFO *)lParam1, (DWORD)lParam2 );
1013 case ICM_DECOMPRESS_QUERY:
1014 return ICCVID_DecompressQuery( info, (LPBITMAPINFO) lParam1,
1015 (LPBITMAPINFO) lParam2 );
1016 case ICM_DECOMPRESS_GET_FORMAT:
1017 return ICCVID_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
1018 (LPBITMAPINFO) lParam2 );
1019 case ICM_DECOMPRESS_BEGIN:
1020 return ICCVID_DecompressBegin( info, (LPBITMAPINFO) lParam1,
1021 (LPBITMAPINFO) lParam2 );
1022 case ICM_DECOMPRESS:
1023 return ICCVID_Decompress( info, (ICDECOMPRESS*) lParam1,
1024 (DWORD) lParam2 );
1025 case ICM_DECOMPRESSEX:
1026 return ICCVID_DecompressEx( info, (ICDECOMPRESSEX*) lParam1,
1027 (DWORD) lParam2 );
1029 case ICM_DECOMPRESS_END:
1030 return ICCVID_DecompressEnd( info );
1032 case ICM_COMPRESS_QUERY:
1033 FIXME("compression not implemented\n");
1034 return ICERR_BADFORMAT;
1036 case ICM_CONFIGURE:
1037 return ICERR_UNSUPPORTED;
1039 default:
1040 FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2);
1042 return ICERR_UNSUPPORTED;
1045 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1047 TRACE("(%p,%ld,%p)\n", hModule, dwReason, lpReserved);
1049 switch (dwReason)
1051 case DLL_PROCESS_ATTACH:
1052 DisableThreadLibraryCalls(hModule);
1053 ICCVID_hModule = hModule;
1054 break;
1056 return TRUE;