comctl32: Constify some variables.
[wine/multimedia.git] / dlls / msrle32 / msrle32.c
blob5decd745a16aa890c1d018d94f4069060b90397c
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 ABS(a) ((a) < 0 ? -(a) : (a))
38 #define SQR(a) ((a) * (a))
40 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
41 static inline WORD ColorCmp(WORD clr1, WORD clr2)
43 register UINT a = (clr1-clr2);
44 return SQR(a);
46 static inline WORD Intensity(RGBQUAD clr)
48 return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
51 #define GetRawPixel(lpbi,lp,x) \
52 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
53 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
55 /*****************************************************************************/
57 /* utility functions */
58 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
59 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
60 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
62 /* compression functions */
63 static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn);
64 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
65 static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
66 static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
68 /* decompression functions */
69 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
70 LPBYTE lpIn, LPBYTE lpOut);
71 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
72 LPBYTE lpIn, LPBYTE lpOut);
74 /* API functions */
75 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
76 LPBITMAPINFOHEADER lpbiOut);
77 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
78 LPCBITMAPINFOHEADER lpbiOut);
79 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
80 LPCBITMAPINFOHEADER lpbiOut);
81 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
82 LPCBITMAPINFOHEADER lpbiOut);
83 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
84 static LRESULT CompressEnd(CodecInfo *pi);
86 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
87 LPBITMAPINFOHEADER lpbiOut);
88 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
89 LPCBITMAPINFOHEADER lpbiOut);
90 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
91 LPCBITMAPINFOHEADER lpbiOut);
92 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
93 static LRESULT DecompressEnd(CodecInfo *pi);
94 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
95 LPBITMAPINFOHEADER lpbiOut);
97 /*****************************************************************************/
99 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
101 /* pre-conditions */
102 assert(lpbi != NULL);
104 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
105 lpbi->biPlanes != 1)
106 return FALSE;
108 if (lpbi->biCompression == BI_RLE4) {
109 if (lpbi->biBitCount != 4 ||
110 (lpbi->biWidth % 2) != 0)
111 return FALSE;
112 } else if (lpbi->biCompression == BI_RLE8) {
113 if (lpbi->biBitCount != 8)
114 return FALSE;
115 } else
116 return FALSE;
118 return TRUE;
121 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
123 /* pre-conditions */
124 assert(lpbi != NULL);
126 /* check structure version/planes/compression */
127 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
128 lpbi->biPlanes != 1)
129 return FALSE;
130 if (lpbi->biCompression != BI_RGB &&
131 lpbi->biCompression != BI_BITFIELDS)
132 return FALSE;
134 /* check bit-depth */
135 if (lpbi->biBitCount != 1 &&
136 lpbi->biBitCount != 4 &&
137 lpbi->biBitCount != 8 &&
138 lpbi->biBitCount != 15 &&
139 lpbi->biBitCount != 16 &&
140 lpbi->biBitCount != 24 &&
141 lpbi->biBitCount != 32)
142 return FALSE;
144 /* check for size(s) */
145 if (!lpbi->biWidth || !lpbi->biHeight)
146 return FALSE; /* image with zero size, makes no sense so error ! */
147 if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
148 return FALSE; /* image too big ! */
150 /* check for nonexistent colortable for hi- and true-color DIB's */
151 if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
152 return FALSE;
154 return TRUE;
157 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
159 INT diff = 0x00FFFFFF;
160 UINT i;
161 UINT idx = 0;
163 /* pre-conditions */
164 assert(clrs != NULL);
166 for (i = 0; i < count; i++) {
167 int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed);
168 int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
169 int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue);
171 r = r*r + g*g + b*b;
173 if (r < diff) {
174 idx = i;
175 diff = r;
176 if (diff == 0)
177 break;
181 return idx;
184 /*****************************************************************************/
186 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn)
188 WORD wIntensityTbl[256];
189 DWORD lInLine, lOutLine;
190 LPWORD lpOut;
191 UINT i;
192 LONG y;
194 /* pre-conditions */
195 assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
196 assert(pi->pCurFrame != NULL);
198 lInLine = DIBWIDTHBYTES(*lpbiIn);
199 lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
200 lpOut = pi->pCurFrame;
202 assert(lpbiIn->biClrUsed != 0);
205 const RGBQUAD *lp =
206 (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
208 for (i = 0; i < lpbiIn->biClrUsed; i++)
209 wIntensityTbl[i] = Intensity(lp[i]);
212 for (y = 0; y < lpbiIn->biHeight; y++) {
213 LONG x;
215 switch (lpbiIn->biBitCount) {
216 case 1:
217 for (x = 0; x < lpbiIn->biWidth / 8; x++) {
218 for (i = 0; i < 7; i++)
219 lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
221 break;
222 case 4:
223 for (x = 0; x < lpbiIn->biWidth / 2; x++) {
224 lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
225 lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
227 break;
228 case 8:
229 for (x = 0; x < lpbiIn->biWidth; x++)
230 lpOut[x] = wIntensityTbl[lpIn[x]];
231 break;
234 lpIn += lInLine;
235 lpOut += lOutLine;
239 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
241 LONG a, b, size;
243 /* pre-condition */
244 assert(lpbi != NULL);
246 a = lpbi->biWidth / 255;
247 b = lpbi->biWidth % 255;
248 if (lpbi->biBitCount <= 4) {
249 a /= 2;
250 b /= 2;
253 size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
254 return size * lpbi->biHeight;
257 /* lpP => current pos in previous frame
258 * lpA => previous pos in current frame
259 * lpB => current pos in current frame
261 static INT countDiffRLE4(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
263 INT count;
264 WORD clr1, clr2;
266 /* pre-conditions */
267 assert(lpA && lpB && lDist >= 0 && width > 0);
269 if (pos >= width)
270 return 0;
271 if (pos+1 == width)
272 return 1;
274 clr1 = lpB[pos++];
275 clr2 = lpB[pos];
277 count = 2;
278 while (pos + 1 < width) {
279 WORD clr3, clr4;
281 clr3 = lpB[++pos];
282 if (pos + 1 >= width)
283 return count + 1;
285 clr4 = lpB[++pos];
286 if (ColorCmp(clr1, clr3) <= lDist &&
287 ColorCmp(clr2, clr4) <= lDist) {
288 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
289 if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
290 ColorCmp(clr2,lpB[pos+2]) <= lDist) {
291 if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
292 ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
293 return count - 3; /* followed by at least 4 encodable pixels */
294 return count - 2;
296 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
297 /* 'compare' with previous frame for end of diff */
298 INT count2 = 0;
300 /* FIXME */
302 if (count2 >= 8)
303 return count;
305 pos -= count2;
308 count += 2;
309 clr1 = clr3;
310 clr2 = clr4;
313 return count;
316 /* lpP => current pos in previous frame
317 * lpA => previous pos in current frame
318 * lpB => current pos in current frame
320 static INT countDiffRLE8(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
322 INT count;
324 for (count = 0; pos < width; pos++, count++) {
325 if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
326 /* diff at end? -- look-ahead for some more encodable pixel */
327 if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
328 return count - 1;
329 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
330 return count - 1;
331 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
332 /* 'compare' with previous frame for end of diff */
333 INT count2 = 0;
335 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
336 if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
337 break;
339 if (count2 > 4)
340 return count;
342 pos -= count2;
346 return count;
349 static INT MSRLE32_CompressRLE4Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
351 LPBYTE lpOut = *ppOut;
352 INT count, pos;
353 WORD clr1, clr2;
355 /* try to encode as many pixel as possible */
356 count = 1;
357 pos = x;
358 clr1 = lpC[pos++];
359 if (pos < lpbi->biWidth) {
360 clr2 = lpC[pos];
361 for (++count; pos + 1 < lpbi->biWidth; ) {
362 ++pos;
363 if (ColorCmp(clr1, lpC[pos]) > lDist)
364 break;
365 count++;
366 if (pos + 1 >= lpbi->biWidth)
367 break;
368 ++pos;
369 if (ColorCmp(clr2, lpC[pos]) > lDist)
370 break;
371 count++;
375 if (count < 4) {
376 /* add some pixel for absoluting if possible */
377 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
379 assert(count > 0);
381 /* check for near end of line */
382 if (x + count > lpbi->biWidth)
383 count = lpbi->biWidth - x;
385 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
386 while (count > 2) {
387 INT i;
388 INT size = min(count, 254);
389 int bytes = ((size + 1) & (~1)) / 2;
390 BOOL extra_byte = bytes & 0x01;
392 *lpSizeImage += 2 + bytes + extra_byte;
393 assert(((*lpSizeImage) % 2) == 0);
394 count -= size;
395 *lpOut++ = 0;
396 *lpOut++ = size;
397 for (i = 0; i < size; i += 2) {
398 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
399 x++;
400 if (i + 1 < size) {
401 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
402 x++;
403 } else
404 clr2 = 0;
406 *lpOut++ = (clr1 << 4) | clr2;
408 if (extra_byte)
409 *lpOut++ = 0;
412 if (count > 0) {
413 /* too little for absoluting so we must encode them */
414 assert(count <= 2);
416 *lpSizeImage += 2;
417 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
418 x++;
419 if (count == 2) {
420 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
421 x++;
422 } else
423 clr2 = 0;
424 *lpOut++ = count;
425 *lpOut++ = (clr1 << 4) | clr2;
427 } else {
428 /* encode count pixel(s) */
429 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
430 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
432 x += count;
433 while (count > 0) {
434 INT size = min(count, 254);
436 *lpSizeImage += 2;
437 count -= size;
438 *lpOut++ = size;
439 *lpOut++ = clr1;
443 *ppOut = lpOut;
445 return x;
448 static INT MSRLE32_CompressRLE8Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
450 LPBYTE lpOut = *ppOut;
451 INT count, pos;
452 WORD clr;
454 assert(lpbi->biBitCount <= 8);
455 assert(lpbi->biCompression == BI_RGB);
457 /* try to encode as much as possible */
458 pos = x;
459 clr = lpC[pos++];
460 for (count = 1; pos < lpbi->biWidth; count++) {
461 if (ColorCmp(clr, lpC[pos++]) > lDist)
462 break;
465 if (count < 2) {
466 /* add some more pixels for absoluting if possible */
467 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
469 assert(count > 0);
471 /* check for over end of line */
472 if (x + count > lpbi->biWidth)
473 count = lpbi->biWidth - x;
475 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
476 while (count > 2) {
477 INT i;
478 INT size = min(count, 255);
479 BOOL extra_byte = size % 2;
481 *lpSizeImage += 2 + size + extra_byte;
482 count -= size;
483 *lpOut++ = 0;
484 *lpOut++ = size;
485 for (i = 0; i < size; i++) {
486 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
487 x++;
489 if (extra_byte)
490 *lpOut++ = 0;
492 if (count > 0) {
493 /* too little for absoluting so we must encode them even if it's expensive! */
494 assert(count <= 2);
496 *lpSizeImage += 2 * count;
497 *lpOut++ = 1;
498 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
499 x++;
501 if (count == 2) {
502 *lpOut++ = 1;
503 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
504 x++;
507 } else {
508 /* encode count pixel(s) */
509 clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
511 /* optimize end of line */
512 if (x + count + 1 == lpbi->biWidth)
513 count++;
515 x += count;
516 while (count > 0) {
517 INT size = min(count, 255);
519 *lpSizeImage += 2;
520 count -= size;
521 *lpOut++ = size;
522 *lpOut++ = clr;
526 *ppOut = lpOut;
528 return x;
531 LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
533 LPWORD lpC;
534 LONG lLine, lInLine, lDist;
535 LPBYTE lpOutStart = lpOut;
537 /* pre-conditions */
538 assert(pi != NULL && lpbiOut != NULL);
539 assert(lpIn != NULL && lpOut != NULL);
540 assert(pi->pCurFrame != NULL);
542 lpC = pi->pCurFrame;
543 lDist = QUALITY_to_DIST(pi->dwQuality);
544 lInLine = DIBWIDTHBYTES(*lpbiIn);
545 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
547 lpbiOut->biSizeImage = 0;
548 if (isKey) {
549 /* keyframe -- convert internal frame to output format */
550 INT x, y;
552 for (y = 0; y < lpbiOut->biHeight; y++) {
553 x = 0;
555 do {
556 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
557 &lpOut, &lpbiOut->biSizeImage);
558 } while (x < lpbiOut->biWidth);
560 lpC += lLine;
561 lpIn += lInLine;
563 /* add EOL -- end of line */
564 lpbiOut->biSizeImage += 2;
565 *(LPWORD)lpOut = 0;
566 lpOut += sizeof(WORD);
567 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
569 } else {
570 /* delta-frame -- compute delta between last and this internal frame */
571 LPWORD lpP;
572 INT x, y;
573 INT jumpx, jumpy;
575 assert(pi->pPrevFrame != NULL);
577 lpP = pi->pPrevFrame;
578 jumpy = 0;
579 jumpx = -1;
581 for (y = 0; y < lpbiOut->biHeight; y++) {
582 x = 0;
584 do {
585 INT count, pos;
587 if (jumpx == -1)
588 jumpx = x;
589 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
590 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
591 break;
594 if (pos == lpbiOut->biWidth && count > 8) {
595 /* (count > 8) secures that we will save space */
596 jumpy++;
597 break;
598 } else if (jumpy || jumpx != pos) {
599 /* time to jump */
600 assert(jumpx != -1);
602 if (pos < jumpx) {
603 /* can only jump in positive direction -- jump until EOL, EOL */
604 INT w = lpbiOut->biWidth - jumpx;
606 assert(jumpy > 0);
607 assert(w >= 4);
609 jumpx = 0;
610 jumpy--;
611 /* if (w % 255 == 2) then equal costs
612 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
613 * else it will be cheaper
615 while (w > 0) {
616 lpbiOut->biSizeImage += 4;
617 *lpOut++ = 0;
618 *lpOut++ = 2;
619 *lpOut = min(w, 255);
620 w -= *lpOut++;
621 *lpOut++ = 0;
623 /* add EOL -- end of line */
624 lpbiOut->biSizeImage += 2;
625 *((LPWORD)lpOut) = 0;
626 lpOut += sizeof(WORD);
629 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
631 /* write out real jump(s) */
632 while (jumpy || pos != jumpx) {
633 lpbiOut->biSizeImage += 4;
634 *lpOut++ = 0;
635 *lpOut++ = 2;
636 *lpOut = min(pos - jumpx, 255);
637 x += *lpOut;
638 jumpx += *lpOut++;
639 *lpOut = min(jumpy, 255);
640 jumpy -= *lpOut++;
643 jumpy = 0;
646 jumpx = -1;
648 if (x < lpbiOut->biWidth) {
649 /* skipped the 'same' things corresponding to previous frame */
650 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
651 &lpOut, &lpbiOut->biSizeImage);
653 } while (x < lpbiOut->biWidth);
655 lpP += lLine;
656 lpC += lLine;
657 lpIn += lInLine;
659 if (jumpy == 0) {
660 assert(jumpx == -1);
662 /* add EOL -- end of line */
663 lpbiOut->biSizeImage += 2;
664 *((LPWORD)lpOut) = 0;
665 lpOut += sizeof(WORD);
666 assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
670 /* add EOL -- will be changed to EOI */
671 lpbiOut->biSizeImage += 2;
672 *((LPWORD)lpOut) = 0;
673 lpOut += sizeof(WORD);
676 /* change EOL to EOI -- end of image */
677 lpOut[-1] = 1;
678 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
680 return ICERR_OK;
683 LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
685 LPWORD lpC;
686 LONG lDist, lInLine, lLine;
687 LPBYTE lpOutStart = lpOut;
689 assert(pi != NULL && lpbiOut != NULL);
690 assert(lpIn != NULL && lpOut != NULL);
691 assert(pi->pCurFrame != NULL);
693 lpC = pi->pCurFrame;
694 lDist = QUALITY_to_DIST(pi->dwQuality);
695 lInLine = DIBWIDTHBYTES(*lpbiIn);
696 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
698 lpbiOut->biSizeImage = 0;
699 if (isKey) {
700 /* keyframe -- convert internal frame to output format */
701 INT x, y;
703 for (y = 0; y < lpbiOut->biHeight; y++) {
704 x = 0;
706 do {
707 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
708 &lpOut, &lpbiOut->biSizeImage);
709 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
710 } while (x < lpbiOut->biWidth);
712 lpC += lLine;
713 lpIn += lInLine;
715 /* add EOL -- end of line */
716 lpbiOut->biSizeImage += 2;
717 *((LPWORD)lpOut) = 0;
718 lpOut += sizeof(WORD);
719 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
721 } else {
722 /* delta-frame -- compute delta between last and this internal frame */
723 LPWORD lpP;
724 INT x, y;
725 INT jumpx, jumpy;
727 assert(pi->pPrevFrame != NULL);
729 lpP = pi->pPrevFrame;
730 jumpx = -1;
731 jumpy = 0;
733 for (y = 0; y < lpbiOut->biHeight; y++) {
734 x = 0;
736 do {
737 INT count, pos;
739 if (jumpx == -1)
740 jumpx = x;
741 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
742 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
743 break;
746 if (pos == lpbiOut->biWidth && count > 4) {
747 /* (count > 4) secures that we will save space */
748 jumpy++;
749 break;
750 } else if (jumpy || jumpx != pos) {
751 /* time to jump */
752 assert(jumpx != -1);
754 if (pos < jumpx) {
755 /* can only jump in positive direction -- do an EOL then jump */
756 assert(jumpy > 0);
758 jumpx = 0;
759 jumpy--;
761 /* add EOL -- end of line */
762 lpbiOut->biSizeImage += 2;
763 *((LPWORD)lpOut) = 0;
764 lpOut += sizeof(WORD);
765 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
768 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
770 /* write out real jump(s) */
771 while (jumpy || pos != jumpx) {
772 lpbiOut->biSizeImage += 4;
773 *lpOut++ = 0;
774 *lpOut++ = 2;
775 *lpOut = min(pos - jumpx, 255);
776 jumpx += *lpOut++;
777 *lpOut = min(jumpy, 255);
778 jumpy -= *lpOut++;
780 x = pos;
782 jumpy = 0;
785 jumpx = -1;
787 if (x < lpbiOut->biWidth) {
788 /* skip the 'same' things corresponding to previous frame */
789 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
790 &lpOut, &lpbiOut->biSizeImage);
791 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
793 } while (x < lpbiOut->biWidth);
795 lpP += lLine;
796 lpC += lLine;
797 lpIn += lInLine;
799 if (jumpy == 0) {
800 /* add EOL -- end of line */
801 lpbiOut->biSizeImage += 2;
802 *((LPWORD)lpOut) = 0;
803 lpOut += sizeof(WORD);
804 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
808 /* add EOL -- will be changed to EOI */
809 lpbiOut->biSizeImage += 2;
810 *((LPWORD)lpOut) = 0;
811 lpOut += sizeof(WORD);
814 /* change EOL to EOI -- end of image */
815 lpOut[-1] = 1;
816 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
818 return ICERR_OK;
821 /*****************************************************************************/
823 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
824 LPBYTE lpIn, LPBYTE lpOut)
826 int bytes_per_pixel;
827 int line_size;
828 int pixel_ptr = 0;
829 int i;
830 BOOL bEndFlag = FALSE;
832 assert(pi != NULL);
833 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
834 assert(lpIn != NULL && lpOut != NULL);
836 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
837 line_size = DIBWIDTHBYTES(*lpbi);
839 do {
840 BYTE code0, code1;
842 code0 = *lpIn++;
843 code1 = *lpIn++;
845 if (code0 == 0) {
846 int extra_byte;
848 switch (code1) {
849 case 0: /* EOL - end of line */
850 pixel_ptr = 0;
851 lpOut += line_size;
852 break;
853 case 1: /* EOI - end of image */
854 bEndFlag = TRUE;
855 break;
856 case 2: /* skip */
857 pixel_ptr += *lpIn++ * bytes_per_pixel;
858 lpOut += *lpIn++ * line_size;
859 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
860 pixel_ptr = 0;
861 lpOut += line_size;
863 break;
864 default: /* absolute mode */
865 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
867 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
868 return ICERR_ERROR;
870 code0 = code1;
871 for (i = 0; i < code0 / 2; i++) {
872 if (bytes_per_pixel == 1) {
873 code1 = lpIn[i];
874 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
875 if (2 * i + 1 <= code0)
876 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
877 } else if (bytes_per_pixel == 2) {
878 code1 = lpIn[i] >> 4;
879 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
880 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
882 if (2 * i + 1 <= code0) {
883 code1 = lpIn[i] & 0x0F;
884 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
885 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
887 } else {
888 code1 = lpIn[i] >> 4;
889 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
890 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
891 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
892 pixel_ptr += bytes_per_pixel;
894 if (2 * i + 1 <= code0) {
895 code1 = lpIn[i] & 0x0F;
896 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
897 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
898 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
899 pixel_ptr += bytes_per_pixel;
903 if (code0 & 0x01) {
904 if (bytes_per_pixel == 1) {
905 code1 = lpIn[i];
906 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
907 } else if (bytes_per_pixel == 2) {
908 code1 = lpIn[i] >> 4;
909 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
910 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
911 } else {
912 code1 = lpIn[i] >> 4;
913 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
914 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
915 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
916 pixel_ptr += bytes_per_pixel;
918 lpIn++;
920 lpIn += code0 / 2;
922 /* if the RLE code is odd, skip a byte in the stream */
923 if (extra_byte)
924 lpIn++;
926 } else {
927 /* coded mode */
928 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
929 return ICERR_ERROR;
931 if (bytes_per_pixel == 1) {
932 BYTE c1 = pi->palette_map[(code1 >> 4)];
933 BYTE c2 = pi->palette_map[(code1 & 0x0F)];
935 for (i = 0; i < code0; i++) {
936 if ((i & 1) == 0)
937 lpOut[pixel_ptr++] = c1;
938 else
939 lpOut[pixel_ptr++] = c2;
941 } else if (bytes_per_pixel == 2) {
942 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
943 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
945 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
946 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
948 for (i = 0; i < code0; i++) {
949 if ((i & 1) == 0) {
950 lpOut[pixel_ptr++] = hi1;
951 lpOut[pixel_ptr++] = lo1;
952 } else {
953 lpOut[pixel_ptr++] = hi2;
954 lpOut[pixel_ptr++] = lo2;
957 } else {
958 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
959 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
960 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
962 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
963 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
964 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
966 for (i = 0; i < code0; i++) {
967 if ((i & 1) == 0) {
968 lpOut[pixel_ptr + 0] = b1;
969 lpOut[pixel_ptr + 1] = g1;
970 lpOut[pixel_ptr + 2] = r1;
971 } else {
972 lpOut[pixel_ptr + 0] = b2;
973 lpOut[pixel_ptr + 1] = g2;
974 lpOut[pixel_ptr + 2] = r2;
976 pixel_ptr += bytes_per_pixel;
980 } while (! bEndFlag);
982 return ICERR_OK;
985 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
986 LPBYTE lpIn, LPBYTE lpOut)
988 int bytes_per_pixel;
989 int line_size;
990 int pixel_ptr = 0;
991 BOOL bEndFlag = FALSE;
993 assert(pi != NULL);
994 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
995 assert(lpIn != NULL && lpOut != NULL);
997 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
998 line_size = DIBWIDTHBYTES(*lpbi);
1000 do {
1001 BYTE code0, code1;
1003 code0 = *lpIn++;
1004 code1 = *lpIn++;
1006 if (code0 == 0) {
1007 int extra_byte;
1009 switch (code1) {
1010 case 0: /* EOL - end of line */
1011 pixel_ptr = 0;
1012 lpOut += line_size;
1013 break;
1014 case 1: /* EOI - end of image */
1015 bEndFlag = TRUE;
1016 break;
1017 case 2: /* skip */
1018 pixel_ptr += *lpIn++ * bytes_per_pixel;
1019 lpOut += *lpIn++ * line_size;
1020 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1021 pixel_ptr = 0;
1022 lpOut += line_size;
1024 break;
1025 default: /* absolute mode */
1026 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1027 WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1028 return ICERR_ERROR;
1030 extra_byte = code1 & 0x01;
1032 code0 = code1;
1033 while (code0--) {
1034 code1 = *lpIn++;
1035 if (bytes_per_pixel == 1) {
1036 lpOut[pixel_ptr] = pi->palette_map[code1];
1037 } else if (bytes_per_pixel == 2) {
1038 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1039 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1040 } else {
1041 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1042 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1043 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1045 pixel_ptr += bytes_per_pixel;
1048 /* if the RLE code is odd, skip a byte in the stream */
1049 if (extra_byte)
1050 lpIn++;
1052 } else {
1053 /* coded mode */
1054 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1055 WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1056 return ICERR_ERROR;
1059 if (bytes_per_pixel == 1) {
1060 code1 = pi->palette_map[code1];
1061 while (code0--)
1062 lpOut[pixel_ptr++] = code1;
1063 } else if (bytes_per_pixel == 2) {
1064 BYTE hi = pi->palette_map[code1 * 2 + 0];
1065 BYTE lo = pi->palette_map[code1 * 2 + 1];
1067 while (code0--) {
1068 lpOut[pixel_ptr + 0] = hi;
1069 lpOut[pixel_ptr + 1] = lo;
1070 pixel_ptr += bytes_per_pixel;
1072 } else {
1073 BYTE r = pi->palette_map[code1 * 4 + 2];
1074 BYTE g = pi->palette_map[code1 * 4 + 1];
1075 BYTE b = pi->palette_map[code1 * 4 + 0];
1077 while (code0--) {
1078 lpOut[pixel_ptr + 0] = b;
1079 lpOut[pixel_ptr + 1] = g;
1080 lpOut[pixel_ptr + 2] = r;
1081 pixel_ptr += bytes_per_pixel;
1085 } while (! bEndFlag);
1087 return ICERR_OK;
1090 /*****************************************************************************/
1092 static CodecInfo* Open(LPICOPEN icinfo)
1094 CodecInfo* pi = NULL;
1096 if (icinfo == NULL) {
1097 TRACE("(NULL)\n");
1098 return (LPVOID)0xFFFF0000;
1101 if (icinfo->fccType != ICTYPE_VIDEO) return NULL;
1103 TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo,
1104 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1105 icinfo->fccHandler, (char*)&icinfo->fccHandler,
1106 icinfo->dwVersion,icinfo->dwFlags);
1108 switch (icinfo->fccHandler) {
1109 case FOURCC_RLE:
1110 case FOURCC_RLE4:
1111 case FOURCC_RLE8:
1112 case FOURCC_MRLE:
1113 break;
1114 case mmioFOURCC('m','r','l','e'):
1115 icinfo->fccHandler = FOURCC_MRLE;
1116 break;
1117 default:
1118 WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
1119 icinfo->fccHandler,(char*)&icinfo->fccHandler);
1120 return NULL;
1123 pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
1125 if (pi != NULL) {
1126 pi->fccHandler = icinfo->fccHandler;
1128 pi->bCompress = FALSE;
1129 pi->dwQuality = MSRLE32_DEFAULTQUALITY;
1130 pi->nPrevFrame = -1;
1131 pi->pPrevFrame = pi->pCurFrame = NULL;
1133 pi->bDecompress = FALSE;
1134 pi->palette_map = NULL;
1137 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1139 return pi;
1142 static LRESULT Close(CodecInfo *pi)
1144 TRACE("(%p)\n", pi);
1146 /* pre-condition */
1147 assert(pi != NULL);
1149 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1150 CompressEnd(pi);
1152 LocalFree((HLOCAL)pi);
1153 return 1;
1156 static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1158 /* pre-condition */
1159 assert(pi != NULL);
1161 /* check parameters */
1162 if (icinfo == NULL)
1163 return sizeof(ICINFO);
1164 if (dwSize < sizeof(ICINFO))
1165 return 0;
1167 icinfo->dwSize = sizeof(ICINFO);
1168 icinfo->fccType = ICTYPE_VIDEO;
1169 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1170 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1171 icinfo->dwVersion = ICVERSION;
1172 icinfo->dwVersionICM = ICVERSION;
1174 LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
1175 LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
1177 return sizeof(ICINFO);
1180 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1182 /* pre-condition */
1183 assert(pi != NULL);
1185 if (lQuality == -1)
1186 lQuality = MSRLE32_DEFAULTQUALITY;
1187 else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1188 return ICERR_BADPARAM;
1190 pi->dwQuality = (DWORD)lQuality;
1192 return ICERR_OK;
1195 static LRESULT Configure(CodecInfo *pi, HWND hWnd)
1197 /* pre-condition */
1198 assert(pi != NULL);
1200 /* FIXME */
1201 return ICERR_OK;
1204 static LRESULT About(CodecInfo *pi, HWND hWnd)
1206 WCHAR szTitle[20];
1207 WCHAR szAbout[128];
1209 /* pre-condition */
1210 assert(MSRLE32_hModule != 0);
1212 LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
1213 LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
1215 MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1217 return ICERR_OK;
1220 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1221 LPBITMAPINFOHEADER lpbiOut)
1223 LRESULT size;
1225 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1227 /* pre-condition */
1228 assert(pi != NULL);
1230 /* check parameters -- need at least input format */
1231 if (lpbiIn == NULL) {
1232 if (lpbiOut != NULL)
1233 return ICERR_BADPARAM;
1234 return 0;
1237 /* handle unsupported input format */
1238 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1239 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1241 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1243 switch (pi->fccHandler) {
1244 case FOURCC_RLE4:
1245 size = 1 << 4;
1246 break;
1247 case FOURCC_RLE8:
1248 size = 1 << 8;
1249 break;
1250 case FOURCC_RLE:
1251 case FOURCC_MRLE:
1252 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1253 break;
1254 default:
1255 return ICERR_ERROR;
1258 if (lpbiIn->biClrUsed != 0)
1259 size = lpbiIn->biClrUsed;
1261 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1263 if (lpbiOut != NULL) {
1264 lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
1265 lpbiOut->biWidth = lpbiIn->biWidth;
1266 lpbiOut->biHeight = lpbiIn->biHeight;
1267 lpbiOut->biPlanes = 1;
1268 if (pi->fccHandler == FOURCC_RLE4 ||
1269 lpbiIn->biBitCount <= 4) {
1270 lpbiOut->biCompression = BI_RLE4;
1271 lpbiOut->biBitCount = 4;
1272 } else {
1273 lpbiOut->biCompression = BI_RLE8;
1274 lpbiOut->biBitCount = 8;
1276 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
1277 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1278 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1279 if (lpbiIn->biClrUsed == 0)
1280 size = 1<<lpbiIn->biBitCount;
1281 else
1282 size = lpbiIn->biClrUsed;
1283 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
1284 lpbiOut->biClrImportant = 0;
1286 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1287 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1289 return ICERR_OK;
1290 } else
1291 return size;
1294 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1295 LPCBITMAPINFOHEADER lpbiOut)
1297 /* pre-condition */
1298 assert(pi != NULL);
1300 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1302 /* check parameter -- need at least one format */
1303 if (lpbiIn == NULL && lpbiOut == NULL)
1304 return 0;
1305 /* check if the given format is supported */
1306 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1307 return 0;
1309 /* the worst case is coding the complete image in absolute mode. */
1310 if (lpbiIn)
1311 return MSRLE32_GetMaxCompressedSize(lpbiIn);
1312 else
1313 return MSRLE32_GetMaxCompressedSize(lpbiOut);
1316 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1317 LPCBITMAPINFOHEADER lpbiOut)
1319 /* pre-condition */
1320 assert(pi != NULL);
1322 /* need at least one format */
1323 if (lpbiIn == NULL && lpbiOut == NULL)
1324 return ICERR_BADPARAM;
1326 /* check input format if given */
1327 if (lpbiIn != NULL) {
1328 if (!isSupportedDIB(lpbiIn))
1329 return ICERR_BADFORMAT;
1331 /* for 4-bit need an even width */
1332 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1333 return ICERR_BADFORMAT;
1335 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1336 return ICERR_UNSUPPORTED;
1337 else if (lpbiIn->biBitCount > 8)
1338 return ICERR_UNSUPPORTED;
1341 /* check output format if given */
1342 if (lpbiOut != NULL) {
1343 if (!isSupportedMRLE(lpbiOut))
1344 return ICERR_BADFORMAT;
1346 if (lpbiIn != NULL) {
1347 if (lpbiIn->biWidth != lpbiOut->biWidth)
1348 return ICERR_UNSUPPORTED;
1349 if (lpbiIn->biHeight != lpbiOut->biHeight)
1350 return ICERR_UNSUPPORTED;
1351 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1352 return ICERR_UNSUPPORTED;
1356 return ICERR_OK;
1359 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1360 LPCBITMAPINFOHEADER lpbiOut)
1362 const RGBQUAD *rgbIn;
1363 const RGBQUAD *rgbOut;
1364 UINT i;
1365 size_t size;
1367 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1369 /* pre-condition */
1370 assert(pi != NULL);
1372 /* check parameters -- need both formats */
1373 if (lpbiIn == NULL || lpbiOut == NULL)
1374 return ICERR_BADPARAM;
1375 /* And both must be supported */
1376 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1377 return ICERR_BADFORMAT;
1379 /* FIXME: cannot compress and decompress at same time! */
1380 if (pi->bDecompress) {
1381 FIXME("cannot compress and decompress at same time!\n");
1382 return ICERR_ERROR;
1385 if (pi->bCompress)
1386 CompressEnd(pi);
1388 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1389 pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1390 if (pi->pPrevFrame == NULL)
1391 return ICERR_MEMORY;
1392 pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1393 if (pi->pCurFrame == NULL) {
1394 CompressEnd(pi);
1395 return ICERR_MEMORY;
1397 pi->nPrevFrame = -1;
1398 pi->bCompress = TRUE;
1400 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1401 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1403 switch (lpbiOut->biBitCount) {
1404 case 4:
1405 case 8:
1406 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1407 if (pi->palette_map == NULL) {
1408 CompressEnd(pi);
1409 return ICERR_MEMORY;
1412 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1413 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1415 break;
1418 return ICERR_OK;
1421 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1423 int i;
1425 TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
1427 /* pre-condition */
1428 assert(pi != NULL);
1430 /* check parameters */
1431 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1432 return ICERR_BADPARAM;
1433 if (!lpic->lpbiOutput || !lpic->lpOutput ||
1434 !lpic->lpbiInput || !lpic->lpInput)
1435 return ICERR_BADPARAM;
1437 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);
1439 if (! pi->bCompress) {
1440 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1441 if (hr != ICERR_OK)
1442 return hr;
1443 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1444 return ICERR_BADFORMAT;
1446 if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1447 /* we continue in the sequence so we need to initialize
1448 * our internal framedata */
1450 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1451 } else if (lpic->lFrameNum == pi->nPrevFrame) {
1452 /* Oops, compress same frame again ? Okay, as you wish.
1453 * No need to recompute internal framedata, because we only swapped buffers */
1454 LPWORD pTmp = pi->pPrevFrame;
1456 pi->pPrevFrame = pi->pCurFrame;
1457 pi->pCurFrame = pTmp;
1458 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1459 LPWORD pTmp;
1461 WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1462 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1463 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1464 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1465 return ICERR_BADFORMAT;
1467 WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1468 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1470 /* swap buffers for current and previous frame */
1471 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1472 pTmp = pi->pPrevFrame;
1473 pi->pPrevFrame = pi->pCurFrame;
1474 pi->pCurFrame = pTmp;
1475 pi->nPrevFrame = lpic->lFrameNum;
1478 for (i = 0; i < 3; i++) {
1479 SetQuality(pi, lpic->dwQuality);
1481 lpic->lpbiOutput->biSizeImage = 0;
1483 if (lpic->lpbiOutput->biBitCount == 4)
1484 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1485 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1486 else
1487 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1488 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1490 if (lpic->dwFrameSize == 0 ||
1491 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1492 break;
1494 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1495 if (lpic->lpbiOutput->biBitCount == 4)
1496 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1497 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1498 else
1499 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1500 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1502 if (lpic->dwFrameSize == 0 ||
1503 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1504 WARN("switched to keyframe, was small enough!\n");
1505 *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1506 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
1507 StreamFromFOURCC(*lpic->lpckid));
1508 break;
1512 if (lpic->dwQuality < 1000)
1513 break;
1515 lpic->dwQuality -= 1000; /* reduce quality by 10% */
1518 { /* swap buffer for current and previous frame */
1519 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1520 register LPWORD pTmp = pi->pPrevFrame;
1522 pi->pPrevFrame = pi->pCurFrame;
1523 pi->pCurFrame = pTmp;
1524 pi->nPrevFrame = lpic->lFrameNum;
1527 return ICERR_OK;
1530 static LRESULT CompressEnd(CodecInfo *pi)
1532 TRACE("(%p)\n",pi);
1534 if (pi != NULL) {
1535 if (pi->pPrevFrame != NULL)
1537 GlobalUnlock(GlobalHandle(pi->pPrevFrame));
1538 GlobalFree(GlobalHandle(pi->pPrevFrame));
1540 if (pi->pCurFrame != NULL)
1542 GlobalUnlock(GlobalHandle(pi->pCurFrame));
1543 GlobalFree(GlobalHandle(pi->pCurFrame));
1545 pi->pPrevFrame = NULL;
1546 pi->pCurFrame = NULL;
1547 pi->nPrevFrame = -1;
1548 pi->bCompress = FALSE;
1551 return ICERR_OK;
1554 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1555 LPBITMAPINFOHEADER lpbiOut)
1557 DWORD size;
1559 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1561 /* pre-condition */
1562 assert(pi != NULL);
1564 if (lpbiIn == NULL)
1565 return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1567 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1568 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1570 size = lpbiIn->biSize;
1572 if (lpbiIn->biBitCount <= 8)
1573 size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1575 if (lpbiOut != NULL) {
1576 memcpy(lpbiOut, lpbiIn, size);
1577 lpbiOut->biCompression = BI_RGB;
1578 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1580 return ICERR_OK;
1581 } else
1582 return size;
1585 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1586 LPCBITMAPINFOHEADER lpbiOut)
1588 LRESULT hr = ICERR_OK;
1590 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1592 /* pre-condition */
1593 assert(pi != NULL);
1595 /* need at least one format */
1596 if (lpbiIn == NULL && lpbiOut == NULL)
1597 return ICERR_BADPARAM;
1599 /* check input format if given */
1600 if (lpbiIn != NULL) {
1601 if (!isSupportedMRLE(lpbiIn))
1602 return ICERR_BADFORMAT;
1605 /* check output format if given */
1606 if (lpbiOut != NULL) {
1607 if (!isSupportedDIB(lpbiOut))
1608 hr = ICERR_BADFORMAT;
1610 if (lpbiIn != NULL) {
1611 if (lpbiIn->biWidth != lpbiOut->biWidth)
1612 hr = ICERR_UNSUPPORTED;
1613 if (lpbiIn->biHeight != lpbiOut->biHeight)
1614 hr = ICERR_UNSUPPORTED;
1615 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1616 hr = ICERR_UNSUPPORTED;
1620 return hr;
1623 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1624 LPCBITMAPINFOHEADER lpbiOut)
1626 const RGBQUAD *rgbIn;
1627 const RGBQUAD *rgbOut;
1628 UINT i;
1630 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1632 /* pre-condition */
1633 assert(pi != NULL);
1635 /* check parameters */
1636 if (lpbiIn == NULL || lpbiOut == NULL)
1637 return ICERR_BADPARAM;
1638 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1639 return ICERR_BADFORMAT;
1641 /* FIXME: cannot compress and decompress at a time! */
1642 if (pi->bCompress) {
1643 FIXME("cannot compress and decompress at same time!\n");
1644 return ICERR_ERROR;
1647 if (pi->bDecompress)
1648 DecompressEnd(pi);
1650 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1651 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1653 switch (lpbiOut->biBitCount) {
1654 case 4:
1655 case 8:
1656 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1657 if (pi->palette_map == NULL)
1658 return ICERR_MEMORY;
1660 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1661 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1663 break;
1664 case 15:
1665 case 16:
1666 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1667 if (pi->palette_map == NULL)
1668 return ICERR_MEMORY;
1670 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1671 WORD color;
1673 if (lpbiOut->biBitCount == 15)
1674 color = ((rgbIn[i].rgbRed >> 3) << 10)
1675 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1676 else
1677 color = ((rgbIn[i].rgbRed >> 3) << 11)
1678 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1680 pi->palette_map[i * 2 + 1] = color >> 8;
1681 pi->palette_map[i * 2 + 0] = color & 0xFF;
1683 break;
1684 case 24:
1685 case 32:
1686 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1687 if (pi->palette_map == NULL)
1688 return ICERR_MEMORY;
1689 memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1690 break;
1693 pi->bDecompress = TRUE;
1695 return ICERR_OK;
1698 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1700 TRACE("(%p,%p,%u)\n",pi,pic,dwSize);
1702 /* pre-condition */
1703 assert(pi != NULL);
1705 /* check parameters */
1706 if (pic == NULL)
1707 return ICERR_BADPARAM;
1708 if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1709 pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1710 return ICERR_BADPARAM;
1712 /* check formats */
1713 if (! pi->bDecompress) {
1714 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1715 if (hr != ICERR_OK)
1716 return hr;
1717 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1718 return ICERR_BADFORMAT;
1720 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
1721 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1723 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1724 if (pic->lpbiInput->biBitCount == 4)
1725 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1726 else
1727 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1730 static LRESULT DecompressEnd(CodecInfo *pi)
1732 TRACE("(%p)\n",pi);
1734 /* pre-condition */
1735 assert(pi != NULL);
1737 pi->bDecompress = FALSE;
1739 if (pi->palette_map != NULL) {
1740 LocalFree((HLOCAL)pi->palette_map);
1741 pi->palette_map = NULL;
1744 return ICERR_OK;
1747 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1748 LPBITMAPINFOHEADER lpbiOut)
1750 int size;
1752 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1754 /* pre-condition */
1755 assert(pi != NULL);
1757 /* check parameters */
1758 if (lpbiIn == NULL || lpbiOut == NULL)
1759 return ICERR_BADPARAM;
1761 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1762 return ICERR_BADFORMAT;
1764 if (lpbiOut->biBitCount > 8)
1765 return ICERR_ERROR;
1767 if (lpbiIn->biBitCount <= 8) {
1768 if (lpbiIn->biClrUsed > 0)
1769 size = lpbiIn->biClrUsed;
1770 else
1771 size = (1 << lpbiIn->biBitCount);
1773 lpbiOut->biClrUsed = size;
1775 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1776 } /* else could never occur ! */
1778 return ICERR_OK;
1781 /* DriverProc - entry point for an installable driver */
1782 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
1783 LPARAM lParam1, LPARAM lParam2)
1785 CodecInfo *pi = (CodecInfo*)dwDrvID;
1787 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
1789 switch (uMsg) {
1790 /* standard driver messages */
1791 case DRV_LOAD:
1792 return DRVCNF_OK;
1793 case DRV_OPEN:
1794 return (LRESULT)Open((ICOPEN*)lParam2);
1795 case DRV_CLOSE:
1796 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1797 Close(pi);
1798 return DRVCNF_OK;
1799 case DRV_ENABLE:
1800 case DRV_DISABLE:
1801 return DRVCNF_OK;
1802 case DRV_FREE:
1803 return DRVCNF_OK;
1804 case DRV_QUERYCONFIGURE:
1805 return DRVCNF_CANCEL; /* FIXME */
1806 case DRV_CONFIGURE:
1807 return DRVCNF_OK; /* FIXME */
1808 case DRV_INSTALL:
1809 case DRV_REMOVE:
1810 return DRVCNF_OK;
1812 /* installable compression manager messages */
1813 case ICM_CONFIGURE:
1814 FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1815 if (lParam1 == -1)
1816 return ICERR_UNSUPPORTED; /* FIXME */
1817 else
1818 return Configure(pi, (HWND)lParam1);
1819 case ICM_ABOUT:
1820 if (lParam1 == -1)
1821 return ICERR_OK;
1822 else
1823 return About(pi, (HWND)lParam1);
1824 case ICM_GETSTATE:
1825 case ICM_SETSTATE:
1826 return 0; /* no state */
1827 case ICM_GETINFO:
1828 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1829 case ICM_GETDEFAULTQUALITY:
1830 if ((LPVOID)lParam1 != NULL) {
1831 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1832 return ICERR_OK;
1834 break;
1835 case ICM_GETQUALITY:
1836 if ((LPVOID)lParam1 != NULL) {
1837 *((LPDWORD)lParam1) = pi->dwQuality;
1838 return ICERR_OK;
1840 break;
1841 case ICM_SETQUALITY:
1842 return SetQuality(pi, *(LPLONG)lParam1);
1843 case ICM_COMPRESS_GET_FORMAT:
1844 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1845 (LPBITMAPINFOHEADER)lParam2);
1846 case ICM_COMPRESS_GET_SIZE:
1847 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1848 (LPCBITMAPINFOHEADER)lParam2);
1849 case ICM_COMPRESS_QUERY:
1850 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1851 (LPCBITMAPINFOHEADER)lParam2);
1852 case ICM_COMPRESS_BEGIN:
1853 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1854 (LPCBITMAPINFOHEADER)lParam2);
1855 case ICM_COMPRESS:
1856 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1857 case ICM_COMPRESS_END:
1858 return CompressEnd(pi);
1859 case ICM_DECOMPRESS_GET_FORMAT:
1860 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1861 (LPBITMAPINFOHEADER)lParam2);
1862 case ICM_DECOMPRESS_QUERY:
1863 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1864 (LPCBITMAPINFOHEADER)lParam2);
1865 case ICM_DECOMPRESS_BEGIN:
1866 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1867 (LPCBITMAPINFOHEADER)lParam2);
1868 case ICM_DECOMPRESS:
1869 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1870 case ICM_DECOMPRESS_END:
1871 return DecompressEnd(pi);
1872 case ICM_DECOMPRESS_SET_PALETTE:
1873 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1874 return ICERR_UNSUPPORTED;
1875 case ICM_DECOMPRESS_GET_PALETTE:
1876 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1877 (LPBITMAPINFOHEADER)lParam2);
1878 case ICM_GETDEFAULTKEYFRAMERATE:
1879 if ((LPVOID)lParam1 != NULL)
1880 *(LPDWORD)lParam1 = 15;
1881 return ICERR_OK;
1882 default:
1883 if (uMsg < DRV_USER)
1884 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1885 else
1886 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1889 return ICERR_UNSUPPORTED;
1892 /* DllMain - library initialization code */
1893 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1895 TRACE("(%p,%d,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
1897 switch (dwReason) {
1898 case DLL_PROCESS_ATTACH:
1899 DisableThreadLibraryCalls(hModule);
1900 MSRLE32_hModule = hModule;
1901 break;
1903 case DLL_PROCESS_DETACH:
1904 break;
1907 return TRUE;