2 * Copyright 2002-2003 Michael Günnewig
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * - some improvements possible
21 * - implement DecompressSetPalette? -- do we need it for anything?
26 #include "msrle_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
35 static HINSTANCE MSRLE32_hModule = 0;
37 #define ABS(a) ((a) < 0 ? -(a) : (a))
38 #define SQR(a) ((a) * (a))
40 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
41 static inline WORD ColorCmp(WORD clr1, WORD clr2)
43 register UINT a = (clr1-clr2);
46 static inline WORD Intensity(RGBQUAD clr)
48 return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
51 #define GetRawPixel(lpbi,lp,x) \
52 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
53 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
55 /*****************************************************************************/
57 /* utility functions */
58 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
59 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
60 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
62 /* compression functions */
63 static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn);
64 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
65 static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
66 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
67 LPBYTE lpOut, BOOL isKey);
68 static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
69 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
70 LPBYTE lpOut, BOOL isKey);
72 /* decompression functions */
73 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
74 const BYTE *lpIn, LPBYTE lpOut);
75 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
76 const BYTE *lpIn, LPBYTE lpOut);
79 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
80 LPBITMAPINFOHEADER lpbiOut);
81 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
82 LPCBITMAPINFOHEADER lpbiOut);
83 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
84 LPCBITMAPINFOHEADER lpbiOut);
85 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
86 LPCBITMAPINFOHEADER lpbiOut);
87 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
88 static LRESULT CompressEnd(CodecInfo *pi);
90 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
91 LPBITMAPINFOHEADER lpbiOut);
92 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
93 LPCBITMAPINFOHEADER lpbiOut);
94 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
95 LPCBITMAPINFOHEADER lpbiOut);
96 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
97 static LRESULT DecompressEnd(CodecInfo *pi);
98 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
99 LPBITMAPINFOHEADER lpbiOut);
101 /*****************************************************************************/
103 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
106 assert(lpbi != NULL);
108 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
112 if (lpbi->biCompression == BI_RLE4) {
113 if (lpbi->biBitCount != 4 ||
114 (lpbi->biWidth % 2) != 0)
116 } else if (lpbi->biCompression == BI_RLE8) {
117 if (lpbi->biBitCount != 8)
125 static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
128 assert(lpbi != NULL);
130 /* check structure version/planes/compression */
131 if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
134 if (lpbi->biCompression != BI_RGB &&
135 lpbi->biCompression != BI_BITFIELDS)
138 /* check bit-depth */
139 if (lpbi->biBitCount != 1 &&
140 lpbi->biBitCount != 4 &&
141 lpbi->biBitCount != 8 &&
142 lpbi->biBitCount != 15 &&
143 lpbi->biBitCount != 16 &&
144 lpbi->biBitCount != 24 &&
145 lpbi->biBitCount != 32)
148 /* check for size(s) */
149 if (!lpbi->biWidth || !lpbi->biHeight)
150 return FALSE; /* image with zero size, makes no sense so error ! */
151 if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
152 return FALSE; /* image too big ! */
154 /* check for nonexistent colortable for hi- and true-color DIB's */
155 if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
161 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
163 INT diff = 0x00FFFFFF;
168 assert(clrs != NULL);
170 for (i = 0; i < count; i++) {
171 int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed);
172 int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
173 int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue);
188 /*****************************************************************************/
190 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn)
192 WORD wIntensityTbl[256];
193 DWORD lInLine, lOutLine;
199 assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
200 assert(pi->pCurFrame != NULL);
202 lInLine = DIBWIDTHBYTES(*lpbiIn);
203 lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
204 lpOut = pi->pCurFrame;
206 assert(lpbiIn->biClrUsed != 0);
210 (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
212 for (i = 0; i < lpbiIn->biClrUsed; i++)
213 wIntensityTbl[i] = Intensity(lp[i]);
216 for (y = 0; y < lpbiIn->biHeight; y++) {
219 switch (lpbiIn->biBitCount) {
221 for (x = 0; x < lpbiIn->biWidth / 8; x++) {
222 for (i = 0; i < 7; i++)
223 lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
227 for (x = 0; x < lpbiIn->biWidth / 2; x++) {
228 lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
229 lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
233 for (x = 0; x < lpbiIn->biWidth; x++)
234 lpOut[x] = wIntensityTbl[lpIn[x]];
243 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
248 assert(lpbi != NULL);
250 a = lpbi->biWidth / 255;
251 b = lpbi->biWidth % 255;
252 if (lpbi->biBitCount <= 4) {
257 size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
258 return size * lpbi->biHeight;
261 /* lpP => current pos in previous frame
262 * lpA => previous pos in current frame
263 * lpB => current pos in current frame
265 static INT countDiffRLE4(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
271 assert(lpA && lpB && lDist >= 0 && width > 0);
282 while (pos + 1 < width) {
286 if (pos + 1 >= width)
290 if (ColorCmp(clr1, clr3) <= lDist &&
291 ColorCmp(clr2, clr4) <= lDist) {
292 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
293 if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
294 ColorCmp(clr2,lpB[pos+2]) <= lDist) {
295 if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
296 ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
297 return count - 3; /* followed by at least 4 encodable pixels */
300 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
301 /* 'compare' with previous frame for end of diff */
320 /* lpP => current pos in previous frame
321 * lpA => previous pos in current frame
322 * lpB => current pos in current frame
324 static INT countDiffRLE8(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
328 for (count = 0; pos < width; pos++, count++) {
329 if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
330 /* diff at end? -- look-ahead for some more encodable pixel */
331 if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
333 if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
335 } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
336 /* 'compare' with previous frame for end of diff */
339 for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
340 if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
353 static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP,
354 const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
355 const BYTE *lpIn, LONG lDist,
356 INT x, LPBYTE *ppOut,
359 LPBYTE lpOut = *ppOut;
363 /* try to encode as many pixel as possible */
367 if (pos < lpbi->biWidth) {
369 for (++count; pos + 1 < lpbi->biWidth; ) {
371 if (ColorCmp(clr1, lpC[pos]) > lDist)
374 if (pos + 1 >= lpbi->biWidth)
377 if (ColorCmp(clr2, lpC[pos]) > lDist)
384 /* add some pixel for absoluting if possible */
385 count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
389 /* check for near end of line */
390 if (x + count > lpbi->biWidth)
391 count = lpbi->biWidth - x;
393 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
396 INT size = min(count, 254);
397 int bytes = ((size + 1) & (~1)) / 2;
398 BOOL extra_byte = bytes & 0x01;
400 *lpSizeImage += 2 + bytes + extra_byte;
401 assert(((*lpSizeImage) % 2) == 0);
405 for (i = 0; i < size; i += 2) {
406 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
409 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
414 *lpOut++ = (clr1 << 4) | clr2;
421 /* too little for absoluting so we must encode them */
425 clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
428 clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
433 *lpOut++ = (clr1 << 4) | clr2;
436 /* encode count pixel(s) */
437 clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
438 pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
442 INT size = min(count, 254);
456 static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
457 const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
458 const BYTE *lpIn, LONG lDist,
459 INT x, LPBYTE *ppOut,
462 LPBYTE lpOut = *ppOut;
466 assert(lpbi->biBitCount <= 8);
467 assert(lpbi->biCompression == BI_RGB);
469 /* try to encode as much as possible */
472 for (count = 1; pos < lpbi->biWidth; count++) {
473 if (ColorCmp(clr, lpC[pos++]) > lDist)
478 /* add some more pixels for absoluting if possible */
479 count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
483 /* check for over end of line */
484 if (x + count > lpbi->biWidth)
485 count = lpbi->biWidth - x;
487 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
490 INT size = min(count, 255);
491 BOOL extra_byte = size % 2;
493 *lpSizeImage += 2 + size + extra_byte;
497 for (i = 0; i < size; i++) {
498 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
505 /* too little for absoluting so we must encode them even if it's expensive! */
508 *lpSizeImage += 2 * count;
510 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
515 *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
520 /* encode count pixel(s) */
521 clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
523 /* optimize end of line */
524 if (x + count + 1 == lpbi->biWidth)
529 INT size = min(count, 255);
543 LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
544 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
545 LPBYTE lpOut, BOOL isKey)
548 LONG lLine, lInLine, lDist;
549 LPBYTE lpOutStart = lpOut;
552 assert(pi != NULL && lpbiOut != NULL);
553 assert(lpIn != NULL && lpOut != NULL);
554 assert(pi->pCurFrame != NULL);
557 lDist = QUALITY_to_DIST(pi->dwQuality);
558 lInLine = DIBWIDTHBYTES(*lpbiIn);
559 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
561 lpbiOut->biSizeImage = 0;
563 /* keyframe -- convert internal frame to output format */
566 for (y = 0; y < lpbiOut->biHeight; y++) {
570 x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
571 &lpOut, &lpbiOut->biSizeImage);
572 } while (x < lpbiOut->biWidth);
577 /* add EOL -- end of line */
578 lpbiOut->biSizeImage += 2;
580 lpOut += sizeof(WORD);
581 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
584 /* delta-frame -- compute delta between last and this internal frame */
589 assert(pi->pPrevFrame != NULL);
591 lpP = pi->pPrevFrame;
595 for (y = 0; y < lpbiOut->biHeight; y++) {
603 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
604 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
608 if (pos == lpbiOut->biWidth && count > 8) {
609 /* (count > 8) secures that we will save space */
612 } else if (jumpy || jumpx != pos) {
617 /* can only jump in positive direction -- jump until EOL, EOL */
618 INT w = lpbiOut->biWidth - jumpx;
625 /* if (w % 255 == 2) then equal costs
626 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
627 * else it will be cheaper
630 lpbiOut->biSizeImage += 4;
633 *lpOut = min(w, 255);
637 /* add EOL -- end of line */
638 lpbiOut->biSizeImage += 2;
639 *((LPWORD)lpOut) = 0;
640 lpOut += sizeof(WORD);
643 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
645 /* write out real jump(s) */
646 while (jumpy || pos != jumpx) {
647 lpbiOut->biSizeImage += 4;
650 *lpOut = min(pos - jumpx, 255);
653 *lpOut = min(jumpy, 255);
662 if (x < lpbiOut->biWidth) {
663 /* skipped the 'same' things corresponding to previous frame */
664 x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
665 &lpOut, &lpbiOut->biSizeImage);
667 } while (x < lpbiOut->biWidth);
676 /* add EOL -- end of line */
677 lpbiOut->biSizeImage += 2;
678 *((LPWORD)lpOut) = 0;
679 lpOut += sizeof(WORD);
680 assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
684 /* add EOL -- will be changed to EOI */
685 lpbiOut->biSizeImage += 2;
686 *((LPWORD)lpOut) = 0;
687 lpOut += sizeof(WORD);
690 /* change EOL to EOI -- end of image */
692 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
697 LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
698 const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
699 LPBYTE lpOut, BOOL isKey)
702 LONG lDist, lInLine, lLine;
703 LPBYTE lpOutStart = lpOut;
705 assert(pi != NULL && lpbiOut != NULL);
706 assert(lpIn != NULL && lpOut != NULL);
707 assert(pi->pCurFrame != NULL);
710 lDist = QUALITY_to_DIST(pi->dwQuality);
711 lInLine = DIBWIDTHBYTES(*lpbiIn);
712 lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
714 lpbiOut->biSizeImage = 0;
716 /* keyframe -- convert internal frame to output format */
719 for (y = 0; y < lpbiOut->biHeight; y++) {
723 x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
724 &lpOut, &lpbiOut->biSizeImage);
725 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
726 } while (x < lpbiOut->biWidth);
731 /* add EOL -- end of line */
732 lpbiOut->biSizeImage += 2;
733 *((LPWORD)lpOut) = 0;
734 lpOut += sizeof(WORD);
735 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
738 /* delta-frame -- compute delta between last and this internal frame */
743 assert(pi->pPrevFrame != NULL);
745 lpP = pi->pPrevFrame;
749 for (y = 0; y < lpbiOut->biHeight; y++) {
757 for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
758 if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
762 if (pos == lpbiOut->biWidth && count > 4) {
763 /* (count > 4) secures that we will save space */
766 } else if (jumpy || jumpx != pos) {
771 /* can only jump in positive direction -- do an EOL then jump */
777 /* add EOL -- end of line */
778 lpbiOut->biSizeImage += 2;
779 *((LPWORD)lpOut) = 0;
780 lpOut += sizeof(WORD);
781 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
784 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
786 /* write out real jump(s) */
787 while (jumpy || pos != jumpx) {
788 lpbiOut->biSizeImage += 4;
791 *lpOut = min(pos - jumpx, 255);
793 *lpOut = min(jumpy, 255);
803 if (x < lpbiOut->biWidth) {
804 /* skip the 'same' things corresponding to previous frame */
805 x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
806 &lpOut, &lpbiOut->biSizeImage);
807 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
809 } while (x < lpbiOut->biWidth);
816 /* add EOL -- end of line */
817 lpbiOut->biSizeImage += 2;
818 *((LPWORD)lpOut) = 0;
819 lpOut += sizeof(WORD);
820 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
824 /* add EOL -- will be changed to EOI */
825 lpbiOut->biSizeImage += 2;
826 *((LPWORD)lpOut) = 0;
827 lpOut += sizeof(WORD);
830 /* change EOL to EOI -- end of image */
832 assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
837 /*****************************************************************************/
839 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
840 const BYTE *lpIn, LPBYTE lpOut)
846 BOOL bEndFlag = FALSE;
849 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
850 assert(lpIn != NULL && lpOut != NULL);
852 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
853 line_size = DIBWIDTHBYTES(*lpbi);
865 case 0: /* EOL - end of line */
869 case 1: /* EOI - end of image */
873 pixel_ptr += *lpIn++ * bytes_per_pixel;
874 lpOut += *lpIn++ * line_size;
875 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
880 default: /* absolute mode */
881 extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
883 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
887 for (i = 0; i < code0 / 2; i++) {
888 if (bytes_per_pixel == 1) {
890 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
891 if (2 * i + 1 <= code0)
892 lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
893 } else if (bytes_per_pixel == 2) {
894 code1 = lpIn[i] >> 4;
895 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
896 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
898 if (2 * i + 1 <= code0) {
899 code1 = lpIn[i] & 0x0F;
900 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
901 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
904 code1 = lpIn[i] >> 4;
905 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
906 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
907 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
908 pixel_ptr += bytes_per_pixel;
910 if (2 * i + 1 <= code0) {
911 code1 = lpIn[i] & 0x0F;
912 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
913 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
914 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
915 pixel_ptr += bytes_per_pixel;
920 if (bytes_per_pixel == 1) {
922 lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
923 } else if (bytes_per_pixel == 2) {
924 code1 = lpIn[i] >> 4;
925 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
926 lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
928 code1 = lpIn[i] >> 4;
929 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
930 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
931 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
932 pixel_ptr += bytes_per_pixel;
938 /* if the RLE code is odd, skip a byte in the stream */
944 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
947 if (bytes_per_pixel == 1) {
948 BYTE c1 = pi->palette_map[(code1 >> 4)];
949 BYTE c2 = pi->palette_map[(code1 & 0x0F)];
951 for (i = 0; i < code0; i++) {
953 lpOut[pixel_ptr++] = c1;
955 lpOut[pixel_ptr++] = c2;
957 } else if (bytes_per_pixel == 2) {
958 BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
959 BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
961 BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
962 BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
964 for (i = 0; i < code0; i++) {
966 lpOut[pixel_ptr++] = hi1;
967 lpOut[pixel_ptr++] = lo1;
969 lpOut[pixel_ptr++] = hi2;
970 lpOut[pixel_ptr++] = lo2;
974 BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
975 BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
976 BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
978 BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
979 BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
980 BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
982 for (i = 0; i < code0; i++) {
984 lpOut[pixel_ptr + 0] = b1;
985 lpOut[pixel_ptr + 1] = g1;
986 lpOut[pixel_ptr + 2] = r1;
988 lpOut[pixel_ptr + 0] = b2;
989 lpOut[pixel_ptr + 1] = g2;
990 lpOut[pixel_ptr + 2] = r2;
992 pixel_ptr += bytes_per_pixel;
996 } while (! bEndFlag);
1001 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
1002 const BYTE *lpIn, LPBYTE lpOut)
1004 int bytes_per_pixel;
1007 BOOL bEndFlag = FALSE;
1010 assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
1011 assert(lpIn != NULL && lpOut != NULL);
1013 bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
1014 line_size = DIBWIDTHBYTES(*lpbi);
1026 case 0: /* EOL - end of line */
1030 case 1: /* EOI - end of image */
1034 pixel_ptr += *lpIn++ * bytes_per_pixel;
1035 lpOut += *lpIn++ * line_size;
1036 if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1041 default: /* absolute mode */
1042 if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1043 WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1046 extra_byte = code1 & 0x01;
1051 if (bytes_per_pixel == 1) {
1052 lpOut[pixel_ptr] = pi->palette_map[code1];
1053 } else if (bytes_per_pixel == 2) {
1054 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1055 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1057 lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1058 lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1059 lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1061 pixel_ptr += bytes_per_pixel;
1064 /* if the RLE code is odd, skip a byte in the stream */
1070 if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1071 WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1075 if (bytes_per_pixel == 1) {
1076 code1 = pi->palette_map[code1];
1078 lpOut[pixel_ptr++] = code1;
1079 } else if (bytes_per_pixel == 2) {
1080 BYTE hi = pi->palette_map[code1 * 2 + 0];
1081 BYTE lo = pi->palette_map[code1 * 2 + 1];
1084 lpOut[pixel_ptr + 0] = hi;
1085 lpOut[pixel_ptr + 1] = lo;
1086 pixel_ptr += bytes_per_pixel;
1089 BYTE r = pi->palette_map[code1 * 4 + 2];
1090 BYTE g = pi->palette_map[code1 * 4 + 1];
1091 BYTE b = pi->palette_map[code1 * 4 + 0];
1094 lpOut[pixel_ptr + 0] = b;
1095 lpOut[pixel_ptr + 1] = g;
1096 lpOut[pixel_ptr + 2] = r;
1097 pixel_ptr += bytes_per_pixel;
1101 } while (! bEndFlag);
1106 /*****************************************************************************/
1108 static CodecInfo* Open(LPICOPEN icinfo)
1110 CodecInfo* pi = NULL;
1112 if (icinfo == NULL) {
1114 return (LPVOID)0xFFFF0000;
1117 if (icinfo->fccType != ICTYPE_VIDEO) return NULL;
1119 TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo,
1120 icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1121 icinfo->fccHandler, (char*)&icinfo->fccHandler,
1122 icinfo->dwVersion,icinfo->dwFlags);
1124 switch (icinfo->fccHandler) {
1130 case mmioFOURCC('m','r','l','e'):
1131 icinfo->fccHandler = FOURCC_MRLE;
1134 WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
1135 icinfo->fccHandler,(char*)&icinfo->fccHandler);
1139 pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
1142 pi->fccHandler = icinfo->fccHandler;
1144 pi->bCompress = FALSE;
1145 pi->dwQuality = MSRLE32_DEFAULTQUALITY;
1146 pi->nPrevFrame = -1;
1147 pi->pPrevFrame = pi->pCurFrame = NULL;
1149 pi->bDecompress = FALSE;
1150 pi->palette_map = NULL;
1153 icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1158 static LRESULT Close(CodecInfo *pi)
1160 TRACE("(%p)\n", pi);
1165 if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1168 LocalFree((HLOCAL)pi);
1172 static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1177 /* check parameters */
1179 return sizeof(ICINFO);
1180 if (dwSize < sizeof(ICINFO))
1183 icinfo->dwSize = sizeof(ICINFO);
1184 icinfo->fccType = ICTYPE_VIDEO;
1185 icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1186 icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1187 icinfo->dwVersion = ICVERSION;
1188 icinfo->dwVersionICM = ICVERSION;
1190 LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
1191 LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
1193 return sizeof(ICINFO);
1196 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1202 lQuality = MSRLE32_DEFAULTQUALITY;
1203 else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1204 return ICERR_BADPARAM;
1206 pi->dwQuality = (DWORD)lQuality;
1211 static LRESULT Configure(const CodecInfo *pi, HWND hWnd)
1220 static LRESULT About(CodecInfo *pi, HWND hWnd)
1226 assert(MSRLE32_hModule != 0);
1228 LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
1229 LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
1231 MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1236 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1237 LPBITMAPINFOHEADER lpbiOut)
1241 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1246 /* check parameters -- need at least input format */
1247 if (lpbiIn == NULL) {
1248 if (lpbiOut != NULL)
1249 return ICERR_BADPARAM;
1253 /* handle unsupported input format */
1254 if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1255 return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1257 assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1259 switch (pi->fccHandler) {
1268 size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1274 if (lpbiIn->biClrUsed != 0)
1275 size = lpbiIn->biClrUsed;
1277 size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1279 if (lpbiOut != NULL) {
1280 lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
1281 lpbiOut->biWidth = lpbiIn->biWidth;
1282 lpbiOut->biHeight = lpbiIn->biHeight;
1283 lpbiOut->biPlanes = 1;
1284 if (pi->fccHandler == FOURCC_RLE4 ||
1285 lpbiIn->biBitCount <= 4) {
1286 lpbiOut->biCompression = BI_RLE4;
1287 lpbiOut->biBitCount = 4;
1289 lpbiOut->biCompression = BI_RLE8;
1290 lpbiOut->biBitCount = 8;
1292 lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
1293 lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1294 lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1295 if (lpbiIn->biClrUsed == 0)
1296 size = 1<<lpbiIn->biBitCount;
1298 size = lpbiIn->biClrUsed;
1299 lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
1300 lpbiOut->biClrImportant = 0;
1302 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1303 (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1310 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1311 LPCBITMAPINFOHEADER lpbiOut)
1316 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1318 /* check parameter -- need at least one format */
1319 if (lpbiIn == NULL && lpbiOut == NULL)
1321 /* check if the given format is supported */
1322 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1325 /* the worst case is coding the complete image in absolute mode. */
1327 return MSRLE32_GetMaxCompressedSize(lpbiIn);
1329 return MSRLE32_GetMaxCompressedSize(lpbiOut);
1332 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1333 LPCBITMAPINFOHEADER lpbiOut)
1338 /* need at least one format */
1339 if (lpbiIn == NULL && lpbiOut == NULL)
1340 return ICERR_BADPARAM;
1342 /* check input format if given */
1343 if (lpbiIn != NULL) {
1344 if (!isSupportedDIB(lpbiIn))
1345 return ICERR_BADFORMAT;
1347 /* for 4-bit need an even width */
1348 if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1349 return ICERR_BADFORMAT;
1351 if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1352 return ICERR_UNSUPPORTED;
1353 else if (lpbiIn->biBitCount > 8)
1354 return ICERR_UNSUPPORTED;
1357 /* check output format if given */
1358 if (lpbiOut != NULL) {
1359 if (!isSupportedMRLE(lpbiOut))
1360 return ICERR_BADFORMAT;
1362 if (lpbiIn != NULL) {
1363 if (lpbiIn->biWidth != lpbiOut->biWidth)
1364 return ICERR_UNSUPPORTED;
1365 if (lpbiIn->biHeight != lpbiOut->biHeight)
1366 return ICERR_UNSUPPORTED;
1367 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1368 return ICERR_UNSUPPORTED;
1375 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1376 LPCBITMAPINFOHEADER lpbiOut)
1378 const RGBQUAD *rgbIn;
1379 const RGBQUAD *rgbOut;
1383 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1388 /* check parameters -- need both formats */
1389 if (lpbiIn == NULL || lpbiOut == NULL)
1390 return ICERR_BADPARAM;
1391 /* And both must be supported */
1392 if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1393 return ICERR_BADFORMAT;
1395 /* FIXME: cannot compress and decompress at same time! */
1396 if (pi->bDecompress) {
1397 FIXME("cannot compress and decompress at same time!\n");
1404 size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1405 pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1406 if (pi->pPrevFrame == NULL)
1407 return ICERR_MEMORY;
1408 pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1409 if (pi->pCurFrame == NULL) {
1411 return ICERR_MEMORY;
1413 pi->nPrevFrame = -1;
1414 pi->bCompress = TRUE;
1416 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1417 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1419 switch (lpbiOut->biBitCount) {
1422 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1423 if (pi->palette_map == NULL) {
1425 return ICERR_MEMORY;
1428 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1429 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1437 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1441 TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
1446 /* check parameters */
1447 if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1448 return ICERR_BADPARAM;
1449 if (!lpic->lpbiOutput || !lpic->lpOutput ||
1450 !lpic->lpbiInput || !lpic->lpInput)
1451 return ICERR_BADPARAM;
1453 TRACE("lpic={0x%X,%p,%p,%p,%p,%p,%p,%d,%u,%u,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev);
1455 if (! pi->bCompress) {
1456 LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1459 } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1460 return ICERR_BADFORMAT;
1462 if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1463 /* we continue in the sequence so we need to initialize
1464 * our internal framedata */
1466 computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1467 } else if (lpic->lFrameNum == pi->nPrevFrame) {
1468 /* Oops, compress same frame again ? Okay, as you wish.
1469 * No need to recompute internal framedata, because we only swapped buffers */
1470 LPWORD pTmp = pi->pPrevFrame;
1472 pi->pPrevFrame = pi->pCurFrame;
1473 pi->pCurFrame = pTmp;
1474 } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1477 WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1478 if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1479 return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1480 if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1481 return ICERR_BADFORMAT;
1483 WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1484 computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1486 /* swap buffers for current and previous frame */
1487 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1488 pTmp = pi->pPrevFrame;
1489 pi->pPrevFrame = pi->pCurFrame;
1490 pi->pCurFrame = pTmp;
1491 pi->nPrevFrame = lpic->lFrameNum;
1494 for (i = 0; i < 3; i++) {
1495 SetQuality(pi, lpic->dwQuality);
1497 lpic->lpbiOutput->biSizeImage = 0;
1499 if (lpic->lpbiOutput->biBitCount == 4)
1500 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1501 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1503 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1504 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1506 if (lpic->dwFrameSize == 0 ||
1507 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1510 if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1511 if (lpic->lpbiOutput->biBitCount == 4)
1512 MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1513 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1515 MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1516 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1518 if (lpic->dwFrameSize == 0 ||
1519 lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1520 WARN("switched to keyframe, was small enough!\n");
1521 *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1522 *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
1523 StreamFromFOURCC(*lpic->lpckid));
1528 if (lpic->dwQuality < 1000)
1531 lpic->dwQuality -= 1000; /* reduce quality by 10% */
1534 { /* swap buffer for current and previous frame */
1535 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1536 register LPWORD pTmp = pi->pPrevFrame;
1538 pi->pPrevFrame = pi->pCurFrame;
1539 pi->pCurFrame = pTmp;
1540 pi->nPrevFrame = lpic->lFrameNum;
1546 static LRESULT CompressEnd(CodecInfo *pi)
1551 if (pi->pPrevFrame != NULL)
1553 GlobalUnlock(GlobalHandle(pi->pPrevFrame));
1554 GlobalFree(GlobalHandle(pi->pPrevFrame));
1556 if (pi->pCurFrame != NULL)
1558 GlobalUnlock(GlobalHandle(pi->pCurFrame));
1559 GlobalFree(GlobalHandle(pi->pCurFrame));
1561 pi->pPrevFrame = NULL;
1562 pi->pCurFrame = NULL;
1563 pi->nPrevFrame = -1;
1564 pi->bCompress = FALSE;
1570 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1571 LPBITMAPINFOHEADER lpbiOut)
1575 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1581 return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1583 if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1584 return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1586 size = lpbiIn->biSize;
1588 if (lpbiIn->biBitCount <= 8)
1589 size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1591 if (lpbiOut != NULL) {
1592 memcpy(lpbiOut, lpbiIn, size);
1593 lpbiOut->biCompression = BI_RGB;
1594 lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1601 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1602 LPCBITMAPINFOHEADER lpbiOut)
1604 LRESULT hr = ICERR_OK;
1606 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1611 /* need at least one format */
1612 if (lpbiIn == NULL && lpbiOut == NULL)
1613 return ICERR_BADPARAM;
1615 /* check input format if given */
1616 if (lpbiIn != NULL) {
1617 if (!isSupportedMRLE(lpbiIn))
1618 return ICERR_BADFORMAT;
1621 /* check output format if given */
1622 if (lpbiOut != NULL) {
1623 if (!isSupportedDIB(lpbiOut))
1624 hr = ICERR_BADFORMAT;
1626 if (lpbiIn != NULL) {
1627 if (lpbiIn->biWidth != lpbiOut->biWidth)
1628 hr = ICERR_UNSUPPORTED;
1629 if (lpbiIn->biHeight != lpbiOut->biHeight)
1630 hr = ICERR_UNSUPPORTED;
1631 if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1632 hr = ICERR_UNSUPPORTED;
1639 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1640 LPCBITMAPINFOHEADER lpbiOut)
1642 const RGBQUAD *rgbIn;
1643 const RGBQUAD *rgbOut;
1646 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1651 /* check parameters */
1652 if (lpbiIn == NULL || lpbiOut == NULL)
1653 return ICERR_BADPARAM;
1654 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1655 return ICERR_BADFORMAT;
1657 /* FIXME: cannot compress and decompress at a time! */
1658 if (pi->bCompress) {
1659 FIXME("cannot compress and decompress at same time!\n");
1663 if (pi->bDecompress)
1666 rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
1667 rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1669 switch (lpbiOut->biBitCount) {
1672 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1673 if (pi->palette_map == NULL)
1674 return ICERR_MEMORY;
1676 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1677 pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1682 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1683 if (pi->palette_map == NULL)
1684 return ICERR_MEMORY;
1686 for (i = 0; i < lpbiIn->biClrUsed; i++) {
1689 if (lpbiOut->biBitCount == 15)
1690 color = ((rgbIn[i].rgbRed >> 3) << 10)
1691 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1693 color = ((rgbIn[i].rgbRed >> 3) << 11)
1694 | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1696 pi->palette_map[i * 2 + 1] = color >> 8;
1697 pi->palette_map[i * 2 + 0] = color & 0xFF;
1702 pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1703 if (pi->palette_map == NULL)
1704 return ICERR_MEMORY;
1705 memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1709 pi->bDecompress = TRUE;
1714 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1716 TRACE("(%p,%p,%u)\n",pi,pic,dwSize);
1721 /* check parameters */
1723 return ICERR_BADPARAM;
1724 if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1725 pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1726 return ICERR_BADPARAM;
1729 if (! pi->bDecompress) {
1730 LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1733 } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1734 return ICERR_BADFORMAT;
1736 assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
1737 assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1739 pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1740 if (pic->lpbiInput->biBitCount == 4)
1741 return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1743 return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1746 static LRESULT DecompressEnd(CodecInfo *pi)
1753 pi->bDecompress = FALSE;
1755 if (pi->palette_map != NULL) {
1756 LocalFree((HLOCAL)pi->palette_map);
1757 pi->palette_map = NULL;
1763 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1764 LPBITMAPINFOHEADER lpbiOut)
1768 TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1773 /* check parameters */
1774 if (lpbiIn == NULL || lpbiOut == NULL)
1775 return ICERR_BADPARAM;
1777 if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1778 return ICERR_BADFORMAT;
1780 if (lpbiOut->biBitCount > 8)
1783 if (lpbiIn->biBitCount <= 8) {
1784 if (lpbiIn->biClrUsed > 0)
1785 size = lpbiIn->biClrUsed;
1787 size = (1 << lpbiIn->biBitCount);
1789 lpbiOut->biClrUsed = size;
1791 memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1792 } /* else could never occur ! */
1797 /* DriverProc - entry point for an installable driver */
1798 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
1799 LPARAM lParam1, LPARAM lParam2)
1801 CodecInfo *pi = (CodecInfo*)dwDrvID;
1803 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
1806 /* standard driver messages */
1810 return (LRESULT)Open((ICOPEN*)lParam2);
1812 if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1820 case DRV_QUERYCONFIGURE:
1821 return DRVCNF_CANCEL; /* FIXME */
1823 return DRVCNF_OK; /* FIXME */
1828 /* installable compression manager messages */
1830 FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1832 return ICERR_UNSUPPORTED; /* FIXME */
1834 return Configure(pi, (HWND)lParam1);
1839 return About(pi, (HWND)lParam1);
1842 return 0; /* no state */
1844 return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1845 case ICM_GETDEFAULTQUALITY:
1846 if ((LPVOID)lParam1 != NULL) {
1847 *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1851 case ICM_GETQUALITY:
1852 if ((LPVOID)lParam1 != NULL) {
1853 *((LPDWORD)lParam1) = pi->dwQuality;
1857 case ICM_SETQUALITY:
1858 return SetQuality(pi, *(LPLONG)lParam1);
1859 case ICM_COMPRESS_GET_FORMAT:
1860 return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1861 (LPBITMAPINFOHEADER)lParam2);
1862 case ICM_COMPRESS_GET_SIZE:
1863 return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1864 (LPCBITMAPINFOHEADER)lParam2);
1865 case ICM_COMPRESS_QUERY:
1866 return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1867 (LPCBITMAPINFOHEADER)lParam2);
1868 case ICM_COMPRESS_BEGIN:
1869 return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1870 (LPCBITMAPINFOHEADER)lParam2);
1872 return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1873 case ICM_COMPRESS_END:
1874 return CompressEnd(pi);
1875 case ICM_DECOMPRESS_GET_FORMAT:
1876 return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1877 (LPBITMAPINFOHEADER)lParam2);
1878 case ICM_DECOMPRESS_QUERY:
1879 return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1880 (LPCBITMAPINFOHEADER)lParam2);
1881 case ICM_DECOMPRESS_BEGIN:
1882 return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1883 (LPCBITMAPINFOHEADER)lParam2);
1884 case ICM_DECOMPRESS:
1885 return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1886 case ICM_DECOMPRESS_END:
1887 return DecompressEnd(pi);
1888 case ICM_DECOMPRESS_SET_PALETTE:
1889 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1890 return ICERR_UNSUPPORTED;
1891 case ICM_DECOMPRESS_GET_PALETTE:
1892 return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1893 (LPBITMAPINFOHEADER)lParam2);
1894 case ICM_GETDEFAULTKEYFRAMERATE:
1895 if ((LPVOID)lParam1 != NULL)
1896 *(LPDWORD)lParam1 = 15;
1899 if (uMsg < DRV_USER)
1900 return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1902 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1905 return ICERR_UNSUPPORTED;
1908 /* DllMain - library initialization code */
1909 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1911 TRACE("(%p,%d,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
1914 case DLL_PROCESS_ATTACH:
1915 DisableThreadLibraryCalls(hModule);
1916 MSRLE32_hModule = hModule;
1919 case DLL_PROCESS_DETACH: