Fixed lvalue casts for new compiler.
[wine/wine-gecko.git] / dlls / msrle32 / msrle32.c
blobe4ee0bf34d603a7b9f1b6d584827145725f9c6f1
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? -- does 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 void LoadWideString(UINT id, LPWSTR str, INT len);
62 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
64 /* compression functions */
65 static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn);
66 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
67 static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
68 static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
70 /* decompression functions */
71 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
72 LPBYTE lpIn, LPBYTE lpOut);
73 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
74 LPBYTE lpIn, LPBYTE lpOut);
76 /* API functions */
77 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
78 LPBITMAPINFOHEADER lpbiOut);
79 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
80 LPCBITMAPINFOHEADER lpbiOut);
81 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
82 LPCBITMAPINFOHEADER lpbiOut);
83 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
84 LPCBITMAPINFOHEADER lpbiOut);
85 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
86 static LRESULT CompressEnd(CodecInfo *pi);
88 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
89 LPBITMAPINFOHEADER lpbiOut);
90 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
91 LPCBITMAPINFOHEADER lpbiOut);
92 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
93 LPCBITMAPINFOHEADER lpbiOut);
94 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
95 static LRESULT DecompressEnd(CodecInfo *pi);
96 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
97 LPBITMAPINFOHEADER lpbiOut);
99 /*****************************************************************************/
101 static void LoadWideString(UINT id, LPWSTR str, INT len)
103 char szTemp[80];
105 LoadStringA(MSRLE32_hModule, id, szTemp, sizeof(szTemp));
106 MultiByteToWideChar(CP_ACP, 0, szTemp, -1, str, len);
109 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
111 /* pre-conditions */
112 assert(lpbi != NULL);
114 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \
115 lpbi->biPlanes != 1)
116 return FALSE;
118 if (lpbi->biCompression == BI_RLE4) {
119 if (lpbi->biBitCount != 4 || \
120 (lpbi->biWidth % 2) != 0)
121 return FALSE;
122 } else if (lpbi->biCompression == BI_RLE8) {
123 if (lpbi->biBitCount != 8)
124 return FALSE;
125 } else
126 return FALSE;
128 return TRUE;
131 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
133 /* pre-conditions */
134 assert(lpbi != NULL);
136 /* check structure version/planes/compression */
137 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
138 lpbi->biPlanes != 1)
139 return FALSE;
140 if (lpbi->biCompression != BI_RGB &&
141 lpbi->biCompression != BI_BITFIELDS)
142 return FALSE;
144 /* check bit-depth */
145 if (lpbi->biBitCount != 1 &&
146 lpbi->biBitCount != 4 &&
147 lpbi->biBitCount != 8 &&
148 lpbi->biBitCount != 15 &&
149 lpbi->biBitCount != 16 &&
150 lpbi->biBitCount != 24 &&
151 lpbi->biBitCount != 32)
152 return FALSE;
154 /* check for size(s) */
155 if (!lpbi->biWidth || !lpbi->biHeight)
156 return FALSE; /* image with zero size, makes no sense so error ! */
157 if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
158 return FALSE; /* image too big ! */
160 /* check for non-existent colortable for hi- and true-color DIB's */
161 if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
162 return FALSE;
164 return TRUE;
167 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
169 INT diff = 0x00FFFFFF;
170 UINT i;
171 UINT idx = 0;
173 /* pre-conditions */
174 assert(clrs != NULL);
176 for (i = 0; i < count; i++) {
177 int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed);
178 int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
179 int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue);
181 r = r*r + g*g + b*b;
183 if (r < diff) {
184 idx = i;
185 diff = r;
186 if (diff == 0)
187 break;
191 return idx;
194 /*****************************************************************************/
196 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn)
198 WORD wIntensityTbl[256];
199 DWORD lInLine, lOutLine;
200 LPWORD lpOut;
201 UINT i;
202 LONG y;
204 /* pre-conditions */
205 assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
206 assert(pi->pCurFrame != NULL);
208 lInLine = DIBWIDTHBYTES(*lpbiIn);
209 lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
210 lpOut = pi->pCurFrame;
212 assert(lpbiIn->biClrUsed != 0);
215 const RGBQUAD *lp =
216 (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
218 for (i = 0; i < lpbiIn->biClrUsed; i++)
219 wIntensityTbl[i] = Intensity(lp[i]);
222 for (y = 0; y < lpbiIn->biHeight; y++) {
223 LONG x;
225 switch (lpbiIn->biBitCount) {
226 case 1:
227 for (x = 0; x < lpbiIn->biWidth / 8; x++) {
228 for (i = 0; i < 7; i++)
229 lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
231 break;
232 case 4:
233 for (x = 0; x < lpbiIn->biWidth / 2; x++) {
234 lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
235 lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
237 break;
238 case 8:
239 for (x = 0; x < lpbiIn->biWidth; x++)
240 lpOut[x] = wIntensityTbl[lpIn[x]];
241 break;
244 lpIn += lInLine;
245 lpOut += lOutLine;
249 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
251 LONG a, b, size;
253 /* pre-condition */
254 assert(lpbi != NULL);
256 a = lpbi->biWidth / 255;
257 b = lpbi->biWidth % 255;
258 if (lpbi->biBitCount <= 4) {
259 a /= 2;
260 b /= 2;
263 size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
264 return size * lpbi->biHeight;
267 /* lpP => current pos in previous frame
268 * lpA => previous pos in current frame
269 * lpB => current pos in current frame
271 static INT countDiffRLE4(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
273 INT count;
274 WORD clr1, clr2;
276 /* pre-conditions */
277 assert(lpA && lpB && lDist >= 0 && width > 0);
279 if (pos >= width)
280 return 0;
281 if (pos+1 == width)
282 return 1;
284 clr1 = lpB[pos++];
285 clr2 = lpB[pos];
287 count = 2;
288 while (pos + 1 < width) {
289 WORD clr3, clr4;
291 clr3 = lpB[++pos];
292 if (pos + 1 >= width)
293 return count + 1;
295 clr4 = lpB[++pos];
296 if (ColorCmp(clr1, clr3) <= lDist &&
297 ColorCmp(clr2, clr4) <= lDist) {
298 /* diff at end? -- look-ahead for atleast ?? more encodable pixel */
299 if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
300 ColorCmp(clr2,lpB[pos+2]) <= lDist) {
301 if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
302 ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
303 return count - 3; /* followed by atleast 4 encodable pixels */
304 return count - 2;
306 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
307 /* 'compare' with previous frame for end of diff */
308 INT count2 = 0;
310 /* FIXME */
312 if (count2 >= 8)
313 return count;
315 pos -= count2;
318 count += 2;
319 clr1 = clr3;
320 clr2 = clr4;
323 return count;
326 /* lpP => current pos in previous frame
327 * lpA => previous pos in current frame
328 * lpB => current pos in current frame
330 static INT countDiffRLE8(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
332 INT count;
334 for (count = 0; pos < width; pos++, count++) {
335 if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
336 /* diff at end? -- look-ahead for some more encodable pixel */
337 if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
338 return count - 1;
339 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
340 return count - 1;
341 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
342 /* 'compare' with previous frame for end of diff */
343 INT count2 = 0;
345 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
346 if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
347 break;
349 if (count2 > 4)
350 return count;
352 pos -= count2;
356 return count;
359 static INT MSRLE32_CompressRLE4Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
361 LPBYTE lpOut = *ppOut;
362 INT count, pos;
363 WORD clr1, clr2;
365 /* try to encode as many pixel as possible */
366 count = 1;
367 pos = x;
368 clr1 = lpC[pos++];
369 if (pos < lpbi->biWidth) {
370 clr2 = lpC[pos];
371 for (++count; pos + 1 < lpbi->biWidth; ) {
372 ++pos;
373 if (ColorCmp(clr1, lpC[pos]) > lDist)
374 break;
375 count++;
376 if (pos + 1 >= lpbi->biWidth)
377 break;
378 ++pos;
379 if (ColorCmp(clr2, lpC[pos]) > lDist)
380 break;
381 count++;
385 if (count < 4) {
386 /* add some pixel for absoluting if possible */
387 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
389 assert(count > 0);
391 /* check for near end of line */
392 if (x + count > lpbi->biWidth)
393 count = lpbi->biWidth - x;
395 /* absolute pixel(s) in groups of atleast 3 and maximal 254 pixel */
396 while (count > 2) {
397 INT i;
398 INT size = min(count, 254);
399 int bytes = ((size + 1) & (~1)) / 2;
400 BOOL extra_byte = bytes & 0x01;
402 *lpSizeImage += 2 + bytes + extra_byte;
403 assert(((*lpSizeImage) % 2) == 0);
404 count -= size;
405 *lpOut++ = 0;
406 *lpOut++ = size;
407 for (i = 0; i < size; i += 2) {
408 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
409 x++;
410 if (i + 1 < size) {
411 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
412 x++;
413 } else
414 clr2 = 0;
416 *lpOut++ = (clr1 << 4) | clr2;
418 if (extra_byte)
419 *lpOut++ = 0;
422 if (count > 0) {
423 /* too less for absoluting so we must encode them */
424 assert(count <= 2);
426 *lpSizeImage += 2;
427 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
428 x++;
429 if (count == 2) {
430 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
431 x++;
432 } else
433 clr2 = 0;
434 *lpOut++ = count;
435 *lpOut++ = (clr1 << 4) | clr2;
437 } else {
438 /* encode count pixel(s) */
439 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
440 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
442 x += count;
443 while (count > 0) {
444 INT size = min(count, 254);
446 *lpSizeImage += 2;
447 count -= size;
448 *lpOut++ = size;
449 *lpOut++ = clr1;
453 *ppOut = lpOut;
455 return x;
458 static INT MSRLE32_CompressRLE8Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
460 LPBYTE lpOut = *ppOut;
461 INT count, pos;
462 WORD clr;
464 assert(lpbi->biBitCount <= 8);
465 assert(lpbi->biCompression == BI_RGB);
467 /* try to encode as much as possible */
468 pos = x;
469 clr = lpC[pos++];
470 for (count = 1; pos < lpbi->biWidth; count++) {
471 if (ColorCmp(clr, lpC[pos++]) > lDist)
472 break;
475 if (count < 2) {
476 /* add some more pixels for absoluting if possible */
477 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
479 assert(count > 0);
481 /* check for over end of line */
482 if (x + count > lpbi->biWidth)
483 count = lpbi->biWidth - x;
485 /* absolute pixel(s) in groups of atleast 3 and maximal 255 pixels */
486 while (count > 2) {
487 INT i;
488 INT size = min(count, 255);
489 BOOL extra_byte = size % 2;
491 *lpSizeImage += 2 + size + extra_byte;
492 count -= size;
493 *lpOut++ = 0;
494 *lpOut++ = size;
495 for (i = 0; i < size; i++) {
496 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
497 x++;
499 if (extra_byte)
500 *lpOut++ = 0;
502 if (count > 0) {
503 /* too less for absoluting so we must encode them even if it's expensive! */
504 assert(count <= 2);
506 *lpSizeImage += 2 * count;
507 *lpOut++ = 1;
508 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
509 x++;
511 if (count == 2) {
512 *lpOut++ = 1;
513 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
514 x++;
517 } else {
518 /* encode count pixel(s) */
519 clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
521 /* optimize end of line */
522 if (x + count + 1 == lpbi->biWidth)
523 count++;
525 x += count;
526 while (count > 0) {
527 INT size = min(count, 255);
529 *lpSizeImage += 2;
530 count -= size;
531 *lpOut++ = size;
532 *lpOut++ = clr;
536 *ppOut = lpOut;
538 return x;
541 LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
543 LPWORD lpC;
544 LONG lLine, lInLine, lDist;
545 LPBYTE lpOutStart = lpOut;
547 /* pre-conditions */
548 assert(pi != NULL && lpbiOut != NULL);
549 assert(lpIn != NULL && lpOut != NULL);
550 assert(pi->pCurFrame != NULL);
552 lpC = pi->pCurFrame;
553 lDist = QUALITY_to_DIST(pi->dwQuality);
554 lInLine = DIBWIDTHBYTES(*lpbiIn);
555 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
557 lpbiOut->biSizeImage = 0;
558 if (isKey) {
559 /* keyframe -- convert internal frame to output format */
560 INT x, y;
562 for (y = 0; y < lpbiOut->biHeight; y++) {
563 x = 0;
565 do {
566 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
567 &lpOut, &lpbiOut->biSizeImage);
568 } while (x < lpbiOut->biWidth);
570 lpC += lLine;
571 lpIn += lInLine;
573 /* add EOL -- end of line */
574 lpbiOut->biSizeImage += 2;
575 *(LPWORD)lpOut = 0;
576 lpOut += sizeof(WORD);
577 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
579 } else {
580 /* delta-frame -- compute delta between last and this internal frame */
581 LPWORD lpP;
582 INT x, y;
583 INT jumpx, jumpy;
585 assert(pi->pPrevFrame != NULL);
587 lpP = pi->pPrevFrame;
588 jumpy = 0;
589 jumpx = -1;
591 for (y = 0; y < lpbiOut->biHeight; y++) {
592 x = 0;
594 do {
595 INT count, pos;
597 if (jumpx == -1)
598 jumpx = x;
599 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
600 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
601 break;
604 if (pos == lpbiOut->biWidth && count > 8) {
605 /* (count > 8) secures that we will save space */
606 jumpy++;
607 break;
608 } else if (jumpy || jumpx != pos) {
609 /* time to jump */
610 assert(jumpx != -1);
612 if (pos < jumpx) {
613 /* can only jump in positive direction -- jump until EOL, EOL */
614 INT w = lpbiOut->biWidth - jumpx;
616 assert(jumpy > 0);
617 assert(w >= 4);
619 jumpx = 0;
620 jumpy--;
621 /* if (w % 255 == 2) then equal costs
622 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
623 * else it will be cheaper
625 while (w > 0) {
626 lpbiOut->biSizeImage += 4;
627 *lpOut++ = 0;
628 *lpOut++ = 2;
629 *lpOut = min(w, 255);
630 w -= *lpOut++;
631 *lpOut++ = 0;
633 /* add EOL -- end of line */
634 lpbiOut->biSizeImage += 2;
635 *((LPWORD)lpOut) = 0;
636 lpOut += sizeof(WORD);
639 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
641 /* write out real jump(s) */
642 while (jumpy || pos != jumpx) {
643 lpbiOut->biSizeImage += 4;
644 *lpOut++ = 0;
645 *lpOut++ = 2;
646 *lpOut = min(pos - jumpx, 255);
647 x += *lpOut;
648 jumpx += *lpOut++;
649 *lpOut = min(jumpy, 255);
650 jumpy -= *lpOut++;
653 jumpy = 0;
656 jumpx = -1;
658 if (x < lpbiOut->biWidth) {
659 /* skipped the 'same' things corresponding to previous frame */
660 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
661 &lpOut, &lpbiOut->biSizeImage);
663 } while (x < lpbiOut->biWidth);
665 lpP += lLine;
666 lpC += lLine;
667 lpIn += lInLine;
669 if (jumpy == 0) {
670 assert(jumpx == -1);
672 /* add EOL -- end of line */
673 lpbiOut->biSizeImage += 2;
674 *((LPWORD)lpOut) = 0;
675 lpOut += sizeof(WORD);
676 assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
680 /* add EOL -- will be changed to EOI */
681 lpbiOut->biSizeImage += 2;
682 *((LPWORD)lpOut) = 0;
683 lpOut += sizeof(WORD);
686 /* change EOL to EOI -- end of image */
687 lpOut[-1] = 1;
688 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
690 return ICERR_OK;
693 LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
695 LPWORD lpC;
696 LONG lDist, lInLine, lLine;
697 LPBYTE lpOutStart = lpOut;
699 assert(pi != NULL && lpbiOut != NULL);
700 assert(lpIn != NULL && lpOut != NULL);
701 assert(pi->pCurFrame != NULL);
703 lpC = pi->pCurFrame;
704 lDist = QUALITY_to_DIST(pi->dwQuality);
705 lInLine = DIBWIDTHBYTES(*lpbiIn);
706 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
708 lpbiOut->biSizeImage = 0;
709 if (isKey) {
710 /* keyframe -- convert internal frame to output format */
711 INT x, y;
713 for (y = 0; y < lpbiOut->biHeight; y++) {
714 x = 0;
716 do {
717 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
718 &lpOut, &lpbiOut->biSizeImage);
719 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
720 } while (x < lpbiOut->biWidth);
722 lpC += lLine;
723 lpIn += lInLine;
725 /* add EOL -- end of line */
726 lpbiOut->biSizeImage += 2;
727 *((LPWORD)lpOut) = 0;
728 lpOut += sizeof(WORD);
729 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
731 } else {
732 /* delta-frame -- compute delta between last and this internal frame */
733 LPWORD lpP;
734 INT x, y;
735 INT jumpx, jumpy;
737 assert(pi->pPrevFrame != NULL);
739 lpP = pi->pPrevFrame;
740 jumpx = -1;
741 jumpy = 0;
743 for (y = 0; y < lpbiOut->biHeight; y++) {
744 x = 0;
746 do {
747 INT count, pos;
749 if (jumpx == -1)
750 jumpx = x;
751 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
752 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
753 break;
756 if (pos == lpbiOut->biWidth && count > 4) {
757 /* (count > 4) secures that we will save space */
758 jumpy++;
759 break;
760 } else if (jumpy || jumpx != pos) {
761 /* time to jump */
762 assert(jumpx != -1);
764 if (pos < jumpx) {
765 /* can only jump in positive direction -- do a EOL then jump */
766 assert(jumpy > 0);
768 jumpx = 0;
769 jumpy--;
771 /* add EOL -- end of line */
772 lpbiOut->biSizeImage += 2;
773 *((LPWORD)lpOut) = 0;
774 lpOut += sizeof(WORD);
775 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
778 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
780 /* write out real jump(s) */
781 while (jumpy || pos != jumpx) {
782 lpbiOut->biSizeImage += 4;
783 *lpOut++ = 0;
784 *lpOut++ = 2;
785 *lpOut = min(pos - jumpx, 255);
786 jumpx += *lpOut++;
787 *lpOut = min(jumpy, 255);
788 jumpy -= *lpOut++;
790 x = pos;
792 jumpy = 0;
795 jumpx = -1;
797 if (x < lpbiOut->biWidth) {
798 /* skip the 'same' things corresponding to previous frame */
799 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
800 &lpOut, &lpbiOut->biSizeImage);
801 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
803 } while (x < lpbiOut->biWidth);
805 lpP += lLine;
806 lpC += lLine;
807 lpIn += lInLine;
809 if (jumpy == 0) {
810 /* add EOL -- end of line */
811 lpbiOut->biSizeImage += 2;
812 *((LPWORD)lpOut) = 0;
813 lpOut += sizeof(WORD);
814 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
818 /* add EOL -- will be changed to EOI */
819 lpbiOut->biSizeImage += 2;
820 *((LPWORD)lpOut) = 0;
821 lpOut += sizeof(WORD);
824 /* change EOL to EOI -- end of image */
825 lpOut[-1] = 1;
826 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
828 return ICERR_OK;
831 /*****************************************************************************/
833 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
834 LPBYTE lpIn, LPBYTE lpOut)
836 int bytes_per_pixel;
837 int line_size;
838 int pixel_ptr = 0;
839 int i;
840 BOOL bEndFlag = FALSE;
842 assert(pi != NULL);
843 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
844 assert(lpIn != NULL && lpOut != NULL);
846 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
847 line_size = DIBWIDTHBYTES(*lpbi);
849 do {
850 BYTE code0, code1;
852 code0 = *lpIn++;
853 code1 = *lpIn++;
855 if (code0 == 0) {
856 int extra_byte;
858 switch (code1) {
859 case 0: /* EOL - end of line */
860 pixel_ptr = 0;
861 lpOut += line_size;
862 break;
863 case 1: /* EOI - end of image */
864 bEndFlag = TRUE;
865 break;
866 case 2: /* skip */
867 pixel_ptr += *lpIn++ * bytes_per_pixel;
868 lpOut += *lpIn++ * line_size;
869 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
870 pixel_ptr = 0;
871 lpOut += line_size;
873 break;
874 default: /* absolute mode */
875 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
877 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
878 return ICERR_ERROR;
880 code0 = code1;
881 for (i = 0; i < code0 / 2; i++) {
882 if (bytes_per_pixel == 1) {
883 code1 = lpIn[i];
884 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
885 if (2 * i + 1 <= code0)
886 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
887 } else if (bytes_per_pixel == 2) {
888 code1 = lpIn[i] >> 4;
889 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
890 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
892 if (2 * i + 1 <= code0) {
893 code1 = lpIn[i] & 0x0F;
894 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
895 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
897 } else {
898 code1 = lpIn[i] >> 4;
899 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
900 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
901 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
902 pixel_ptr += bytes_per_pixel;
904 if (2 * i + 1 <= code0) {
905 code1 = lpIn[i] & 0x0F;
906 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
907 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
908 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
909 pixel_ptr += bytes_per_pixel;
913 if (code0 & 0x01) {
914 if (bytes_per_pixel == 1) {
915 code1 = lpIn[i];
916 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
917 } else if (bytes_per_pixel == 2) {
918 code1 = lpIn[i] >> 4;
919 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
920 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
921 } else {
922 code1 = lpIn[i] >> 4;
923 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
924 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
925 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
926 pixel_ptr += bytes_per_pixel;
928 lpIn++;
930 lpIn += code0 / 2;
932 /* if the RLE code is odd, skip a byte in the stream */
933 if (extra_byte)
934 lpIn++;
936 } else {
937 /* coded mode */
938 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
939 return ICERR_ERROR;
941 if (bytes_per_pixel == 1) {
942 BYTE c1 = pi->palette_map[(code1 >> 4)];
943 BYTE c2 = pi->palette_map[(code1 & 0x0F)];
945 for (i = 0; i < code0; i++) {
946 if ((i & 1) == 0)
947 lpOut[pixel_ptr++] = c1;
948 else
949 lpOut[pixel_ptr++] = c2;
951 } else if (bytes_per_pixel == 2) {
952 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
953 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
955 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
956 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
958 for (i = 0; i < code0; i++) {
959 if ((i & 1) == 0) {
960 lpOut[pixel_ptr++] = hi1;
961 lpOut[pixel_ptr++] = lo1;
962 } else {
963 lpOut[pixel_ptr++] = hi2;
964 lpOut[pixel_ptr++] = lo2;
967 } else {
968 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
969 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
970 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
972 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
973 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
974 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
976 for (i = 0; i < code0; i++) {
977 if ((i & 1) == 0) {
978 lpOut[pixel_ptr + 0] = b1;
979 lpOut[pixel_ptr + 1] = g1;
980 lpOut[pixel_ptr + 2] = r1;
981 } else {
982 lpOut[pixel_ptr + 0] = b2;
983 lpOut[pixel_ptr + 1] = g2;
984 lpOut[pixel_ptr + 2] = r2;
986 pixel_ptr += bytes_per_pixel;
990 } while (! bEndFlag);
992 return ICERR_OK;
995 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
996 LPBYTE lpIn, LPBYTE lpOut)
998 int bytes_per_pixel;
999 int line_size;
1000 int pixel_ptr = 0;
1001 BOOL bEndFlag = FALSE;
1003 assert(pi != NULL);
1004 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
1005 assert(lpIn != NULL && lpOut != NULL);
1007 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
1008 line_size = DIBWIDTHBYTES(*lpbi);
1010 do {
1011 BYTE code0, code1;
1013 code0 = *lpIn++;
1014 code1 = *lpIn++;
1016 if (code0 == 0) {
1017 int extra_byte;
1019 switch (code1) {
1020 case 0: /* EOL - end of line */
1021 pixel_ptr = 0;
1022 lpOut += line_size;
1023 break;
1024 case 1: /* EOI - end of image */
1025 bEndFlag = TRUE;
1026 break;
1027 case 2: /* skip */
1028 pixel_ptr += *lpIn++ * bytes_per_pixel;
1029 lpOut += *lpIn++ * line_size;
1030 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1031 pixel_ptr = 0;
1032 lpOut += line_size;
1034 break;
1035 default: /* absolute mode */
1036 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1037 WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1038 return ICERR_ERROR;
1040 extra_byte = code1 & 0x01;
1042 code0 = code1;
1043 while (code0--) {
1044 code1 = *lpIn++;
1045 if (bytes_per_pixel == 1) {
1046 lpOut[pixel_ptr] = pi->palette_map[code1];
1047 } else if (bytes_per_pixel == 2) {
1048 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1049 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1050 } else {
1051 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1052 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1053 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1055 pixel_ptr += bytes_per_pixel;
1058 /* if the RLE code is odd, skip a byte in the stream */
1059 if (extra_byte)
1060 lpIn++;
1062 } else {
1063 /* coded mode */
1064 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1065 WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1066 return ICERR_ERROR;
1069 if (bytes_per_pixel == 1) {
1070 code1 = pi->palette_map[code1];
1071 while (code0--)
1072 lpOut[pixel_ptr++] = code1;
1073 } else if (bytes_per_pixel == 2) {
1074 BYTE hi = pi->palette_map[code1 * 2 + 0];
1075 BYTE lo = pi->palette_map[code1 * 2 + 1];
1077 while (code0--) {
1078 lpOut[pixel_ptr + 0] = hi;
1079 lpOut[pixel_ptr + 1] = lo;
1080 pixel_ptr += bytes_per_pixel;
1082 } else {
1083 BYTE r = pi->palette_map[code1 * 4 + 2];
1084 BYTE g = pi->palette_map[code1 * 4 + 1];
1085 BYTE b = pi->palette_map[code1 * 4 + 0];
1087 while (code0--) {
1088 lpOut[pixel_ptr + 0] = b;
1089 lpOut[pixel_ptr + 1] = g;
1090 lpOut[pixel_ptr + 2] = r;
1091 pixel_ptr += bytes_per_pixel;
1095 } while (! bEndFlag);
1097 return ICERR_OK;
1100 /*****************************************************************************/
1102 static CodecInfo* Open(LPICOPEN icinfo)
1104 CodecInfo* pi = NULL;
1106 if (icinfo == NULL) {
1107 TRACE("(NULL)\n");
1108 return (LPVOID)0xFFFF0000;
1111 TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo,
1112 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1113 icinfo->fccHandler, (char*)&icinfo->fccHandler,
1114 icinfo->dwVersion,icinfo->dwFlags);
1116 if (icinfo->fccType != ICTYPE_VIDEO)
1117 return NULL;
1119 switch (icinfo->fccHandler) {
1120 case FOURCC_RLE:
1121 case FOURCC_RLE4:
1122 case FOURCC_RLE8:
1123 case FOURCC_MRLE:
1124 break;
1125 case mmioFOURCC('m','r','l','e'):
1126 icinfo->fccHandler = FOURCC_MRLE;
1127 break;
1128 default:
1129 WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1130 icinfo->fccHandler,(char*)&icinfo->fccHandler);
1131 return NULL;
1134 pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
1136 if (pi != NULL) {
1137 pi->fccHandler = icinfo->fccHandler;
1139 pi->bCompress = FALSE;
1140 pi->dwQuality = MSRLE32_DEFAULTQUALITY;
1141 pi->nPrevFrame = -1;
1142 pi->pPrevFrame = pi->pCurFrame = NULL;
1144 pi->bDecompress = FALSE;
1145 pi->palette_map = NULL;
1148 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1150 return pi;
1153 static LRESULT Close(CodecInfo *pi)
1155 TRACE("(%p)\n", pi);
1157 /* pre-condition */
1158 assert(pi != NULL);
1160 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1161 CompressEnd(pi);
1163 LocalFree((HLOCAL)pi);
1164 return 1;
1167 static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1169 /* pre-condition */
1170 assert(pi != NULL);
1172 /* check parameters */
1173 if (icinfo == NULL)
1174 return sizeof(ICINFO);
1175 if (dwSize < sizeof(ICINFO))
1176 return 0;
1178 icinfo->dwSize = sizeof(ICINFO);
1179 icinfo->fccType = streamtypeVIDEO;
1180 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1181 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1182 icinfo->dwVersion = MSRLE32_VERSION;
1183 icinfo->dwVersionICM = 0x01040000; /* Version 1.4 build 0 */
1185 LoadWideString(IDS_NAME, icinfo->szName, sizeof(icinfo->szName));
1186 LoadWideString(IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription));
1188 return sizeof(ICINFO);
1191 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1193 /* pre-condition */
1194 assert(pi != NULL);
1196 if (lQuality == -1)
1197 lQuality = MSRLE32_DEFAULTQUALITY;
1198 else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1199 return ICERR_BADPARAM;
1201 pi->dwQuality = (DWORD)lQuality;
1203 return ICERR_OK;
1206 static LRESULT Configure(CodecInfo *pi, HWND hWnd)
1208 /* pre-condition */
1209 assert(pi != NULL);
1211 /* FIXME */
1212 return ICERR_OK;
1215 static LRESULT About(CodecInfo *pi, HWND hWnd)
1217 CHAR szTitle[20];
1218 CHAR szAbout[128];
1220 /* pre-condition */
1221 assert(MSRLE32_hModule != 0);
1223 LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
1224 LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
1226 MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1228 return ICERR_OK;
1231 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1232 LPBITMAPINFOHEADER lpbiOut)
1234 LRESULT size;
1236 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1238 /* pre-condition */
1239 assert(pi != NULL);
1241 /* check parameters -- need atleast input format */
1242 if (lpbiIn == NULL) {
1243 if (lpbiOut != NULL)
1244 return ICERR_BADPARAM;
1245 return 0;
1248 /* handle unsupported input format */
1249 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1250 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1252 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1254 switch (pi->fccHandler) {
1255 case FOURCC_RLE4:
1256 size = 1 << 4;
1257 break;
1258 case FOURCC_RLE8:
1259 size = 1 << 8;
1260 break;
1261 case FOURCC_RLE:
1262 case FOURCC_MRLE:
1263 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1264 break;
1265 default:
1266 return ICERR_ERROR;
1269 if (lpbiIn->biClrUsed != 0)
1270 size = lpbiIn->biClrUsed;
1272 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1274 if (lpbiOut != NULL) {
1275 lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
1276 lpbiOut->biWidth = lpbiIn->biWidth;
1277 lpbiOut->biHeight = lpbiIn->biHeight;
1278 lpbiOut->biPlanes = 1;
1279 if (pi->fccHandler == FOURCC_RLE4 ||
1280 lpbiIn->biBitCount <= 4) {
1281 lpbiOut->biCompression = BI_RLE4;
1282 lpbiOut->biBitCount = 4;
1283 } else {
1284 lpbiOut->biCompression = BI_RLE8;
1285 lpbiOut->biBitCount = 8;
1287 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
1288 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1289 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1290 if (lpbiIn->biClrUsed == 0)
1291 size = 1<<lpbiIn->biBitCount;
1292 else
1293 size = lpbiIn->biClrUsed;
1294 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
1295 lpbiOut->biClrImportant = 0;
1297 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1298 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1300 return ICERR_OK;
1301 } else
1302 return size;
1305 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1306 LPCBITMAPINFOHEADER lpbiOut)
1308 /* pre-condition */
1309 assert(pi != NULL);
1311 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1313 /* check parameter -- need atleast one format */
1314 if (lpbiIn == NULL && lpbiOut == NULL)
1315 return 0;
1316 /* check if the given format is supported */
1317 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1318 return 0;
1320 /* the worst case is coding the complete image in absolute mode. */
1321 if (lpbiIn)
1322 return MSRLE32_GetMaxCompressedSize(lpbiIn);
1323 else
1324 return MSRLE32_GetMaxCompressedSize(lpbiOut);
1327 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1328 LPCBITMAPINFOHEADER lpbiOut)
1330 /* pre-condition */
1331 assert(pi != NULL);
1333 /* need atleast one format */
1334 if (lpbiIn == NULL && lpbiOut == NULL)
1335 return ICERR_BADPARAM;
1337 /* check input format if given */
1338 if (lpbiIn != NULL) {
1339 if (!isSupportedDIB(lpbiIn))
1340 return ICERR_BADFORMAT;
1342 /* for 4-bit need an even width */
1343 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1344 return ICERR_BADFORMAT;
1346 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1347 return ICERR_UNSUPPORTED;
1348 else if (lpbiIn->biBitCount > 8)
1349 return ICERR_UNSUPPORTED;
1352 /* check output format if given */
1353 if (lpbiOut != NULL) {
1354 if (!isSupportedMRLE(lpbiOut))
1355 return ICERR_BADFORMAT;
1357 if (lpbiIn != NULL) {
1358 if (lpbiIn->biWidth != lpbiOut->biWidth)
1359 return ICERR_UNSUPPORTED;
1360 if (lpbiIn->biHeight != lpbiOut->biHeight)
1361 return ICERR_UNSUPPORTED;
1362 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1363 return ICERR_UNSUPPORTED;
1367 return ICERR_OK;
1370 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1371 LPCBITMAPINFOHEADER lpbiOut)
1373 const RGBQUAD *rgbIn;
1374 const RGBQUAD *rgbOut;
1375 UINT i;
1376 size_t size;
1378 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1380 /* pre-condition */
1381 assert(pi != NULL);
1383 /* check parameters -- need both formats */
1384 if (lpbiIn == NULL || lpbiOut == NULL)
1385 return ICERR_BADPARAM;
1386 /* And both must be supported */
1387 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1388 return ICERR_BADFORMAT;
1390 /* FIXME: cannot compress and decompress at same time! */
1391 if (pi->bDecompress) {
1392 FIXME("cannot compress and decompress at same time!\n");
1393 return ICERR_ERROR;
1396 if (pi->bCompress)
1397 CompressEnd(pi);
1399 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1400 pi->pPrevFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1401 if (pi->pPrevFrame == NULL)
1402 return ICERR_MEMORY;
1403 pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1404 if (pi->pCurFrame == NULL) {
1405 CompressEnd(pi);
1406 return ICERR_MEMORY;
1408 pi->nPrevFrame = -1;
1409 pi->bCompress = TRUE;
1411 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1412 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1414 switch (lpbiOut->biBitCount) {
1415 case 4:
1416 case 8:
1417 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1418 if (pi->palette_map == NULL) {
1419 CompressEnd(pi);
1420 return ICERR_MEMORY;
1423 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1424 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1426 break;
1429 return ICERR_OK;
1432 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1434 int i;
1436 TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize);
1438 /* pre-condition */
1439 assert(pi != NULL);
1441 /* check parameters */
1442 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1443 return ICERR_BADPARAM;
1444 if (!lpic->lpbiOutput || !lpic->lpOutput ||
1445 !lpic->lpbiInput || !lpic->lpInput)
1446 return ICERR_BADPARAM;
1448 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);
1450 if (! pi->bCompress) {
1451 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1452 if (hr != ICERR_OK)
1453 return hr;
1454 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1455 return ICERR_BADFORMAT;
1457 if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1458 /* we continue in the sequence so we need to initialize
1459 * our internal framedata */
1461 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1462 } else if (lpic->lFrameNum == pi->nPrevFrame) {
1463 /* Oops, compress same frame again ? Okay, as you wish.
1464 * No need to recompute internal framedata, because we only swapped buffers */
1465 LPWORD pTmp = pi->pPrevFrame;
1467 pi->pPrevFrame = pi->pCurFrame;
1468 pi->pCurFrame = pTmp;
1469 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1470 LPWORD pTmp;
1472 WARN(": prev=%ld cur=%ld gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1473 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1474 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1475 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1476 return ICERR_BADFORMAT;
1478 WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1479 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1481 /* swap buffers for current and previous frame */
1482 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1483 pTmp = pi->pPrevFrame;
1484 pi->pPrevFrame = pi->pCurFrame;
1485 pi->pCurFrame = pTmp;
1486 pi->nPrevFrame = lpic->lFrameNum;
1489 for (i = 0; i < 3; i++) {
1490 SetQuality(pi, lpic->dwQuality);
1492 lpic->lpbiOutput->biSizeImage = 0;
1494 if (lpic->lpbiOutput->biBitCount == 4)
1495 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1496 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1497 else
1498 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1499 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1501 if (lpic->dwFrameSize == 0 ||
1502 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1503 break;
1505 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1506 if (lpic->lpbiOutput->biBitCount == 4)
1507 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1508 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1509 else
1510 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1511 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1513 if (lpic->dwFrameSize == 0 ||
1514 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1515 WARN("switched to keyframe, was small enough!\n");
1516 *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1517 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
1518 StreamFromFOURCC(*lpic->lpckid));
1519 break;
1523 if (lpic->dwQuality < 1000)
1524 break;
1526 lpic->dwQuality -= 1000; /* reduce quality by 10% */
1529 { /* swap buffer for current and previous frame */
1530 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1531 register LPWORD pTmp = pi->pPrevFrame;
1533 pi->pPrevFrame = pi->pCurFrame;
1534 pi->pCurFrame = pTmp;
1535 pi->nPrevFrame = lpic->lFrameNum;
1538 return ICERR_OK;
1541 static LRESULT CompressEnd(CodecInfo *pi)
1543 TRACE("(%p)\n",pi);
1545 if (pi != NULL) {
1546 if (pi->pPrevFrame != NULL)
1547 GlobalFreePtr(pi->pPrevFrame);
1548 if (pi->pCurFrame != NULL)
1549 GlobalFreePtr(pi->pCurFrame);
1550 pi->pPrevFrame = NULL;
1551 pi->pCurFrame = NULL;
1552 pi->nPrevFrame = -1;
1553 pi->bCompress = FALSE;
1556 return ICERR_OK;
1559 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1560 LPBITMAPINFOHEADER lpbiOut)
1562 DWORD size;
1564 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1566 /* pre-condition */
1567 assert(pi != NULL);
1569 if (lpbiIn == NULL)
1570 return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1572 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1573 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1575 size = lpbiIn->biSize;
1577 if (lpbiIn->biBitCount <= 8)
1578 size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1580 if (lpbiOut != NULL) {
1581 memcpy(lpbiOut, lpbiIn, size);
1582 lpbiOut->biCompression = BI_RGB;
1583 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1585 return ICERR_OK;
1586 } else
1587 return size;
1590 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1591 LPCBITMAPINFOHEADER lpbiOut)
1593 LRESULT hr = ICERR_OK;
1595 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1597 /* pre-condition */
1598 assert(pi != NULL);
1600 /* need atleast one format */
1601 if (lpbiIn == NULL && lpbiOut == NULL)
1602 return ICERR_BADPARAM;
1604 /* check input format if given */
1605 if (lpbiIn != NULL) {
1606 if (!isSupportedMRLE(lpbiIn))
1607 return ICERR_BADFORMAT;
1610 /* check output format if given */
1611 if (lpbiOut != NULL) {
1612 if (!isSupportedDIB(lpbiOut))
1613 hr = ICERR_BADFORMAT;
1615 if (lpbiIn != NULL) {
1616 if (lpbiIn->biWidth != lpbiOut->biWidth)
1617 hr = ICERR_UNSUPPORTED;
1618 if (lpbiIn->biHeight != lpbiOut->biHeight)
1619 hr = ICERR_UNSUPPORTED;
1620 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1621 hr = ICERR_UNSUPPORTED;
1625 return hr;
1628 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1629 LPCBITMAPINFOHEADER lpbiOut)
1631 const RGBQUAD *rgbIn;
1632 const RGBQUAD *rgbOut;
1633 UINT i;
1635 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1637 /* pre-condition */
1638 assert(pi != NULL);
1640 /* check parameters */
1641 if (lpbiIn == NULL || lpbiOut == NULL)
1642 return ICERR_BADPARAM;
1643 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1644 return ICERR_BADFORMAT;
1646 /* FIXME: cannot compress and decompress at a time! */
1647 if (pi->bCompress) {
1648 FIXME("cannot compress and decompress at same time!\n");
1649 return ICERR_ERROR;
1652 if (pi->bDecompress)
1653 DecompressEnd(pi);
1655 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1656 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1658 switch (lpbiOut->biBitCount) {
1659 case 4:
1660 case 8:
1661 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1662 if (pi->palette_map == NULL)
1663 return ICERR_MEMORY;
1665 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1666 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1668 break;
1669 case 15:
1670 case 16:
1671 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1672 if (pi->palette_map == NULL)
1673 return ICERR_MEMORY;
1675 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1676 WORD color;
1678 if (lpbiOut->biBitCount == 15)
1679 color = ((rgbIn[i].rgbRed >> 3) << 10)
1680 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1681 else
1682 color = ((rgbIn[i].rgbRed >> 3) << 11)
1683 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1685 pi->palette_map[i * 2 + 1] = color >> 8;
1686 pi->palette_map[i * 2 + 0] = color & 0xFF;
1688 break;
1689 case 24:
1690 case 32:
1691 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1692 if (pi->palette_map == NULL)
1693 return ICERR_MEMORY;
1694 memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1695 break;
1698 pi->bDecompress = TRUE;
1700 return ICERR_OK;
1703 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1705 TRACE("(%p,%p,%lu)\n",pi,pic,dwSize);
1707 /* pre-condition */
1708 assert(pi != NULL);
1710 /* check parameters */
1711 if (pic == NULL)
1712 return ICERR_BADPARAM;
1713 if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1714 pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1715 return ICERR_BADPARAM;
1717 /* check formats */
1718 if (! pi->bDecompress) {
1719 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1720 if (hr != ICERR_OK)
1721 return hr;
1722 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1723 return ICERR_BADFORMAT;
1725 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
1726 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1728 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1729 if (pic->lpbiInput->biBitCount == 4)
1730 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1731 else
1732 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1735 static LRESULT DecompressEnd(CodecInfo *pi)
1737 TRACE("(%p)\n",pi);
1739 /* pre-condition */
1740 assert(pi != NULL);
1742 pi->bDecompress = FALSE;
1744 if (pi->palette_map != NULL) {
1745 LocalFree((HLOCAL)pi->palette_map);
1746 pi->palette_map = NULL;
1749 return ICERR_OK;
1752 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1753 LPBITMAPINFOHEADER lpbiOut)
1755 int size;
1757 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1759 /* pre-condition */
1760 assert(pi != NULL);
1762 /* check parameters */
1763 if (lpbiIn == NULL || lpbiOut == NULL)
1764 return ICERR_BADPARAM;
1766 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1767 return ICERR_BADFORMAT;
1769 if (lpbiOut->biBitCount > 8)
1770 return ICERR_ERROR;
1772 if (lpbiIn->biBitCount <= 8) {
1773 if (lpbiIn->biClrUsed > 0)
1774 size = lpbiIn->biClrUsed;
1775 else
1776 size = (1 << lpbiIn->biBitCount);
1778 lpbiOut->biClrUsed = size;
1780 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1781 } /* else could never occur ! */
1783 return ICERR_OK;
1786 /* DriverProc - entry point for an installable driver */
1787 LRESULT CALLBACK MSRLE32_DriverProc(DWORD dwDrvID, HDRVR hDrv, UINT uMsg,
1788 LPARAM lParam1, LPARAM lParam2)
1790 CodecInfo *pi = (CodecInfo*)dwDrvID;
1792 TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID)dwDrvID, (LPVOID)hDrv,
1793 uMsg, lParam1, lParam2);
1795 switch (uMsg) {
1796 /* standard driver messages */
1797 case DRV_LOAD:
1798 return DRVCNF_OK;
1799 case DRV_OPEN:
1800 if (lParam2 == 0)
1801 return (LRESULT)0xFFFF0000;
1802 else
1803 return (LRESULT)Open((ICOPEN*)lParam2);
1804 case DRV_CLOSE:
1805 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1806 Close(pi);
1807 return DRVCNF_OK;
1808 case DRV_ENABLE:
1809 case DRV_DISABLE:
1810 return DRVCNF_OK;
1811 case DRV_FREE:
1812 return DRVCNF_OK;
1813 case DRV_QUERYCONFIGURE:
1814 return DRVCNF_CANCEL; /* FIXME */
1815 case DRV_CONFIGURE:
1816 return DRVCNF_OK; /* FIXME */
1817 case DRV_INSTALL:
1818 case DRV_REMOVE:
1819 return DRVCNF_OK;
1821 /* installable compression manager messages */
1822 case ICM_CONFIGURE:
1823 FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1824 if (lParam1 == -1)
1825 return ICERR_UNSUPPORTED; /* FIXME */
1826 else
1827 return Configure(pi, (HWND)lParam1);
1828 case ICM_ABOUT:
1829 if (lParam1 == -1)
1830 return ICERR_OK;
1831 else
1832 return About(pi, (HWND)lParam1);
1833 case ICM_GETSTATE:
1834 case ICM_SETSTATE:
1835 return 0; /* no state */
1836 case ICM_GETINFO:
1837 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1838 case ICM_GETDEFAULTQUALITY:
1839 if ((LPVOID)lParam1 != NULL) {
1840 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1841 return ICERR_OK;
1843 break;
1844 case ICM_GETQUALITY:
1845 if ((LPVOID)lParam1 != NULL) {
1846 *((LPDWORD)lParam1) = pi->dwQuality;
1847 return ICERR_OK;
1849 break;
1850 case ICM_SETQUALITY:
1851 return SetQuality(pi, *(LPLONG)lParam1);
1852 break;
1853 case ICM_COMPRESS_GET_FORMAT:
1854 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1855 (LPBITMAPINFOHEADER)lParam2);
1856 case ICM_COMPRESS_GET_SIZE:
1857 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1858 (LPCBITMAPINFOHEADER)lParam2);
1859 case ICM_COMPRESS_QUERY:
1860 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1861 (LPCBITMAPINFOHEADER)lParam2);
1862 case ICM_COMPRESS_BEGIN:
1863 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1864 (LPCBITMAPINFOHEADER)lParam2);
1865 case ICM_COMPRESS:
1866 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1867 case ICM_COMPRESS_END:
1868 return CompressEnd(pi);
1869 case ICM_DECOMPRESS_GET_FORMAT:
1870 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1871 (LPBITMAPINFOHEADER)lParam2);
1872 case ICM_DECOMPRESS_QUERY:
1873 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1874 (LPCBITMAPINFOHEADER)lParam2);
1875 case ICM_DECOMPRESS_BEGIN:
1876 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1877 (LPCBITMAPINFOHEADER)lParam2);
1878 case ICM_DECOMPRESS:
1879 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1880 case ICM_DECOMPRESS_END:
1881 return DecompressEnd(pi);
1882 case ICM_DECOMPRESS_SET_PALETTE:
1883 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1884 return ICERR_UNSUPPORTED;
1885 case ICM_DECOMPRESS_GET_PALETTE:
1886 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1887 (LPBITMAPINFOHEADER)lParam2);
1888 case ICM_GETDEFAULTKEYFRAMERATE:
1889 if ((LPVOID)lParam1 != NULL)
1890 *(LPDWORD)lParam1 = 15;
1891 return ICERR_OK;
1892 default:
1893 if (uMsg < DRV_USER)
1894 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1895 else
1896 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1899 return ICERR_UNSUPPORTED;
1902 /* DllMain - library initialization code */
1903 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1905 TRACE("(%p,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
1907 switch (dwReason) {
1908 case DLL_PROCESS_ATTACH:
1909 DisableThreadLibraryCalls(hModule);
1910 MSRLE32_hModule = hModule;
1911 break;
1913 case DLL_PROCESS_DETACH:
1914 break;
1917 return TRUE;