Add a check for icinfo->fccType in DRV_OPEN message handler of builtin
[wine/wine64.git] / dlls / msrle32 / msrle32.c
blob3fb6c625ffe447c86fa9f9b7d9792988cd50811c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
30 #include "windowsx.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
36 static HINSTANCE MSRLE32_hModule = 0;
38 #define ABS(a) ((a) < 0 ? -(a) : (a))
39 #define SQR(a) ((a) * (a))
41 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
42 inline WORD ColorCmp(WORD clr1, WORD clr2)
44 register UINT a = (clr1-clr2);
45 return SQR(a);
47 inline WORD Intensity(RGBQUAD clr)
49 return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
52 #define GetRawPixel(lpbi,lp,x) \
53 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
54 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
56 /*****************************************************************************/
58 /* utility functions */
59 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
60 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
61 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
63 /* compression functions */
64 static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn);
65 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
66 static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
67 static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
69 /* decompression functions */
70 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
71 LPBYTE lpIn, LPBYTE lpOut);
72 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
73 LPBYTE lpIn, LPBYTE lpOut);
75 /* API functions */
76 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
77 LPBITMAPINFOHEADER lpbiOut);
78 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
79 LPCBITMAPINFOHEADER lpbiOut);
80 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
81 LPCBITMAPINFOHEADER lpbiOut);
82 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
83 LPCBITMAPINFOHEADER lpbiOut);
84 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
85 static LRESULT CompressEnd(CodecInfo *pi);
87 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
88 LPBITMAPINFOHEADER lpbiOut);
89 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
90 LPCBITMAPINFOHEADER lpbiOut);
91 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
92 LPCBITMAPINFOHEADER lpbiOut);
93 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
94 static LRESULT DecompressEnd(CodecInfo *pi);
95 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
96 LPBITMAPINFOHEADER lpbiOut);
98 /*****************************************************************************/
100 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
102 /* pre-conditions */
103 assert(lpbi != NULL);
105 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \
106 lpbi->biPlanes != 1)
107 return FALSE;
109 if (lpbi->biCompression == BI_RLE4) {
110 if (lpbi->biBitCount != 4 || \
111 (lpbi->biWidth % 2) != 0)
112 return FALSE;
113 } else if (lpbi->biCompression == BI_RLE8) {
114 if (lpbi->biBitCount != 8)
115 return FALSE;
116 } else
117 return FALSE;
119 return TRUE;
122 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
124 /* pre-conditions */
125 assert(lpbi != NULL);
127 /* check structure version/planes/compression */
128 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
129 lpbi->biPlanes != 1)
130 return FALSE;
131 if (lpbi->biCompression != BI_RGB &&
132 lpbi->biCompression != BI_BITFIELDS)
133 return FALSE;
135 /* check bit-depth */
136 if (lpbi->biBitCount != 1 &&
137 lpbi->biBitCount != 4 &&
138 lpbi->biBitCount != 8 &&
139 lpbi->biBitCount != 15 &&
140 lpbi->biBitCount != 16 &&
141 lpbi->biBitCount != 24 &&
142 lpbi->biBitCount != 32)
143 return FALSE;
145 /* check for size(s) */
146 if (!lpbi->biWidth || !lpbi->biHeight)
147 return FALSE; /* image with zero size, makes no sense so error ! */
148 if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
149 return FALSE; /* image too big ! */
151 /* check for nonexistent colortable for hi- and true-color DIB's */
152 if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
153 return FALSE;
155 return TRUE;
158 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
160 INT diff = 0x00FFFFFF;
161 UINT i;
162 UINT idx = 0;
164 /* pre-conditions */
165 assert(clrs != NULL);
167 for (i = 0; i < count; i++) {
168 int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed);
169 int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
170 int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue);
172 r = r*r + g*g + b*b;
174 if (r < diff) {
175 idx = i;
176 diff = r;
177 if (diff == 0)
178 break;
182 return idx;
185 /*****************************************************************************/
187 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn)
189 WORD wIntensityTbl[256];
190 DWORD lInLine, lOutLine;
191 LPWORD lpOut;
192 UINT i;
193 LONG y;
195 /* pre-conditions */
196 assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
197 assert(pi->pCurFrame != NULL);
199 lInLine = DIBWIDTHBYTES(*lpbiIn);
200 lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
201 lpOut = pi->pCurFrame;
203 assert(lpbiIn->biClrUsed != 0);
206 const RGBQUAD *lp =
207 (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
209 for (i = 0; i < lpbiIn->biClrUsed; i++)
210 wIntensityTbl[i] = Intensity(lp[i]);
213 for (y = 0; y < lpbiIn->biHeight; y++) {
214 LONG x;
216 switch (lpbiIn->biBitCount) {
217 case 1:
218 for (x = 0; x < lpbiIn->biWidth / 8; x++) {
219 for (i = 0; i < 7; i++)
220 lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
222 break;
223 case 4:
224 for (x = 0; x < lpbiIn->biWidth / 2; x++) {
225 lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
226 lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
228 break;
229 case 8:
230 for (x = 0; x < lpbiIn->biWidth; x++)
231 lpOut[x] = wIntensityTbl[lpIn[x]];
232 break;
235 lpIn += lInLine;
236 lpOut += lOutLine;
240 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
242 LONG a, b, size;
244 /* pre-condition */
245 assert(lpbi != NULL);
247 a = lpbi->biWidth / 255;
248 b = lpbi->biWidth % 255;
249 if (lpbi->biBitCount <= 4) {
250 a /= 2;
251 b /= 2;
254 size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
255 return size * lpbi->biHeight;
258 /* lpP => current pos in previous frame
259 * lpA => previous pos in current frame
260 * lpB => current pos in current frame
262 static INT countDiffRLE4(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
264 INT count;
265 WORD clr1, clr2;
267 /* pre-conditions */
268 assert(lpA && lpB && lDist >= 0 && width > 0);
270 if (pos >= width)
271 return 0;
272 if (pos+1 == width)
273 return 1;
275 clr1 = lpB[pos++];
276 clr2 = lpB[pos];
278 count = 2;
279 while (pos + 1 < width) {
280 WORD clr3, clr4;
282 clr3 = lpB[++pos];
283 if (pos + 1 >= width)
284 return count + 1;
286 clr4 = lpB[++pos];
287 if (ColorCmp(clr1, clr3) <= lDist &&
288 ColorCmp(clr2, clr4) <= lDist) {
289 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
290 if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
291 ColorCmp(clr2,lpB[pos+2]) <= lDist) {
292 if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
293 ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
294 return count - 3; /* followed by at least 4 encodable pixels */
295 return count - 2;
297 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
298 /* 'compare' with previous frame for end of diff */
299 INT count2 = 0;
301 /* FIXME */
303 if (count2 >= 8)
304 return count;
306 pos -= count2;
309 count += 2;
310 clr1 = clr3;
311 clr2 = clr4;
314 return count;
317 /* lpP => current pos in previous frame
318 * lpA => previous pos in current frame
319 * lpB => current pos in current frame
321 static INT countDiffRLE8(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
323 INT count;
325 for (count = 0; pos < width; pos++, count++) {
326 if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
327 /* diff at end? -- look-ahead for some more encodable pixel */
328 if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
329 return count - 1;
330 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
331 return count - 1;
332 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
333 /* 'compare' with previous frame for end of diff */
334 INT count2 = 0;
336 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
337 if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
338 break;
340 if (count2 > 4)
341 return count;
343 pos -= count2;
347 return count;
350 static INT MSRLE32_CompressRLE4Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
352 LPBYTE lpOut = *ppOut;
353 INT count, pos;
354 WORD clr1, clr2;
356 /* try to encode as many pixel as possible */
357 count = 1;
358 pos = x;
359 clr1 = lpC[pos++];
360 if (pos < lpbi->biWidth) {
361 clr2 = lpC[pos];
362 for (++count; pos + 1 < lpbi->biWidth; ) {
363 ++pos;
364 if (ColorCmp(clr1, lpC[pos]) > lDist)
365 break;
366 count++;
367 if (pos + 1 >= lpbi->biWidth)
368 break;
369 ++pos;
370 if (ColorCmp(clr2, lpC[pos]) > lDist)
371 break;
372 count++;
376 if (count < 4) {
377 /* add some pixel for absoluting if possible */
378 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
380 assert(count > 0);
382 /* check for near end of line */
383 if (x + count > lpbi->biWidth)
384 count = lpbi->biWidth - x;
386 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
387 while (count > 2) {
388 INT i;
389 INT size = min(count, 254);
390 int bytes = ((size + 1) & (~1)) / 2;
391 BOOL extra_byte = bytes & 0x01;
393 *lpSizeImage += 2 + bytes + extra_byte;
394 assert(((*lpSizeImage) % 2) == 0);
395 count -= size;
396 *lpOut++ = 0;
397 *lpOut++ = size;
398 for (i = 0; i < size; i += 2) {
399 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
400 x++;
401 if (i + 1 < size) {
402 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
403 x++;
404 } else
405 clr2 = 0;
407 *lpOut++ = (clr1 << 4) | clr2;
409 if (extra_byte)
410 *lpOut++ = 0;
413 if (count > 0) {
414 /* too little for absoluting so we must encode them */
415 assert(count <= 2);
417 *lpSizeImage += 2;
418 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
419 x++;
420 if (count == 2) {
421 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
422 x++;
423 } else
424 clr2 = 0;
425 *lpOut++ = count;
426 *lpOut++ = (clr1 << 4) | clr2;
428 } else {
429 /* encode count pixel(s) */
430 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
431 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
433 x += count;
434 while (count > 0) {
435 INT size = min(count, 254);
437 *lpSizeImage += 2;
438 count -= size;
439 *lpOut++ = size;
440 *lpOut++ = clr1;
444 *ppOut = lpOut;
446 return x;
449 static INT MSRLE32_CompressRLE8Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
451 LPBYTE lpOut = *ppOut;
452 INT count, pos;
453 WORD clr;
455 assert(lpbi->biBitCount <= 8);
456 assert(lpbi->biCompression == BI_RGB);
458 /* try to encode as much as possible */
459 pos = x;
460 clr = lpC[pos++];
461 for (count = 1; pos < lpbi->biWidth; count++) {
462 if (ColorCmp(clr, lpC[pos++]) > lDist)
463 break;
466 if (count < 2) {
467 /* add some more pixels for absoluting if possible */
468 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
470 assert(count > 0);
472 /* check for over end of line */
473 if (x + count > lpbi->biWidth)
474 count = lpbi->biWidth - x;
476 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
477 while (count > 2) {
478 INT i;
479 INT size = min(count, 255);
480 BOOL extra_byte = size % 2;
482 *lpSizeImage += 2 + size + extra_byte;
483 count -= size;
484 *lpOut++ = 0;
485 *lpOut++ = size;
486 for (i = 0; i < size; i++) {
487 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
488 x++;
490 if (extra_byte)
491 *lpOut++ = 0;
493 if (count > 0) {
494 /* too little for absoluting so we must encode them even if it's expensive! */
495 assert(count <= 2);
497 *lpSizeImage += 2 * count;
498 *lpOut++ = 1;
499 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
500 x++;
502 if (count == 2) {
503 *lpOut++ = 1;
504 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
505 x++;
508 } else {
509 /* encode count pixel(s) */
510 clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
512 /* optimize end of line */
513 if (x + count + 1 == lpbi->biWidth)
514 count++;
516 x += count;
517 while (count > 0) {
518 INT size = min(count, 255);
520 *lpSizeImage += 2;
521 count -= size;
522 *lpOut++ = size;
523 *lpOut++ = clr;
527 *ppOut = lpOut;
529 return x;
532 LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
534 LPWORD lpC;
535 LONG lLine, lInLine, lDist;
536 LPBYTE lpOutStart = lpOut;
538 /* pre-conditions */
539 assert(pi != NULL && lpbiOut != NULL);
540 assert(lpIn != NULL && lpOut != NULL);
541 assert(pi->pCurFrame != NULL);
543 lpC = pi->pCurFrame;
544 lDist = QUALITY_to_DIST(pi->dwQuality);
545 lInLine = DIBWIDTHBYTES(*lpbiIn);
546 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
548 lpbiOut->biSizeImage = 0;
549 if (isKey) {
550 /* keyframe -- convert internal frame to output format */
551 INT x, y;
553 for (y = 0; y < lpbiOut->biHeight; y++) {
554 x = 0;
556 do {
557 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
558 &lpOut, &lpbiOut->biSizeImage);
559 } while (x < lpbiOut->biWidth);
561 lpC += lLine;
562 lpIn += lInLine;
564 /* add EOL -- end of line */
565 lpbiOut->biSizeImage += 2;
566 *(LPWORD)lpOut = 0;
567 lpOut += sizeof(WORD);
568 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
570 } else {
571 /* delta-frame -- compute delta between last and this internal frame */
572 LPWORD lpP;
573 INT x, y;
574 INT jumpx, jumpy;
576 assert(pi->pPrevFrame != NULL);
578 lpP = pi->pPrevFrame;
579 jumpy = 0;
580 jumpx = -1;
582 for (y = 0; y < lpbiOut->biHeight; y++) {
583 x = 0;
585 do {
586 INT count, pos;
588 if (jumpx == -1)
589 jumpx = x;
590 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
591 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
592 break;
595 if (pos == lpbiOut->biWidth && count > 8) {
596 /* (count > 8) secures that we will save space */
597 jumpy++;
598 break;
599 } else if (jumpy || jumpx != pos) {
600 /* time to jump */
601 assert(jumpx != -1);
603 if (pos < jumpx) {
604 /* can only jump in positive direction -- jump until EOL, EOL */
605 INT w = lpbiOut->biWidth - jumpx;
607 assert(jumpy > 0);
608 assert(w >= 4);
610 jumpx = 0;
611 jumpy--;
612 /* if (w % 255 == 2) then equal costs
613 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
614 * else it will be cheaper
616 while (w > 0) {
617 lpbiOut->biSizeImage += 4;
618 *lpOut++ = 0;
619 *lpOut++ = 2;
620 *lpOut = min(w, 255);
621 w -= *lpOut++;
622 *lpOut++ = 0;
624 /* add EOL -- end of line */
625 lpbiOut->biSizeImage += 2;
626 *((LPWORD)lpOut) = 0;
627 lpOut += sizeof(WORD);
630 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
632 /* write out real jump(s) */
633 while (jumpy || pos != jumpx) {
634 lpbiOut->biSizeImage += 4;
635 *lpOut++ = 0;
636 *lpOut++ = 2;
637 *lpOut = min(pos - jumpx, 255);
638 x += *lpOut;
639 jumpx += *lpOut++;
640 *lpOut = min(jumpy, 255);
641 jumpy -= *lpOut++;
644 jumpy = 0;
647 jumpx = -1;
649 if (x < lpbiOut->biWidth) {
650 /* skipped the 'same' things corresponding to previous frame */
651 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
652 &lpOut, &lpbiOut->biSizeImage);
654 } while (x < lpbiOut->biWidth);
656 lpP += lLine;
657 lpC += lLine;
658 lpIn += lInLine;
660 if (jumpy == 0) {
661 assert(jumpx == -1);
663 /* add EOL -- end of line */
664 lpbiOut->biSizeImage += 2;
665 *((LPWORD)lpOut) = 0;
666 lpOut += sizeof(WORD);
667 assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
671 /* add EOL -- will be changed to EOI */
672 lpbiOut->biSizeImage += 2;
673 *((LPWORD)lpOut) = 0;
674 lpOut += sizeof(WORD);
677 /* change EOL to EOI -- end of image */
678 lpOut[-1] = 1;
679 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
681 return ICERR_OK;
684 LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
686 LPWORD lpC;
687 LONG lDist, lInLine, lLine;
688 LPBYTE lpOutStart = lpOut;
690 assert(pi != NULL && lpbiOut != NULL);
691 assert(lpIn != NULL && lpOut != NULL);
692 assert(pi->pCurFrame != NULL);
694 lpC = pi->pCurFrame;
695 lDist = QUALITY_to_DIST(pi->dwQuality);
696 lInLine = DIBWIDTHBYTES(*lpbiIn);
697 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
699 lpbiOut->biSizeImage = 0;
700 if (isKey) {
701 /* keyframe -- convert internal frame to output format */
702 INT x, y;
704 for (y = 0; y < lpbiOut->biHeight; y++) {
705 x = 0;
707 do {
708 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
709 &lpOut, &lpbiOut->biSizeImage);
710 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
711 } while (x < lpbiOut->biWidth);
713 lpC += lLine;
714 lpIn += lInLine;
716 /* add EOL -- end of line */
717 lpbiOut->biSizeImage += 2;
718 *((LPWORD)lpOut) = 0;
719 lpOut += sizeof(WORD);
720 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
722 } else {
723 /* delta-frame -- compute delta between last and this internal frame */
724 LPWORD lpP;
725 INT x, y;
726 INT jumpx, jumpy;
728 assert(pi->pPrevFrame != NULL);
730 lpP = pi->pPrevFrame;
731 jumpx = -1;
732 jumpy = 0;
734 for (y = 0; y < lpbiOut->biHeight; y++) {
735 x = 0;
737 do {
738 INT count, pos;
740 if (jumpx == -1)
741 jumpx = x;
742 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
743 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
744 break;
747 if (pos == lpbiOut->biWidth && count > 4) {
748 /* (count > 4) secures that we will save space */
749 jumpy++;
750 break;
751 } else if (jumpy || jumpx != pos) {
752 /* time to jump */
753 assert(jumpx != -1);
755 if (pos < jumpx) {
756 /* can only jump in positive direction -- do an EOL then jump */
757 assert(jumpy > 0);
759 jumpx = 0;
760 jumpy--;
762 /* add EOL -- end of line */
763 lpbiOut->biSizeImage += 2;
764 *((LPWORD)lpOut) = 0;
765 lpOut += sizeof(WORD);
766 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
769 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
771 /* write out real jump(s) */
772 while (jumpy || pos != jumpx) {
773 lpbiOut->biSizeImage += 4;
774 *lpOut++ = 0;
775 *lpOut++ = 2;
776 *lpOut = min(pos - jumpx, 255);
777 jumpx += *lpOut++;
778 *lpOut = min(jumpy, 255);
779 jumpy -= *lpOut++;
781 x = pos;
783 jumpy = 0;
786 jumpx = -1;
788 if (x < lpbiOut->biWidth) {
789 /* skip the 'same' things corresponding to previous frame */
790 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
791 &lpOut, &lpbiOut->biSizeImage);
792 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
794 } while (x < lpbiOut->biWidth);
796 lpP += lLine;
797 lpC += lLine;
798 lpIn += lInLine;
800 if (jumpy == 0) {
801 /* add EOL -- end of line */
802 lpbiOut->biSizeImage += 2;
803 *((LPWORD)lpOut) = 0;
804 lpOut += sizeof(WORD);
805 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
809 /* add EOL -- will be changed to EOI */
810 lpbiOut->biSizeImage += 2;
811 *((LPWORD)lpOut) = 0;
812 lpOut += sizeof(WORD);
815 /* change EOL to EOI -- end of image */
816 lpOut[-1] = 1;
817 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
819 return ICERR_OK;
822 /*****************************************************************************/
824 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
825 LPBYTE lpIn, LPBYTE lpOut)
827 int bytes_per_pixel;
828 int line_size;
829 int pixel_ptr = 0;
830 int i;
831 BOOL bEndFlag = FALSE;
833 assert(pi != NULL);
834 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
835 assert(lpIn != NULL && lpOut != NULL);
837 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
838 line_size = DIBWIDTHBYTES(*lpbi);
840 do {
841 BYTE code0, code1;
843 code0 = *lpIn++;
844 code1 = *lpIn++;
846 if (code0 == 0) {
847 int extra_byte;
849 switch (code1) {
850 case 0: /* EOL - end of line */
851 pixel_ptr = 0;
852 lpOut += line_size;
853 break;
854 case 1: /* EOI - end of image */
855 bEndFlag = TRUE;
856 break;
857 case 2: /* skip */
858 pixel_ptr += *lpIn++ * bytes_per_pixel;
859 lpOut += *lpIn++ * line_size;
860 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
861 pixel_ptr = 0;
862 lpOut += line_size;
864 break;
865 default: /* absolute mode */
866 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
868 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
869 return ICERR_ERROR;
871 code0 = code1;
872 for (i = 0; i < code0 / 2; i++) {
873 if (bytes_per_pixel == 1) {
874 code1 = lpIn[i];
875 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
876 if (2 * i + 1 <= code0)
877 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
878 } else if (bytes_per_pixel == 2) {
879 code1 = lpIn[i] >> 4;
880 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
881 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
883 if (2 * i + 1 <= code0) {
884 code1 = lpIn[i] & 0x0F;
885 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
886 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
888 } else {
889 code1 = lpIn[i] >> 4;
890 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
891 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
892 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
893 pixel_ptr += bytes_per_pixel;
895 if (2 * i + 1 <= code0) {
896 code1 = lpIn[i] & 0x0F;
897 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
898 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
899 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
900 pixel_ptr += bytes_per_pixel;
904 if (code0 & 0x01) {
905 if (bytes_per_pixel == 1) {
906 code1 = lpIn[i];
907 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
908 } else if (bytes_per_pixel == 2) {
909 code1 = lpIn[i] >> 4;
910 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
911 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
912 } else {
913 code1 = lpIn[i] >> 4;
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;
919 lpIn++;
921 lpIn += code0 / 2;
923 /* if the RLE code is odd, skip a byte in the stream */
924 if (extra_byte)
925 lpIn++;
927 } else {
928 /* coded mode */
929 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
930 return ICERR_ERROR;
932 if (bytes_per_pixel == 1) {
933 BYTE c1 = pi->palette_map[(code1 >> 4)];
934 BYTE c2 = pi->palette_map[(code1 & 0x0F)];
936 for (i = 0; i < code0; i++) {
937 if ((i & 1) == 0)
938 lpOut[pixel_ptr++] = c1;
939 else
940 lpOut[pixel_ptr++] = c2;
942 } else if (bytes_per_pixel == 2) {
943 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
944 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
946 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
947 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
949 for (i = 0; i < code0; i++) {
950 if ((i & 1) == 0) {
951 lpOut[pixel_ptr++] = hi1;
952 lpOut[pixel_ptr++] = lo1;
953 } else {
954 lpOut[pixel_ptr++] = hi2;
955 lpOut[pixel_ptr++] = lo2;
958 } else {
959 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
960 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
961 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
963 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
964 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
965 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
967 for (i = 0; i < code0; i++) {
968 if ((i & 1) == 0) {
969 lpOut[pixel_ptr + 0] = b1;
970 lpOut[pixel_ptr + 1] = g1;
971 lpOut[pixel_ptr + 2] = r1;
972 } else {
973 lpOut[pixel_ptr + 0] = b2;
974 lpOut[pixel_ptr + 1] = g2;
975 lpOut[pixel_ptr + 2] = r2;
977 pixel_ptr += bytes_per_pixel;
981 } while (! bEndFlag);
983 return ICERR_OK;
986 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
987 LPBYTE lpIn, LPBYTE lpOut)
989 int bytes_per_pixel;
990 int line_size;
991 int pixel_ptr = 0;
992 BOOL bEndFlag = FALSE;
994 assert(pi != NULL);
995 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
996 assert(lpIn != NULL && lpOut != NULL);
998 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
999 line_size = DIBWIDTHBYTES(*lpbi);
1001 do {
1002 BYTE code0, code1;
1004 code0 = *lpIn++;
1005 code1 = *lpIn++;
1007 if (code0 == 0) {
1008 int extra_byte;
1010 switch (code1) {
1011 case 0: /* EOL - end of line */
1012 pixel_ptr = 0;
1013 lpOut += line_size;
1014 break;
1015 case 1: /* EOI - end of image */
1016 bEndFlag = TRUE;
1017 break;
1018 case 2: /* skip */
1019 pixel_ptr += *lpIn++ * bytes_per_pixel;
1020 lpOut += *lpIn++ * line_size;
1021 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1022 pixel_ptr = 0;
1023 lpOut += line_size;
1025 break;
1026 default: /* absolute mode */
1027 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1028 WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1029 return ICERR_ERROR;
1031 extra_byte = code1 & 0x01;
1033 code0 = code1;
1034 while (code0--) {
1035 code1 = *lpIn++;
1036 if (bytes_per_pixel == 1) {
1037 lpOut[pixel_ptr] = pi->palette_map[code1];
1038 } else if (bytes_per_pixel == 2) {
1039 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1040 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1041 } else {
1042 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1043 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1044 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1046 pixel_ptr += bytes_per_pixel;
1049 /* if the RLE code is odd, skip a byte in the stream */
1050 if (extra_byte)
1051 lpIn++;
1053 } else {
1054 /* coded mode */
1055 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1056 WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1057 return ICERR_ERROR;
1060 if (bytes_per_pixel == 1) {
1061 code1 = pi->palette_map[code1];
1062 while (code0--)
1063 lpOut[pixel_ptr++] = code1;
1064 } else if (bytes_per_pixel == 2) {
1065 BYTE hi = pi->palette_map[code1 * 2 + 0];
1066 BYTE lo = pi->palette_map[code1 * 2 + 1];
1068 while (code0--) {
1069 lpOut[pixel_ptr + 0] = hi;
1070 lpOut[pixel_ptr + 1] = lo;
1071 pixel_ptr += bytes_per_pixel;
1073 } else {
1074 BYTE r = pi->palette_map[code1 * 4 + 2];
1075 BYTE g = pi->palette_map[code1 * 4 + 1];
1076 BYTE b = pi->palette_map[code1 * 4 + 0];
1078 while (code0--) {
1079 lpOut[pixel_ptr + 0] = b;
1080 lpOut[pixel_ptr + 1] = g;
1081 lpOut[pixel_ptr + 2] = r;
1082 pixel_ptr += bytes_per_pixel;
1086 } while (! bEndFlag);
1088 return ICERR_OK;
1091 /*****************************************************************************/
1093 static CodecInfo* Open(LPICOPEN icinfo)
1095 CodecInfo* pi = NULL;
1097 if (icinfo == NULL) {
1098 TRACE("(NULL)\n");
1099 return (LPVOID)0xFFFF0000;
1102 if (icinfo->fccType != ICTYPE_VIDEO) return NULL;
1104 TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo,
1105 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1106 icinfo->fccHandler, (char*)&icinfo->fccHandler,
1107 icinfo->dwVersion,icinfo->dwFlags);
1109 switch (icinfo->fccHandler) {
1110 case FOURCC_RLE:
1111 case FOURCC_RLE4:
1112 case FOURCC_RLE8:
1113 case FOURCC_MRLE:
1114 break;
1115 case mmioFOURCC('m','r','l','e'):
1116 icinfo->fccHandler = FOURCC_MRLE;
1117 break;
1118 default:
1119 WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1120 icinfo->fccHandler,(char*)&icinfo->fccHandler);
1121 return NULL;
1124 pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
1126 if (pi != NULL) {
1127 pi->fccHandler = icinfo->fccHandler;
1129 pi->bCompress = FALSE;
1130 pi->dwQuality = MSRLE32_DEFAULTQUALITY;
1131 pi->nPrevFrame = -1;
1132 pi->pPrevFrame = pi->pCurFrame = NULL;
1134 pi->bDecompress = FALSE;
1135 pi->palette_map = NULL;
1138 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1140 return pi;
1143 static LRESULT Close(CodecInfo *pi)
1145 TRACE("(%p)\n", pi);
1147 /* pre-condition */
1148 assert(pi != NULL);
1150 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1151 CompressEnd(pi);
1153 LocalFree((HLOCAL)pi);
1154 return 1;
1157 static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1159 /* pre-condition */
1160 assert(pi != NULL);
1162 /* check parameters */
1163 if (icinfo == NULL)
1164 return sizeof(ICINFO);
1165 if (dwSize < sizeof(ICINFO))
1166 return 0;
1168 icinfo->dwSize = sizeof(ICINFO);
1169 icinfo->fccType = ICTYPE_VIDEO;
1170 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1171 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1172 icinfo->dwVersion = ICVERSION;
1173 icinfo->dwVersionICM = ICVERSION;
1175 LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
1176 LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
1178 return sizeof(ICINFO);
1181 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1183 /* pre-condition */
1184 assert(pi != NULL);
1186 if (lQuality == -1)
1187 lQuality = MSRLE32_DEFAULTQUALITY;
1188 else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1189 return ICERR_BADPARAM;
1191 pi->dwQuality = (DWORD)lQuality;
1193 return ICERR_OK;
1196 static LRESULT Configure(CodecInfo *pi, HWND hWnd)
1198 /* pre-condition */
1199 assert(pi != NULL);
1201 /* FIXME */
1202 return ICERR_OK;
1205 static LRESULT About(CodecInfo *pi, HWND hWnd)
1207 CHAR szTitle[20];
1208 CHAR szAbout[128];
1210 /* pre-condition */
1211 assert(MSRLE32_hModule != 0);
1213 LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
1214 LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
1216 MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1218 return ICERR_OK;
1221 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1222 LPBITMAPINFOHEADER lpbiOut)
1224 LRESULT size;
1226 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1228 /* pre-condition */
1229 assert(pi != NULL);
1231 /* check parameters -- need at least input format */
1232 if (lpbiIn == NULL) {
1233 if (lpbiOut != NULL)
1234 return ICERR_BADPARAM;
1235 return 0;
1238 /* handle unsupported input format */
1239 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1240 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1242 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1244 switch (pi->fccHandler) {
1245 case FOURCC_RLE4:
1246 size = 1 << 4;
1247 break;
1248 case FOURCC_RLE8:
1249 size = 1 << 8;
1250 break;
1251 case FOURCC_RLE:
1252 case FOURCC_MRLE:
1253 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1254 break;
1255 default:
1256 return ICERR_ERROR;
1259 if (lpbiIn->biClrUsed != 0)
1260 size = lpbiIn->biClrUsed;
1262 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1264 if (lpbiOut != NULL) {
1265 lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
1266 lpbiOut->biWidth = lpbiIn->biWidth;
1267 lpbiOut->biHeight = lpbiIn->biHeight;
1268 lpbiOut->biPlanes = 1;
1269 if (pi->fccHandler == FOURCC_RLE4 ||
1270 lpbiIn->biBitCount <= 4) {
1271 lpbiOut->biCompression = BI_RLE4;
1272 lpbiOut->biBitCount = 4;
1273 } else {
1274 lpbiOut->biCompression = BI_RLE8;
1275 lpbiOut->biBitCount = 8;
1277 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
1278 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1279 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1280 if (lpbiIn->biClrUsed == 0)
1281 size = 1<<lpbiIn->biBitCount;
1282 else
1283 size = lpbiIn->biClrUsed;
1284 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
1285 lpbiOut->biClrImportant = 0;
1287 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1288 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1290 return ICERR_OK;
1291 } else
1292 return size;
1295 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1296 LPCBITMAPINFOHEADER lpbiOut)
1298 /* pre-condition */
1299 assert(pi != NULL);
1301 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1303 /* check parameter -- need at least one format */
1304 if (lpbiIn == NULL && lpbiOut == NULL)
1305 return 0;
1306 /* check if the given format is supported */
1307 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1308 return 0;
1310 /* the worst case is coding the complete image in absolute mode. */
1311 if (lpbiIn)
1312 return MSRLE32_GetMaxCompressedSize(lpbiIn);
1313 else
1314 return MSRLE32_GetMaxCompressedSize(lpbiOut);
1317 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1318 LPCBITMAPINFOHEADER lpbiOut)
1320 /* pre-condition */
1321 assert(pi != NULL);
1323 /* need at least one format */
1324 if (lpbiIn == NULL && lpbiOut == NULL)
1325 return ICERR_BADPARAM;
1327 /* check input format if given */
1328 if (lpbiIn != NULL) {
1329 if (!isSupportedDIB(lpbiIn))
1330 return ICERR_BADFORMAT;
1332 /* for 4-bit need an even width */
1333 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1334 return ICERR_BADFORMAT;
1336 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1337 return ICERR_UNSUPPORTED;
1338 else if (lpbiIn->biBitCount > 8)
1339 return ICERR_UNSUPPORTED;
1342 /* check output format if given */
1343 if (lpbiOut != NULL) {
1344 if (!isSupportedMRLE(lpbiOut))
1345 return ICERR_BADFORMAT;
1347 if (lpbiIn != NULL) {
1348 if (lpbiIn->biWidth != lpbiOut->biWidth)
1349 return ICERR_UNSUPPORTED;
1350 if (lpbiIn->biHeight != lpbiOut->biHeight)
1351 return ICERR_UNSUPPORTED;
1352 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1353 return ICERR_UNSUPPORTED;
1357 return ICERR_OK;
1360 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1361 LPCBITMAPINFOHEADER lpbiOut)
1363 const RGBQUAD *rgbIn;
1364 const RGBQUAD *rgbOut;
1365 UINT i;
1366 size_t size;
1368 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1370 /* pre-condition */
1371 assert(pi != NULL);
1373 /* check parameters -- need both formats */
1374 if (lpbiIn == NULL || lpbiOut == NULL)
1375 return ICERR_BADPARAM;
1376 /* And both must be supported */
1377 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1378 return ICERR_BADFORMAT;
1380 /* FIXME: cannot compress and decompress at same time! */
1381 if (pi->bDecompress) {
1382 FIXME("cannot compress and decompress at same time!\n");
1383 return ICERR_ERROR;
1386 if (pi->bCompress)
1387 CompressEnd(pi);
1389 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1390 pi->pPrevFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1391 if (pi->pPrevFrame == NULL)
1392 return ICERR_MEMORY;
1393 pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1394 if (pi->pCurFrame == NULL) {
1395 CompressEnd(pi);
1396 return ICERR_MEMORY;
1398 pi->nPrevFrame = -1;
1399 pi->bCompress = TRUE;
1401 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1402 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1404 switch (lpbiOut->biBitCount) {
1405 case 4:
1406 case 8:
1407 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1408 if (pi->palette_map == NULL) {
1409 CompressEnd(pi);
1410 return ICERR_MEMORY;
1413 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1414 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1416 break;
1419 return ICERR_OK;
1422 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1424 int i;
1426 TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize);
1428 /* pre-condition */
1429 assert(pi != NULL);
1431 /* check parameters */
1432 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1433 return ICERR_BADPARAM;
1434 if (!lpic->lpbiOutput || !lpic->lpOutput ||
1435 !lpic->lpbiInput || !lpic->lpInput)
1436 return ICERR_BADPARAM;
1438 TRACE("lpic={0x%lX,%p,%p,%p,%p,%p,%p,%ld,%lu,%lu,%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);
1440 if (! pi->bCompress) {
1441 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1442 if (hr != ICERR_OK)
1443 return hr;
1444 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1445 return ICERR_BADFORMAT;
1447 if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1448 /* we continue in the sequence so we need to initialize
1449 * our internal framedata */
1451 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1452 } else if (lpic->lFrameNum == pi->nPrevFrame) {
1453 /* Oops, compress same frame again ? Okay, as you wish.
1454 * No need to recompute internal framedata, because we only swapped buffers */
1455 LPWORD pTmp = pi->pPrevFrame;
1457 pi->pPrevFrame = pi->pCurFrame;
1458 pi->pCurFrame = pTmp;
1459 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1460 LPWORD pTmp;
1462 WARN(": prev=%ld cur=%ld gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1463 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1464 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1465 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1466 return ICERR_BADFORMAT;
1468 WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1469 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1471 /* swap buffers for current and previous frame */
1472 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1473 pTmp = pi->pPrevFrame;
1474 pi->pPrevFrame = pi->pCurFrame;
1475 pi->pCurFrame = pTmp;
1476 pi->nPrevFrame = lpic->lFrameNum;
1479 for (i = 0; i < 3; i++) {
1480 SetQuality(pi, lpic->dwQuality);
1482 lpic->lpbiOutput->biSizeImage = 0;
1484 if (lpic->lpbiOutput->biBitCount == 4)
1485 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1486 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1487 else
1488 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1489 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1491 if (lpic->dwFrameSize == 0 ||
1492 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1493 break;
1495 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1496 if (lpic->lpbiOutput->biBitCount == 4)
1497 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1498 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1499 else
1500 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1501 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1503 if (lpic->dwFrameSize == 0 ||
1504 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1505 WARN("switched to keyframe, was small enough!\n");
1506 *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1507 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
1508 StreamFromFOURCC(*lpic->lpckid));
1509 break;
1513 if (lpic->dwQuality < 1000)
1514 break;
1516 lpic->dwQuality -= 1000; /* reduce quality by 10% */
1519 { /* swap buffer for current and previous frame */
1520 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1521 register LPWORD pTmp = pi->pPrevFrame;
1523 pi->pPrevFrame = pi->pCurFrame;
1524 pi->pCurFrame = pTmp;
1525 pi->nPrevFrame = lpic->lFrameNum;
1528 return ICERR_OK;
1531 static LRESULT CompressEnd(CodecInfo *pi)
1533 TRACE("(%p)\n",pi);
1535 if (pi != NULL) {
1536 if (pi->pPrevFrame != NULL)
1537 GlobalFreePtr(pi->pPrevFrame);
1538 if (pi->pCurFrame != NULL)
1539 GlobalFreePtr(pi->pCurFrame);
1540 pi->pPrevFrame = NULL;
1541 pi->pCurFrame = NULL;
1542 pi->nPrevFrame = -1;
1543 pi->bCompress = FALSE;
1546 return ICERR_OK;
1549 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1550 LPBITMAPINFOHEADER lpbiOut)
1552 DWORD size;
1554 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1556 /* pre-condition */
1557 assert(pi != NULL);
1559 if (lpbiIn == NULL)
1560 return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1562 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1563 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1565 size = lpbiIn->biSize;
1567 if (lpbiIn->biBitCount <= 8)
1568 size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1570 if (lpbiOut != NULL) {
1571 memcpy(lpbiOut, lpbiIn, size);
1572 lpbiOut->biCompression = BI_RGB;
1573 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1575 return ICERR_OK;
1576 } else
1577 return size;
1580 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1581 LPCBITMAPINFOHEADER lpbiOut)
1583 LRESULT hr = ICERR_OK;
1585 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1587 /* pre-condition */
1588 assert(pi != NULL);
1590 /* need at least one format */
1591 if (lpbiIn == NULL && lpbiOut == NULL)
1592 return ICERR_BADPARAM;
1594 /* check input format if given */
1595 if (lpbiIn != NULL) {
1596 if (!isSupportedMRLE(lpbiIn))
1597 return ICERR_BADFORMAT;
1600 /* check output format if given */
1601 if (lpbiOut != NULL) {
1602 if (!isSupportedDIB(lpbiOut))
1603 hr = ICERR_BADFORMAT;
1605 if (lpbiIn != NULL) {
1606 if (lpbiIn->biWidth != lpbiOut->biWidth)
1607 hr = ICERR_UNSUPPORTED;
1608 if (lpbiIn->biHeight != lpbiOut->biHeight)
1609 hr = ICERR_UNSUPPORTED;
1610 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1611 hr = ICERR_UNSUPPORTED;
1615 return hr;
1618 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1619 LPCBITMAPINFOHEADER lpbiOut)
1621 const RGBQUAD *rgbIn;
1622 const RGBQUAD *rgbOut;
1623 UINT i;
1625 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1627 /* pre-condition */
1628 assert(pi != NULL);
1630 /* check parameters */
1631 if (lpbiIn == NULL || lpbiOut == NULL)
1632 return ICERR_BADPARAM;
1633 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1634 return ICERR_BADFORMAT;
1636 /* FIXME: cannot compress and decompress at a time! */
1637 if (pi->bCompress) {
1638 FIXME("cannot compress and decompress at same time!\n");
1639 return ICERR_ERROR;
1642 if (pi->bDecompress)
1643 DecompressEnd(pi);
1645 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1646 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1648 switch (lpbiOut->biBitCount) {
1649 case 4:
1650 case 8:
1651 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1652 if (pi->palette_map == NULL)
1653 return ICERR_MEMORY;
1655 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1656 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1658 break;
1659 case 15:
1660 case 16:
1661 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1662 if (pi->palette_map == NULL)
1663 return ICERR_MEMORY;
1665 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1666 WORD color;
1668 if (lpbiOut->biBitCount == 15)
1669 color = ((rgbIn[i].rgbRed >> 3) << 10)
1670 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1671 else
1672 color = ((rgbIn[i].rgbRed >> 3) << 11)
1673 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1675 pi->palette_map[i * 2 + 1] = color >> 8;
1676 pi->palette_map[i * 2 + 0] = color & 0xFF;
1678 break;
1679 case 24:
1680 case 32:
1681 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1682 if (pi->palette_map == NULL)
1683 return ICERR_MEMORY;
1684 memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1685 break;
1688 pi->bDecompress = TRUE;
1690 return ICERR_OK;
1693 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1695 TRACE("(%p,%p,%lu)\n",pi,pic,dwSize);
1697 /* pre-condition */
1698 assert(pi != NULL);
1700 /* check parameters */
1701 if (pic == NULL)
1702 return ICERR_BADPARAM;
1703 if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1704 pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1705 return ICERR_BADPARAM;
1707 /* check formats */
1708 if (! pi->bDecompress) {
1709 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1710 if (hr != ICERR_OK)
1711 return hr;
1712 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1713 return ICERR_BADFORMAT;
1715 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
1716 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1718 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1719 if (pic->lpbiInput->biBitCount == 4)
1720 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1721 else
1722 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1725 static LRESULT DecompressEnd(CodecInfo *pi)
1727 TRACE("(%p)\n",pi);
1729 /* pre-condition */
1730 assert(pi != NULL);
1732 pi->bDecompress = FALSE;
1734 if (pi->palette_map != NULL) {
1735 LocalFree((HLOCAL)pi->palette_map);
1736 pi->palette_map = NULL;
1739 return ICERR_OK;
1742 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1743 LPBITMAPINFOHEADER lpbiOut)
1745 int size;
1747 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1749 /* pre-condition */
1750 assert(pi != NULL);
1752 /* check parameters */
1753 if (lpbiIn == NULL || lpbiOut == NULL)
1754 return ICERR_BADPARAM;
1756 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1757 return ICERR_BADFORMAT;
1759 if (lpbiOut->biBitCount > 8)
1760 return ICERR_ERROR;
1762 if (lpbiIn->biBitCount <= 8) {
1763 if (lpbiIn->biClrUsed > 0)
1764 size = lpbiIn->biClrUsed;
1765 else
1766 size = (1 << lpbiIn->biBitCount);
1768 lpbiOut->biClrUsed = size;
1770 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1771 } /* else could never occur ! */
1773 return ICERR_OK;
1776 /* DriverProc - entry point for an installable driver */
1777 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
1778 LPARAM lParam1, LPARAM lParam2)
1780 CodecInfo *pi = (CodecInfo*)dwDrvID;
1782 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
1784 switch (uMsg) {
1785 /* standard driver messages */
1786 case DRV_LOAD:
1787 return DRVCNF_OK;
1788 case DRV_OPEN:
1789 return (LRESULT)Open((ICOPEN*)lParam2);
1790 case DRV_CLOSE:
1791 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1792 Close(pi);
1793 return DRVCNF_OK;
1794 case DRV_ENABLE:
1795 case DRV_DISABLE:
1796 return DRVCNF_OK;
1797 case DRV_FREE:
1798 return DRVCNF_OK;
1799 case DRV_QUERYCONFIGURE:
1800 return DRVCNF_CANCEL; /* FIXME */
1801 case DRV_CONFIGURE:
1802 return DRVCNF_OK; /* FIXME */
1803 case DRV_INSTALL:
1804 case DRV_REMOVE:
1805 return DRVCNF_OK;
1807 /* installable compression manager messages */
1808 case ICM_CONFIGURE:
1809 FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1810 if (lParam1 == -1)
1811 return ICERR_UNSUPPORTED; /* FIXME */
1812 else
1813 return Configure(pi, (HWND)lParam1);
1814 case ICM_ABOUT:
1815 if (lParam1 == -1)
1816 return ICERR_OK;
1817 else
1818 return About(pi, (HWND)lParam1);
1819 case ICM_GETSTATE:
1820 case ICM_SETSTATE:
1821 return 0; /* no state */
1822 case ICM_GETINFO:
1823 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1824 case ICM_GETDEFAULTQUALITY:
1825 if ((LPVOID)lParam1 != NULL) {
1826 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1827 return ICERR_OK;
1829 break;
1830 case ICM_GETQUALITY:
1831 if ((LPVOID)lParam1 != NULL) {
1832 *((LPDWORD)lParam1) = pi->dwQuality;
1833 return ICERR_OK;
1835 break;
1836 case ICM_SETQUALITY:
1837 return SetQuality(pi, *(LPLONG)lParam1);
1838 case ICM_COMPRESS_GET_FORMAT:
1839 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1840 (LPBITMAPINFOHEADER)lParam2);
1841 case ICM_COMPRESS_GET_SIZE:
1842 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1843 (LPCBITMAPINFOHEADER)lParam2);
1844 case ICM_COMPRESS_QUERY:
1845 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1846 (LPCBITMAPINFOHEADER)lParam2);
1847 case ICM_COMPRESS_BEGIN:
1848 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1849 (LPCBITMAPINFOHEADER)lParam2);
1850 case ICM_COMPRESS:
1851 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1852 case ICM_COMPRESS_END:
1853 return CompressEnd(pi);
1854 case ICM_DECOMPRESS_GET_FORMAT:
1855 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1856 (LPBITMAPINFOHEADER)lParam2);
1857 case ICM_DECOMPRESS_QUERY:
1858 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1859 (LPCBITMAPINFOHEADER)lParam2);
1860 case ICM_DECOMPRESS_BEGIN:
1861 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1862 (LPCBITMAPINFOHEADER)lParam2);
1863 case ICM_DECOMPRESS:
1864 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1865 case ICM_DECOMPRESS_END:
1866 return DecompressEnd(pi);
1867 case ICM_DECOMPRESS_SET_PALETTE:
1868 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1869 return ICERR_UNSUPPORTED;
1870 case ICM_DECOMPRESS_GET_PALETTE:
1871 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1872 (LPBITMAPINFOHEADER)lParam2);
1873 case ICM_GETDEFAULTKEYFRAMERATE:
1874 if ((LPVOID)lParam1 != NULL)
1875 *(LPDWORD)lParam1 = 15;
1876 return ICERR_OK;
1877 default:
1878 if (uMsg < DRV_USER)
1879 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1880 else
1881 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1884 return ICERR_UNSUPPORTED;
1887 /* DllMain - library initialization code */
1888 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1890 TRACE("(%p,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
1892 switch (dwReason) {
1893 case DLL_PROCESS_ATTACH:
1894 DisableThreadLibraryCalls(hModule);
1895 MSRLE32_hModule = hModule;
1896 break;
1898 case DLL_PROCESS_DETACH:
1899 break;
1902 return TRUE;