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