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