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
20 * - some improvements possible
21 * - implement DecompressSetPalette? -- does we need it for anything?
26 #include "msrle_private.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);
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);
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)
105 LoadStringA(MSRLE32_hModule, id, szTemp, sizeof(szTemp));
106 MultiByteToWideChar(CP_ACP, 0, szTemp, -1, str, len);
109 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
112 assert(lpbi != NULL);
114 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \
118 if (lpbi->biCompression == BI_RLE4) {
119 if (lpbi->biBitCount != 4 || \
120 (lpbi->biWidth % 2) != 0)
122 } else if (lpbi->biCompression == BI_RLE8) {
123 if (lpbi->biBitCount != 8)
131 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
134 assert(lpbi != NULL);
136 /* check structure version/planes/compression */
137 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
140 if (lpbi->biCompression != BI_RGB &&
141 lpbi->biCompression != BI_BITFIELDS)
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)
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)
167 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
169 INT diff = 0x00FFFFFF;
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);
194 /*****************************************************************************/
196 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn)
198 WORD wIntensityTbl[256];
199 DWORD lInLine, lOutLine;
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);
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++) {
225 switch (lpbiIn->biBitCount) {
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];
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)];
239 for (x = 0; x < lpbiIn->biWidth; x++)
240 lpOut[x] = wIntensityTbl[lpIn[x]];
249 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
254 assert(lpbi != NULL);
256 a = lpbi->biWidth / 255;
257 b = lpbi->biWidth % 255;
258 if (lpbi->biBitCount <= 4) {
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)
277 assert(lpA && lpB && lDist >= 0 && width > 0);
288 while (pos + 1 < width) {
292 if (pos + 1 >= width)
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 */
306 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
307 /* 'compare' with previous frame for end of diff */
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)
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)
339 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
341 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
342 /* 'compare' with previous frame for end of diff */
345 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
346 if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
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;
365 /* try to encode as many pixel as possible */
369 if (pos < lpbi->biWidth) {
371 for (++count; pos + 1 < lpbi->biWidth; ) {
373 if (ColorCmp(clr1, lpC[pos]) > lDist)
376 if (pos + 1 >= lpbi->biWidth)
379 if (ColorCmp(clr2, lpC[pos]) > lDist)
386 /* add some pixel for absoluting if possible */
387 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
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 */
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);
407 for (i = 0; i < size; i += 2) {
408 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
411 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
416 *lpOut++ = (clr1 << 4) | clr2;
423 /* too less for absoluting so we must encode them */
427 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
430 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
435 *lpOut++ = (clr1 << 4) | clr2;
438 /* encode count pixel(s) */
439 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
440 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
444 INT size = min(count, 254);
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;
464 assert(lpbi->biBitCount <= 8);
465 assert(lpbi->biCompression == BI_RGB);
467 /* try to encode as much as possible */
470 for (count = 1; pos < lpbi->biWidth; count++) {
471 if (ColorCmp(clr, lpC[pos++]) > lDist)
476 /* add some more pixels for absoluting if possible */
477 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
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 */
488 INT size = min(count, 255);
489 BOOL extra_byte = size % 2;
491 *lpSizeImage += 2 + size + extra_byte;
495 for (i = 0; i < size; i++) {
496 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
503 /* too less for absoluting so we must encode them even if it's expensive! */
506 *lpSizeImage += 2 * count;
508 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
513 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
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)
527 INT size = min(count, 255);
541 LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
544 LONG lLine, lInLine, lDist;
545 LPBYTE lpOutStart = lpOut;
548 assert(pi != NULL && lpbiOut != NULL);
549 assert(lpIn != NULL && lpOut != NULL);
550 assert(pi->pCurFrame != NULL);
553 lDist = QUALITY_to_DIST(pi->dwQuality);
554 lInLine = DIBWIDTHBYTES(*lpbiIn);
555 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
557 lpbiOut->biSizeImage = 0;
559 /* keyframe -- convert internal frame to output format */
562 for (y = 0; y < lpbiOut->biHeight; y++) {
566 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
567 &lpOut, &lpbiOut->biSizeImage);
568 } while (x < lpbiOut->biWidth);
573 /* add EOL -- end of line */
574 lpbiOut->biSizeImage += 2;
575 *((LPWORD)lpOut)++ = 0;
576 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
579 /* delta-frame -- compute delta between last and this internal frame */
584 assert(pi->pPrevFrame != NULL);
586 lpP = pi->pPrevFrame;
590 for (y = 0; y < lpbiOut->biHeight; y++) {
598 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
599 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
603 if (pos == lpbiOut->biWidth && count > 8) {
604 /* (count > 8) secures that we will save space */
607 } else if (jumpy || jumpx != pos) {
612 /* can only jump in positive direction -- jump until EOL, EOL */
613 INT w = lpbiOut->biWidth - jumpx;
620 /* if (w % 255 == 2) then equal costs
621 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
622 * else it will be cheaper
625 lpbiOut->biSizeImage += 4;
628 *lpOut = min(w, 255);
632 /* add EOL -- end of line */
633 lpbiOut->biSizeImage += 2;
634 *((LPWORD)lpOut)++ = 0;
637 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
639 /* write out real jump(s) */
640 while (jumpy || pos != jumpx) {
641 lpbiOut->biSizeImage += 4;
644 *lpOut = min(pos - jumpx, 255);
647 *lpOut = min(jumpy, 255);
656 if (x < lpbiOut->biWidth) {
657 /* skipped the 'same' things corresponding to previous frame */
658 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
659 &lpOut, &lpbiOut->biSizeImage);
661 } while (x < lpbiOut->biWidth);
670 /* add EOL -- end of line */
671 lpbiOut->biSizeImage += 2;
672 *((LPWORD)lpOut)++ = 0;
673 assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
677 /* add EOL -- will be changed to EOI */
678 lpbiOut->biSizeImage += 2;
679 *((LPWORD)lpOut)++ = 0;
682 /* change EOL to EOI -- end of image */
684 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
689 LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
692 LONG lDist, lInLine, lLine;
693 LPBYTE lpOutStart = lpOut;
695 assert(pi != NULL && lpbiOut != NULL);
696 assert(lpIn != NULL && lpOut != NULL);
697 assert(pi->pCurFrame != NULL);
700 lDist = QUALITY_to_DIST(pi->dwQuality);
701 lInLine = DIBWIDTHBYTES(*lpbiIn);
702 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
704 lpbiOut->biSizeImage = 0;
706 /* keyframe -- convert internal frame to output format */
709 for (y = 0; y < lpbiOut->biHeight; y++) {
713 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
714 &lpOut, &lpbiOut->biSizeImage);
715 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
716 } while (x < lpbiOut->biWidth);
721 /* add EOL -- end of line */
722 lpbiOut->biSizeImage += 2;
723 *((LPWORD)lpOut)++ = 0;
724 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
727 /* delta-frame -- compute delta between last and this internal frame */
732 assert(pi->pPrevFrame != NULL);
734 lpP = pi->pPrevFrame;
738 for (y = 0; y < lpbiOut->biHeight; y++) {
746 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
747 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
751 if (pos == lpbiOut->biWidth && count > 4) {
752 /* (count > 4) secures that we will save space */
755 } else if (jumpy || jumpx != pos) {
760 /* can only jump in positive direction -- do a EOL then jump */
766 /* add EOL -- end of line */
767 lpbiOut->biSizeImage += 2;
768 *((LPWORD)lpOut)++ = 0;
769 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
772 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
774 /* write out real jump(s) */
775 while (jumpy || pos != jumpx) {
776 lpbiOut->biSizeImage += 4;
779 *lpOut = min(pos - jumpx, 255);
781 *lpOut = min(jumpy, 255);
791 if (x < lpbiOut->biWidth) {
792 /* skip the 'same' things corresponding to previous frame */
793 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
794 &lpOut, &lpbiOut->biSizeImage);
795 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
797 } while (x < lpbiOut->biWidth);
804 /* add EOL -- end of line */
805 lpbiOut->biSizeImage += 2;
806 *((LPWORD)lpOut)++ = 0;
807 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
811 /* add EOL -- will be changed to EOI */
812 lpbiOut->biSizeImage += 2;
813 *((LPWORD)lpOut)++ = 0;
816 /* change EOL to EOI -- end of image */
818 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
823 /*****************************************************************************/
825 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
826 LPBYTE lpIn, LPBYTE lpOut)
832 BOOL bEndFlag = FALSE;
835 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
836 assert(lpIn != NULL && lpOut != NULL);
838 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
839 line_size = DIBWIDTHBYTES(*lpbi);
851 case 0: /* EOL - end of line */
855 case 1: /* EOI - end of image */
859 pixel_ptr += *lpIn++ * bytes_per_pixel;
860 lpOut += *lpIn++ * line_size;
861 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
866 default: /* absolute mode */
867 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
869 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
873 for (i = 0; i < code0 / 2; i++) {
874 if (bytes_per_pixel == 1) {
876 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
877 if (2 * i + 1 <= code0)
878 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
879 } else if (bytes_per_pixel == 2) {
880 code1 = lpIn[i] >> 4;
881 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
882 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
884 if (2 * i + 1 <= code0) {
885 code1 = lpIn[i] & 0x0F;
886 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
887 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
890 code1 = lpIn[i] >> 4;
891 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
892 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
893 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
894 pixel_ptr += bytes_per_pixel;
896 if (2 * i + 1 <= code0) {
897 code1 = lpIn[i] & 0x0F;
898 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
899 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
900 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
901 pixel_ptr += bytes_per_pixel;
906 if (bytes_per_pixel == 1) {
908 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
909 } else if (bytes_per_pixel == 2) {
910 code1 = lpIn[i] >> 4;
911 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
912 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
914 code1 = lpIn[i] >> 4;
915 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
916 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
917 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
918 pixel_ptr += bytes_per_pixel;
924 /* if the RLE code is odd, skip a byte in the stream */
930 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
933 if (bytes_per_pixel == 1) {
934 BYTE c1 = pi->palette_map[(code1 >> 4)];
935 BYTE c2 = pi->palette_map[(code1 & 0x0F)];
937 for (i = 0; i < code0; i++) {
939 lpOut[pixel_ptr++] = c1;
941 lpOut[pixel_ptr++] = c2;
943 } else if (bytes_per_pixel == 2) {
944 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
945 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
947 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
948 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
950 for (i = 0; i < code0; i++) {
952 lpOut[pixel_ptr++] = hi1;
953 lpOut[pixel_ptr++] = lo1;
955 lpOut[pixel_ptr++] = hi2;
956 lpOut[pixel_ptr++] = lo2;
960 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
961 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
962 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
964 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
965 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
966 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
968 for (i = 0; i < code0; i++) {
970 lpOut[pixel_ptr + 0] = b1;
971 lpOut[pixel_ptr + 1] = g1;
972 lpOut[pixel_ptr + 2] = r1;
974 lpOut[pixel_ptr + 0] = b2;
975 lpOut[pixel_ptr + 1] = g2;
976 lpOut[pixel_ptr + 2] = r2;
978 pixel_ptr += bytes_per_pixel;
982 } while (! bEndFlag);
987 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
988 LPBYTE lpIn, LPBYTE lpOut)
993 BOOL bEndFlag = FALSE;
996 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
997 assert(lpIn != NULL && lpOut != NULL);
999 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
1000 line_size = DIBWIDTHBYTES(*lpbi);
1012 case 0: /* EOL - end of line */
1016 case 1: /* EOI - end of image */
1020 pixel_ptr += *lpIn++ * bytes_per_pixel;
1021 lpOut += *lpIn++ * line_size;
1022 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1027 default: /* absolute mode */
1028 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1029 WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1032 extra_byte = code1 & 0x01;
1037 if (bytes_per_pixel == 1) {
1038 lpOut[pixel_ptr] = pi->palette_map[code1];
1039 } else if (bytes_per_pixel == 2) {
1040 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1041 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1043 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1044 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1045 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1047 pixel_ptr += bytes_per_pixel;
1050 /* if the RLE code is odd, skip a byte in the stream */
1056 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1057 WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1061 if (bytes_per_pixel == 1) {
1062 code1 = pi->palette_map[code1];
1064 lpOut[pixel_ptr++] = code1;
1065 } else if (bytes_per_pixel == 2) {
1066 BYTE hi = pi->palette_map[code1 * 2 + 0];
1067 BYTE lo = pi->palette_map[code1 * 2 + 1];
1070 lpOut[pixel_ptr + 0] = hi;
1071 lpOut[pixel_ptr + 1] = lo;
1072 pixel_ptr += bytes_per_pixel;
1075 BYTE r = pi->palette_map[code1 * 4 + 2];
1076 BYTE g = pi->palette_map[code1 * 4 + 1];
1077 BYTE b = pi->palette_map[code1 * 4 + 0];
1080 lpOut[pixel_ptr + 0] = b;
1081 lpOut[pixel_ptr + 1] = g;
1082 lpOut[pixel_ptr + 2] = r;
1083 pixel_ptr += bytes_per_pixel;
1087 } while (! bEndFlag);
1092 /*****************************************************************************/
1094 static CodecInfo* Open(LPICOPEN icinfo)
1096 CodecInfo* pi = NULL;
1098 if (icinfo == NULL) {
1100 return (LPVOID)0xFFFF0000;
1103 TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo,
1104 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1105 icinfo->fccHandler, (char*)&icinfo->fccHandler,
1106 icinfo->dwVersion,icinfo->dwFlags);
1108 if (icinfo->fccType != ICTYPE_VIDEO)
1111 switch (icinfo->fccHandler) {
1117 case mmioFOURCC('m','r','l','e'):
1118 icinfo->fccHandler = FOURCC_MRLE;
1121 WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1122 icinfo->fccHandler,(char*)&icinfo->fccHandler);
1126 pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
1129 pi->fccHandler = icinfo->fccHandler;
1131 pi->bCompress = FALSE;
1132 pi->dwQuality = MSRLE32_DEFAULTQUALITY;
1133 pi->nPrevFrame = -1;
1134 pi->pPrevFrame = pi->pCurFrame = NULL;
1136 pi->bDecompress = FALSE;
1137 pi->palette_map = NULL;
1140 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1145 static LRESULT Close(CodecInfo *pi)
1147 TRACE("(%p)\n", pi);
1152 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1155 LocalFree((HLOCAL)pi);
1159 static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1164 /* check parameters */
1166 return sizeof(ICINFO);
1167 if (dwSize < sizeof(ICINFO))
1170 icinfo->dwSize = sizeof(ICINFO);
1171 icinfo->fccType = streamtypeVIDEO;
1172 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1173 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1174 icinfo->dwVersion = MSRLE32_VERSION;
1175 icinfo->dwVersionICM = 0x01040000; /* Version 1.4 build 0 */
1177 LoadWideString(IDS_NAME, icinfo->szName, sizeof(icinfo->szName));
1178 LoadWideString(IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription));
1180 return sizeof(ICINFO);
1183 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1189 lQuality = MSRLE32_DEFAULTQUALITY;
1190 else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1191 return ICERR_BADPARAM;
1193 pi->dwQuality = (DWORD)lQuality;
1198 static LRESULT Configure(CodecInfo *pi, HWND hWnd)
1207 static LRESULT About(CodecInfo *pi, HWND hWnd)
1213 assert(MSRLE32_hModule != 0);
1215 LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
1216 LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
1218 MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1223 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1224 LPBITMAPINFOHEADER lpbiOut)
1228 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1233 /* check parameters -- need atleast input format */
1234 if (lpbiIn == NULL) {
1235 if (lpbiOut != NULL)
1236 return ICERR_BADPARAM;
1240 /* handle unsupported input format */
1241 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1242 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1244 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1246 switch (pi->fccHandler) {
1255 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1261 if (lpbiIn->biClrUsed != 0)
1262 size = lpbiIn->biClrUsed;
1264 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1266 if (lpbiOut != NULL) {
1267 lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
1268 lpbiOut->biWidth = lpbiIn->biWidth;
1269 lpbiOut->biHeight = lpbiIn->biHeight;
1270 lpbiOut->biPlanes = 1;
1271 if (pi->fccHandler == FOURCC_RLE4 ||
1272 lpbiIn->biBitCount <= 4) {
1273 lpbiOut->biCompression = BI_RLE4;
1274 lpbiOut->biBitCount = 4;
1276 lpbiOut->biCompression = BI_RLE8;
1277 lpbiOut->biBitCount = 8;
1279 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
1280 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1281 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1282 if (lpbiIn->biClrUsed == 0)
1283 size = 1<<lpbiIn->biBitCount;
1285 size = lpbiIn->biClrUsed;
1286 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
1287 lpbiOut->biClrImportant = 0;
1289 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1290 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1297 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1298 LPCBITMAPINFOHEADER lpbiOut)
1303 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1305 /* check parameter -- need atleast one format */
1306 if (lpbiIn == NULL && lpbiOut == NULL)
1308 /* check if the given format is supported */
1309 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1312 /* the worst case is coding the complete image in absolute mode. */
1314 return MSRLE32_GetMaxCompressedSize(lpbiIn);
1316 return MSRLE32_GetMaxCompressedSize(lpbiOut);
1319 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1320 LPCBITMAPINFOHEADER lpbiOut)
1325 /* need atleast one format */
1326 if (lpbiIn == NULL && lpbiOut == NULL)
1327 return ICERR_BADPARAM;
1329 /* check input format if given */
1330 if (lpbiIn != NULL) {
1331 if (!isSupportedDIB(lpbiIn))
1332 return ICERR_BADFORMAT;
1334 /* for 4-bit need an even width */
1335 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1336 return ICERR_BADFORMAT;
1338 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1339 return ICERR_UNSUPPORTED;
1340 else if (lpbiIn->biBitCount > 8)
1341 return ICERR_UNSUPPORTED;
1344 /* check output format if given */
1345 if (lpbiOut != NULL) {
1346 if (!isSupportedMRLE(lpbiOut))
1347 return ICERR_BADFORMAT;
1349 if (lpbiIn != NULL) {
1350 if (lpbiIn->biWidth != lpbiOut->biWidth)
1351 return ICERR_UNSUPPORTED;
1352 if (lpbiIn->biHeight != lpbiOut->biHeight)
1353 return ICERR_UNSUPPORTED;
1354 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1355 return ICERR_UNSUPPORTED;
1362 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1363 LPCBITMAPINFOHEADER lpbiOut)
1365 const RGBQUAD *rgbIn;
1366 const RGBQUAD *rgbOut;
1370 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1375 /* check parameters -- need both formats */
1376 if (lpbiIn == NULL || lpbiOut == NULL)
1377 return ICERR_BADPARAM;
1378 /* And both must be supported */
1379 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1380 return ICERR_BADFORMAT;
1382 /* FIXME: cannot compress and decompress at same time! */
1383 if (pi->bDecompress) {
1384 FIXME("cannot compress and decompress at same time!\n");
1391 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1392 pi->pPrevFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1393 if (pi->pPrevFrame == NULL)
1394 return ICERR_MEMORY;
1395 pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1396 if (pi->pCurFrame == NULL) {
1398 return ICERR_MEMORY;
1400 pi->nPrevFrame = -1;
1401 pi->bCompress = TRUE;
1403 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1404 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1406 switch (lpbiOut->biBitCount) {
1409 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1410 if (pi->palette_map == NULL) {
1412 return ICERR_MEMORY;
1415 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1416 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1424 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1428 TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize);
1433 /* check parameters */
1434 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1435 return ICERR_BADPARAM;
1436 if (!lpic->lpbiOutput || !lpic->lpOutput ||
1437 !lpic->lpbiInput || !lpic->lpInput)
1438 return ICERR_BADPARAM;
1440 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);
1442 if (! pi->bCompress) {
1443 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1446 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1447 return ICERR_BADFORMAT;
1449 if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1450 /* we continue in the sequence so we need to initialize
1451 * our internal framedata */
1453 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1454 } else if (lpic->lFrameNum == pi->nPrevFrame) {
1455 /* Oops, compress same frame again ? Okay, as you wish.
1456 * No need to recompute internal framedata, because we only swapped buffers */
1457 LPWORD pTmp = pi->pPrevFrame;
1459 pi->pPrevFrame = pi->pCurFrame;
1460 pi->pCurFrame = pTmp;
1461 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1464 WARN(": prev=%ld cur=%ld gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1465 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1466 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1467 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1468 return ICERR_BADFORMAT;
1470 WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1471 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1473 /* swap buffers for current and previous frame */
1474 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1475 pTmp = pi->pPrevFrame;
1476 pi->pPrevFrame = pi->pCurFrame;
1477 pi->pCurFrame = pTmp;
1478 pi->nPrevFrame = lpic->lFrameNum;
1481 for (i = 0; i < 3; i++) {
1482 SetQuality(pi, lpic->dwQuality);
1484 lpic->lpbiOutput->biSizeImage = 0;
1486 if (lpic->lpbiOutput->biBitCount == 4)
1487 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1488 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1490 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1491 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1493 if (lpic->dwFrameSize == 0 ||
1494 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1497 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1498 if (lpic->lpbiOutput->biBitCount == 4)
1499 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1500 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1502 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1503 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1505 if (lpic->dwFrameSize == 0 ||
1506 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1507 WARN("switched to keyframe, was small enough!\n");
1508 *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1509 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
1510 StreamFromFOURCC(*lpic->lpckid));
1515 if (lpic->dwQuality < 1000)
1518 lpic->dwQuality -= 1000; /* reduce quality by 10% */
1521 { /* swap buffer for current and previous frame */
1522 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1523 register LPWORD pTmp = pi->pPrevFrame;
1525 pi->pPrevFrame = pi->pCurFrame;
1526 pi->pCurFrame = pTmp;
1527 pi->nPrevFrame = lpic->lFrameNum;
1533 static LRESULT CompressEnd(CodecInfo *pi)
1538 if (pi->pPrevFrame != NULL)
1539 GlobalFreePtr(pi->pPrevFrame);
1540 if (pi->pCurFrame != NULL)
1541 GlobalFreePtr(pi->pCurFrame);
1542 pi->pPrevFrame = NULL;
1543 pi->pCurFrame = NULL;
1544 pi->nPrevFrame = -1;
1545 pi->bCompress = FALSE;
1551 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1552 LPBITMAPINFOHEADER lpbiOut)
1556 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1562 return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1564 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1565 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1567 size = lpbiIn->biSize;
1569 if (lpbiIn->biBitCount <= 8)
1570 size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1572 if (lpbiOut != NULL) {
1573 memcpy(lpbiOut, lpbiIn, size);
1574 lpbiOut->biCompression = BI_RGB;
1575 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1582 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1583 LPCBITMAPINFOHEADER lpbiOut)
1585 LRESULT hr = ICERR_OK;
1587 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1592 /* need atleast one format */
1593 if (lpbiIn == NULL && lpbiOut == NULL)
1594 return ICERR_BADPARAM;
1596 /* check input format if given */
1597 if (lpbiIn != NULL) {
1598 if (!isSupportedMRLE(lpbiIn))
1599 return ICERR_BADFORMAT;
1602 /* check output format if given */
1603 if (lpbiOut != NULL) {
1604 if (!isSupportedDIB(lpbiOut))
1605 hr = ICERR_BADFORMAT;
1607 if (lpbiIn != NULL) {
1608 if (lpbiIn->biWidth != lpbiOut->biWidth)
1609 hr = ICERR_UNSUPPORTED;
1610 if (lpbiIn->biHeight != lpbiOut->biHeight)
1611 hr = ICERR_UNSUPPORTED;
1612 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1613 hr = ICERR_UNSUPPORTED;
1620 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1621 LPCBITMAPINFOHEADER lpbiOut)
1623 const RGBQUAD *rgbIn;
1624 const RGBQUAD *rgbOut;
1627 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1632 /* check parameters */
1633 if (lpbiIn == NULL || lpbiOut == NULL)
1634 return ICERR_BADPARAM;
1635 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1636 return ICERR_BADFORMAT;
1638 /* FIXME: cannot compress and decompress at a time! */
1639 if (pi->bCompress) {
1640 FIXME("cannot compress and decompress at same time!\n");
1644 if (pi->bDecompress)
1647 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1648 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1650 switch (lpbiOut->biBitCount) {
1653 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1654 if (pi->palette_map == NULL)
1655 return ICERR_MEMORY;
1657 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1658 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1663 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1664 if (pi->palette_map == NULL)
1665 return ICERR_MEMORY;
1667 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1670 if (lpbiOut->biBitCount == 15)
1671 color = ((rgbIn[i].rgbRed >> 3) << 10)
1672 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1674 color = ((rgbIn[i].rgbRed >> 3) << 11)
1675 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1677 pi->palette_map[i * 2 + 1] = color >> 8;
1678 pi->palette_map[i * 2 + 0] = color & 0xFF;
1683 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1684 if (pi->palette_map == NULL)
1685 return ICERR_MEMORY;
1686 memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1690 pi->bDecompress = TRUE;
1695 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1697 TRACE("(%p,%p,%lu)\n",pi,pic,dwSize);
1702 /* check parameters */
1704 return ICERR_BADPARAM;
1705 if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1706 pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1707 return ICERR_BADPARAM;
1710 if (! pi->bDecompress) {
1711 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1714 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1715 return ICERR_BADFORMAT;
1717 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
1718 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1720 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1721 if (pic->lpbiInput->biBitCount == 4)
1722 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1724 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1727 static LRESULT DecompressEnd(CodecInfo *pi)
1734 pi->bDecompress = FALSE;
1736 if (pi->palette_map != NULL) {
1737 LocalFree((HLOCAL)pi->palette_map);
1738 pi->palette_map = NULL;
1744 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1745 LPBITMAPINFOHEADER lpbiOut)
1749 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1754 /* check parameters */
1755 if (lpbiIn == NULL || lpbiOut == NULL)
1756 return ICERR_BADPARAM;
1758 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1759 return ICERR_BADFORMAT;
1761 if (lpbiOut->biBitCount > 8)
1764 if (lpbiIn->biBitCount <= 8) {
1765 if (lpbiIn->biClrUsed > 0)
1766 size = lpbiIn->biClrUsed;
1768 size = (1 << lpbiIn->biBitCount);
1770 lpbiOut->biClrUsed = size;
1772 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1773 } /* else could never occur ! */
1778 /* DriverProc - entry point for an installable driver */
1779 LRESULT CALLBACK MSRLE32_DriverProc(DWORD dwDrvID, HDRVR hDrv, UINT uMsg,
1780 LPARAM lParam1, LPARAM lParam2)
1782 CodecInfo *pi = (CodecInfo*)dwDrvID;
1784 TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID)dwDrvID, (LPVOID)hDrv,
1785 uMsg, lParam1, lParam2);
1788 /* standard driver messages */
1793 return (LRESULT)0xFFFF0000;
1795 return (LRESULT)Open((ICOPEN*)lParam2);
1797 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1805 case DRV_QUERYCONFIGURE:
1806 return DRVCNF_CANCEL; /* FIXME */
1808 return DRVCNF_OK; /* FIXME */
1813 /* installable compression manager messages */
1815 FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1817 return ICERR_UNSUPPORTED; /* FIXME */
1819 return Configure(pi, (HWND)lParam1);
1824 return About(pi, (HWND)lParam1);
1827 return 0; /* no state */
1829 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1830 case ICM_GETDEFAULTQUALITY:
1831 if ((LPVOID)lParam1 != NULL) {
1832 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1836 case ICM_GETQUALITY:
1837 if ((LPVOID)lParam1 != NULL) {
1838 *((LPDWORD)lParam1) = pi->dwQuality;
1842 case ICM_SETQUALITY:
1843 return SetQuality(pi, *(LPLONG)lParam1);
1845 case ICM_COMPRESS_GET_FORMAT:
1846 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1847 (LPBITMAPINFOHEADER)lParam2);
1848 case ICM_COMPRESS_GET_SIZE:
1849 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1850 (LPCBITMAPINFOHEADER)lParam2);
1851 case ICM_COMPRESS_QUERY:
1852 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1853 (LPCBITMAPINFOHEADER)lParam2);
1854 case ICM_COMPRESS_BEGIN:
1855 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1856 (LPCBITMAPINFOHEADER)lParam2);
1858 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1859 case ICM_COMPRESS_END:
1860 return CompressEnd(pi);
1861 case ICM_DECOMPRESS_GET_FORMAT:
1862 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1863 (LPBITMAPINFOHEADER)lParam2);
1864 case ICM_DECOMPRESS_QUERY:
1865 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1866 (LPCBITMAPINFOHEADER)lParam2);
1867 case ICM_DECOMPRESS_BEGIN:
1868 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1869 (LPCBITMAPINFOHEADER)lParam2);
1870 case ICM_DECOMPRESS:
1871 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1872 case ICM_DECOMPRESS_END:
1873 return DecompressEnd(pi);
1874 case ICM_DECOMPRESS_SET_PALETTE:
1875 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1876 return ICERR_UNSUPPORTED;
1877 case ICM_DECOMPRESS_GET_PALETTE:
1878 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1879 (LPBITMAPINFOHEADER)lParam2);
1880 case ICM_GETDEFAULTKEYFRAMERATE:
1881 if ((LPVOID)lParam1 != NULL)
1882 *(LPDWORD)lParam1 = 15;
1885 if (uMsg < DRV_USER)
1886 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1888 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1891 return ICERR_UNSUPPORTED;
1894 /* DllMain - library initialization code */
1895 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1897 TRACE("(%p,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
1900 case DLL_PROCESS_ATTACH:
1901 DisableThreadLibraryCalls(hModule);
1902 MSRLE32_hModule = hModule;
1905 case DLL_PROCESS_DETACH: