ole32/tests: Relax the reference counting tests a bit. We only care whether reference...
[wine/hramrach.git] / dlls / msrle32 / msrle32.c
blobe1570279c1a40a159638b2d93d3052408c6d347d
1 /*
2 * Copyright 2002-2003 Michael Günnewig
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.
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.
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
19 /* TODO:
20 * - some improvements possible
21 * - implement DecompressSetPalette? -- do we need it for anything?
24 #include <assert.h>
26 #include "msrle_private.h"
28 #include "winnls.h"
29 #include "winuser.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
35 static HINSTANCE MSRLE32_hModule = 0;
37 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
39 #define ABS(a) ((a) < 0 ? -(a) : (a))
40 #define SQR(a) ((a) * (a))
42 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
43 static inline WORD ColorCmp(WORD clr1, WORD clr2)
45 register UINT a = (clr1-clr2);
46 return SQR(a);
48 static inline WORD Intensity(RGBQUAD clr)
50 return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
53 #define GetRawPixel(lpbi,lp,x) \
54 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
55 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
57 /*****************************************************************************/
59 /* utility functions */
60 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
61 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
62 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
64 /* compression functions */
65 static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn);
66 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
67 static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
68 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
69 LPBYTE lpOut, BOOL isKey);
70 static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
71 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
72 LPBYTE lpOut, BOOL isKey);
74 /* decompression functions */
75 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
76 const BYTE *lpIn, LPBYTE lpOut);
77 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
78 const BYTE *lpIn, LPBYTE lpOut);
80 /* API functions */
81 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
82 LPBITMAPINFOHEADER lpbiOut);
83 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
84 LPCBITMAPINFOHEADER lpbiOut);
85 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
86 LPCBITMAPINFOHEADER lpbiOut);
87 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
88 LPCBITMAPINFOHEADER lpbiOut);
89 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
90 static LRESULT CompressEnd(CodecInfo *pi);
92 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
93 LPBITMAPINFOHEADER lpbiOut);
94 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
95 LPCBITMAPINFOHEADER lpbiOut);
96 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
97 LPCBITMAPINFOHEADER lpbiOut);
98 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
99 static LRESULT DecompressEnd(CodecInfo *pi);
100 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
101 LPBITMAPINFOHEADER lpbiOut);
103 /*****************************************************************************/
105 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
107 /* pre-conditions */
108 assert(lpbi != NULL);
110 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
111 lpbi->biPlanes != 1)
112 return FALSE;
114 if (lpbi->biCompression == BI_RLE4) {
115 if (lpbi->biBitCount != 4 ||
116 (lpbi->biWidth % 2) != 0)
117 return FALSE;
118 } else if (lpbi->biCompression == BI_RLE8) {
119 if (lpbi->biBitCount != 8)
120 return FALSE;
121 } else
122 return FALSE;
124 return TRUE;
127 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
129 /* pre-conditions */
130 assert(lpbi != NULL);
132 /* check structure version/planes/compression */
133 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
134 lpbi->biPlanes != 1)
135 return FALSE;
136 if (lpbi->biCompression != BI_RGB &&
137 lpbi->biCompression != BI_BITFIELDS)
138 return FALSE;
140 /* check bit-depth */
141 if (lpbi->biBitCount != 1 &&
142 lpbi->biBitCount != 4 &&
143 lpbi->biBitCount != 8 &&
144 lpbi->biBitCount != 15 &&
145 lpbi->biBitCount != 16 &&
146 lpbi->biBitCount != 24 &&
147 lpbi->biBitCount != 32)
148 return FALSE;
150 /* check for size(s) */
151 if (!lpbi->biWidth || !lpbi->biHeight)
152 return FALSE; /* image with zero size, makes no sense so error ! */
153 if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
154 return FALSE; /* image too big ! */
156 /* check for nonexistent colortable for hi- and true-color DIB's */
157 if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
158 return FALSE;
160 return TRUE;
163 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
165 INT diff = 0x00FFFFFF;
166 UINT i;
167 UINT idx = 0;
169 /* pre-conditions */
170 assert(clrs != NULL);
172 for (i = 0; i < count; i++) {
173 int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed);
174 int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
175 int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue);
177 r = r*r + g*g + b*b;
179 if (r < diff) {
180 idx = i;
181 diff = r;
182 if (diff == 0)
183 break;
187 return idx;
190 /*****************************************************************************/
192 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn)
194 WORD wIntensityTbl[256];
195 DWORD lInLine, lOutLine;
196 LPWORD lpOut;
197 UINT i;
198 LONG y;
200 /* pre-conditions */
201 assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
202 assert(pi->pCurFrame != NULL);
204 lInLine = DIBWIDTHBYTES(*lpbiIn);
205 lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
206 lpOut = pi->pCurFrame;
208 assert(lpbiIn->biClrUsed != 0);
211 const RGBQUAD *lp =
212 (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
214 for (i = 0; i < lpbiIn->biClrUsed; i++)
215 wIntensityTbl[i] = Intensity(lp[i]);
218 for (y = 0; y < lpbiIn->biHeight; y++) {
219 LONG x;
221 switch (lpbiIn->biBitCount) {
222 case 1:
223 for (x = 0; x < lpbiIn->biWidth / 8; x++) {
224 for (i = 0; i < 7; i++)
225 lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
227 break;
228 case 4:
229 for (x = 0; x < lpbiIn->biWidth / 2; x++) {
230 lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
231 lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
233 break;
234 case 8:
235 for (x = 0; x < lpbiIn->biWidth; x++)
236 lpOut[x] = wIntensityTbl[lpIn[x]];
237 break;
240 lpIn += lInLine;
241 lpOut += lOutLine;
245 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
247 LONG a, b, size;
249 /* pre-condition */
250 assert(lpbi != NULL);
252 a = lpbi->biWidth / 255;
253 b = lpbi->biWidth % 255;
254 if (lpbi->biBitCount <= 4) {
255 a /= 2;
256 b /= 2;
259 size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
260 return size * lpbi->biHeight;
263 /* lpP => current pos in previous frame
264 * lpA => previous pos in current frame
265 * lpB => current pos in current frame
267 static INT countDiffRLE4(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
269 INT count;
270 WORD clr1, clr2;
272 /* pre-conditions */
273 assert(lpA && lpB && lDist >= 0 && width > 0);
275 if (pos >= width)
276 return 0;
277 if (pos+1 == width)
278 return 1;
280 clr1 = lpB[pos++];
281 clr2 = lpB[pos];
283 count = 2;
284 while (pos + 1 < width) {
285 WORD clr3, clr4;
287 clr3 = lpB[++pos];
288 if (pos + 1 >= width)
289 return count + 1;
291 clr4 = lpB[++pos];
292 if (ColorCmp(clr1, clr3) <= lDist &&
293 ColorCmp(clr2, clr4) <= lDist) {
294 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
295 if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
296 ColorCmp(clr2,lpB[pos+2]) <= lDist) {
297 if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
298 ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
299 return count - 3; /* followed by at least 4 encodable pixels */
300 return count - 2;
302 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
303 /* 'compare' with previous frame for end of diff */
304 INT count2 = 0;
306 /* FIXME */
308 if (count2 >= 8)
309 return count;
311 pos -= count2;
314 count += 2;
315 clr1 = clr3;
316 clr2 = clr4;
319 return count;
322 /* lpP => current pos in previous frame
323 * lpA => previous pos in current frame
324 * lpB => current pos in current frame
326 static INT countDiffRLE8(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
328 INT count;
330 for (count = 0; pos < width; pos++, count++) {
331 if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
332 /* diff at end? -- look-ahead for some more encodable pixel */
333 if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
334 return count - 1;
335 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
336 return count - 1;
337 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
338 /* 'compare' with previous frame for end of diff */
339 INT count2 = 0;
341 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
342 if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
343 break;
345 if (count2 > 4)
346 return count;
348 pos -= count2;
352 return count;
355 static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP,
356 const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
357 const BYTE *lpIn, LONG lDist,
358 INT x, LPBYTE *ppOut,
359 DWORD *lpSizeImage)
361 LPBYTE lpOut = *ppOut;
362 INT count, pos;
363 WORD clr1, clr2;
365 /* try to encode as many pixel as possible */
366 count = 1;
367 pos = x;
368 clr1 = lpC[pos++];
369 if (pos < lpbi->biWidth) {
370 clr2 = lpC[pos];
371 for (++count; pos + 1 < lpbi->biWidth; ) {
372 ++pos;
373 if (ColorCmp(clr1, lpC[pos]) > lDist)
374 break;
375 count++;
376 if (pos + 1 >= lpbi->biWidth)
377 break;
378 ++pos;
379 if (ColorCmp(clr2, lpC[pos]) > lDist)
380 break;
381 count++;
385 if (count < 4) {
386 /* add some pixel for absoluting if possible */
387 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
389 assert(count > 0);
391 /* check for near end of line */
392 if (x + count > lpbi->biWidth)
393 count = lpbi->biWidth - x;
395 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
396 while (count > 2) {
397 INT i;
398 INT size = min(count, 254);
399 int bytes = ((size + 1) & (~1)) / 2;
400 int extra_byte = bytes & 0x01;
402 *lpSizeImage += 2 + bytes + extra_byte;
403 assert(((*lpSizeImage) % 2) == 0);
404 count -= size;
405 *lpOut++ = 0;
406 *lpOut++ = size;
407 for (i = 0; i < size; i += 2) {
408 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
409 x++;
410 if (i + 1 < size) {
411 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
412 x++;
413 } else
414 clr2 = 0;
416 *lpOut++ = (clr1 << 4) | clr2;
418 if (extra_byte)
419 *lpOut++ = 0;
422 if (count > 0) {
423 /* too little for absoluting so we must encode them */
424 assert(count <= 2);
426 *lpSizeImage += 2;
427 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
428 x++;
429 if (count == 2) {
430 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
431 x++;
432 } else
433 clr2 = 0;
434 *lpOut++ = count;
435 *lpOut++ = (clr1 << 4) | clr2;
437 } else {
438 /* encode count pixel(s) */
439 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
440 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
442 x += count;
443 while (count > 0) {
444 INT size = min(count, 254);
446 *lpSizeImage += 2;
447 count -= size;
448 *lpOut++ = size;
449 *lpOut++ = clr1;
453 *ppOut = lpOut;
455 return x;
458 static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
459 const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
460 const BYTE *lpIn, LONG lDist,
461 INT x, LPBYTE *ppOut,
462 DWORD *lpSizeImage)
464 LPBYTE lpOut = *ppOut;
465 INT count, pos;
466 WORD clr;
468 assert(lpbi->biBitCount <= 8);
469 assert(lpbi->biCompression == BI_RGB);
471 /* try to encode as much as possible */
472 pos = x;
473 clr = lpC[pos++];
474 for (count = 1; pos < lpbi->biWidth; count++) {
475 if (ColorCmp(clr, lpC[pos++]) > lDist)
476 break;
479 if (count < 2) {
480 /* add some more pixels for absoluting if possible */
481 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
483 assert(count > 0);
485 /* check for over end of line */
486 if (x + count > lpbi->biWidth)
487 count = lpbi->biWidth - x;
489 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
490 while (count > 2) {
491 INT i;
492 INT size = min(count, 255);
493 int extra_byte = size % 2;
495 *lpSizeImage += 2 + size + extra_byte;
496 count -= size;
497 *lpOut++ = 0;
498 *lpOut++ = size;
499 for (i = 0; i < size; i++) {
500 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
501 x++;
503 if (extra_byte)
504 *lpOut++ = 0;
506 if (count > 0) {
507 /* too little for absoluting so we must encode them even if it's expensive! */
508 assert(count <= 2);
510 *lpSizeImage += 2 * count;
511 *lpOut++ = 1;
512 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
513 x++;
515 if (count == 2) {
516 *lpOut++ = 1;
517 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
518 x++;
521 } else {
522 /* encode count pixel(s) */
523 clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
525 /* optimize end of line */
526 if (x + count + 1 == lpbi->biWidth)
527 count++;
529 x += count;
530 while (count > 0) {
531 INT size = min(count, 255);
533 *lpSizeImage += 2;
534 count -= size;
535 *lpOut++ = size;
536 *lpOut++ = clr;
540 *ppOut = lpOut;
542 return x;
545 LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
546 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
547 LPBYTE lpOut, BOOL isKey)
549 LPWORD lpC;
550 LONG lLine, lInLine, lDist;
551 LPBYTE lpOutStart = lpOut;
553 /* pre-conditions */
554 assert(pi != NULL && lpbiOut != NULL);
555 assert(lpIn != NULL && lpOut != NULL);
556 assert(pi->pCurFrame != NULL);
558 lpC = pi->pCurFrame;
559 lDist = QUALITY_to_DIST(pi->dwQuality);
560 lInLine = DIBWIDTHBYTES(*lpbiIn);
561 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
563 lpbiOut->biSizeImage = 0;
564 if (isKey) {
565 /* keyframe -- convert internal frame to output format */
566 INT x, y;
568 for (y = 0; y < lpbiOut->biHeight; y++) {
569 x = 0;
571 do {
572 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
573 &lpOut, &lpbiOut->biSizeImage);
574 } while (x < lpbiOut->biWidth);
576 lpC += lLine;
577 lpIn += lInLine;
579 /* add EOL -- end of line */
580 lpbiOut->biSizeImage += 2;
581 *(LPWORD)lpOut = 0;
582 lpOut += sizeof(WORD);
583 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
585 } else {
586 /* delta-frame -- compute delta between last and this internal frame */
587 LPWORD lpP;
588 INT x, y;
589 INT jumpx, jumpy;
591 assert(pi->pPrevFrame != NULL);
593 lpP = pi->pPrevFrame;
594 jumpy = 0;
595 jumpx = -1;
597 for (y = 0; y < lpbiOut->biHeight; y++) {
598 x = 0;
600 do {
601 INT count, pos;
603 if (jumpx == -1)
604 jumpx = x;
605 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
606 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
607 break;
610 if (pos == lpbiOut->biWidth && count > 8) {
611 /* (count > 8) secures that we will save space */
612 jumpy++;
613 break;
614 } else if (jumpy || jumpx != pos) {
615 /* time to jump */
616 assert(jumpx != -1);
618 if (pos < jumpx) {
619 /* can only jump in positive direction -- jump until EOL, EOL */
620 INT w = lpbiOut->biWidth - jumpx;
622 assert(jumpy > 0);
623 assert(w >= 4);
625 jumpx = 0;
626 jumpy--;
627 /* if (w % 255 == 2) then equal costs
628 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
629 * else it will be cheaper
631 while (w > 0) {
632 lpbiOut->biSizeImage += 4;
633 *lpOut++ = 0;
634 *lpOut++ = 2;
635 *lpOut = min(w, 255);
636 w -= *lpOut++;
637 *lpOut++ = 0;
639 /* add EOL -- end of line */
640 lpbiOut->biSizeImage += 2;
641 *((LPWORD)lpOut) = 0;
642 lpOut += sizeof(WORD);
645 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
647 /* write out real jump(s) */
648 while (jumpy || pos != jumpx) {
649 lpbiOut->biSizeImage += 4;
650 *lpOut++ = 0;
651 *lpOut++ = 2;
652 *lpOut = min(pos - jumpx, 255);
653 x += *lpOut;
654 jumpx += *lpOut++;
655 *lpOut = min(jumpy, 255);
656 jumpy -= *lpOut++;
659 jumpy = 0;
662 jumpx = -1;
664 if (x < lpbiOut->biWidth) {
665 /* skipped the 'same' things corresponding to previous frame */
666 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
667 &lpOut, &lpbiOut->biSizeImage);
669 } while (x < lpbiOut->biWidth);
671 lpP += lLine;
672 lpC += lLine;
673 lpIn += lInLine;
675 if (jumpy == 0) {
676 assert(jumpx == -1);
678 /* add EOL -- end of line */
679 lpbiOut->biSizeImage += 2;
680 *((LPWORD)lpOut) = 0;
681 lpOut += sizeof(WORD);
682 assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
686 /* add EOL -- will be changed to EOI */
687 lpbiOut->biSizeImage += 2;
688 *((LPWORD)lpOut) = 0;
689 lpOut += sizeof(WORD);
692 /* change EOL to EOI -- end of image */
693 lpOut[-1] = 1;
694 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
696 return ICERR_OK;
699 LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
700 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
701 LPBYTE lpOut, BOOL isKey)
703 LPWORD lpC;
704 LONG lDist, lInLine, lLine;
705 LPBYTE lpOutStart = lpOut;
707 assert(pi != NULL && lpbiOut != NULL);
708 assert(lpIn != NULL && lpOut != NULL);
709 assert(pi->pCurFrame != NULL);
711 lpC = pi->pCurFrame;
712 lDist = QUALITY_to_DIST(pi->dwQuality);
713 lInLine = DIBWIDTHBYTES(*lpbiIn);
714 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
716 lpbiOut->biSizeImage = 0;
717 if (isKey) {
718 /* keyframe -- convert internal frame to output format */
719 INT x, y;
721 for (y = 0; y < lpbiOut->biHeight; y++) {
722 x = 0;
724 do {
725 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
726 &lpOut, &lpbiOut->biSizeImage);
727 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
728 } while (x < lpbiOut->biWidth);
730 lpC += lLine;
731 lpIn += lInLine;
733 /* add EOL -- end of line */
734 lpbiOut->biSizeImage += 2;
735 *((LPWORD)lpOut) = 0;
736 lpOut += sizeof(WORD);
737 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
739 } else {
740 /* delta-frame -- compute delta between last and this internal frame */
741 LPWORD lpP;
742 INT x, y;
743 INT jumpx, jumpy;
745 assert(pi->pPrevFrame != NULL);
747 lpP = pi->pPrevFrame;
748 jumpx = -1;
749 jumpy = 0;
751 for (y = 0; y < lpbiOut->biHeight; y++) {
752 x = 0;
754 do {
755 INT count, pos;
757 if (jumpx == -1)
758 jumpx = x;
759 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
760 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
761 break;
764 if (pos == lpbiOut->biWidth && count > 4) {
765 /* (count > 4) secures that we will save space */
766 jumpy++;
767 break;
768 } else if (jumpy || jumpx != pos) {
769 /* time to jump */
770 assert(jumpx != -1);
772 if (pos < jumpx) {
773 /* can only jump in positive direction -- do an EOL then jump */
774 assert(jumpy > 0);
776 jumpx = 0;
777 jumpy--;
779 /* add EOL -- end of line */
780 lpbiOut->biSizeImage += 2;
781 *((LPWORD)lpOut) = 0;
782 lpOut += sizeof(WORD);
783 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
786 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
788 /* write out real jump(s) */
789 while (jumpy || pos != jumpx) {
790 lpbiOut->biSizeImage += 4;
791 *lpOut++ = 0;
792 *lpOut++ = 2;
793 *lpOut = min(pos - jumpx, 255);
794 jumpx += *lpOut++;
795 *lpOut = min(jumpy, 255);
796 jumpy -= *lpOut++;
798 x = pos;
800 jumpy = 0;
803 jumpx = -1;
805 if (x < lpbiOut->biWidth) {
806 /* skip the 'same' things corresponding to previous frame */
807 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
808 &lpOut, &lpbiOut->biSizeImage);
809 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
811 } while (x < lpbiOut->biWidth);
813 lpP += lLine;
814 lpC += lLine;
815 lpIn += lInLine;
817 if (jumpy == 0) {
818 /* add EOL -- end of line */
819 lpbiOut->biSizeImage += 2;
820 *((LPWORD)lpOut) = 0;
821 lpOut += sizeof(WORD);
822 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
826 /* add EOL -- will be changed to EOI */
827 lpbiOut->biSizeImage += 2;
828 *((LPWORD)lpOut) = 0;
829 lpOut += sizeof(WORD);
832 /* change EOL to EOI -- end of image */
833 lpOut[-1] = 1;
834 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
836 return ICERR_OK;
839 /*****************************************************************************/
841 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
842 const BYTE *lpIn, LPBYTE lpOut)
844 int bytes_per_pixel;
845 int line_size;
846 int pixel_ptr = 0;
847 int i;
848 BOOL bEndFlag = FALSE;
850 assert(pi != NULL);
851 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
852 assert(lpIn != NULL && lpOut != NULL);
854 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
855 line_size = DIBWIDTHBYTES(*lpbi);
857 do {
858 BYTE code0, code1;
860 code0 = *lpIn++;
861 code1 = *lpIn++;
863 if (code0 == 0) {
864 int extra_byte;
866 switch (code1) {
867 case 0: /* EOL - end of line */
868 pixel_ptr = 0;
869 lpOut += line_size;
870 break;
871 case 1: /* EOI - end of image */
872 bEndFlag = TRUE;
873 break;
874 case 2: /* skip */
875 pixel_ptr += *lpIn++ * bytes_per_pixel;
876 lpOut += *lpIn++ * line_size;
877 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
878 pixel_ptr = 0;
879 lpOut += line_size;
881 break;
882 default: /* absolute mode */
883 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
885 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
886 return ICERR_ERROR;
888 code0 = code1;
889 for (i = 0; i < code0 / 2; i++) {
890 if (bytes_per_pixel == 1) {
891 code1 = lpIn[i];
892 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
893 if (2 * i + 1 <= code0)
894 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
895 } else if (bytes_per_pixel == 2) {
896 code1 = lpIn[i] >> 4;
897 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
898 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
900 if (2 * i + 1 <= code0) {
901 code1 = lpIn[i] & 0x0F;
902 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
903 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
905 } else {
906 code1 = lpIn[i] >> 4;
907 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
908 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
909 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
910 pixel_ptr += bytes_per_pixel;
912 if (2 * i + 1 <= code0) {
913 code1 = lpIn[i] & 0x0F;
914 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
915 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
916 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
917 pixel_ptr += bytes_per_pixel;
921 if (code0 & 0x01) {
922 if (bytes_per_pixel == 1) {
923 code1 = lpIn[i];
924 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
925 } else if (bytes_per_pixel == 2) {
926 code1 = lpIn[i] >> 4;
927 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
928 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
929 } else {
930 code1 = lpIn[i] >> 4;
931 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
932 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
933 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
934 pixel_ptr += bytes_per_pixel;
936 lpIn++;
938 lpIn += code0 / 2;
940 /* if the RLE code is odd, skip a byte in the stream */
941 if (extra_byte)
942 lpIn++;
944 } else {
945 /* coded mode */
946 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
947 return ICERR_ERROR;
949 if (bytes_per_pixel == 1) {
950 BYTE c1 = pi->palette_map[(code1 >> 4)];
951 BYTE c2 = pi->palette_map[(code1 & 0x0F)];
953 for (i = 0; i < code0; i++) {
954 if ((i & 1) == 0)
955 lpOut[pixel_ptr++] = c1;
956 else
957 lpOut[pixel_ptr++] = c2;
959 } else if (bytes_per_pixel == 2) {
960 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
961 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
963 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
964 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
966 for (i = 0; i < code0; i++) {
967 if ((i & 1) == 0) {
968 lpOut[pixel_ptr++] = hi1;
969 lpOut[pixel_ptr++] = lo1;
970 } else {
971 lpOut[pixel_ptr++] = hi2;
972 lpOut[pixel_ptr++] = lo2;
975 } else {
976 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
977 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
978 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
980 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
981 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
982 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
984 for (i = 0; i < code0; i++) {
985 if ((i & 1) == 0) {
986 lpOut[pixel_ptr + 0] = b1;
987 lpOut[pixel_ptr + 1] = g1;
988 lpOut[pixel_ptr + 2] = r1;
989 } else {
990 lpOut[pixel_ptr + 0] = b2;
991 lpOut[pixel_ptr + 1] = g2;
992 lpOut[pixel_ptr + 2] = r2;
994 pixel_ptr += bytes_per_pixel;
998 } while (! bEndFlag);
1000 return ICERR_OK;
1003 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
1004 const BYTE *lpIn, LPBYTE lpOut)
1006 int bytes_per_pixel;
1007 int line_size;
1008 int pixel_ptr = 0;
1009 BOOL bEndFlag = FALSE;
1011 assert(pi != NULL);
1012 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
1013 assert(lpIn != NULL && lpOut != NULL);
1015 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
1016 line_size = DIBWIDTHBYTES(*lpbi);
1018 do {
1019 BYTE code0, code1;
1021 code0 = *lpIn++;
1022 code1 = *lpIn++;
1024 if (code0 == 0) {
1025 int extra_byte;
1027 switch (code1) {
1028 case 0: /* EOL - end of line */
1029 pixel_ptr = 0;
1030 lpOut += line_size;
1031 break;
1032 case 1: /* EOI - end of image */
1033 bEndFlag = TRUE;
1034 break;
1035 case 2: /* skip */
1036 pixel_ptr += *lpIn++ * bytes_per_pixel;
1037 lpOut += *lpIn++ * line_size;
1038 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1039 pixel_ptr = 0;
1040 lpOut += line_size;
1042 break;
1043 default: /* absolute mode */
1044 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1045 WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1046 return ICERR_ERROR;
1048 extra_byte = code1 & 0x01;
1050 code0 = code1;
1051 while (code0--) {
1052 code1 = *lpIn++;
1053 if (bytes_per_pixel == 1) {
1054 lpOut[pixel_ptr] = pi->palette_map[code1];
1055 } else if (bytes_per_pixel == 2) {
1056 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1057 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1058 } else {
1059 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1060 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1061 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1063 pixel_ptr += bytes_per_pixel;
1066 /* if the RLE code is odd, skip a byte in the stream */
1067 if (extra_byte)
1068 lpIn++;
1070 } else {
1071 /* coded mode */
1072 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1073 WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1074 return ICERR_ERROR;
1077 if (bytes_per_pixel == 1) {
1078 code1 = pi->palette_map[code1];
1079 while (code0--)
1080 lpOut[pixel_ptr++] = code1;
1081 } else if (bytes_per_pixel == 2) {
1082 BYTE hi = pi->palette_map[code1 * 2 + 0];
1083 BYTE lo = pi->palette_map[code1 * 2 + 1];
1085 while (code0--) {
1086 lpOut[pixel_ptr + 0] = hi;
1087 lpOut[pixel_ptr + 1] = lo;
1088 pixel_ptr += bytes_per_pixel;
1090 } else {
1091 BYTE r = pi->palette_map[code1 * 4 + 2];
1092 BYTE g = pi->palette_map[code1 * 4 + 1];
1093 BYTE b = pi->palette_map[code1 * 4 + 0];
1095 while (code0--) {
1096 lpOut[pixel_ptr + 0] = b;
1097 lpOut[pixel_ptr + 1] = g;
1098 lpOut[pixel_ptr + 2] = r;
1099 pixel_ptr += bytes_per_pixel;
1103 } while (! bEndFlag);
1105 return ICERR_OK;
1108 /*****************************************************************************/
1110 static CodecInfo* Open(LPICOPEN icinfo)
1112 CodecInfo* pi = NULL;
1114 if (icinfo == NULL) {
1115 TRACE("(NULL)\n");
1116 return (LPVOID)0xFFFF0000;
1119 if (compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return NULL;
1121 TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo,
1122 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1123 icinfo->fccHandler, (char*)&icinfo->fccHandler,
1124 icinfo->dwVersion,icinfo->dwFlags);
1126 switch (icinfo->fccHandler) {
1127 case FOURCC_RLE:
1128 case FOURCC_RLE4:
1129 case FOURCC_RLE8:
1130 case FOURCC_MRLE:
1131 break;
1132 case mmioFOURCC('m','r','l','e'):
1133 icinfo->fccHandler = FOURCC_MRLE;
1134 break;
1135 default:
1136 WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
1137 icinfo->fccHandler,(char*)&icinfo->fccHandler);
1138 return NULL;
1141 pi = LocalAlloc(LPTR, sizeof(CodecInfo));
1143 if (pi != NULL) {
1144 pi->fccHandler = icinfo->fccHandler;
1146 pi->bCompress = FALSE;
1147 pi->dwQuality = MSRLE32_DEFAULTQUALITY;
1148 pi->nPrevFrame = -1;
1149 pi->pPrevFrame = pi->pCurFrame = NULL;
1151 pi->bDecompress = FALSE;
1152 pi->palette_map = NULL;
1155 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1157 return pi;
1160 static LRESULT Close(CodecInfo *pi)
1162 TRACE("(%p)\n", pi);
1164 /* pre-condition */
1165 assert(pi != NULL);
1167 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1168 CompressEnd(pi);
1170 LocalFree(pi);
1171 return 1;
1174 static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1176 /* pre-condition */
1177 assert(pi != NULL);
1179 /* check parameters */
1180 if (icinfo == NULL)
1181 return sizeof(ICINFO);
1182 if (dwSize < sizeof(ICINFO))
1183 return 0;
1185 icinfo->dwSize = sizeof(ICINFO);
1186 icinfo->fccType = ICTYPE_VIDEO;
1187 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1188 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1189 icinfo->dwVersion = ICVERSION;
1190 icinfo->dwVersionICM = ICVERSION;
1192 LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
1193 LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
1195 return sizeof(ICINFO);
1198 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1200 /* pre-condition */
1201 assert(pi != NULL);
1203 if (lQuality == -1)
1204 lQuality = MSRLE32_DEFAULTQUALITY;
1205 else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1206 return ICERR_BADPARAM;
1208 pi->dwQuality = (DWORD)lQuality;
1210 return ICERR_OK;
1213 static LRESULT Configure(const CodecInfo *pi, HWND hWnd)
1215 /* pre-condition */
1216 assert(pi != NULL);
1218 /* FIXME */
1219 return ICERR_OK;
1222 static LRESULT About(CodecInfo *pi, HWND hWnd)
1224 WCHAR szTitle[20];
1225 WCHAR szAbout[128];
1227 /* pre-condition */
1228 assert(MSRLE32_hModule != 0);
1230 LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
1231 LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)/sizeof(szAbout[0]));
1233 MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1235 return ICERR_OK;
1238 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1239 LPBITMAPINFOHEADER lpbiOut)
1241 LRESULT size;
1243 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1245 /* pre-condition */
1246 assert(pi != NULL);
1248 /* check parameters -- need at least input format */
1249 if (lpbiIn == NULL) {
1250 if (lpbiOut != NULL)
1251 return ICERR_BADPARAM;
1252 return 0;
1255 /* handle unsupported input format */
1256 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1257 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1259 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1261 switch (pi->fccHandler) {
1262 case FOURCC_RLE4:
1263 size = 1 << 4;
1264 break;
1265 case FOURCC_RLE8:
1266 size = 1 << 8;
1267 break;
1268 case FOURCC_RLE:
1269 case FOURCC_MRLE:
1270 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1271 break;
1272 default:
1273 return ICERR_ERROR;
1276 if (lpbiIn->biClrUsed != 0)
1277 size = lpbiIn->biClrUsed;
1279 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1281 if (lpbiOut != NULL) {
1282 lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
1283 lpbiOut->biWidth = lpbiIn->biWidth;
1284 lpbiOut->biHeight = lpbiIn->biHeight;
1285 lpbiOut->biPlanes = 1;
1286 if (pi->fccHandler == FOURCC_RLE4 ||
1287 lpbiIn->biBitCount <= 4) {
1288 lpbiOut->biCompression = BI_RLE4;
1289 lpbiOut->biBitCount = 4;
1290 } else {
1291 lpbiOut->biCompression = BI_RLE8;
1292 lpbiOut->biBitCount = 8;
1294 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
1295 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1296 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1297 if (lpbiIn->biClrUsed == 0)
1298 size = 1<<lpbiIn->biBitCount;
1299 else
1300 size = lpbiIn->biClrUsed;
1301 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
1302 lpbiOut->biClrImportant = 0;
1304 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1305 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1307 return ICERR_OK;
1308 } else
1309 return size;
1312 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1313 LPCBITMAPINFOHEADER lpbiOut)
1315 /* pre-condition */
1316 assert(pi != NULL);
1318 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1320 /* check parameter -- need at least one format */
1321 if (lpbiIn == NULL && lpbiOut == NULL)
1322 return 0;
1323 /* check if the given format is supported */
1324 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1325 return 0;
1327 /* the worst case is coding the complete image in absolute mode. */
1328 if (lpbiIn)
1329 return MSRLE32_GetMaxCompressedSize(lpbiIn);
1330 else
1331 return MSRLE32_GetMaxCompressedSize(lpbiOut);
1334 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1335 LPCBITMAPINFOHEADER lpbiOut)
1337 /* pre-condition */
1338 assert(pi != NULL);
1340 /* need at least one format */
1341 if (lpbiIn == NULL && lpbiOut == NULL)
1342 return ICERR_BADPARAM;
1344 /* check input format if given */
1345 if (lpbiIn != NULL) {
1346 if (!isSupportedDIB(lpbiIn))
1347 return ICERR_BADFORMAT;
1349 /* for 4-bit need an even width */
1350 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1351 return ICERR_BADFORMAT;
1353 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1354 return ICERR_UNSUPPORTED;
1355 else if (lpbiIn->biBitCount > 8)
1356 return ICERR_UNSUPPORTED;
1359 /* check output format if given */
1360 if (lpbiOut != NULL) {
1361 if (!isSupportedMRLE(lpbiOut))
1362 return ICERR_BADFORMAT;
1364 if (lpbiIn != NULL) {
1365 if (lpbiIn->biWidth != lpbiOut->biWidth)
1366 return ICERR_UNSUPPORTED;
1367 if (lpbiIn->biHeight != lpbiOut->biHeight)
1368 return ICERR_UNSUPPORTED;
1369 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1370 return ICERR_UNSUPPORTED;
1374 return ICERR_OK;
1377 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1378 LPCBITMAPINFOHEADER lpbiOut)
1380 const RGBQUAD *rgbIn;
1381 const RGBQUAD *rgbOut;
1382 UINT i;
1383 size_t size;
1385 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1387 /* pre-condition */
1388 assert(pi != NULL);
1390 /* check parameters -- need both formats */
1391 if (lpbiIn == NULL || lpbiOut == NULL)
1392 return ICERR_BADPARAM;
1393 /* And both must be supported */
1394 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1395 return ICERR_BADFORMAT;
1397 /* FIXME: cannot compress and decompress at same time! */
1398 if (pi->bDecompress) {
1399 FIXME("cannot compress and decompress at same time!\n");
1400 return ICERR_ERROR;
1403 if (pi->bCompress)
1404 CompressEnd(pi);
1406 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1407 pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1408 if (pi->pPrevFrame == NULL)
1409 return ICERR_MEMORY;
1410 pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1411 if (pi->pCurFrame == NULL) {
1412 CompressEnd(pi);
1413 return ICERR_MEMORY;
1415 pi->nPrevFrame = -1;
1416 pi->bCompress = TRUE;
1418 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1419 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1421 switch (lpbiOut->biBitCount) {
1422 case 4:
1423 case 8:
1424 pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
1425 if (pi->palette_map == NULL) {
1426 CompressEnd(pi);
1427 return ICERR_MEMORY;
1430 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1431 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1433 break;
1436 return ICERR_OK;
1439 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1441 int i;
1443 TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
1445 /* pre-condition */
1446 assert(pi != NULL);
1448 /* check parameters */
1449 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1450 return ICERR_BADPARAM;
1451 if (!lpic->lpbiOutput || !lpic->lpOutput ||
1452 !lpic->lpbiInput || !lpic->lpInput)
1453 return ICERR_BADPARAM;
1455 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);
1457 if (! pi->bCompress) {
1458 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1459 if (hr != ICERR_OK)
1460 return hr;
1461 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1462 return ICERR_BADFORMAT;
1464 if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1465 /* we continue in the sequence so we need to initialize
1466 * our internal framedata */
1468 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1469 } else if (lpic->lFrameNum == pi->nPrevFrame) {
1470 /* Oops, compress same frame again ? Okay, as you wish.
1471 * No need to recompute internal framedata, because we only swapped buffers */
1472 LPWORD pTmp = pi->pPrevFrame;
1474 pi->pPrevFrame = pi->pCurFrame;
1475 pi->pCurFrame = pTmp;
1476 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1477 LPWORD pTmp;
1479 WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1480 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1481 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1482 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1483 return ICERR_BADFORMAT;
1485 WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1486 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1488 /* swap buffers for current and previous frame */
1489 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1490 pTmp = pi->pPrevFrame;
1491 pi->pPrevFrame = pi->pCurFrame;
1492 pi->pCurFrame = pTmp;
1493 pi->nPrevFrame = lpic->lFrameNum;
1496 for (i = 0; i < 3; i++) {
1497 SetQuality(pi, lpic->dwQuality);
1499 lpic->lpbiOutput->biSizeImage = 0;
1501 if (lpic->lpbiOutput->biBitCount == 4)
1502 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
1503 lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1504 else
1505 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
1506 lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1508 if (lpic->dwFrameSize == 0 ||
1509 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1510 break;
1512 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1513 if (lpic->lpbiOutput->biBitCount == 4)
1514 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
1515 lpic->lpbiOutput, lpic->lpOutput, TRUE);
1516 else
1517 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
1518 lpic->lpbiOutput, lpic->lpOutput, TRUE);
1520 if (lpic->dwFrameSize == 0 ||
1521 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1522 WARN("switched to keyframe, was small enough!\n");
1523 *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1524 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
1525 StreamFromFOURCC(*lpic->lpckid));
1526 break;
1530 if (lpic->dwQuality < 1000)
1531 break;
1533 lpic->dwQuality -= 1000; /* reduce quality by 10% */
1536 { /* swap buffer for current and previous frame */
1537 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1538 register LPWORD pTmp = pi->pPrevFrame;
1540 pi->pPrevFrame = pi->pCurFrame;
1541 pi->pCurFrame = pTmp;
1542 pi->nPrevFrame = lpic->lFrameNum;
1545 return ICERR_OK;
1548 static LRESULT CompressEnd(CodecInfo *pi)
1550 TRACE("(%p)\n",pi);
1552 if (pi != NULL) {
1553 if (pi->pPrevFrame != NULL)
1555 GlobalUnlock(GlobalHandle(pi->pPrevFrame));
1556 GlobalFree(GlobalHandle(pi->pPrevFrame));
1558 if (pi->pCurFrame != NULL)
1560 GlobalUnlock(GlobalHandle(pi->pCurFrame));
1561 GlobalFree(GlobalHandle(pi->pCurFrame));
1563 pi->pPrevFrame = NULL;
1564 pi->pCurFrame = NULL;
1565 pi->nPrevFrame = -1;
1566 pi->bCompress = FALSE;
1569 return ICERR_OK;
1572 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1573 LPBITMAPINFOHEADER lpbiOut)
1575 DWORD size;
1577 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1579 /* pre-condition */
1580 assert(pi != NULL);
1582 if (lpbiIn == NULL)
1583 return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1585 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1586 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1588 size = lpbiIn->biSize;
1590 if (lpbiIn->biBitCount <= 8)
1591 size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1593 if (lpbiOut != NULL) {
1594 memcpy(lpbiOut, lpbiIn, size);
1595 lpbiOut->biCompression = BI_RGB;
1596 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1598 return ICERR_OK;
1599 } else
1600 return size;
1603 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1604 LPCBITMAPINFOHEADER lpbiOut)
1606 LRESULT hr = ICERR_OK;
1608 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1610 /* pre-condition */
1611 assert(pi != NULL);
1613 /* need at least one format */
1614 if (lpbiIn == NULL && lpbiOut == NULL)
1615 return ICERR_BADPARAM;
1617 /* check input format if given */
1618 if (lpbiIn != NULL) {
1619 if (!isSupportedMRLE(lpbiIn))
1620 return ICERR_BADFORMAT;
1623 /* check output format if given */
1624 if (lpbiOut != NULL) {
1625 if (!isSupportedDIB(lpbiOut))
1626 hr = ICERR_BADFORMAT;
1628 if (lpbiIn != NULL) {
1629 if (lpbiIn->biWidth != lpbiOut->biWidth)
1630 hr = ICERR_UNSUPPORTED;
1631 if (lpbiIn->biHeight != lpbiOut->biHeight)
1632 hr = ICERR_UNSUPPORTED;
1633 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1634 hr = ICERR_UNSUPPORTED;
1638 return hr;
1641 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1642 LPCBITMAPINFOHEADER lpbiOut)
1644 const RGBQUAD *rgbIn;
1645 const RGBQUAD *rgbOut;
1646 UINT i;
1648 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1650 /* pre-condition */
1651 assert(pi != NULL);
1653 /* check parameters */
1654 if (lpbiIn == NULL || lpbiOut == NULL)
1655 return ICERR_BADPARAM;
1656 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1657 return ICERR_BADFORMAT;
1659 /* FIXME: cannot compress and decompress at a time! */
1660 if (pi->bCompress) {
1661 FIXME("cannot compress and decompress at same time!\n");
1662 return ICERR_ERROR;
1665 if (pi->bDecompress)
1666 DecompressEnd(pi);
1668 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1669 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1671 switch (lpbiOut->biBitCount) {
1672 case 4:
1673 case 8:
1674 pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
1675 if (pi->palette_map == NULL)
1676 return ICERR_MEMORY;
1678 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1679 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1681 break;
1682 case 15:
1683 case 16:
1684 pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1685 if (pi->palette_map == NULL)
1686 return ICERR_MEMORY;
1688 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1689 WORD color;
1691 if (lpbiOut->biBitCount == 15)
1692 color = ((rgbIn[i].rgbRed >> 3) << 10)
1693 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1694 else
1695 color = ((rgbIn[i].rgbRed >> 3) << 11)
1696 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1698 pi->palette_map[i * 2 + 1] = color >> 8;
1699 pi->palette_map[i * 2 + 0] = color & 0xFF;
1701 break;
1702 case 24:
1703 case 32:
1704 pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1705 if (pi->palette_map == NULL)
1706 return ICERR_MEMORY;
1707 memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1708 break;
1711 pi->bDecompress = TRUE;
1713 return ICERR_OK;
1716 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1718 TRACE("(%p,%p,%u)\n",pi,pic,dwSize);
1720 /* pre-condition */
1721 assert(pi != NULL);
1723 /* check parameters */
1724 if (pic == NULL)
1725 return ICERR_BADPARAM;
1726 if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1727 pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1728 return ICERR_BADPARAM;
1730 /* check formats */
1731 if (! pi->bDecompress) {
1732 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1733 if (hr != ICERR_OK)
1734 return hr;
1735 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1736 return ICERR_BADFORMAT;
1738 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
1739 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1741 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1742 if (pic->lpbiInput->biBitCount == 4)
1743 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1744 else
1745 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1748 static LRESULT DecompressEnd(CodecInfo *pi)
1750 TRACE("(%p)\n",pi);
1752 /* pre-condition */
1753 assert(pi != NULL);
1755 pi->bDecompress = FALSE;
1757 if (pi->palette_map != NULL) {
1758 LocalFree(pi->palette_map);
1759 pi->palette_map = NULL;
1762 return ICERR_OK;
1765 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1766 LPBITMAPINFOHEADER lpbiOut)
1768 int size;
1770 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1772 /* pre-condition */
1773 assert(pi != NULL);
1775 /* check parameters */
1776 if (lpbiIn == NULL || lpbiOut == NULL)
1777 return ICERR_BADPARAM;
1779 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1780 return ICERR_BADFORMAT;
1782 if (lpbiOut->biBitCount > 8)
1783 return ICERR_ERROR;
1785 if (lpbiIn->biBitCount <= 8) {
1786 if (lpbiIn->biClrUsed > 0)
1787 size = lpbiIn->biClrUsed;
1788 else
1789 size = (1 << lpbiIn->biBitCount);
1791 lpbiOut->biClrUsed = size;
1793 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1794 } /* else could never occur ! */
1796 return ICERR_OK;
1799 /* DriverProc - entry point for an installable driver */
1800 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
1801 LPARAM lParam1, LPARAM lParam2)
1803 CodecInfo *pi = (CodecInfo*)dwDrvID;
1805 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
1807 switch (uMsg) {
1808 /* standard driver messages */
1809 case DRV_LOAD:
1810 return DRVCNF_OK;
1811 case DRV_OPEN:
1812 return (LRESULT)Open((ICOPEN*)lParam2);
1813 case DRV_CLOSE:
1814 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1815 Close(pi);
1816 return DRVCNF_OK;
1817 case DRV_ENABLE:
1818 case DRV_DISABLE:
1819 return DRVCNF_OK;
1820 case DRV_FREE:
1821 return DRVCNF_OK;
1822 case DRV_QUERYCONFIGURE:
1823 return DRVCNF_CANCEL; /* FIXME */
1824 case DRV_CONFIGURE:
1825 return DRVCNF_OK; /* FIXME */
1826 case DRV_INSTALL:
1827 case DRV_REMOVE:
1828 return DRVCNF_OK;
1830 /* installable compression manager messages */
1831 case ICM_CONFIGURE:
1832 FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1833 if (lParam1 == -1)
1834 return ICERR_UNSUPPORTED; /* FIXME */
1835 else
1836 return Configure(pi, (HWND)lParam1);
1837 case ICM_ABOUT:
1838 if (lParam1 == -1)
1839 return ICERR_OK;
1840 else
1841 return About(pi, (HWND)lParam1);
1842 case ICM_GETSTATE:
1843 case ICM_SETSTATE:
1844 return 0; /* no state */
1845 case ICM_GETINFO:
1846 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1847 case ICM_GETDEFAULTQUALITY:
1848 if ((LPVOID)lParam1 != NULL) {
1849 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1850 return ICERR_OK;
1852 break;
1853 case ICM_GETQUALITY:
1854 if ((LPVOID)lParam1 != NULL) {
1855 *((LPDWORD)lParam1) = pi->dwQuality;
1856 return ICERR_OK;
1858 break;
1859 case ICM_SETQUALITY:
1860 return SetQuality(pi, *(LPLONG)lParam1);
1861 case ICM_COMPRESS_GET_FORMAT:
1862 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1863 (LPBITMAPINFOHEADER)lParam2);
1864 case ICM_COMPRESS_GET_SIZE:
1865 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1866 (LPCBITMAPINFOHEADER)lParam2);
1867 case ICM_COMPRESS_QUERY:
1868 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1869 (LPCBITMAPINFOHEADER)lParam2);
1870 case ICM_COMPRESS_BEGIN:
1871 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1872 (LPCBITMAPINFOHEADER)lParam2);
1873 case ICM_COMPRESS:
1874 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1875 case ICM_COMPRESS_END:
1876 return CompressEnd(pi);
1877 case ICM_DECOMPRESS_GET_FORMAT:
1878 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1879 (LPBITMAPINFOHEADER)lParam2);
1880 case ICM_DECOMPRESS_QUERY:
1881 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1882 (LPCBITMAPINFOHEADER)lParam2);
1883 case ICM_DECOMPRESS_BEGIN:
1884 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1885 (LPCBITMAPINFOHEADER)lParam2);
1886 case ICM_DECOMPRESS:
1887 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1888 case ICM_DECOMPRESS_END:
1889 return DecompressEnd(pi);
1890 case ICM_DECOMPRESS_SET_PALETTE:
1891 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1892 return ICERR_UNSUPPORTED;
1893 case ICM_DECOMPRESS_GET_PALETTE:
1894 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1895 (LPBITMAPINFOHEADER)lParam2);
1896 case ICM_GETDEFAULTKEYFRAMERATE:
1897 if ((LPVOID)lParam1 != NULL)
1898 *(LPDWORD)lParam1 = 15;
1899 return ICERR_OK;
1900 default:
1901 if (uMsg < DRV_USER)
1902 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1903 else
1904 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1907 return ICERR_UNSUPPORTED;
1910 /* DllMain - library initialization code */
1911 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1913 TRACE("(%p,%d,%p)\n",hModule,dwReason,lpReserved);
1915 switch (dwReason) {
1916 case DLL_PROCESS_ATTACH:
1917 DisableThreadLibraryCalls(hModule);
1918 MSRLE32_hModule = hModule;
1919 break;
1921 case DLL_PROCESS_DETACH:
1922 break;
1925 return TRUE;