2 * Copyright 2002 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 * - compression of RLE4 is buggy -- see FIXME's
21 * - many improvements possible
22 * - implement DecompressSetPalette? -- does we need it for anything?
27 #include "msrle_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(msrle32
);
37 static HINSTANCE MSRLE32_hModule
= 0;
39 #define ABS(a) ((a) < 0 ? -(a) : (a))
40 #define SQR(a) ((a) * (a))
42 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
43 inline WORD
ColorCmp(WORD clr1
, WORD clr2
)
45 register UINT a
= (clr1
-clr2
);
48 inline WORD
Intensity(RGBQUAD clr
)
50 return (30 * clr
.rgbRed
+ 59 * clr
.rgbGreen
+ 11 * clr
.rgbBlue
)/4;
53 #define GetRawPixel(lpbi,lp,x) \
54 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
55 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
57 /*****************************************************************************/
59 /* utility functions */
60 static BOOL
isSupportedDIB(LPCBITMAPINFOHEADER lpbi
);
61 static BOOL
isSupportedMRLE(LPCBITMAPINFOHEADER lpbi
);
62 static void LoadWideString(UINT id
, LPWSTR str
, INT len
);
63 static BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
);
65 /* compression functions */
66 static void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
);
67 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
);
68 static LRESULT
MSRLE32_CompressRLE4(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
);
69 static LRESULT
MSRLE32_CompressRLE8(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
);
71 /* decompression functions */
72 static LRESULT
MSRLE32_DecompressRLE4(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
73 LPBYTE lpIn
, LPBYTE lpOut
);
74 static LRESULT
MSRLE32_DecompressRLE8(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
75 LPBYTE lpIn
, LPBYTE lpOut
);
78 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
79 LPBITMAPINFOHEADER lpbiOut
);
80 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
81 LPCBITMAPINFOHEADER lpbiOut
);
82 static LRESULT
CompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
83 LPCBITMAPINFOHEADER lpbiOut
);
84 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
85 LPCBITMAPINFOHEADER lpbiOut
);
86 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
);
87 static LRESULT
CompressEnd(CodecInfo
*pi
);
89 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
90 LPBITMAPINFOHEADER lpbiOut
);
91 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
92 LPCBITMAPINFOHEADER lpbiOut
);
93 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
94 LPCBITMAPINFOHEADER lpbiOut
);
95 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
);
96 static LRESULT
DecompressEnd(CodecInfo
*pi
);
97 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
98 LPBITMAPINFOHEADER lpbiOut
);
100 /*****************************************************************************/
102 static void LoadWideString(UINT id
, LPWSTR str
, INT len
)
106 LoadStringA(MSRLE32_hModule
, id
, szTemp
, sizeof(szTemp
));
107 MultiByteToWideChar(CP_ACP
, 0, szTemp
, -1, str
, len
);
110 static BOOL
isSupportedMRLE(LPCBITMAPINFOHEADER lpbi
)
113 assert(lpbi
!= NULL
);
115 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) || \
119 if (lpbi
->biCompression
== BI_RLE4
) {
120 if (lpbi
->biBitCount
!= 4 || \
121 (lpbi
->biWidth
% 2) != 0)
123 } else if (lpbi
->biCompression
== BI_RLE8
) {
124 if (lpbi
->biBitCount
!= 8)
132 static BOOL
isSupportedDIB(LPCBITMAPINFOHEADER lpbi
)
135 assert(lpbi
!= NULL
);
137 /* check structure version/planes/compression */
138 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) ||
141 if (lpbi
->biCompression
!= BI_RGB
&&
142 lpbi
->biCompression
!= BI_BITFIELDS
)
145 /* check bit-depth */
146 if (lpbi
->biBitCount
!= 1 &&
147 lpbi
->biBitCount
!= 4 &&
148 lpbi
->biBitCount
!= 8 &&
149 lpbi
->biBitCount
!= 15 &&
150 lpbi
->biBitCount
!= 16 &&
151 lpbi
->biBitCount
!= 24 &&
152 lpbi
->biBitCount
!= 32)
155 /* check for size(s) */
156 if (!lpbi
->biWidth
|| !lpbi
->biHeight
)
157 return FALSE
; /* image with zero size, makes no sense so error ! */
158 if (DIBWIDTHBYTES(*lpbi
) * lpbi
->biHeight
>= (1UL << 31) - 1)
159 return FALSE
; /* image too big ! */
161 /* check for non existing colortable for hi- and true-color DIB's */
162 if (lpbi
->biBitCount
>= 15 && lpbi
->biClrUsed
> 0)
168 static BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
)
170 INT diff
= 0x00FFFFFF;
175 assert(clrs
!= NULL
);
177 for (i
= 0; i
< count
; i
++) {
178 int r
= ((int)clrs
[i
].rgbRed
- (int)clr
.rgbRed
);
179 int g
= ((int)clrs
[i
].rgbGreen
- (int)clr
.rgbGreen
);
180 int b
= ((int)clrs
[i
].rgbBlue
- (int)clr
.rgbBlue
);
195 /*****************************************************************************/
197 void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
)
199 WORD wIntensityTbl
[256];
200 LONG lInLine
, lOutLine
;
205 assert(pi
!= NULL
&& lpbiIn
!= NULL
&& lpIn
!= NULL
);
206 assert(pi
->pCurFrame
!= NULL
);
208 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
209 lOutLine
= WIDTHBYTES(lpbiIn
->biWidth
* 8*sizeof(WORD
)) / 2;
210 lpOut
= pi
->pCurFrame
;
212 assert(lpbiIn
->biClrUsed
!= 0);
215 const RGBQUAD
*lp
= (LPRGBQUAD
)((LPBYTE
)lpbiIn
+ lpbiIn
->biSize
);
217 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++)
218 wIntensityTbl
[i
] = Intensity(lp
[i
]);
221 for (y
= 0; y
< lpbiIn
->biHeight
; y
++) {
224 switch (lpbiIn
->biBitCount
) {
226 for (x
= 0; x
< lpbiIn
->biWidth
; x
+= 8) {
227 for (i
= 0; i
< 7; i
++)
228 lpOut
[x
+ i
] = wIntensityTbl
[(lpIn
[x
] >> (7 - i
)) & 1];
232 for (x
= 0; x
< lpbiIn
->biWidth
; x
+= 2) {
233 lpOut
[x
+ 0] = wIntensityTbl
[(lpIn
[x
] >> 4)];
234 lpOut
[x
+ 1] = wIntensityTbl
[(lpIn
[x
] & 0x0F)];
238 for (x
= 0; x
< lpbiIn
->biWidth
; x
++)
239 lpOut
[x
] = wIntensityTbl
[lpIn
[x
]];
248 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
)
253 assert(lpbi
!= NULL
);
255 a
= lpbi
->biWidth
/ 255;
256 b
= lpbi
->biWidth
% 255;
257 if (lpbi
->biBitCount
<= 4) {
262 size
= (2 + a
* (2 + ((a
+ 2) & ~2)) + b
* (2 + ((b
+ 2) & ~2)));
263 return size
* lpbi
->biHeight
;
266 /* lpP => current pos in previous frame
267 * lpA => previous pos in current frame
268 * lpB => current pos in current frame
270 static INT
countDiffRLE4(LPWORD lpP
, LPWORD lpA
, LPWORD lpB
, INT pos
, LONG lDist
, LONG width
)
276 assert(lpA
&& lpB
&& lDist
>= 0 && width
> 0);
287 while (pos
+ 1 < width
) {
291 if (pos
+ 1 >= width
)
295 if (ColorCmp(clr1
, clr3
) <= lDist
&&
296 ColorCmp(clr2
, clr4
) <= lDist
) {
297 /* diff at end? -- look-ahead for atleast ?? more encodable pixel */
302 } else if (lpP
&& ColorCmp(lpP
[pos
], lpB
[pos
]) <= lDist
) {
303 /* 'compare' with previous frame for end of diff */
322 /* lpP => current pos in previous frame
323 * lpA => previous pos in current frame
324 * lpB => current pos in current frame
326 static INT
countDiffRLE8(LPWORD lpP
, LPWORD lpA
, LPWORD lpB
, INT pos
, LONG lDist
, LONG width
)
330 for (count
= 0; pos
< width
; pos
++, count
++) {
331 if (ColorCmp(lpA
[pos
], lpB
[pos
]) <= lDist
) {
332 /* diff at end? -- look-ahead for atleast one more encodable pixel */
333 if (pos
+ 1 < width
&& ColorCmp(lpA
[pos
], lpB
[pos
+1]) <= 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(CodecInfo
*pi
, LPWORD lpP
, LPWORD lpC
, LPCBITMAPINFOHEADER lpbi
, BYTE
*lpIn
, LONG lDist
, INT x
, LPBYTE
*ppOut
, DWORD
*lpSizeImage
)
355 LPBYTE lpOut
= *ppOut
;
359 /* try to encode as many pixel as possible */
363 if (pos
< lpbi
->biWidth
) {
365 for (++count
; pos
+ 1 < lpbi
->biWidth
; ) {
367 if (ColorCmp(clr1
, lpC
[pos
]) > lDist
)
370 if (pos
+ 1 >= lpbi
->biWidth
)
373 if (ColorCmp(clr2
, lpC
[pos
]) > lDist
)
380 /* add some pixel for absoluting if possible */
381 count
+= countDiffRLE4(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
383 /* check for near end of line */
384 if (x
+ count
> lpbi
->biWidth
)
385 count
= lpbi
->biWidth
- x
;
387 /* absolute pixel(s) in groups of atleast 3 and maximal 254 pixel */
390 INT size
= min(count
, 254);
391 BOOL extra_byte
= size
% 2;
393 *lpSizeImage
+= 2 + size
+ extra_byte
;
397 for (i
= 0; i
< size
; i
+= 2) {
398 clr1
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
401 clr2
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
406 *lpOut
++ = (clr1
<< 4) | clr2
;
413 /* too less for absoluting so we must encode them */
417 clr1
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
420 clr2
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
425 *lpOut
++ = (clr1
<< 4) | clr2
;
428 /* encode count pixel(s) */
429 clr1
= ((pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)] << 4) |
430 pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
+ 1)]);
434 INT size
= min(count
, 254);
448 static INT
MSRLE32_CompressRLE8Line(CodecInfo
*pi
, LPWORD lpP
, LPWORD lpC
, LPCBITMAPINFOHEADER lpbi
, BYTE
*lpIn
, LONG lDist
, INT x
, LPBYTE
*ppOut
, DWORD
*lpSizeImage
)
450 LPBYTE lpOut
= *ppOut
;
454 assert(lpbi
->biBitCount
<= 8);
455 assert(lpbi
->biCompression
== BI_RGB
);
457 /* try to encode as much as possible */
460 for (count
= 1; pos
< lpbi
->biWidth
; count
++) {
461 if (ColorCmp(clr
, lpC
[pos
++]) > lDist
)
466 /* add some more pixels for absoluting if possible */
467 count
+= countDiffRLE8(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
469 /* check for over end of line */
470 if (x
+ count
> lpbi
->biWidth
)
471 count
= lpbi
->biWidth
- x
;
473 /* absolute pixel(s) in groups of atleast 3 and maximal 255 pixels */
476 INT size
= min(count
, 255);
477 BOOL extra_byte
= size
% 2;
479 *lpSizeImage
+= 2 + size
+ extra_byte
;
483 for (i
= 0; i
< size
; i
++) {
484 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
491 /* too less for absoluting so we must encode them even if it's expensive! */
494 *lpSizeImage
+= 2 * count
;
496 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
501 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
506 /* encode count pixel(s) */
507 clr
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
509 /* optimize end of line */
510 if (x
+ count
+ 1 == lpbi
->biWidth
)
515 INT size
= min(count
, 255);
529 LRESULT
MSRLE32_CompressRLE4(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
)
532 LONG lLine
, lInLine
, lDist
;
535 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
536 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
537 assert(pi
->pCurFrame
!= NULL
);
540 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
541 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
542 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
544 lpbiOut
->biSizeImage
= 0;
546 /* keyframe -- convert internal frame to output format */
549 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
553 x
= MSRLE32_CompressRLE4Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
554 &lpOut
, &lpbiOut
->biSizeImage
);
555 } while (x
< lpbiOut
->biWidth
);
560 /* add EOL -- end of line */
561 lpbiOut
->biSizeImage
+= 2;
562 *((LPWORD
)lpOut
)++ = 0;
565 /* delta-frame -- compute delta between last and this internal frame */
570 assert(pi
->pPrevFrame
!= NULL
);
572 lpP
= pi
->pPrevFrame
;
576 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
584 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
585 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
589 if (pos
== lpbiOut
->biWidth
&& count
> 8) {
590 /* (count > 8) secures that we will save space */
593 } else if (jumpy
|| jumpx
!= pos
) {
598 /* can only jump in positive direction -- jump until EOL, EOL */
599 INT w
= lpbiOut
->biWidth
- jumpx
;
606 /* if (w % 255 == 2) then equal costs
607 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
608 * else it will be cheaper
611 lpbiOut
->biSizeImage
+= 4;
614 *lpOut
= min(w
, 255);
618 /* add EOL -- end of line */
619 lpbiOut
->biSizeImage
+= 2;
620 *((LPWORD
)lpOut
)++ = 0;
623 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
625 /* write out real jump(s) */
626 while (jumpy
|| pos
!= jumpx
) {
627 lpbiOut
->biSizeImage
+= 4;
630 *lpOut
= min(pos
- jumpx
, 255);
633 *lpOut
= min(jumpy
, 255);
642 if (x
< lpbiOut
->biWidth
) {
643 /* skipped the 'same' things corresponding to previous frame */
644 x
= MSRLE32_CompressRLE4Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
645 &lpOut
, &lpbiOut
->biSizeImage
);
647 } while (x
< lpbiOut
->biWidth
);
656 /* add EOL -- end of line */
657 lpbiOut
->biSizeImage
+= 2;
658 *((LPWORD
)lpOut
)++ = 0;
663 /* add EOI -- end of image */
664 lpbiOut
->biSizeImage
+= 2;
671 LRESULT
MSRLE32_CompressRLE8(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
)
674 LONG lDist
, lInLine
, lLine
;
676 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
677 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
678 assert(pi
->pCurFrame
!= NULL
);
681 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
682 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
683 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
685 lpbiOut
->biSizeImage
= 0;
687 /* keyframe -- convert internal frame to output format */
690 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
694 x
= MSRLE32_CompressRLE8Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
695 &lpOut
, &lpbiOut
->biSizeImage
);
696 } while (x
< lpbiOut
->biWidth
);
701 /* add EOL -- end of line */
702 lpbiOut
->biSizeImage
+= 2;
703 *((LPWORD
)lpOut
)++ = 0;
706 /* delta-frame -- compute delta between last and this internal frame */
711 assert(pi
->pPrevFrame
!= NULL
);
713 lpP
= pi
->pPrevFrame
;
717 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
725 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
726 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
730 if (pos
== lpbiOut
->biWidth
&& count
> 4) {
731 /* (count > 4) secures that we will save space */
734 } else if (jumpy
|| jumpx
!= pos
) {
739 /* can only jump in positive direction -- do a EOL then jump */
745 /* add EOL -- end of line */
746 lpbiOut
->biSizeImage
+= 2;
747 *((LPWORD
)lpOut
)++ = 0;
750 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
752 /* write out real jump(s) */
753 while (jumpy
|| pos
!= jumpx
) {
754 lpbiOut
->biSizeImage
+= 4;
757 *lpOut
= min(pos
- jumpx
, 255);
759 *lpOut
= min(jumpy
, 255);
769 if (x
< lpbiOut
->biWidth
) {
770 /* skip the 'same' things corresponding to previous frame */
771 x
= MSRLE32_CompressRLE8Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
772 &lpOut
, &lpbiOut
->biSizeImage
);
774 } while (x
< lpbiOut
->biWidth
);
781 /* add EOL -- end of line */
782 lpbiOut
->biSizeImage
+= 2;
789 /* add EOI -- end of image */
790 lpbiOut
->biSizeImage
+= 2;
797 /*****************************************************************************/
799 static LRESULT
MSRLE32_DecompressRLE4(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
800 LPBYTE lpIn
, LPBYTE lpOut
)
806 BOOL bEndFlag
= FALSE
;
809 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
810 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
812 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
813 line_size
= DIBWIDTHBYTES(*lpbi
);
825 case 0: /* EOL - end of line */
829 case 1: /* EOI - end of image */
833 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
834 lpOut
+= *lpIn
++ * line_size
;
835 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
840 default: /* absolute mode */
841 extra_byte
= (code1
/ 2) & 0x01;
843 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
)
847 for (i
= 0; i
< code0
/ 2; i
++) {
848 if (bytes_per_pixel
== 1) {
850 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
852 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
& 0x0F)];
853 } else if (bytes_per_pixel
== 2) {
854 code1
= lpIn
[i
] >> 4;
855 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
856 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
858 if (2 * i
<= code0
) {
859 code1
= lpIn
[i
] & 0x0F;
860 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
861 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
864 code1
= lpIn
[i
] >> 4;
865 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
866 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
867 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
868 pixel_ptr
+= bytes_per_pixel
;
870 if (2 * i
<= code0
) {
871 code1
= lpIn
[i
] & 0x0F;
872 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
873 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
874 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
875 pixel_ptr
+= bytes_per_pixel
;
881 /* if the RLE code is odd, skip a byte in the stream */
887 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
)
890 if (bytes_per_pixel
== 1) {
891 BYTE c1
= pi
->palette_map
[(code1
>> 4)];
892 BYTE c2
= pi
->palette_map
[(code1
& 0x0F)];
894 for (i
= 0; i
< code0
; i
++) {
896 lpOut
[pixel_ptr
++] = c1
;
898 lpOut
[pixel_ptr
++] = c2
;
900 } else if (bytes_per_pixel
== 2) {
901 BYTE hi1
= pi
->palette_map
[(code1
>> 4) * 2 + 0];
902 BYTE lo1
= pi
->palette_map
[(code1
>> 4) * 2 + 1];
904 BYTE hi2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 0];
905 BYTE lo2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 1];
907 for (i
= 0; i
< code0
; i
++) {
909 lpOut
[pixel_ptr
++] = hi1
;
910 lpOut
[pixel_ptr
++] = lo1
;
912 lpOut
[pixel_ptr
++] = hi2
;
913 lpOut
[pixel_ptr
++] = lo2
;
917 BYTE b1
= pi
->palette_map
[(code1
>> 4) * 4 + 0];
918 BYTE g1
= pi
->palette_map
[(code1
>> 4) * 4 + 1];
919 BYTE r1
= pi
->palette_map
[(code1
>> 4) * 4 + 2];
921 BYTE b2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 0];
922 BYTE g2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 1];
923 BYTE r2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 2];
925 for (i
= 0; i
< code0
; i
++) {
927 lpOut
[pixel_ptr
+ 0] = b1
;
928 lpOut
[pixel_ptr
+ 1] = g1
;
929 lpOut
[pixel_ptr
+ 2] = r1
;
931 lpOut
[pixel_ptr
+ 0] = b2
;
932 lpOut
[pixel_ptr
+ 1] = g2
;
933 lpOut
[pixel_ptr
+ 2] = r2
;
935 pixel_ptr
+= bytes_per_pixel
;
939 } while (! bEndFlag
);
944 static LRESULT
MSRLE32_DecompressRLE8(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
945 LPBYTE lpIn
, LPBYTE lpOut
)
950 BOOL bEndFlag
= FALSE
;
953 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
954 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
956 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
957 line_size
= DIBWIDTHBYTES(*lpbi
);
969 case 0: /* EOL - end of line */
973 case 1: /* EOI - end of image */
977 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
978 lpOut
+= *lpIn
++ * line_size
;
979 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
984 default: /* absolute mode */
985 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
) {
986 WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
989 extra_byte
= code1
& 0x01;
994 if (bytes_per_pixel
== 1) {
995 lpOut
[pixel_ptr
] = pi
->palette_map
[code1
];
996 } else if (bytes_per_pixel
== 2) {
997 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 2 + 0];
998 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 2 + 1];
1000 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
1001 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
1002 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
1004 pixel_ptr
+= bytes_per_pixel
;
1007 /* if the RLE code is odd, skip a byte in the stream */
1013 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
) {
1014 WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1018 if (bytes_per_pixel
== 1) {
1019 code1
= pi
->palette_map
[code1
];
1021 lpOut
[pixel_ptr
++] = code1
;
1022 } else if (bytes_per_pixel
== 2) {
1023 BYTE hi
= pi
->palette_map
[code1
* 2 + 0];
1024 BYTE lo
= pi
->palette_map
[code1
* 2 + 1];
1027 lpOut
[pixel_ptr
+ 0] = hi
;
1028 lpOut
[pixel_ptr
+ 1] = lo
;
1029 pixel_ptr
+= bytes_per_pixel
;
1032 BYTE r
= pi
->palette_map
[code1
* 4 + 2];
1033 BYTE g
= pi
->palette_map
[code1
* 4 + 1];
1034 BYTE b
= pi
->palette_map
[code1
* 4 + 0];
1037 lpOut
[pixel_ptr
+ 0] = b
;
1038 lpOut
[pixel_ptr
+ 1] = g
;
1039 lpOut
[pixel_ptr
+ 2] = r
;
1040 pixel_ptr
+= bytes_per_pixel
;
1044 } while (! bEndFlag
);
1049 /*****************************************************************************/
1051 static CodecInfo
* Open(LPICOPEN icinfo
)
1053 CodecInfo
* pi
= NULL
;
1055 if (icinfo
== NULL
) {
1057 return (LPVOID
)0xFFFF0000;
1060 TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo
,
1061 icinfo
->dwSize
, icinfo
->fccType
, (char*)&icinfo
->fccType
,
1062 icinfo
->fccHandler
, (char*)&icinfo
->fccHandler
,
1063 icinfo
->dwVersion
,icinfo
->dwFlags
);
1065 if (icinfo
->fccType
!= ICTYPE_VIDEO
)
1068 switch (icinfo
->fccHandler
) {
1074 case mmioFOURCC('m','r','l','e'):
1075 icinfo
->fccHandler
= FOURCC_MRLE
;
1078 WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1079 icinfo
->fccHandler
,(char*)&icinfo
->fccHandler
);
1083 pi
= (CodecInfo
*)LocalAlloc(LPTR
, sizeof(CodecInfo
));
1086 pi
->fccHandler
= icinfo
->fccHandler
;
1088 pi
->bCompress
= FALSE
;
1089 pi
->dwQuality
= MSRLE32_DEFAULTQUALITY
;
1090 pi
->nPrevFrame
= -1;
1091 pi
->pPrevFrame
= pi
->pCurFrame
= NULL
;
1093 pi
->bDecompress
= FALSE
;
1094 pi
->palette_map
= NULL
;
1097 icinfo
->dwError
= (pi
!= NULL
? ICERR_OK
: ICERR_MEMORY
);
1102 static LRESULT
Close(CodecInfo
*pi
)
1104 TRACE("(%p)\n", pi
);
1109 if (pi
->pPrevFrame
!= NULL
|| pi
->pCurFrame
!= NULL
)
1112 LocalFree((HLOCAL
)pi
);
1116 static LRESULT
GetInfo(CodecInfo
*pi
, ICINFO
*icinfo
, DWORD dwSize
)
1121 /* check parameters */
1123 return sizeof(ICINFO
);
1124 if (dwSize
< sizeof(ICINFO
))
1127 icinfo
->dwSize
= sizeof(ICINFO
);
1128 icinfo
->fccType
= streamtypeVIDEO
;
1129 icinfo
->fccHandler
= (pi
!= NULL
? pi
->fccHandler
: FOURCC_MRLE
);
1130 icinfo
->dwFlags
= VIDCF_QUALITY
| VIDCF_TEMPORAL
| VIDCF_CRUNCH
| VIDCF_FASTTEMPORALC
;
1131 icinfo
->dwVersion
= MSRLE32_VERSION
;
1132 icinfo
->dwVersionICM
= 0x01040000; /* Version 1.4 build 0 */
1134 LoadWideString(IDS_NAME
, icinfo
->szName
, sizeof(icinfo
->szName
));
1135 LoadWideString(IDS_DESCRIPTION
, icinfo
->szDescription
, sizeof(icinfo
->szDescription
));
1137 return sizeof(ICINFO
);
1140 static LRESULT
SetQuality(CodecInfo
*pi
, LONG lQuality
)
1146 lQuality
= MSRLE32_DEFAULTQUALITY
;
1147 else if (ICQUALITY_LOW
> lQuality
|| lQuality
> ICQUALITY_HIGH
)
1148 return ICERR_BADPARAM
;
1150 pi
->dwQuality
= (DWORD
)lQuality
;
1155 static LRESULT
Configure(CodecInfo
*pi
, HWND hWnd
)
1164 static LRESULT
About(CodecInfo
*pi
, HWND hWnd
)
1170 assert(MSRLE32_hModule
!= 0);
1172 LoadStringA(MSRLE32_hModule
, IDS_NAME
, szTitle
, sizeof(szTitle
));
1173 LoadStringA(MSRLE32_hModule
, IDS_ABOUT
, szAbout
, sizeof(szAbout
));
1175 MessageBoxA(hWnd
, szAbout
, szTitle
, MB_OK
|MB_ICONINFORMATION
);
1180 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1181 LPBITMAPINFOHEADER lpbiOut
)
1185 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1190 /* check parameters -- need atleast input format */
1191 if (lpbiIn
== NULL
) {
1192 if (lpbiOut
!= NULL
)
1193 return ICERR_BADPARAM
;
1197 /* handle unsupported input format */
1198 if (CompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1199 return (lpbiOut
== NULL
? ICERR_BADFORMAT
: 0);
1201 assert(0 < lpbiIn
->biBitCount
&& lpbiIn
->biBitCount
<= 8);
1203 switch (pi
->fccHandler
) {
1212 size
= (lpbiIn
->biBitCount
<= 4 ? 1 << 4 : 1 << 8);
1218 if (lpbiIn
->biClrUsed
!= 0)
1219 size
= lpbiIn
->biClrUsed
;
1221 size
= sizeof(BITMAPINFOHEADER
) + size
* sizeof(RGBQUAD
);
1223 if (lpbiOut
!= NULL
) {
1224 lpbiOut
->biSize
= sizeof(BITMAPINFOHEADER
);
1225 lpbiOut
->biWidth
= lpbiIn
->biWidth
;
1226 lpbiOut
->biHeight
= lpbiIn
->biHeight
;
1227 lpbiOut
->biPlanes
= 1;
1228 if (pi
->fccHandler
== FOURCC_RLE4
||
1229 lpbiIn
->biBitCount
<= 4) {
1230 lpbiOut
->biCompression
= BI_RLE4
;
1231 lpbiOut
->biBitCount
= 4;
1233 lpbiOut
->biCompression
= BI_RLE8
;
1234 lpbiOut
->biBitCount
= 8;
1236 lpbiOut
->biSizeImage
= MSRLE32_GetMaxCompressedSize(lpbiOut
);
1237 lpbiOut
->biXPelsPerMeter
= lpbiIn
->biXPelsPerMeter
;
1238 lpbiOut
->biYPelsPerMeter
= lpbiIn
->biYPelsPerMeter
;
1239 if (lpbiIn
->biClrUsed
== 0)
1240 size
= 1<<lpbiIn
->biBitCount
;
1242 size
= lpbiIn
->biClrUsed
;
1243 lpbiOut
->biClrUsed
= min(size
, 1u << lpbiOut
->biBitCount
);
1244 lpbiOut
->biClrImportant
= 0;
1246 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
,
1247 (LPBYTE
)lpbiIn
+ lpbiIn
->biSize
, lpbiOut
->biClrUsed
* sizeof(RGBQUAD
));
1254 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1255 LPCBITMAPINFOHEADER lpbiOut
)
1260 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1262 /* check parameter -- need atleast one format */
1263 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1265 /* check if the given format is supported */
1266 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1269 /* the worst case is coding the complete image in absolute mode. */
1271 return MSRLE32_GetMaxCompressedSize(lpbiIn
);
1273 return MSRLE32_GetMaxCompressedSize(lpbiOut
);
1276 static LRESULT
CompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1277 LPCBITMAPINFOHEADER lpbiOut
)
1282 /* need atleast one format */
1283 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1284 return ICERR_BADPARAM
;
1286 /* check input format if given */
1287 if (lpbiIn
!= NULL
) {
1288 if (!isSupportedDIB(lpbiIn
))
1289 return ICERR_BADFORMAT
;
1291 /* for 4-bit need an even width */
1292 if (lpbiIn
->biBitCount
<= 4 && (lpbiIn
->biWidth
% 2))
1293 return ICERR_BADFORMAT
;
1295 if (pi
->fccHandler
== FOURCC_RLE4
&& lpbiIn
->biBitCount
> 4)
1296 return ICERR_UNSUPPORTED
;
1297 else if (lpbiIn
->biBitCount
> 8)
1298 return ICERR_UNSUPPORTED
;
1301 /* check output format if given */
1302 if (lpbiOut
!= NULL
) {
1303 if (!isSupportedMRLE(lpbiOut
))
1304 return ICERR_BADFORMAT
;
1306 if (lpbiIn
!= NULL
) {
1307 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1308 return ICERR_UNSUPPORTED
;
1309 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1310 return ICERR_UNSUPPORTED
;
1311 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1312 return ICERR_UNSUPPORTED
;
1319 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1320 LPCBITMAPINFOHEADER lpbiOut
)
1327 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1332 /* check parameters -- need both formats */
1333 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1334 return ICERR_BADPARAM
;
1335 /* And both must be supported */
1336 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1337 return ICERR_BADFORMAT
;
1339 /* FIXME: cannot compress and decompress at a time! */
1340 if (pi
->bDecompress
) {
1341 FIXME("cannot compress and decompress at same time!\n");
1348 size
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2 * lpbiOut
->biHeight
;
1349 pi
->pPrevFrame
= (LPWORD
)GlobalAllocPtr(GPTR
, size
* sizeof(WORD
));
1350 if (pi
->pPrevFrame
== NULL
)
1351 return ICERR_MEMORY
;
1352 pi
->pCurFrame
= (LPWORD
)GlobalAllocPtr(GPTR
, size
* sizeof(WORD
));
1353 if (pi
->pCurFrame
== NULL
) {
1355 return ICERR_MEMORY
;
1357 pi
->nPrevFrame
= -1;
1358 pi
->bCompress
= TRUE
;
1360 rgbIn
= (RGBQUAD
*)((LPBYTE
)lpbiIn
+ lpbiIn
->biSize
);
1361 rgbOut
= (RGBQUAD
*)((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
);
1363 switch (lpbiOut
->biBitCount
) {
1366 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1367 if (pi
->palette_map
== NULL
) {
1369 return ICERR_MEMORY
;
1372 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1373 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1381 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
)
1385 TRACE("(%p,%p,%lu)\n",pi
,lpic
,dwSize
);
1390 /* check parameters */
1391 if (lpic
== NULL
|| dwSize
< sizeof(ICCOMPRESS
))
1392 return ICERR_BADPARAM
;
1393 if (!lpic
->lpbiOutput
|| !lpic
->lpOutput
||
1394 !lpic
->lpbiInput
|| !lpic
->lpInput
)
1395 return ICERR_BADPARAM
;
1397 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
);
1399 if (! pi
->bCompress
) {
1400 LRESULT hr
= CompressBegin(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
);
1403 } else if (CompressQuery(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
) != ICERR_OK
)
1404 return ICERR_BADFORMAT
;
1406 if (lpic
->lFrameNum
>= pi
->nPrevFrame
+ 1) {
1407 /* we continue in the sequence so we need to initialize
1408 * our internal framedata */
1410 computeInternalFrame(pi
, lpic
->lpbiInput
, lpic
->lpInput
);
1411 } else if (lpic
->lFrameNum
== pi
->nPrevFrame
) {
1412 /* Oops, compress same frame again ? Okay, as you wish.
1413 * No need to recompute internal framedata, because we only swapped buffers */
1414 LPWORD pTmp
= pi
->pPrevFrame
;
1416 FIXME(": prev=%ld cur=%ld swap\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1417 pi
->pPrevFrame
= pi
->pCurFrame
;
1418 pi
->pCurFrame
= pTmp
;
1419 } else if ((lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1422 WARN(": prev=%ld cur=%ld gone back? -- untested",pi
->nPrevFrame
,lpic
->lFrameNum
);
1423 if (lpic
->lpbiPrev
== NULL
|| lpic
->lpPrev
== NULL
)
1424 return ICERR_GOTOKEYFRAME
; /* Need a keyframe if you go back */
1425 if (CompressQuery(pi
, lpic
->lpbiPrev
, lpic
->lpbiOutput
) != ICERR_OK
)
1426 return ICERR_BADFORMAT
;
1428 WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1429 computeInternalFrame(pi
, lpic
->lpbiPrev
, lpic
->lpPrev
);
1431 /* swap buffers for current and previous frame */
1432 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1433 pTmp
= pi
->pPrevFrame
;
1434 pi
->pPrevFrame
= pi
->pCurFrame
;
1435 pi
->pCurFrame
= pTmp
;
1436 pi
->nPrevFrame
= lpic
->lFrameNum
;
1439 for (i
= 0; i
< 3; i
++) {
1440 SetQuality(pi
, lpic
->dwQuality
);
1442 lpic
->lpbiOutput
->biSizeImage
= 0;
1444 if (lpic
->lpbiOutput
->biBitCount
== 4)
1445 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1446 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1447 /*MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1448 lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);*/
1450 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1451 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1453 if (lpic
->dwFrameSize
== 0 ||
1454 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
)
1457 if ((*lpic
->lpdwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1458 if (lpic
->lpbiOutput
->biBitCount
== 4)
1459 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1460 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1462 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1463 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1465 if (lpic
->dwFrameSize
== 0 ||
1466 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
) {
1467 WARN("switched to keyframe, was small enough!\n");
1468 *lpic
->lpdwFlags
|= ICCOMPRESS_KEYFRAME
;
1469 *lpic
->lpckid
= MAKEAVICKID(cktypeDIBbits
,
1470 StreamFromFOURCC(*lpic
->lpckid
));
1475 if (lpic
->dwQuality
< 1000)
1478 lpic
->dwQuality
-= 1000; /* reduce quality by 10% */
1481 { /* swap buffer for current and previous frame */
1482 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1483 register LPWORD pTmp
= pi
->pPrevFrame
;
1485 pi
->pPrevFrame
= pi
->pCurFrame
;
1486 pi
->pCurFrame
= pTmp
;
1487 pi
->nPrevFrame
= lpic
->lFrameNum
;
1493 static LRESULT
CompressEnd(CodecInfo
*pi
)
1498 if (pi
->pPrevFrame
!= NULL
)
1499 GlobalFreePtr(pi
->pPrevFrame
);
1500 if (pi
->pCurFrame
!= NULL
)
1501 GlobalFreePtr(pi
->pCurFrame
);
1502 pi
->pPrevFrame
= NULL
;
1503 pi
->pCurFrame
= NULL
;
1504 pi
->nPrevFrame
= -1;
1505 pi
->bCompress
= FALSE
;
1511 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1512 LPBITMAPINFOHEADER lpbiOut
)
1516 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1522 return (lpbiOut
!= NULL
? ICERR_BADPARAM
: 0);
1524 if (DecompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1525 return (lpbiOut
!= NULL
? ICERR_BADFORMAT
: 0);
1527 size
= lpbiIn
->biSize
;
1529 if (lpbiOut
!= NULL
) {
1530 memcpy(lpbiOut
, lpbiIn
, size
);
1531 lpbiOut
->biBitCount
= 32;
1532 lpbiOut
->biCompression
= BI_RGB
;
1533 lpbiOut
->biSizeImage
= DIBWIDTHBYTES(*lpbiOut
) * lpbiOut
->biHeight
;
1534 lpbiOut
->biClrImportant
= 0;
1536 if (lpbiOut
->biBitCount
<= 8 && lpbiOut
->biClrUsed
== 0)
1537 lpbiOut
->biClrUsed
= 1 << lpbiOut
->biBitCount
;
1539 lpbiOut
->biClrUsed
= 0;
1546 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1547 LPCBITMAPINFOHEADER lpbiOut
)
1549 LRESULT hr
= ICERR_OK
;
1551 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1556 /* need atleast one format */
1557 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1558 return ICERR_BADPARAM
;
1560 /* check input format if given */
1561 if (lpbiIn
!= NULL
) {
1562 if (!isSupportedMRLE(lpbiIn
))
1563 return ICERR_BADFORMAT
;
1566 /* check output format if given */
1567 if (lpbiOut
!= NULL
) {
1568 if (!isSupportedDIB(lpbiOut
))
1569 hr
= ICERR_BADFORMAT
;
1571 if (lpbiIn
!= NULL
) {
1572 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1573 hr
= ICERR_UNSUPPORTED
;
1574 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1575 hr
= ICERR_UNSUPPORTED
;
1576 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1577 hr
= ICERR_UNSUPPORTED
;
1584 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1585 LPCBITMAPINFOHEADER lpbiOut
)
1591 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1596 /* check parameters */
1597 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1598 return ICERR_BADPARAM
;
1599 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1600 return ICERR_BADFORMAT
;
1602 /* FIXME: cannot compress and decompress at a time! */
1603 if (pi
->bCompress
) {
1604 FIXME("cannot compress and decompress at same time!\n");
1608 if (pi
->bDecompress
)
1611 rgbIn
= (RGBQUAD
*)((LPBYTE
)lpbiIn
+ lpbiIn
->biSize
);
1612 rgbOut
= (RGBQUAD
*)((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
);
1614 switch (lpbiOut
->biBitCount
) {
1617 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1618 if (pi
->palette_map
== NULL
)
1619 return ICERR_MEMORY
;
1621 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1622 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1627 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* 2);
1628 if (pi
->palette_map
== NULL
)
1629 return ICERR_MEMORY
;
1631 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1634 if (lpbiOut
->biBitCount
== 15)
1635 color
= ((rgbIn
[i
].rgbRed
>> 3) << 10)
1636 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1638 color
= ((rgbIn
[i
].rgbRed
>> 3) << 11)
1639 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1641 pi
->palette_map
[i
* 2 + 1] = color
>> 8;
1642 pi
->palette_map
[i
* 2 + 0] = color
& 0xFF;
1647 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1648 if (pi
->palette_map
== NULL
)
1649 return ICERR_MEMORY
;
1650 memcpy(pi
->palette_map
, rgbIn
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1654 pi
->bDecompress
= TRUE
;
1659 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
)
1661 TRACE("(%p,%p,%lu)\n",pi
,pic
,dwSize
);
1666 /* check parameters */
1668 return ICERR_BADPARAM
;
1669 if (pic
->lpbiInput
== NULL
|| pic
->lpInput
== NULL
||
1670 pic
->lpbiOutput
== NULL
|| pic
->lpOutput
== NULL
)
1671 return ICERR_BADPARAM
;
1674 if (! pi
->bDecompress
) {
1675 LRESULT hr
= DecompressBegin(pi
, pic
->lpbiInput
, pic
->lpbiOutput
);
1678 } else if (DecompressQuery(pi
, pic
->lpbiInput
, pic
->lpbiOutput
) != ICERR_OK
)
1679 return ICERR_BADFORMAT
;
1681 assert(pic
->lpbiInput
->biWidth
== pic
->lpbiOutput
->biWidth
);
1682 assert(pic
->lpbiInput
->biHeight
== pic
->lpbiOutput
->biHeight
);
1684 pic
->lpbiOutput
->biSizeImage
= DIBWIDTHBYTES(*pic
->lpbiOutput
) * pic
->lpbiOutput
->biHeight
;
1685 if (pic
->lpbiInput
->biBitCount
== 4)
1686 return MSRLE32_DecompressRLE4(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1688 return MSRLE32_DecompressRLE8(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1691 static LRESULT
DecompressEnd(CodecInfo
*pi
)
1698 pi
->bDecompress
= FALSE
;
1700 if (pi
->palette_map
!= NULL
) {
1701 LocalFree((HLOCAL
)pi
->palette_map
);
1702 pi
->palette_map
= NULL
;
1708 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1709 LPBITMAPINFOHEADER lpbiOut
)
1713 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1718 /* check parameters */
1719 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1720 return ICERR_BADPARAM
;
1722 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1723 return ICERR_BADFORMAT
;
1725 if (lpbiOut
->biBitCount
> 8)
1728 if (lpbiIn
->biBitCount
<= 8) {
1729 if (lpbiIn
->biClrUsed
> 0)
1730 size
= lpbiIn
->biClrUsed
;
1732 size
= (1 << lpbiIn
->biBitCount
);
1734 lpbiOut
->biClrUsed
= size
;
1736 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
, (LPBYTE
)lpbiIn
+ lpbiIn
->biSize
, size
* sizeof(RGBQUAD
));
1737 } /* else could never occur ! */
1742 /* DriverProc - entry point for an installable driver */
1743 LRESULT CALLBACK
MSRLE32_DriverProc(DWORD dwDrvID
, HDRVR hDrv
, UINT uMsg
,
1744 LPARAM lParam1
, LPARAM lParam2
)
1746 CodecInfo
*pi
= (CodecInfo
*)dwDrvID
;
1748 TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID
)dwDrvID
, (LPVOID
)hDrv
,
1749 uMsg
, lParam1
, lParam2
);
1752 /* standard driver messages */
1757 return (LRESULT
)0xFFFF0000;
1759 return (LRESULT
)Open((ICOPEN
*)lParam2
);
1761 if (dwDrvID
!= 0xFFFF0000 && (LPVOID
)dwDrvID
!= NULL
)
1769 case DRV_QUERYCONFIGURE
:
1770 return DRVCNF_CANCEL
; /* FIXME */
1772 return DRVCNF_OK
; /* FIXME */
1777 /* installable compression manager messages */
1779 FIXME("ICM_CONFIGURE (%ld)\n",lParam1
);
1781 return ICERR_UNSUPPORTED
; /* FIXME */
1783 return Configure(pi
, (HWND
)lParam1
);
1788 return About(pi
, (HWND
)lParam1
);
1791 return 0; /* no state */
1793 return GetInfo(pi
, (ICINFO
*)lParam1
, (DWORD
)lParam2
);
1794 case ICM_GETDEFAULTQUALITY
:
1795 if ((LPVOID
)lParam1
!= NULL
) {
1796 *((LPDWORD
)lParam1
) = MSRLE32_DEFAULTQUALITY
;
1800 case ICM_GETQUALITY
:
1801 if ((LPVOID
)lParam1
!= NULL
) {
1802 *((LPDWORD
)lParam1
) = pi
->dwQuality
;
1806 case ICM_SETQUALITY
:
1807 return SetQuality(pi
, *(LPLONG
)lParam1
);
1809 case ICM_COMPRESS_GET_FORMAT
:
1810 return CompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1811 (LPBITMAPINFOHEADER
)lParam2
);
1812 case ICM_COMPRESS_GET_SIZE
:
1813 return CompressGetSize(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1814 (LPCBITMAPINFOHEADER
)lParam2
);
1815 case ICM_COMPRESS_QUERY
:
1816 return CompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1817 (LPCBITMAPINFOHEADER
)lParam2
);
1818 case ICM_COMPRESS_BEGIN
:
1819 return CompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1820 (LPCBITMAPINFOHEADER
)lParam2
);
1822 return Compress(pi
, (ICCOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1823 case ICM_COMPRESS_END
:
1824 return CompressEnd(pi
);
1825 case ICM_DECOMPRESS_GET_FORMAT
:
1826 return DecompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1827 (LPBITMAPINFOHEADER
)lParam2
);
1828 case ICM_DECOMPRESS_QUERY
:
1829 return DecompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1830 (LPCBITMAPINFOHEADER
)lParam2
);
1831 case ICM_DECOMPRESS_BEGIN
:
1832 return DecompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1833 (LPCBITMAPINFOHEADER
)lParam2
);
1834 case ICM_DECOMPRESS
:
1835 return Decompress(pi
, (ICDECOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1836 case ICM_DECOMPRESS_END
:
1837 return DecompressEnd(pi
);
1838 case ICM_DECOMPRESS_SET_PALETTE
:
1839 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi
, (LPVOID
)lParam1
, (LPVOID
)lParam2
);
1840 return ICERR_UNSUPPORTED
;
1841 case ICM_DECOMPRESS_GET_PALETTE
:
1842 return DecompressGetPalette(pi
, (LPBITMAPINFOHEADER
)lParam1
,
1843 (LPBITMAPINFOHEADER
)lParam2
);
1844 case ICM_GETDEFAULTKEYFRAMERATE
:
1845 if ((LPVOID
)lParam1
!= NULL
)
1846 *(LPDWORD
)lParam1
= 15;
1849 if (uMsg
< DRV_USER
)
1850 return DefDriverProc(dwDrvID
, hDrv
, uMsg
, lParam1
, lParam2
);
1852 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg
,lParam1
,lParam2
);
1855 return ICERR_UNSUPPORTED
;
1858 /* DllMain - library initialization code */
1859 BOOL WINAPI
MSRLE32_DllMain(HINSTANCE hModule
, DWORD dwReason
, LPVOID lpReserved
)
1861 TRACE("(%p,%ld,%p)\n",(LPVOID
)hModule
,dwReason
,lpReserved
);
1864 case DLL_PROCESS_ATTACH
:
1865 if (MSRLE32_hModule
== 0)
1866 MSRLE32_hModule
= hModule
;
1868 case DLL_THREAD_ATTACH
:
1870 case DLL_THREAD_DETACH
:
1872 case DLL_PROCESS_DETACH
: