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 } 1077