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