1 /* 2 * Copyright 2002-2003 Michael Günnewig 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 /* TODO: 20 * - some improvements possible 21 * - implement DecompressSetPalette? -- do we need it for anything? 22 */ 23 24 #include <assert.h> 25 26 #include "msrle_private.h" 27 28 #include "winnls.h" 29 #include "winuser.h" 30 31 #include "wine/debug.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(msrle32); 34 35 static HINSTANCE MSRLE32_hModule = 0; 36 37 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) 38 39 static inline WORD ColorCmp(WORD clr1, WORD clr2) 40 { 41 UINT a = clr1 - clr2; 42 return a * a; 43 } 44 static inline WORD Intensity(RGBQUAD clr) 45 { 46 return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4; 47 } 48 49 #define GetRawPixel(lpbi,lp,x) \ 50 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \ 51 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x])) 52 53 /*****************************************************************************/ 54 55 /* utility functions */ 56 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi); 57 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi); 58 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr); 59 60 /* compression functions */ 61 static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn); 62 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi); 63 static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 64 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, 65 LPBYTE lpOut, BOOL isKey); 66 static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 67 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, 68 LPBYTE lpOut, BOOL isKey); 69 70 /* decompression functions */ 71 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, 72 const BYTE *lpIn, LPBYTE lpOut); 73 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, 74 const BYTE *lpIn, LPBYTE lpOut); 75 76 /* API functions */ 77 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 78 LPBITMAPINFOHEADER lpbiOut); 79 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 80 LPCBITMAPINFOHEADER lpbiOut); 81 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 82 LPCBITMAPINFOHEADER lpbiOut); 83 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 84 LPCBITMAPINFOHEADER lpbiOut); 85 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize); 86 static LRESULT CompressEnd(CodecInfo *pi); 87 88 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 89 LPBITMAPINFOHEADER lpbiOut); 90 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 91 LPCBITMAPINFOHEADER lpbiOut); 92 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 93 LPCBITMAPINFOHEADER lpbiOut); 94 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize); 95 static LRESULT DecompressEnd(CodecInfo *pi); 96 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 97 LPBITMAPINFOHEADER lpbiOut); 98 99 /*****************************************************************************/ 100 101 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi) 102 { 103 /* pre-conditions */ 104 assert(lpbi != NULL); 105 106 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || 107 lpbi->biPlanes != 1) 108 return FALSE; 109 110 if (lpbi->biCompression == BI_RLE4) { 111 if (lpbi->biBitCount != 4 || 112 (lpbi->biWidth % 2) != 0) 113 return FALSE; 114 } else if (lpbi->biCompression == BI_RLE8) { 115 if (lpbi->biBitCount != 8) 116 return FALSE; 117 } else 118 return FALSE; 119 120 return TRUE; 121 } 122 123 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi) 124 { 125 /* pre-conditions */ 126 assert(lpbi != NULL); 127 128 /* check structure version/planes/compression */ 129 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || 130 lpbi->biPlanes != 1) 131 return FALSE; 132 if (lpbi->biCompression != BI_RGB && 133 lpbi->biCompression != BI_BITFIELDS) 134 return FALSE; 135 136 /* check bit-depth */ 137 if (lpbi->biBitCount != 1 && 138 lpbi->biBitCount != 4 && 139 lpbi->biBitCount != 8 && 140 lpbi->biBitCount != 15 && 141 lpbi->biBitCount != 16 && 142 lpbi->biBitCount != 24 && 143 lpbi->biBitCount != 32) 144 return FALSE; 145 146 /* check for size(s) */ 147 if (!lpbi->biWidth || !lpbi->biHeight) 148 return FALSE; /* image with zero size, makes no sense so error ! */ 149 if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1) 150 return FALSE; /* image too big ! */ 151 152 /* check for nonexistent colortable for hi- and true-color DIB's */ 153 if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0) 154 return FALSE; 155 156 return TRUE; 157 } 158 159 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr) 160 { 161 INT diff = 0x00FFFFFF; 162 UINT i; 163 UINT idx = 0; 164 165 /* pre-conditions */ 166 assert(clrs != NULL); 167 168 for (i = 0; i < count; i++) { 169 int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed); 170 int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen); 171 int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue); 172 173 r = r*r + g*g + b*b; 174 175 if (r < diff) { 176 idx = i; 177 diff = r; 178 if (diff == 0) 179 break; 180 } 181 } 182 183 return idx; 184 } 185 186 /*****************************************************************************/ 187 188 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn) 189 { 190 WORD wIntensityTbl[256]; 191 DWORD lInLine, lOutLine; 192 LPWORD lpOut; 193 UINT i; 194 LONG y; 195 196 /* pre-conditions */ 197 assert(pi != NULL && lpbiIn != NULL && lpIn != NULL); 198 assert(pi->pCurFrame != NULL); 199 200 lInLine = DIBWIDTHBYTES(*lpbiIn); 201 lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u; 202 lpOut = pi->pCurFrame; 203 204 assert(lpbiIn->biClrUsed != 0); 205 206 { 207 const RGBQUAD *lp = 208 (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize); 209 210 for (i = 0; i < lpbiIn->biClrUsed; i++) 211 wIntensityTbl[i] = Intensity(lp[i]); 212 } 213 214 for (y = 0; y < lpbiIn->biHeight; y++) { 215 LONG x; 216 217 switch (lpbiIn->biBitCount) { 218 case 1: 219 for (x = 0; x < lpbiIn->biWidth / 8; x++) { 220 for (i = 0; i < 7; i++) 221 lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1]; 222 } 223 break; 224 case 4: 225 for (x = 0; x < lpbiIn->biWidth / 2; x++) { 226 lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)]; 227 lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)]; 228 } 229 break; 230 case 8: 231 for (x = 0; x < lpbiIn->biWidth; x++) 232 lpOut[x] = wIntensityTbl[lpIn[x]]; 233 break; 234 } 235 236 lpIn += lInLine; 237 lpOut += lOutLine; 238 } 239 } 240 241 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi) 242 { 243 LONG a, b, size; 244 245 /* pre-condition */ 246 assert(lpbi != NULL); 247 248 a = lpbi->biWidth / 255; 249 b = lpbi->biWidth % 255; 250 if (lpbi->biBitCount <= 4) { 251 a /= 2; 252 b /= 2; 253 } 254 255 size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2))); 256 return size * lpbi->biHeight + 2; 257 } 258 259 /* lpP => current pos in previous frame 260 * lpA => previous pos in current frame 261 * lpB => current pos in current frame 262 */ 263 static INT countDiffRLE4(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width) 264 { 265 INT count; 266 WORD clr1, clr2; 267 268 /* pre-conditions */ 269 assert(lpA && lpB && lDist >= 0 && width > 0); 270 271 if (pos >= width) 272 return 0; 273 if (pos+1 == width) 274 return 1; 275 276 clr1 = lpB[pos++]; 277 clr2 = lpB[pos]; 278 279 count = 2; 280 while (pos + 1 < width) { 281 WORD clr3, clr4; 282 283 clr3 = lpB[++pos]; 284 if (pos + 1 >= width) 285 return count + 1; 286 287 clr4 = lpB[++pos]; 288 if (ColorCmp(clr1, clr3) <= lDist && 289 ColorCmp(clr2, clr4) <= lDist) { 290 /* diff at end? -- look-ahead for at least ?? more encodable pixels */ 291 if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist && 292 ColorCmp(clr2,lpB[pos+2]) <= lDist) { 293 if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist && 294 ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist) 295 return count - 3; /* followed by at least 4 encodable pixels */ 296 return count - 2; 297 } 298 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { 299 /* 'compare' with previous frame for end of diff */ 300 INT count2 = 0; 301 302 /* FIXME */ 303 304 if (count2 >= 8) 305 return count; 306 307 pos -= count2; 308 } 309 310 count += 2; 311 clr1 = clr3; 312 clr2 = clr4; 313 } 314 315 return count; 316 } 317 318 /* lpP => current pos in previous frame 319 * lpA => previous pos in current frame 320 * lpB => current pos in current frame 321 */ 322 static INT countDiffRLE8(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width) 323 { 324 INT count; 325 326 for (count = 0; pos < width; pos++, count++) { 327 if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) { 328 /* diff at end? -- look-ahead for some more encodable pixel */ 329 if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist) 330 return count - 1; 331 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist) 332 return count - 1; 333 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { 334 /* 'compare' with previous frame for end of diff */ 335 INT count2 = 0; 336 337 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) { 338 if (ColorCmp(lpP[pos], lpB[pos]) > lDist) 339 break; 340 } 341 if (count2 > 4) 342 return count; 343 344 pos -= count2; 345 } 346 } 347 348 return count; 349 } 350 351 static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP, 352 const WORD *lpC, LPCBITMAPINFOHEADER lpbi, 353 const BYTE *lpIn, LONG lDist, 354 INT x, LPBYTE *ppOut, 355 DWORD *lpSizeImage) 356 { 357 LPBYTE lpOut = *ppOut; 358 INT count, pos; 359 WORD clr1, clr2; 360 361 /* try to encode as many pixel as possible */ 362 count = 1; 363 pos = x; 364 clr1 = lpC[pos++]; 365 if (pos < lpbi->biWidth) { 366 clr2 = lpC[pos]; 367 for (++count; pos + 1 < lpbi->biWidth; ) { 368 ++pos; 369 if (ColorCmp(clr1, lpC[pos]) > lDist) 370 break; 371 count++; 372 if (pos + 1 >= lpbi->biWidth) 373 break; 374 ++pos; 375 if (ColorCmp(clr2, lpC[pos]) > lDist) 376 break; 377 count++; 378 } 379 } 380 381 if (count < 4) { 382 /* add some pixel for absoluting if possible */ 383 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); 384 385 assert(count > 0); 386 387 /* check for near end of line */ 388 if (x + count > lpbi->biWidth) 389 count = lpbi->biWidth - x; 390 391 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */ 392 while (count > 2) { 393 INT i; 394 INT size = min(count, 254); 395 int bytes = ((size + 1) & (~1)) / 2; 396 int extra_byte = bytes & 0x01; 397 398 *lpSizeImage += 2 + bytes + extra_byte; 399 assert(((*lpSizeImage) % 2) == 0); 400 count -= size; 401 *lpOut++ = 0; 402 *lpOut++ = size; 403 for (i = 0; i < size; i += 2) { 404 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 405 x++; 406 if (i + 1 < size) { 407 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 408 x++; 409 } else 410 clr2 = 0; 411 412 *lpOut++ = (clr1 << 4) | clr2; 413 } 414 if (extra_byte) 415 *lpOut++ = 0; 416 } 417 418 if (count > 0) { 419 /* too little for absoluting so we must encode them */ 420 assert(count <= 2); 421 422 *lpSizeImage += 2; 423 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 424 x++; 425 if (count == 2) { 426 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 427 x++; 428 } else 429 clr2 = 0; 430 *lpOut++ = count; 431 *lpOut++ = (clr1 << 4) | clr2; 432 } 433 } else { 434 /* encode count pixel(s) */ 435 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) | 436 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]); 437 438 x += count; 439 while (count > 0) { 440 INT size = min(count, 254); 441 442 *lpSizeImage += 2; 443 count -= size; 444 *lpOut++ = size; 445 *lpOut++ = clr1; 446 } 447 } 448 449 *ppOut = lpOut; 450 451 return x; 452 } 453 454 static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP, 455 const WORD *lpC, LPCBITMAPINFOHEADER lpbi, 456 const BYTE *lpIn, INT x, LPBYTE *ppOut, 457 DWORD *lpSizeImage) 458 { 459 LPBYTE lpOut = *ppOut; 460 INT count, pos; 461 WORD clr; 462 463 assert(lpbi->biBitCount <= 8); 464 assert(lpbi->biCompression == BI_RGB); 465 466 /* try to encode as much as possible */ 467 pos = x; 468 clr = lpC[pos++]; 469 for (count = 1; pos < lpbi->biWidth; count++) { 470 if (ColorCmp(clr, lpC[pos++]) > 0) 471 break; 472 } 473 474 if (count < 2) { 475 /* add some more pixels for absoluting if possible */ 476 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, 0, lpbi->biWidth); 477 478 assert(count > 0); 479 480 /* check for over end of line */ 481 if (x + count > lpbi->biWidth) 482 count = lpbi->biWidth - x; 483 484 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */ 485 while (count > 2) { 486 INT i; 487 INT size = min(count, 255); 488 int extra_byte = size % 2; 489 490 *lpSizeImage += 2 + size + extra_byte; 491 count -= size; 492 *lpOut++ = 0; 493 *lpOut++ = size; 494 for (i = 0; i < size; i++) { 495 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 496 x++; 497 } 498 if (extra_byte) 499 *lpOut++ = 0; 500 } 501 if (count > 0) { 502 /* too little for absoluting so we must encode them even if it's expensive! */ 503 assert(count <= 2); 504 505 *lpSizeImage += 2 * count; 506 *lpOut++ = 1; 507 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 508 x++; 509 510 if (count == 2) { 511 *lpOut++ = 1; 512 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 513 x++; 514 } 515 } 516 } else { 517 /* encode count pixel(s) */ 518 clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; 519 520 /* optimize end of line */ 521 if (x + count + 1 == lpbi->biWidth) 522 count++; 523 524 x += count; 525 while (count > 0) { 526 INT size = min(count, 255); 527 528 *lpSizeImage += 2; 529 count -= size; 530 *lpOut++ = size; 531 *lpOut++ = clr; 532 } 533 } 534 535 *ppOut = lpOut; 536 537 return x; 538 } 539 540 LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 541 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, 542 LPBYTE lpOut, BOOL isKey) 543 { 544 LPWORD lpC; 545 LONG lLine, lInLine; 546 LPBYTE lpOutStart = lpOut; 547 548 /* pre-conditions */ 549 assert(pi != NULL && lpbiOut != NULL); 550 assert(lpIn != NULL && lpOut != NULL); 551 assert(pi->pCurFrame != NULL); 552 553 lpC = pi->pCurFrame; 554 lInLine = DIBWIDTHBYTES(*lpbiIn); 555 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2; 556 557 lpbiOut->biSizeImage = 0; 558 if (isKey) { 559 /* keyframe -- convert internal frame to output format */ 560 INT x, y; 561 562 for (y = 0; y < lpbiOut->biHeight; y++) { 563 x = 0; 564 565 do { 566 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, 0, x, 567 &lpOut, &lpbiOut->biSizeImage); 568 } while (x < lpbiOut->biWidth); 569 570 lpC += lLine; 571 lpIn += lInLine; 572 573 /* add EOL -- end of line */ 574 lpbiOut->biSizeImage += 2; 575 *(LPWORD)lpOut = 0; 576 lpOut += sizeof(WORD); 577 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 578 } 579 } else { 580 /* delta-frame -- compute delta between last and this internal frame */ 581 LPWORD lpP; 582 INT x, y; 583 INT jumpx, jumpy; 584 585 assert(pi->pPrevFrame != NULL); 586 587 lpP = pi->pPrevFrame; 588 jumpy = 0; 589 jumpx = -1; 590 591 for (y = 0; y < lpbiOut->biHeight; y++) { 592 x = 0; 593 594 do { 595 INT count, pos; 596 597 if (jumpx == -1) 598 jumpx = x; 599 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) { 600 if (ColorCmp(lpP[pos], lpC[pos]) > 0) 601 break; 602 } 603 604 if (pos == lpbiOut->biWidth && count > 8) { 605 /* (count > 8) secures that we will save space */ 606 jumpy++; 607 break; 608 } else if (jumpy || jumpx != pos) { 609 /* time to jump */ 610 assert(jumpx != -1); 611 612 if (pos < jumpx) { 613 /* can only jump in positive direction -- jump until EOL, EOL */ 614 INT w = lpbiOut->biWidth - jumpx; 615 616 assert(jumpy > 0); 617 assert(w >= 4); 618 619 jumpx = 0; 620 jumpy--; 621 /* if (w % 255 == 2) then equal costs 622 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive 623 * else it will be cheaper 624 */ 625 while (w > 0) { 626 lpbiOut->biSizeImage += 4; 627 *lpOut++ = 0; 628 *lpOut++ = 2; 629 *lpOut = min(w, 255); 630 w -= *lpOut++; 631 *lpOut++ = 0; 632 } 633 /* add EOL -- end of line */ 634 lpbiOut->biSizeImage += 2; 635 *((LPWORD)lpOut) = 0; 636 lpOut += sizeof(WORD); 637 } 638 639 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */ 640 641 /* write out real jump(s) */ 642 while (jumpy || pos != jumpx) { 643 lpbiOut->biSizeImage += 4; 644 *lpOut++ = 0; 645 *lpOut++ = 2; 646 *lpOut = min(pos - jumpx, 255); 647 x += *lpOut; 648 jumpx += *lpOut++; 649 *lpOut = min(jumpy, 255); 650 jumpy -= *lpOut++; 651 } 652 653 jumpy = 0; 654 } 655 656 jumpx = -1; 657 658 if (x < lpbiOut->biWidth) { 659 /* skipped the 'same' things corresponding to previous frame */ 660 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, 0, x, 661 &lpOut, &lpbiOut->biSizeImage); 662 } 663 } while (x < lpbiOut->biWidth); 664 665 lpP += lLine; 666 lpC += lLine; 667 lpIn += lInLine; 668 669 if (jumpy == 0) { 670 assert(jumpx == -1); 671 672 /* add EOL -- end of line */ 673 lpbiOut->biSizeImage += 2; 674 *((LPWORD)lpOut) = 0; 675 lpOut += sizeof(WORD); 676 assert(lpOut == lpOutStart + lpbiOut->biSizeImage); 677 } 678 } 679 680 /* add EOL -- will be changed to EOI */ 681 lpbiOut->biSizeImage += 2; 682 *((LPWORD)lpOut) = 0; 683 lpOut += sizeof(WORD); 684 } 685 686 /* change EOL to EOI -- end of image */ 687 lpOut[-1] = 1; 688 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 689 690 return ICERR_OK; 691 } 692 693 LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 694 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, 695 LPBYTE lpOut, BOOL isKey) 696 { 697 LPWORD lpC; 698 LONG lInLine, lLine; 699 LPBYTE lpOutStart = lpOut; 700 701 assert(pi != NULL && lpbiOut != NULL); 702 assert(lpIn != NULL && lpOut != NULL); 703 assert(pi->pCurFrame != NULL); 704 705 lpC = pi->pCurFrame; 706 lInLine = DIBWIDTHBYTES(*lpbiIn); 707 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2; 708 709 lpbiOut->biSizeImage = 0; 710 if (isKey) { 711 /* keyframe -- convert internal frame to output format */ 712 INT x, y; 713 714 for (y = 0; y < lpbiOut->biHeight; y++) { 715 x = 0; 716 717 do { 718 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, x, 719 &lpOut, &lpbiOut->biSizeImage); 720 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 721 } while (x < lpbiOut->biWidth); 722 723 lpC += lLine; 724 lpIn += lInLine; 725 726 /* add EOL -- end of line */ 727 lpbiOut->biSizeImage += 2; 728 *((LPWORD)lpOut) = 0; 729 lpOut += sizeof(WORD); 730 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 731 } 732 } else { 733 /* delta-frame -- compute delta between last and this internal frame */ 734 LPWORD lpP; 735 INT x, y; 736 INT jumpx, jumpy; 737 738 assert(pi->pPrevFrame != NULL); 739 740 lpP = pi->pPrevFrame; 741 jumpx = -1; 742 jumpy = 0; 743 744 for (y = 0; y < lpbiOut->biHeight; y++) { 745 x = 0; 746 747 do { 748 INT count, pos; 749 750 if (jumpx == -1) 751 jumpx = x; 752 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) { 753 if (ColorCmp(lpP[pos], lpC[pos]) > 0) 754 break; 755 } 756 757 if (pos == lpbiOut->biWidth && count > 4) { 758 /* (count > 4) secures that we will save space */ 759 jumpy++; 760 break; 761 } else if (jumpy || jumpx != pos) { 762 /* time to jump */ 763 assert(jumpx != -1); 764 765 if (pos < jumpx) { 766 /* can only jump in positive direction -- do an EOL then jump */ 767 assert(jumpy > 0); 768 769 jumpx = 0; 770 jumpy--; 771 772 /* add EOL -- end of line */ 773 lpbiOut->biSizeImage += 2; 774 *((LPWORD)lpOut) = 0; 775 lpOut += sizeof(WORD); 776 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 777 } 778 779 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */ 780 781 /* write out real jump(s) */ 782 while (jumpy || pos != jumpx) { 783 lpbiOut->biSizeImage += 4; 784 *lpOut++ = 0; 785 *lpOut++ = 2; 786 *lpOut = min(pos - jumpx, 255); 787 jumpx += *lpOut++; 788 *lpOut = min(jumpy, 255); 789 jumpy -= *lpOut++; 790 } 791 x = pos; 792 793 jumpy = 0; 794 } 795 796 jumpx = -1; 797 798 if (x < lpbiOut->biWidth) { 799 /* skip the 'same' things corresponding to previous frame */ 800 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, x, 801 &lpOut, &lpbiOut->biSizeImage); 802 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 803 } 804 } while (x < lpbiOut->biWidth); 805 806 lpP += lLine; 807 lpC += lLine; 808 lpIn += lInLine; 809 810 if (jumpy == 0) { 811 /* add EOL -- end of line */ 812 lpbiOut->biSizeImage += 2; 813 *((LPWORD)lpOut) = 0; 814 lpOut += sizeof(WORD); 815 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 816 } 817 } 818 819 /* add EOL */ 820 lpbiOut->biSizeImage += 2; 821 *((LPWORD)lpOut) = 0; 822 lpOut += sizeof(WORD); 823 } 824 825 /* add EOI -- end of image */ 826 lpbiOut->biSizeImage += 2; 827 *lpOut++ = 0; 828 *lpOut++ = 1; 829 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); 830 831 return ICERR_OK; 832 } 833 834 /*****************************************************************************/ 835 836 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, 837 const BYTE *lpIn, LPBYTE lpOut) 838 { 839 int bytes_per_pixel; 840 int line_size; 841 int pixel_ptr = 0; 842 int i; 843 BOOL bEndFlag = FALSE; 844 845 assert(pi != NULL); 846 assert(lpbi != NULL && lpbi->biCompression == BI_RGB); 847 assert(lpIn != NULL && lpOut != NULL); 848 849 bytes_per_pixel = (lpbi->biBitCount + 1) / 8; 850 line_size = DIBWIDTHBYTES(*lpbi); 851 852 do { 853 BYTE code0, code1; 854 855 code0 = *lpIn++; 856 code1 = *lpIn++; 857 858 if (code0 == 0) { 859 int extra_byte; 860 861 switch (code1) { 862 case 0: /* EOL - end of line */ 863 pixel_ptr = 0; 864 lpOut += line_size; 865 break; 866 case 1: /* EOI - end of image */ 867 bEndFlag = TRUE; 868 break; 869 case 2: /* skip */ 870 pixel_ptr += *lpIn++ * bytes_per_pixel; 871 lpOut += *lpIn++ * line_size; 872 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) { 873 pixel_ptr = 0; 874 lpOut += line_size; 875 } 876 break; 877 default: /* absolute mode */ 878 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01; 879 880 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) 881 return ICERR_ERROR; 882 883 code0 = code1; 884 for (i = 0; i < code0 / 2; i++) { 885 if (bytes_per_pixel == 1) { 886 code1 = lpIn[i]; 887 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)]; 888 if (2 * i + 1 <= code0) 889 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)]; 890 } else if (bytes_per_pixel == 2) { 891 code1 = lpIn[i] >> 4; 892 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0]; 893 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1]; 894 895 if (2 * i + 1 <= code0) { 896 code1 = lpIn[i] & 0x0F; 897 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0]; 898 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1]; 899 } 900 } else { 901 code1 = lpIn[i] >> 4; 902 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; 903 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; 904 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; 905 pixel_ptr += bytes_per_pixel; 906 907 if (2 * i + 1 <= code0) { 908 code1 = lpIn[i] & 0x0F; 909 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; 910 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; 911 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; 912 pixel_ptr += bytes_per_pixel; 913 } 914 } 915 } 916 if (code0 & 0x01) { 917 if (bytes_per_pixel == 1) { 918 code1 = lpIn[i]; 919 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)]; 920 } else if (bytes_per_pixel == 2) { 921 code1 = lpIn[i] >> 4; 922 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0]; 923 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1]; 924 } else { 925 code1 = lpIn[i] >> 4; 926 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; 927 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; 928 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; 929 pixel_ptr += bytes_per_pixel; 930 } 931 lpIn++; 932 } 933 lpIn += code0 / 2; 934 935 /* if the RLE code is odd, skip a byte in the stream */ 936 if (extra_byte) 937 lpIn++; 938 }; 939 } else { 940 /* coded mode */ 941 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) 942 return ICERR_ERROR; 943 944 if (bytes_per_pixel == 1) { 945 BYTE c1 = pi->palette_map[(code1 >> 4)]; 946 BYTE c2 = pi->palette_map[(code1 & 0x0F)]; 947 948 for (i = 0; i < code0; i++) { 949 if ((i & 1) == 0) 950 lpOut[pixel_ptr++] = c1; 951 else 952 lpOut[pixel_ptr++] = c2; 953 } 954 } else if (bytes_per_pixel == 2) { 955 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0]; 956 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1]; 957 958 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0]; 959 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1]; 960 961 for (i = 0; i < code0; i++) { 962 if ((i & 1) == 0) { 963 lpOut[pixel_ptr++] = hi1; 964 lpOut[pixel_ptr++] = lo1; 965 } else { 966 lpOut[pixel_ptr++] = hi2; 967 lpOut[pixel_ptr++] = lo2; 968 } 969 } 970 } else { 971 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0]; 972 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1]; 973 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2]; 974 975 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0]; 976 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1]; 977 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2]; 978 979 for (i = 0; i < code0; i++) { 980 if ((i & 1) == 0) { 981 lpOut[pixel_ptr + 0] = b1; 982 lpOut[pixel_ptr + 1] = g1; 983 lpOut[pixel_ptr + 2] = r1; 984 } else { 985 lpOut[pixel_ptr + 0] = b2; 986 lpOut[pixel_ptr + 1] = g2; 987 lpOut[pixel_ptr + 2] = r2; 988 } 989 pixel_ptr += bytes_per_pixel; 990 } 991 } 992 } 993 } while (! bEndFlag); 994 995 return ICERR_OK; 996 } 997 998 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, 999 const BYTE *lpIn, LPBYTE lpOut) 1000 { 1001 int bytes_per_pixel; 1002 int line_size; 1003 int pixel_ptr = 0; 1004 BOOL bEndFlag = FALSE; 1005 1006 assert(pi != NULL); 1007 assert(lpbi != NULL && lpbi->biCompression == BI_RGB); 1008 assert(lpIn != NULL && lpOut != NULL); 1009 1010 bytes_per_pixel = (lpbi->biBitCount + 1) / 8; 1011 line_size = DIBWIDTHBYTES(*lpbi); 1012 1013 do { 1014 BYTE code0, code1; 1015 1016 code0 = *lpIn++; 1017 code1 = *lpIn++; 1018 1019 if (code0 == 0) { 1020 int extra_byte; 1021 1022 switch (code1) { 1023 case 0: /* EOL - end of line */ 1024 pixel_ptr = 0; 1025 lpOut += line_size; 1026 break; 1027 case 1: /* EOI - end of image */ 1028 bEndFlag = TRUE; 1029 break; 1030 case 2: /* skip */ 1031 pixel_ptr += *lpIn++ * bytes_per_pixel; 1032 lpOut += *lpIn++ * line_size; 1033 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) { 1034 pixel_ptr = 0; 1035 lpOut += line_size; 1036 } 1037 break; 1038 default: /* absolute mode */ 1039 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) { 1040 WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth); 1041 return ICERR_ERROR; 1042 } 1043 extra_byte = code1 & 0x01; 1044 1045 code0 = code1; 1046 while (code0--) { 1047 code1 = *lpIn++; 1048 if (bytes_per_pixel == 1) { 1049 lpOut[pixel_ptr] = pi->palette_map[code1]; 1050 } else if (bytes_per_pixel == 2) { 1051 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0]; 1052 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1]; 1053 } else { 1054 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; 1055 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; 1056 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; 1057 } 1058 pixel_ptr += bytes_per_pixel; 1059 } 1060 1061 /* if the RLE code is odd, skip a byte in the stream */ 1062 if (extra_byte) 1063 lpIn++; 1064 }; 1065 } else { 1066 /* coded mode */ 1067 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) { 1068 WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth); 1069 return ICERR_ERROR; 1070 } 1071 1072 if (bytes_per_pixel == 1) { 1073 code1 = pi->palette_map[code1]; 1074 while (code0--) 1075 lpOut[pixel_ptr++] = code1; 1076 } else if (bytes_per_pixel == 2) { 1077 BYTE hi = pi->palette_map[code1 * 2 + 0]; 1078 BYTE lo = pi->palette_map[code1 * 2 + 1]; 1079 1080 while (code0--) { 1081 lpOut[pixel_ptr + 0] = hi; 1082 lpOut[pixel_ptr + 1] = lo; 1083 pixel_ptr += bytes_per_pixel; 1084 } 1085 } else { 1086 BYTE r = pi->palette_map[code1 * 4 + 2]; 1087 BYTE g = pi->palette_map[code1 * 4 + 1]; 1088 BYTE b = pi->palette_map[code1 * 4 + 0]; 1089 1090 while (code0--) { 1091 lpOut[pixel_ptr + 0] = b; 1092 lpOut[pixel_ptr + 1] = g; 1093 lpOut[pixel_ptr + 2] = r; 1094 pixel_ptr += bytes_per_pixel; 1095 } 1096 } 1097 } 1098 } while (! bEndFlag); 1099 1100 return ICERR_OK; 1101 } 1102 1103 /*****************************************************************************/ 1104 1105 static CodecInfo* Open(LPICOPEN icinfo) 1106 { 1107 CodecInfo* pi = NULL; 1108 1109 if (icinfo == NULL) { 1110 TRACE("(NULL)\n"); 1111 return (LPVOID)0xFFFF0000; 1112 } 1113 1114 if (compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return NULL; 1115 1116 TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo, 1117 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType, 1118 icinfo->fccHandler, (char*)&icinfo->fccHandler, 1119 icinfo->dwVersion,icinfo->dwFlags); 1120 1121 switch (icinfo->fccHandler) { 1122 case FOURCC_RLE: 1123 case FOURCC_RLE4: 1124 case FOURCC_RLE8: 1125 case FOURCC_MRLE: 1126 break; 1127 case mmioFOURCC('m','r','l','e'): 1128 icinfo->fccHandler = FOURCC_MRLE; 1129 break; 1130 default: 1131 WARN("unknown FOURCC = 0x%08X(%4.4s) !\n", 1132 icinfo->fccHandler,(char*)&icinfo->fccHandler); 1133 return NULL; 1134 } 1135 1136 pi = LocalAlloc(LPTR, sizeof(CodecInfo)); 1137 1138 if (pi != NULL) { 1139 pi->fccHandler = icinfo->fccHandler; 1140 1141 pi->bCompress = FALSE; 1142 pi->nPrevFrame = -1; 1143 pi->pPrevFrame = pi->pCurFrame = NULL; 1144 1145 pi->bDecompress = FALSE; 1146 pi->palette_map = NULL; 1147 } 1148 1149 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY); 1150 1151 return pi; 1152 } 1153 1154 static LRESULT Close(CodecInfo *pi) 1155 { 1156 TRACE("(%p)\n", pi); 1157 1158 /* pre-condition */ 1159 assert(pi != NULL); 1160 1161 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL) 1162 CompressEnd(pi); 1163 1164 LocalFree(pi); 1165 return 1; 1166 } 1167 1168 static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize) 1169 { 1170 /* pre-condition */ 1171 assert(pi != NULL); 1172 1173 /* check parameters */ 1174 if (icinfo == NULL) 1175 return sizeof(ICINFO); 1176 if (dwSize < sizeof(ICINFO)) 1177 return 0; 1178 1179 icinfo->dwSize = sizeof(ICINFO); 1180 icinfo->fccType = ICTYPE_VIDEO; 1181 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE); 1182 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC; 1183 icinfo->dwVersion = ICVERSION; 1184 icinfo->dwVersionICM = ICVERSION; 1185 1186 LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR)); 1187 LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR)); 1188 1189 return sizeof(ICINFO); 1190 } 1191 1192 static LRESULT Configure(const CodecInfo *pi, HWND hWnd) 1193 { 1194 /* pre-condition */ 1195 assert(pi != NULL); 1196 1197 /* FIXME */ 1198 return ICERR_OK; 1199 } 1200 1201 static LRESULT About(CodecInfo *pi, HWND hWnd) 1202 { 1203 WCHAR szTitle[20]; 1204 WCHAR szAbout[128]; 1205 1206 /* pre-condition */ 1207 assert(MSRLE32_hModule != 0); 1208 1209 LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)/sizeof(szTitle[0])); 1210 LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)/sizeof(szAbout[0])); 1211 1212 MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION); 1213 1214 return ICERR_OK; 1215 } 1216 1217 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1218 LPBITMAPINFOHEADER lpbiOut) 1219 { 1220 LRESULT size; 1221 1222 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1223 1224 /* pre-condition */ 1225 assert(pi != NULL); 1226 1227 /* check parameters -- need at least input format */ 1228 if (lpbiIn == NULL) { 1229 if (lpbiOut != NULL) 1230 return ICERR_BADPARAM; 1231 return 0; 1232 } 1233 1234 /* handle unsupported input format */ 1235 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK) 1236 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0); 1237 1238 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8); 1239 1240 switch (pi->fccHandler) { 1241 case FOURCC_RLE4: 1242 size = 1 << 4; 1243 break; 1244 case FOURCC_RLE8: 1245 size = 1 << 8; 1246 break; 1247 case FOURCC_RLE: 1248 case FOURCC_MRLE: 1249 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8); 1250 break; 1251 default: 1252 return ICERR_ERROR; 1253 } 1254 1255 if (lpbiIn->biClrUsed != 0) 1256 size = lpbiIn->biClrUsed; 1257 1258 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD); 1259 1260 if (lpbiOut != NULL) { 1261 lpbiOut->biSize = sizeof(BITMAPINFOHEADER); 1262 lpbiOut->biWidth = lpbiIn->biWidth; 1263 lpbiOut->biHeight = lpbiIn->biHeight; 1264 lpbiOut->biPlanes = 1; 1265 if (pi->fccHandler == FOURCC_RLE4 || 1266 lpbiIn->biBitCount <= 4) { 1267 lpbiOut->biCompression = BI_RLE4; 1268 lpbiOut->biBitCount = 4; 1269 } else { 1270 lpbiOut->biCompression = BI_RLE8; 1271 lpbiOut->biBitCount = 8; 1272 } 1273 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut); 1274 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter; 1275 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter; 1276 if (lpbiIn->biClrUsed == 0) 1277 size = 1<<lpbiIn->biBitCount; 1278 else 1279 size = lpbiIn->biClrUsed; 1280 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount); 1281 lpbiOut->biClrImportant = 0; 1282 1283 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, 1284 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD)); 1285 1286 return ICERR_OK; 1287 } else 1288 return size; 1289 } 1290 1291 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1292 LPCBITMAPINFOHEADER lpbiOut) 1293 { 1294 /* pre-condition */ 1295 assert(pi != NULL); 1296 1297 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1298 1299 /* check parameter -- need at least one format */ 1300 if (lpbiIn == NULL && lpbiOut == NULL) 1301 return 0; 1302 /* check if the given format is supported */ 1303 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) 1304 return 0; 1305 1306 /* the worst case is coding the complete image in absolute mode. */ 1307 if (lpbiIn) 1308 return MSRLE32_GetMaxCompressedSize(lpbiIn); 1309 else 1310 return MSRLE32_GetMaxCompressedSize(lpbiOut); 1311 } 1312 1313 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1314 LPCBITMAPINFOHEADER lpbiOut) 1315 { 1316 /* pre-condition */ 1317 assert(pi != NULL); 1318 1319 /* need at least one format */ 1320 if (lpbiIn == NULL && lpbiOut == NULL) 1321 return ICERR_BADPARAM; 1322 1323 /* check input format if given */ 1324 if (lpbiIn != NULL) { 1325 if (!isSupportedDIB(lpbiIn)) 1326 return ICERR_BADFORMAT; 1327 1328 /* for 4-bit need an even width */ 1329 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2)) 1330 return ICERR_BADFORMAT; 1331 1332 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4) 1333 return ICERR_UNSUPPORTED; 1334 else if (lpbiIn->biBitCount > 8) 1335 return ICERR_UNSUPPORTED; 1336 } 1337 1338 /* check output format if given */ 1339 if (lpbiOut != NULL) { 1340 if (!isSupportedMRLE(lpbiOut)) 1341 return ICERR_BADFORMAT; 1342 1343 if (lpbiIn != NULL) { 1344 if (lpbiIn->biWidth != lpbiOut->biWidth) 1345 return ICERR_UNSUPPORTED; 1346 if (lpbiIn->biHeight != lpbiOut->biHeight) 1347 return ICERR_UNSUPPORTED; 1348 if (lpbiIn->biBitCount > lpbiOut->biBitCount) 1349 return ICERR_UNSUPPORTED; 1350 } 1351 } 1352 1353 return ICERR_OK; 1354 } 1355 1356 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1357 LPCBITMAPINFOHEADER lpbiOut) 1358 { 1359 const RGBQUAD *rgbIn; 1360 const RGBQUAD *rgbOut; 1361 UINT i; 1362 size_t size; 1363 1364 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1365 1366 /* pre-condition */ 1367 assert(pi != NULL); 1368 1369 /* check parameters -- need both formats */ 1370 if (lpbiIn == NULL || lpbiOut == NULL) 1371 return ICERR_BADPARAM; 1372 /* And both must be supported */ 1373 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) 1374 return ICERR_BADFORMAT; 1375 1376 /* FIXME: cannot compress and decompress at same time! */ 1377 if (pi->bDecompress) { 1378 FIXME("cannot compress and decompress at same time!\n"); 1379 return ICERR_ERROR; 1380 } 1381 1382 if (pi->bCompress) 1383 CompressEnd(pi); 1384 1385 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight; 1386 pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD))); 1387 if (pi->pPrevFrame == NULL) 1388 return ICERR_MEMORY; 1389 pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD))); 1390 if (pi->pCurFrame == NULL) { 1391 CompressEnd(pi); 1392 return ICERR_MEMORY; 1393 } 1394 pi->nPrevFrame = -1; 1395 pi->bCompress = TRUE; 1396 1397 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize); 1398 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize); 1399 1400 switch (lpbiOut->biBitCount) { 1401 case 4: 1402 case 8: 1403 pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed); 1404 if (pi->palette_map == NULL) { 1405 CompressEnd(pi); 1406 return ICERR_MEMORY; 1407 } 1408 1409 for (i = 0; i < lpbiIn->biClrUsed; i++) { 1410 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]); 1411 } 1412 break; 1413 }; 1414 1415 return ICERR_OK; 1416 } 1417 1418 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize) 1419 { 1420 BOOL is_key; 1421 int i; 1422 1423 TRACE("(%p,%p,%u)\n",pi,lpic,dwSize); 1424 1425 /* pre-condition */ 1426 assert(pi != NULL); 1427 1428 /* check parameters */ 1429 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS)) 1430 return ICERR_BADPARAM; 1431 if (!lpic->lpbiOutput || !lpic->lpOutput || 1432 !lpic->lpbiInput || !lpic->lpInput) 1433 return ICERR_BADPARAM; 1434 1435 TRACE("lpic={0x%X,%p,%p,%p,%p,%p,%p,%d,%u,%u,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev); 1436 1437 if (! pi->bCompress) { 1438 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput); 1439 if (hr != ICERR_OK) 1440 return hr; 1441 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK) 1442 return ICERR_BADFORMAT; 1443 1444 if (lpic->lFrameNum >= pi->nPrevFrame + 1) { 1445 /* we continue in the sequence so we need to initialize 1446 * our internal framedata */ 1447 1448 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput); 1449 } else if (lpic->lFrameNum == pi->nPrevFrame) { 1450 /* Oops, compress same frame again ? Okay, as you wish. 1451 * No need to recompute internal framedata, because we only swapped buffers */ 1452 LPWORD pTmp = pi->pPrevFrame; 1453 1454 pi->pPrevFrame = pi->pCurFrame; 1455 pi->pCurFrame = pTmp; 1456 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) { 1457 LPWORD pTmp; 1458 1459 WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum); 1460 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL) 1461 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */ 1462 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK) 1463 return ICERR_BADFORMAT; 1464 1465 WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum); 1466 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev); 1467 1468 /* swap buffers for current and previous frame */ 1469 /* Don't free and alloc new -- costs too much time and they are of equal size ! */ 1470 pTmp = pi->pPrevFrame; 1471 pi->pPrevFrame = pi->pCurFrame; 1472 pi->pCurFrame = pTmp; 1473 pi->nPrevFrame = lpic->lFrameNum; 1474 } 1475 1476 is_key = (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0; 1477 1478 for (i = 0; i < 3; i++) { 1479 lpic->lpbiOutput->biSizeImage = 0; 1480 1481 if (lpic->lpbiOutput->biBitCount == 4) 1482 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput, lpic->lpbiOutput, lpic->lpOutput, is_key); 1483 else 1484 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput, lpic->lpbiOutput, lpic->lpOutput, is_key); 1485 1486 if (lpic->dwFrameSize == 0 || 1487 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) 1488 break; 1489 1490 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) { 1491 if (lpic->lpbiOutput->biBitCount == 4) 1492 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput, 1493 lpic->lpbiOutput, lpic->lpOutput, TRUE); 1494 else 1495 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput, 1496 lpic->lpbiOutput, lpic->lpOutput, TRUE); 1497 1498 if (lpic->dwFrameSize == 0 || 1499 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) { 1500 WARN("switched to keyframe, was small enough!\n"); 1501 is_key = TRUE; 1502 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits, 1503 StreamFromFOURCC(*lpic->lpckid)); 1504 break; 1505 } 1506 } 1507 1508 if (lpic->dwQuality < 1000) 1509 break; 1510 1511 lpic->dwQuality -= 1000; /* reduce quality by 10% */ 1512 } 1513 1514 { /* swap buffer for current and previous frame */ 1515 /* Don't free and alloc new -- costs too much time and they are of equal size ! */ 1516 LPWORD pTmp = pi->pPrevFrame; 1517 1518 pi->pPrevFrame = pi->pCurFrame; 1519 pi->pCurFrame = pTmp; 1520 pi->nPrevFrame = lpic->lFrameNum; 1521 } 1522 1523 /* FIXME: What is AVIIF_TWOCC? */ 1524 *lpic->lpdwFlags |= AVIIF_TWOCC | (is_key ? AVIIF_KEYFRAME : 0); 1525 return ICERR_OK; 1526 } 1527 1528 static LRESULT CompressEnd(CodecInfo *pi) 1529 { 1530 TRACE("(%p)\n",pi); 1531 1532 if (pi != NULL) { 1533 if (pi->pPrevFrame != NULL) 1534 { 1535 GlobalUnlock(GlobalHandle(pi->pPrevFrame)); 1536 GlobalFree(GlobalHandle(pi->pPrevFrame)); 1537 } 1538 if (pi->pCurFrame != NULL) 1539 { 1540 GlobalUnlock(GlobalHandle(pi->pCurFrame)); 1541 GlobalFree(GlobalHandle(pi->pCurFrame)); 1542 } 1543 pi->pPrevFrame = NULL; 1544 pi->pCurFrame = NULL; 1545 pi->nPrevFrame = -1; 1546 pi->bCompress = FALSE; 1547 } 1548 1549 return ICERR_OK; 1550 } 1551 1552 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1553 LPBITMAPINFOHEADER lpbiOut) 1554 { 1555 DWORD size; 1556 1557 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1558 1559 /* pre-condition */ 1560 assert(pi != NULL); 1561 1562 if (lpbiIn == NULL) 1563 return (lpbiOut != NULL ? ICERR_BADPARAM : 0); 1564 1565 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK) 1566 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0); 1567 1568 size = lpbiIn->biSize; 1569 1570 if (lpbiIn->biBitCount <= 8) { 1571 int colors; 1572 1573 if (lpbiIn->biClrUsed == 0) 1574 colors = 1 << lpbiIn->biBitCount; 1575 else 1576 colors = lpbiIn->biClrUsed; 1577 1578 size += colors * sizeof(RGBQUAD); 1579 } 1580 1581 if (lpbiOut != NULL) { 1582 memcpy(lpbiOut, lpbiIn, size); 1583 lpbiOut->biCompression = BI_RGB; 1584 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight; 1585 1586 return ICERR_OK; 1587 } else 1588 return size; 1589 } 1590 1591 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1592 LPCBITMAPINFOHEADER lpbiOut) 1593 { 1594 LRESULT hr = ICERR_OK; 1595 1596 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1597 1598 /* pre-condition */ 1599 assert(pi != NULL); 1600 1601 /* need at least one format */ 1602 if (lpbiIn == NULL && lpbiOut == NULL) 1603 return ICERR_BADPARAM; 1604 1605 /* check input format if given */ 1606 if (lpbiIn != NULL) { 1607 if (!isSupportedMRLE(lpbiIn) && !isSupportedDIB(lpbiIn)) 1608 return ICERR_BADFORMAT; 1609 } 1610 1611 /* check output format if given */ 1612 if (lpbiOut != NULL) { 1613 if (!isSupportedDIB(lpbiOut)) 1614 hr = ICERR_BADFORMAT; 1615 1616 if (lpbiIn != NULL) { 1617 if (lpbiIn->biWidth != lpbiOut->biWidth) 1618 hr = ICERR_UNSUPPORTED; 1619 if (lpbiIn->biHeight != lpbiOut->biHeight) 1620 hr = ICERR_UNSUPPORTED; 1621 if (lpbiIn->biBitCount > lpbiOut->biBitCount) 1622 hr = ICERR_UNSUPPORTED; 1623 } 1624 } 1625 1626 return hr; 1627 } 1628 1629 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1630 LPCBITMAPINFOHEADER lpbiOut) 1631 { 1632 const RGBQUAD *rgbIn; 1633 const RGBQUAD *rgbOut; 1634 UINT i; 1635 1636 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1637 1638 /* pre-condition */ 1639 assert(pi != NULL); 1640 1641 /* check parameters */ 1642 if (lpbiIn == NULL || lpbiOut == NULL) 1643 return ICERR_BADPARAM; 1644 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) 1645 return ICERR_BADFORMAT; 1646 1647 /* FIXME: cannot compress and decompress at a time! */ 1648 if (pi->bCompress) { 1649 FIXME("cannot compress and decompress at same time!\n"); 1650 return ICERR_ERROR; 1651 } 1652 1653 if (pi->bDecompress) 1654 DecompressEnd(pi); 1655 1656 if (lpbiIn->biCompression != BI_RGB) 1657 { 1658 int colors; 1659 1660 if (lpbiIn->biBitCount <= 8 && lpbiIn->biClrUsed == 0) 1661 colors = 1 << lpbiIn->biBitCount; 1662 else 1663 colors = lpbiIn->biClrUsed; 1664 1665 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize); 1666 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize); 1667 1668 switch (lpbiOut->biBitCount) { 1669 case 4: 1670 case 8: 1671 pi->palette_map = LocalAlloc(LPTR, colors); 1672 if (pi->palette_map == NULL) 1673 return ICERR_MEMORY; 1674 1675 for (i = 0; i < colors; i++) 1676 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(colors, rgbOut, rgbIn[i]); 1677 break; 1678 case 15: 1679 case 16: 1680 pi->palette_map = LocalAlloc(LPTR, colors * 2); 1681 if (pi->palette_map == NULL) 1682 return ICERR_MEMORY; 1683 1684 for (i = 0; i < colors; i++) { 1685 WORD color; 1686 1687 if (lpbiOut->biBitCount == 15) 1688 color = ((rgbIn[i].rgbRed >> 3) << 10) 1689 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3); 1690 else 1691 color = ((rgbIn[i].rgbRed >> 3) << 11) 1692 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3); 1693 1694 pi->palette_map[i * 2 + 1] = color >> 8; 1695 pi->palette_map[i * 2 + 0] = color & 0xFF; 1696 }; 1697 break; 1698 case 24: 1699 case 32: 1700 pi->palette_map = LocalAlloc(LPTR, colors * sizeof(RGBQUAD)); 1701 if (pi->palette_map == NULL) 1702 return ICERR_MEMORY; 1703 memcpy(pi->palette_map, rgbIn, colors * sizeof(RGBQUAD)); 1704 break; 1705 }; 1706 } 1707 pi->bDecompress = TRUE; 1708 1709 return ICERR_OK; 1710 } 1711 1712 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize) 1713 { 1714 TRACE("(%p,%p,%u)\n",pi,pic,dwSize); 1715 1716 /* pre-condition */ 1717 assert(pi != NULL); 1718 1719 /* check parameters */ 1720 if (pic == NULL) 1721 return ICERR_BADPARAM; 1722 if (pic->lpbiInput == NULL || pic->lpInput == NULL || 1723 pic->lpbiOutput == NULL || pic->lpOutput == NULL) 1724 return ICERR_BADPARAM; 1725 1726 /* check formats */ 1727 if (! pi->bDecompress) { 1728 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput); 1729 if (hr != ICERR_OK) 1730 return hr; 1731 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK) 1732 return ICERR_BADFORMAT; 1733 1734 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth); 1735 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight); 1736 1737 /* Uncompressed frame? */ 1738 if (pic->lpbiInput->biCompression == BI_RGB) 1739 { 1740 pic->lpbiOutput->biSizeImage = pic->lpbiInput->biSizeImage; 1741 memcpy(pic->lpOutput, pic->lpInput, pic->lpbiOutput->biSizeImage); 1742 return ICERR_OK; 1743 } 1744 1745 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight; 1746 if (pic->lpbiInput->biBitCount == 4) 1747 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput); 1748 else 1749 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput); 1750 } 1751 1752 static LRESULT DecompressEnd(CodecInfo *pi) 1753 { 1754 TRACE("(%p)\n",pi); 1755 1756 /* pre-condition */ 1757 assert(pi != NULL); 1758 1759 pi->bDecompress = FALSE; 1760 1761 if (pi->palette_map != NULL) { 1762 LocalFree(pi->palette_map); 1763 pi->palette_map = NULL; 1764 } 1765 1766 return ICERR_OK; 1767 } 1768 1769 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, 1770 LPBITMAPINFOHEADER lpbiOut) 1771 { 1772 int size; 1773 1774 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); 1775 1776 /* pre-condition */ 1777 assert(pi != NULL); 1778 1779 /* check parameters */ 1780 if (lpbiIn == NULL || lpbiOut == NULL) 1781 return ICERR_BADPARAM; 1782 1783 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) 1784 return ICERR_BADFORMAT; 1785 1786 if (lpbiOut->biBitCount > 8) 1787 return ICERR_ERROR; 1788 1789 if (lpbiIn->biBitCount <= 8) { 1790 if (lpbiIn->biClrUsed > 0) 1791 size = lpbiIn->biClrUsed; 1792 else 1793 size = (1 << lpbiIn->biBitCount); 1794 1795 lpbiOut->biClrUsed = size; 1796 1797 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD)); 1798 } /* else could never occur ! */ 1799 1800 return ICERR_OK; 1801 } 1802 1803 /* DriverProc - entry point for an installable driver */ 1804 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg, 1805 LPARAM lParam1, LPARAM lParam2) 1806 { 1807 CodecInfo *pi = (CodecInfo*)dwDrvID; 1808 1809 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2); 1810 1811 switch (uMsg) { 1812 /* standard driver messages */ 1813 case DRV_LOAD: 1814 return DRVCNF_OK; 1815 case DRV_OPEN: 1816 return (LRESULT)Open((ICOPEN*)lParam2); 1817 case DRV_CLOSE: 1818 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL) 1819 Close(pi); 1820 return DRVCNF_OK; 1821 case DRV_ENABLE: 1822 case DRV_DISABLE: 1823 return DRVCNF_OK; 1824 case DRV_FREE: 1825 return DRVCNF_OK; 1826 case DRV_QUERYCONFIGURE: 1827 return DRVCNF_CANCEL; /* FIXME */ 1828 case DRV_CONFIGURE: 1829 return DRVCNF_OK; /* FIXME */ 1830 case DRV_INSTALL: 1831 case DRV_REMOVE: 1832 return DRVCNF_OK; 1833 1834 /* installable compression manager messages */ 1835 case ICM_CONFIGURE: 1836 FIXME("ICM_CONFIGURE (%ld)\n",lParam1); 1837 if (lParam1 == -1) 1838 return ICERR_UNSUPPORTED; /* FIXME */ 1839 else 1840 return Configure(pi, (HWND)lParam1); 1841 case ICM_ABOUT: 1842 if (lParam1 == -1) 1843 return ICERR_OK; 1844 else 1845 return About(pi, (HWND)lParam1); 1846 case ICM_GETSTATE: 1847 case ICM_SETSTATE: 1848 return 0; /* no state */ 1849 case ICM_GETINFO: 1850 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2); 1851 case ICM_GETDEFAULTQUALITY: 1852 if ((LPVOID)lParam1 != NULL) { 1853 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY; 1854 return ICERR_OK; 1855 } 1856 break; 1857 case ICM_COMPRESS_GET_FORMAT: 1858 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1, 1859 (LPBITMAPINFOHEADER)lParam2); 1860 case ICM_COMPRESS_GET_SIZE: 1861 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1, 1862 (LPCBITMAPINFOHEADER)lParam2); 1863 case ICM_COMPRESS_QUERY: 1864 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1, 1865 (LPCBITMAPINFOHEADER)lParam2); 1866 case ICM_COMPRESS_BEGIN: 1867 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1, 1868 (LPCBITMAPINFOHEADER)lParam2); 1869 case ICM_COMPRESS: 1870 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2); 1871 case ICM_COMPRESS_END: 1872 return CompressEnd(pi); 1873 case ICM_DECOMPRESS_GET_FORMAT: 1874 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1, 1875 (LPBITMAPINFOHEADER)lParam2); 1876 case ICM_DECOMPRESS_QUERY: 1877 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1, 1878 (LPCBITMAPINFOHEADER)lParam2); 1879 case ICM_DECOMPRESS_BEGIN: 1880 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1, 1881 (LPCBITMAPINFOHEADER)lParam2); 1882 case ICM_DECOMPRESS: 1883 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2); 1884 case ICM_DECOMPRESS_END: 1885 return DecompressEnd(pi); 1886 case ICM_DECOMPRESS_SET_PALETTE: 1887 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2); 1888 return ICERR_UNSUPPORTED; 1889 case ICM_DECOMPRESS_GET_PALETTE: 1890 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1, 1891 (LPBITMAPINFOHEADER)lParam2); 1892 case ICM_GETDEFAULTKEYFRAMERATE: 1893 if ((LPVOID)lParam1 != NULL) 1894 *(LPDWORD)lParam1 = 15; 1895 return ICERR_OK; 1896 default: 1897 if (uMsg < DRV_USER) 1898 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2); 1899 else 1900 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2); 1901 }; 1902 1903 return ICERR_UNSUPPORTED; 1904 } 1905 1906 /* DllMain - library initialization code */ 1907 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) 1908 { 1909 TRACE("(%p,%d,%p)\n",hModule,dwReason,lpReserved); 1910 1911 switch (dwReason) { 1912 case DLL_PROCESS_ATTACH: 1913 DisableThreadLibraryCalls(hModule); 1914 MSRLE32_hModule = hModule; 1915 break; 1916 } 1917 1918 return TRUE; 1919 } 1920