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