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 compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
39 #define ABS(a) ((a) < 0 ? -(a) : (a))
40 #define SQR(a) ((a) * (a))
42 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
43 static inline WORD
ColorCmp(WORD clr1
, WORD clr2
)
45 register UINT a
= (clr1
-clr2
);
48 static 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 BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
);
64 /* compression functions */
65 static void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, const BYTE
*lpIn
);
66 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
);
67 static LRESULT
MSRLE32_CompressRLE4(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
68 const BYTE
*lpIn
, LPBITMAPINFOHEADER lpbiOut
,
69 LPBYTE lpOut
, BOOL isKey
);
70 static LRESULT
MSRLE32_CompressRLE8(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
71 const BYTE
*lpIn
, LPBITMAPINFOHEADER lpbiOut
,
72 LPBYTE lpOut
, BOOL isKey
);
74 /* decompression functions */
75 static LRESULT
MSRLE32_DecompressRLE4(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
76 const BYTE
*lpIn
, LPBYTE lpOut
);
77 static LRESULT
MSRLE32_DecompressRLE8(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
78 const BYTE
*lpIn
, LPBYTE lpOut
);
81 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
82 LPBITMAPINFOHEADER lpbiOut
);
83 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
84 LPCBITMAPINFOHEADER lpbiOut
);
85 static LRESULT
CompressQuery(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
86 LPCBITMAPINFOHEADER lpbiOut
);
87 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
88 LPCBITMAPINFOHEADER lpbiOut
);
89 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
);
90 static LRESULT
CompressEnd(CodecInfo
*pi
);
92 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
93 LPBITMAPINFOHEADER lpbiOut
);
94 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
95 LPCBITMAPINFOHEADER lpbiOut
);
96 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
97 LPCBITMAPINFOHEADER lpbiOut
);
98 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
);
99 static LRESULT
DecompressEnd(CodecInfo
*pi
);
100 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
101 LPBITMAPINFOHEADER lpbiOut
);
103 /*****************************************************************************/
105 static BOOL
isSupportedMRLE(LPCBITMAPINFOHEADER lpbi
)
108 assert(lpbi
!= NULL
);
110 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) ||
114 if (lpbi
->biCompression
== BI_RLE4
) {
115 if (lpbi
->biBitCount
!= 4 ||
116 (lpbi
->biWidth
% 2) != 0)
118 } else if (lpbi
->biCompression
== BI_RLE8
) {
119 if (lpbi
->biBitCount
!= 8)
127 static BOOL
isSupportedDIB(LPCBITMAPINFOHEADER lpbi
)
130 assert(lpbi
!= NULL
);
132 /* check structure version/planes/compression */
133 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) ||
136 if (lpbi
->biCompression
!= BI_RGB
&&
137 lpbi
->biCompression
!= BI_BITFIELDS
)
140 /* check bit-depth */
141 if (lpbi
->biBitCount
!= 1 &&
142 lpbi
->biBitCount
!= 4 &&
143 lpbi
->biBitCount
!= 8 &&
144 lpbi
->biBitCount
!= 15 &&
145 lpbi
->biBitCount
!= 16 &&
146 lpbi
->biBitCount
!= 24 &&
147 lpbi
->biBitCount
!= 32)
150 /* check for size(s) */
151 if (!lpbi
->biWidth
|| !lpbi
->biHeight
)
152 return FALSE
; /* image with zero size, makes no sense so error ! */
153 if (DIBWIDTHBYTES(*lpbi
) * (DWORD
)lpbi
->biHeight
>= (1UL << 31) - 1)
154 return FALSE
; /* image too big ! */
156 /* check for nonexistent colortable for hi- and true-color DIB's */
157 if (lpbi
->biBitCount
>= 15 && lpbi
->biClrUsed
> 0)
163 static BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
)
165 INT diff
= 0x00FFFFFF;
170 assert(clrs
!= NULL
);
172 for (i
= 0; i
< count
; i
++) {
173 int r
= ((int)clrs
[i
].rgbRed
- (int)clr
.rgbRed
);
174 int g
= ((int)clrs
[i
].rgbGreen
- (int)clr
.rgbGreen
);
175 int b
= ((int)clrs
[i
].rgbBlue
- (int)clr
.rgbBlue
);
190 /*****************************************************************************/
192 void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, const BYTE
*lpIn
)
194 WORD wIntensityTbl
[256];
195 DWORD lInLine
, lOutLine
;
201 assert(pi
!= NULL
&& lpbiIn
!= NULL
&& lpIn
!= NULL
);
202 assert(pi
->pCurFrame
!= NULL
);
204 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
205 lOutLine
= WIDTHBYTES((WORD
)lpbiIn
->biWidth
* 8u * sizeof(WORD
)) / 2u;
206 lpOut
= pi
->pCurFrame
;
208 assert(lpbiIn
->biClrUsed
!= 0);
212 (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
214 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++)
215 wIntensityTbl
[i
] = Intensity(lp
[i
]);
218 for (y
= 0; y
< lpbiIn
->biHeight
; y
++) {
221 switch (lpbiIn
->biBitCount
) {
223 for (x
= 0; x
< lpbiIn
->biWidth
/ 8; x
++) {
224 for (i
= 0; i
< 7; i
++)
225 lpOut
[8 * x
+ i
] = wIntensityTbl
[(lpIn
[x
] >> (7 - i
)) & 1];
229 for (x
= 0; x
< lpbiIn
->biWidth
/ 2; x
++) {
230 lpOut
[2 * x
+ 0] = wIntensityTbl
[(lpIn
[x
] >> 4)];
231 lpOut
[2 * x
+ 1] = wIntensityTbl
[(lpIn
[x
] & 0x0F)];
235 for (x
= 0; x
< lpbiIn
->biWidth
; x
++)
236 lpOut
[x
] = wIntensityTbl
[lpIn
[x
]];
245 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
)
250 assert(lpbi
!= NULL
);
252 a
= lpbi
->biWidth
/ 255;
253 b
= lpbi
->biWidth
% 255;
254 if (lpbi
->biBitCount
<= 4) {
259 size
= (2 + a
* (2 + ((a
+ 2) & ~2)) + b
* (2 + ((b
+ 2) & ~2)));
260 return size
* lpbi
->biHeight
;
263 /* lpP => current pos in previous frame
264 * lpA => previous pos in current frame
265 * lpB => current pos in current frame
267 static INT
countDiffRLE4(const WORD
*lpP
, const WORD
*lpA
, const WORD
*lpB
, INT pos
, LONG lDist
, LONG width
)
273 assert(lpA
&& lpB
&& lDist
>= 0 && width
> 0);
284 while (pos
+ 1 < width
) {
288 if (pos
+ 1 >= width
)
292 if (ColorCmp(clr1
, clr3
) <= lDist
&&
293 ColorCmp(clr2
, clr4
) <= lDist
) {
294 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
295 if (pos
+ 2 < width
&& ColorCmp(clr1
,lpB
[pos
+1]) <= lDist
&&
296 ColorCmp(clr2
,lpB
[pos
+2]) <= lDist
) {
297 if (pos
+ 4 < width
&& ColorCmp(lpB
[pos
+1],lpB
[pos
+3]) <= lDist
&&
298 ColorCmp(lpB
[pos
+2],lpB
[pos
+4]) <= lDist
)
299 return count
- 3; /* followed by at least 4 encodable pixels */
302 } else if (lpP
!= NULL
&& 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(const WORD
*lpP
, const WORD
*lpA
, const WORD
*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 some more encodable pixel */
333 if (pos
+ 1 < width
&& ColorCmp(lpB
[pos
], lpB
[pos
+1]) <= lDist
)
335 if (pos
+ 2 < width
&& ColorCmp(lpB
[pos
+1], lpB
[pos
+2]) <= lDist
)
337 } else if (lpP
!= NULL
&& ColorCmp(lpP
[pos
], lpB
[pos
]) <= lDist
) {
338 /* 'compare' with previous frame for end of diff */
341 for (count2
= 0, pos
++; pos
< width
&& count2
<= 5; pos
++, count2
++) {
342 if (ColorCmp(lpP
[pos
], lpB
[pos
]) > lDist
)
355 static INT
MSRLE32_CompressRLE4Line(const CodecInfo
*pi
, const WORD
*lpP
,
356 const WORD
*lpC
, LPCBITMAPINFOHEADER lpbi
,
357 const BYTE
*lpIn
, LONG lDist
,
358 INT x
, LPBYTE
*ppOut
,
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 at least 3 and at most 254 pixels */
398 INT size
= min(count
, 254);
399 int bytes
= ((size
+ 1) & (~1)) / 2;
400 int 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 little 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(const CodecInfo
*pi
, const WORD
*lpP
,
459 const WORD
*lpC
, LPCBITMAPINFOHEADER lpbi
,
460 const BYTE
*lpIn
, LONG lDist
,
461 INT x
, LPBYTE
*ppOut
,
464 LPBYTE lpOut
= *ppOut
;
468 assert(lpbi
->biBitCount
<= 8);
469 assert(lpbi
->biCompression
== BI_RGB
);
471 /* try to encode as much as possible */
474 for (count
= 1; pos
< lpbi
->biWidth
; count
++) {
475 if (ColorCmp(clr
, lpC
[pos
++]) > lDist
)
480 /* add some more pixels for absoluting if possible */
481 count
+= countDiffRLE8(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
485 /* check for over end of line */
486 if (x
+ count
> lpbi
->biWidth
)
487 count
= lpbi
->biWidth
- x
;
489 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
492 INT size
= min(count
, 255);
493 int extra_byte
= size
% 2;
495 *lpSizeImage
+= 2 + size
+ extra_byte
;
499 for (i
= 0; i
< size
; i
++) {
500 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
507 /* too little for absoluting so we must encode them even if it's expensive! */
510 *lpSizeImage
+= 2 * count
;
512 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
517 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
522 /* encode count pixel(s) */
523 clr
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
525 /* optimize end of line */
526 if (x
+ count
+ 1 == lpbi
->biWidth
)
531 INT size
= min(count
, 255);
545 LRESULT
MSRLE32_CompressRLE4(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
546 const BYTE
*lpIn
, LPBITMAPINFOHEADER lpbiOut
,
547 LPBYTE lpOut
, BOOL isKey
)
550 LONG lLine
, lInLine
, lDist
;
551 LPBYTE lpOutStart
= lpOut
;
554 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
555 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
556 assert(pi
->pCurFrame
!= NULL
);
559 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
560 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
561 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
563 lpbiOut
->biSizeImage
= 0;
565 /* keyframe -- convert internal frame to output format */
568 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
572 x
= MSRLE32_CompressRLE4Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
573 &lpOut
, &lpbiOut
->biSizeImage
);
574 } while (x
< lpbiOut
->biWidth
);
579 /* add EOL -- end of line */
580 lpbiOut
->biSizeImage
+= 2;
582 lpOut
+= sizeof(WORD
);
583 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
586 /* delta-frame -- compute delta between last and this internal frame */
591 assert(pi
->pPrevFrame
!= NULL
);
593 lpP
= pi
->pPrevFrame
;
597 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
605 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
606 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
610 if (pos
== lpbiOut
->biWidth
&& count
> 8) {
611 /* (count > 8) secures that we will save space */
614 } else if (jumpy
|| jumpx
!= pos
) {
619 /* can only jump in positive direction -- jump until EOL, EOL */
620 INT w
= lpbiOut
->biWidth
- jumpx
;
627 /* if (w % 255 == 2) then equal costs
628 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
629 * else it will be cheaper
632 lpbiOut
->biSizeImage
+= 4;
635 *lpOut
= min(w
, 255);
639 /* add EOL -- end of line */
640 lpbiOut
->biSizeImage
+= 2;
641 *((LPWORD
)lpOut
) = 0;
642 lpOut
+= sizeof(WORD
);
645 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
647 /* write out real jump(s) */
648 while (jumpy
|| pos
!= jumpx
) {
649 lpbiOut
->biSizeImage
+= 4;
652 *lpOut
= min(pos
- jumpx
, 255);
655 *lpOut
= min(jumpy
, 255);
664 if (x
< lpbiOut
->biWidth
) {
665 /* skipped the 'same' things corresponding to previous frame */
666 x
= MSRLE32_CompressRLE4Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
667 &lpOut
, &lpbiOut
->biSizeImage
);
669 } while (x
< lpbiOut
->biWidth
);
678 /* add EOL -- end of line */
679 lpbiOut
->biSizeImage
+= 2;
680 *((LPWORD
)lpOut
) = 0;
681 lpOut
+= sizeof(WORD
);
682 assert(lpOut
== lpOutStart
+ lpbiOut
->biSizeImage
);
686 /* add EOL -- will be changed to EOI */
687 lpbiOut
->biSizeImage
+= 2;
688 *((LPWORD
)lpOut
) = 0;
689 lpOut
+= sizeof(WORD
);
692 /* change EOL to EOI -- end of image */
694 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
699 LRESULT
MSRLE32_CompressRLE8(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
700 const BYTE
*lpIn
, LPBITMAPINFOHEADER lpbiOut
,
701 LPBYTE lpOut
, BOOL isKey
)
704 LONG lDist
, lInLine
, lLine
;
705 LPBYTE lpOutStart
= lpOut
;
707 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
708 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
709 assert(pi
->pCurFrame
!= NULL
);
712 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
713 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
714 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
716 lpbiOut
->biSizeImage
= 0;
718 /* keyframe -- convert internal frame to output format */
721 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
725 x
= MSRLE32_CompressRLE8Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
726 &lpOut
, &lpbiOut
->biSizeImage
);
727 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
728 } while (x
< lpbiOut
->biWidth
);
733 /* add EOL -- end of line */
734 lpbiOut
->biSizeImage
+= 2;
735 *((LPWORD
)lpOut
) = 0;
736 lpOut
+= sizeof(WORD
);
737 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
740 /* delta-frame -- compute delta between last and this internal frame */
745 assert(pi
->pPrevFrame
!= NULL
);
747 lpP
= pi
->pPrevFrame
;
751 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
759 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
760 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
764 if (pos
== lpbiOut
->biWidth
&& count
> 4) {
765 /* (count > 4) secures that we will save space */
768 } else if (jumpy
|| jumpx
!= pos
) {
773 /* can only jump in positive direction -- do an EOL then jump */
779 /* add EOL -- end of line */
780 lpbiOut
->biSizeImage
+= 2;
781 *((LPWORD
)lpOut
) = 0;
782 lpOut
+= sizeof(WORD
);
783 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
786 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
788 /* write out real jump(s) */
789 while (jumpy
|| pos
!= jumpx
) {
790 lpbiOut
->biSizeImage
+= 4;
793 *lpOut
= min(pos
- jumpx
, 255);
795 *lpOut
= min(jumpy
, 255);
805 if (x
< lpbiOut
->biWidth
) {
806 /* skip the 'same' things corresponding to previous frame */
807 x
= MSRLE32_CompressRLE8Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
808 &lpOut
, &lpbiOut
->biSizeImage
);
809 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
811 } while (x
< lpbiOut
->biWidth
);
818 /* add EOL -- end of line */
819 lpbiOut
->biSizeImage
+= 2;
820 *((LPWORD
)lpOut
) = 0;
821 lpOut
+= sizeof(WORD
);
822 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
826 /* add EOL -- will be changed to EOI */
827 lpbiOut
->biSizeImage
+= 2;
828 *((LPWORD
)lpOut
) = 0;
829 lpOut
+= sizeof(WORD
);
832 /* change EOL to EOI -- end of image */
834 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
839 /*****************************************************************************/
841 static LRESULT
MSRLE32_DecompressRLE4(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
842 const BYTE
*lpIn
, LPBYTE lpOut
)
848 BOOL bEndFlag
= FALSE
;
851 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
852 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
854 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
855 line_size
= DIBWIDTHBYTES(*lpbi
);
867 case 0: /* EOL - end of line */
871 case 1: /* EOI - end of image */
875 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
876 lpOut
+= *lpIn
++ * line_size
;
877 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
882 default: /* absolute mode */
883 extra_byte
= (((code1
+ 1) & (~1)) / 2) & 0x01;
885 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
)
889 for (i
= 0; i
< code0
/ 2; i
++) {
890 if (bytes_per_pixel
== 1) {
892 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
893 if (2 * i
+ 1 <= code0
)
894 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
& 0x0F)];
895 } else if (bytes_per_pixel
== 2) {
896 code1
= lpIn
[i
] >> 4;
897 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
898 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
900 if (2 * i
+ 1 <= code0
) {
901 code1
= lpIn
[i
] & 0x0F;
902 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
903 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
906 code1
= lpIn
[i
] >> 4;
907 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
908 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
909 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
910 pixel_ptr
+= bytes_per_pixel
;
912 if (2 * i
+ 1 <= code0
) {
913 code1
= lpIn
[i
] & 0x0F;
914 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
915 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
916 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
917 pixel_ptr
+= bytes_per_pixel
;
922 if (bytes_per_pixel
== 1) {
924 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
925 } else if (bytes_per_pixel
== 2) {
926 code1
= lpIn
[i
] >> 4;
927 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
928 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
930 code1
= lpIn
[i
] >> 4;
931 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
932 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
933 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
934 pixel_ptr
+= bytes_per_pixel
;
940 /* if the RLE code is odd, skip a byte in the stream */
946 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
)
949 if (bytes_per_pixel
== 1) {
950 BYTE c1
= pi
->palette_map
[(code1
>> 4)];
951 BYTE c2
= pi
->palette_map
[(code1
& 0x0F)];
953 for (i
= 0; i
< code0
; i
++) {
955 lpOut
[pixel_ptr
++] = c1
;
957 lpOut
[pixel_ptr
++] = c2
;
959 } else if (bytes_per_pixel
== 2) {
960 BYTE hi1
= pi
->palette_map
[(code1
>> 4) * 2 + 0];
961 BYTE lo1
= pi
->palette_map
[(code1
>> 4) * 2 + 1];
963 BYTE hi2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 0];
964 BYTE lo2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 1];
966 for (i
= 0; i
< code0
; i
++) {
968 lpOut
[pixel_ptr
++] = hi1
;
969 lpOut
[pixel_ptr
++] = lo1
;
971 lpOut
[pixel_ptr
++] = hi2
;
972 lpOut
[pixel_ptr
++] = lo2
;
976 BYTE b1
= pi
->palette_map
[(code1
>> 4) * 4 + 0];
977 BYTE g1
= pi
->palette_map
[(code1
>> 4) * 4 + 1];
978 BYTE r1
= pi
->palette_map
[(code1
>> 4) * 4 + 2];
980 BYTE b2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 0];
981 BYTE g2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 1];
982 BYTE r2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 2];
984 for (i
= 0; i
< code0
; i
++) {
986 lpOut
[pixel_ptr
+ 0] = b1
;
987 lpOut
[pixel_ptr
+ 1] = g1
;
988 lpOut
[pixel_ptr
+ 2] = r1
;
990 lpOut
[pixel_ptr
+ 0] = b2
;
991 lpOut
[pixel_ptr
+ 1] = g2
;
992 lpOut
[pixel_ptr
+ 2] = r2
;
994 pixel_ptr
+= bytes_per_pixel
;
998 } while (! bEndFlag
);
1003 static LRESULT
MSRLE32_DecompressRLE8(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
1004 const BYTE
*lpIn
, LPBYTE lpOut
)
1006 int bytes_per_pixel
;
1009 BOOL bEndFlag
= FALSE
;
1012 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
1013 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
1015 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
1016 line_size
= DIBWIDTHBYTES(*lpbi
);
1028 case 0: /* EOL - end of line */
1032 case 1: /* EOI - end of image */
1036 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
1037 lpOut
+= *lpIn
++ * line_size
;
1038 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
1043 default: /* absolute mode */
1044 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
) {
1045 WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1048 extra_byte
= code1
& 0x01;
1053 if (bytes_per_pixel
== 1) {
1054 lpOut
[pixel_ptr
] = pi
->palette_map
[code1
];
1055 } else if (bytes_per_pixel
== 2) {
1056 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 2 + 0];
1057 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 2 + 1];
1059 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
1060 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
1061 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
1063 pixel_ptr
+= bytes_per_pixel
;
1066 /* if the RLE code is odd, skip a byte in the stream */
1072 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
) {
1073 WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1077 if (bytes_per_pixel
== 1) {
1078 code1
= pi
->palette_map
[code1
];
1080 lpOut
[pixel_ptr
++] = code1
;
1081 } else if (bytes_per_pixel
== 2) {
1082 BYTE hi
= pi
->palette_map
[code1
* 2 + 0];
1083 BYTE lo
= pi
->palette_map
[code1
* 2 + 1];
1086 lpOut
[pixel_ptr
+ 0] = hi
;
1087 lpOut
[pixel_ptr
+ 1] = lo
;
1088 pixel_ptr
+= bytes_per_pixel
;
1091 BYTE r
= pi
->palette_map
[code1
* 4 + 2];
1092 BYTE g
= pi
->palette_map
[code1
* 4 + 1];
1093 BYTE b
= pi
->palette_map
[code1
* 4 + 0];
1096 lpOut
[pixel_ptr
+ 0] = b
;
1097 lpOut
[pixel_ptr
+ 1] = g
;
1098 lpOut
[pixel_ptr
+ 2] = r
;
1099 pixel_ptr
+= bytes_per_pixel
;
1103 } while (! bEndFlag
);
1108 /*****************************************************************************/
1110 static CodecInfo
* Open(LPICOPEN icinfo
)
1112 CodecInfo
* pi
= NULL
;
1114 if (icinfo
== NULL
) {
1116 return (LPVOID
)0xFFFF0000;
1119 if (compare_fourcc(icinfo
->fccType
, ICTYPE_VIDEO
)) return NULL
;
1121 TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo
,
1122 icinfo
->dwSize
, icinfo
->fccType
, (char*)&icinfo
->fccType
,
1123 icinfo
->fccHandler
, (char*)&icinfo
->fccHandler
,
1124 icinfo
->dwVersion
,icinfo
->dwFlags
);
1126 switch (icinfo
->fccHandler
) {
1132 case mmioFOURCC('m','r','l','e'):
1133 icinfo
->fccHandler
= FOURCC_MRLE
;
1136 WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
1137 icinfo
->fccHandler
,(char*)&icinfo
->fccHandler
);
1141 pi
= LocalAlloc(LPTR
, sizeof(CodecInfo
));
1144 pi
->fccHandler
= icinfo
->fccHandler
;
1146 pi
->bCompress
= FALSE
;
1147 pi
->dwQuality
= MSRLE32_DEFAULTQUALITY
;
1148 pi
->nPrevFrame
= -1;
1149 pi
->pPrevFrame
= pi
->pCurFrame
= NULL
;
1151 pi
->bDecompress
= FALSE
;
1152 pi
->palette_map
= NULL
;
1155 icinfo
->dwError
= (pi
!= NULL
? ICERR_OK
: ICERR_MEMORY
);
1160 static LRESULT
Close(CodecInfo
*pi
)
1162 TRACE("(%p)\n", pi
);
1167 if (pi
->pPrevFrame
!= NULL
|| pi
->pCurFrame
!= NULL
)
1174 static LRESULT
GetInfo(const CodecInfo
*pi
, ICINFO
*icinfo
, DWORD dwSize
)
1179 /* check parameters */
1181 return sizeof(ICINFO
);
1182 if (dwSize
< sizeof(ICINFO
))
1185 icinfo
->dwSize
= sizeof(ICINFO
);
1186 icinfo
->fccType
= ICTYPE_VIDEO
;
1187 icinfo
->fccHandler
= (pi
!= NULL
? pi
->fccHandler
: FOURCC_MRLE
);
1188 icinfo
->dwFlags
= VIDCF_QUALITY
| VIDCF_TEMPORAL
| VIDCF_CRUNCH
| VIDCF_FASTTEMPORALC
;
1189 icinfo
->dwVersion
= ICVERSION
;
1190 icinfo
->dwVersionICM
= ICVERSION
;
1192 LoadStringW(MSRLE32_hModule
, IDS_NAME
, icinfo
->szName
, sizeof(icinfo
->szName
)/sizeof(WCHAR
));
1193 LoadStringW(MSRLE32_hModule
, IDS_DESCRIPTION
, icinfo
->szDescription
, sizeof(icinfo
->szDescription
)/sizeof(WCHAR
));
1195 return sizeof(ICINFO
);
1198 static LRESULT
SetQuality(CodecInfo
*pi
, LONG lQuality
)
1204 lQuality
= MSRLE32_DEFAULTQUALITY
;
1205 else if (ICQUALITY_LOW
> lQuality
|| lQuality
> ICQUALITY_HIGH
)
1206 return ICERR_BADPARAM
;
1208 pi
->dwQuality
= (DWORD
)lQuality
;
1213 static LRESULT
Configure(const CodecInfo
*pi
, HWND hWnd
)
1222 static LRESULT
About(CodecInfo
*pi
, HWND hWnd
)
1228 assert(MSRLE32_hModule
!= 0);
1230 LoadStringW(MSRLE32_hModule
, IDS_NAME
, szTitle
, sizeof(szTitle
)/sizeof(szTitle
[0]));
1231 LoadStringW(MSRLE32_hModule
, IDS_ABOUT
, szAbout
, sizeof(szAbout
)/sizeof(szAbout
[0]));
1233 MessageBoxW(hWnd
, szAbout
, szTitle
, MB_OK
|MB_ICONINFORMATION
);
1238 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1239 LPBITMAPINFOHEADER lpbiOut
)
1243 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1248 /* check parameters -- need at least input format */
1249 if (lpbiIn
== NULL
) {
1250 if (lpbiOut
!= NULL
)
1251 return ICERR_BADPARAM
;
1255 /* handle unsupported input format */
1256 if (CompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1257 return (lpbiOut
== NULL
? ICERR_BADFORMAT
: 0);
1259 assert(0 < lpbiIn
->biBitCount
&& lpbiIn
->biBitCount
<= 8);
1261 switch (pi
->fccHandler
) {
1270 size
= (lpbiIn
->biBitCount
<= 4 ? 1 << 4 : 1 << 8);
1276 if (lpbiIn
->biClrUsed
!= 0)
1277 size
= lpbiIn
->biClrUsed
;
1279 size
= sizeof(BITMAPINFOHEADER
) + size
* sizeof(RGBQUAD
);
1281 if (lpbiOut
!= NULL
) {
1282 lpbiOut
->biSize
= sizeof(BITMAPINFOHEADER
);
1283 lpbiOut
->biWidth
= lpbiIn
->biWidth
;
1284 lpbiOut
->biHeight
= lpbiIn
->biHeight
;
1285 lpbiOut
->biPlanes
= 1;
1286 if (pi
->fccHandler
== FOURCC_RLE4
||
1287 lpbiIn
->biBitCount
<= 4) {
1288 lpbiOut
->biCompression
= BI_RLE4
;
1289 lpbiOut
->biBitCount
= 4;
1291 lpbiOut
->biCompression
= BI_RLE8
;
1292 lpbiOut
->biBitCount
= 8;
1294 lpbiOut
->biSizeImage
= MSRLE32_GetMaxCompressedSize(lpbiOut
);
1295 lpbiOut
->biXPelsPerMeter
= lpbiIn
->biXPelsPerMeter
;
1296 lpbiOut
->biYPelsPerMeter
= lpbiIn
->biYPelsPerMeter
;
1297 if (lpbiIn
->biClrUsed
== 0)
1298 size
= 1<<lpbiIn
->biBitCount
;
1300 size
= lpbiIn
->biClrUsed
;
1301 lpbiOut
->biClrUsed
= min(size
, 1 << lpbiOut
->biBitCount
);
1302 lpbiOut
->biClrImportant
= 0;
1304 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
,
1305 (const BYTE
*)lpbiIn
+ lpbiIn
->biSize
, lpbiOut
->biClrUsed
* sizeof(RGBQUAD
));
1312 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1313 LPCBITMAPINFOHEADER lpbiOut
)
1318 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1320 /* check parameter -- need at least one format */
1321 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1323 /* check if the given format is supported */
1324 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1327 /* the worst case is coding the complete image in absolute mode. */
1329 return MSRLE32_GetMaxCompressedSize(lpbiIn
);
1331 return MSRLE32_GetMaxCompressedSize(lpbiOut
);
1334 static LRESULT
CompressQuery(const CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1335 LPCBITMAPINFOHEADER lpbiOut
)
1340 /* need at least one format */
1341 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1342 return ICERR_BADPARAM
;
1344 /* check input format if given */
1345 if (lpbiIn
!= NULL
) {
1346 if (!isSupportedDIB(lpbiIn
))
1347 return ICERR_BADFORMAT
;
1349 /* for 4-bit need an even width */
1350 if (lpbiIn
->biBitCount
<= 4 && (lpbiIn
->biWidth
% 2))
1351 return ICERR_BADFORMAT
;
1353 if (pi
->fccHandler
== FOURCC_RLE4
&& lpbiIn
->biBitCount
> 4)
1354 return ICERR_UNSUPPORTED
;
1355 else if (lpbiIn
->biBitCount
> 8)
1356 return ICERR_UNSUPPORTED
;
1359 /* check output format if given */
1360 if (lpbiOut
!= NULL
) {
1361 if (!isSupportedMRLE(lpbiOut
))
1362 return ICERR_BADFORMAT
;
1364 if (lpbiIn
!= NULL
) {
1365 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1366 return ICERR_UNSUPPORTED
;
1367 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1368 return ICERR_UNSUPPORTED
;
1369 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1370 return ICERR_UNSUPPORTED
;
1377 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1378 LPCBITMAPINFOHEADER lpbiOut
)
1380 const RGBQUAD
*rgbIn
;
1381 const RGBQUAD
*rgbOut
;
1385 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1390 /* check parameters -- need both formats */
1391 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1392 return ICERR_BADPARAM
;
1393 /* And both must be supported */
1394 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1395 return ICERR_BADFORMAT
;
1397 /* FIXME: cannot compress and decompress at same time! */
1398 if (pi
->bDecompress
) {
1399 FIXME("cannot compress and decompress at same time!\n");
1406 size
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2 * lpbiOut
->biHeight
;
1407 pi
->pPrevFrame
= GlobalLock(GlobalAlloc(GPTR
, size
* sizeof(WORD
)));
1408 if (pi
->pPrevFrame
== NULL
)
1409 return ICERR_MEMORY
;
1410 pi
->pCurFrame
= GlobalLock(GlobalAlloc(GPTR
, size
* sizeof(WORD
)));
1411 if (pi
->pCurFrame
== NULL
) {
1413 return ICERR_MEMORY
;
1415 pi
->nPrevFrame
= -1;
1416 pi
->bCompress
= TRUE
;
1418 rgbIn
= (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
1419 rgbOut
= (const RGBQUAD
*)((const BYTE
*)lpbiOut
+ lpbiOut
->biSize
);
1421 switch (lpbiOut
->biBitCount
) {
1424 pi
->palette_map
= LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1425 if (pi
->palette_map
== NULL
) {
1427 return ICERR_MEMORY
;
1430 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1431 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1439 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
)
1443 TRACE("(%p,%p,%u)\n",pi
,lpic
,dwSize
);
1448 /* check parameters */
1449 if (lpic
== NULL
|| dwSize
< sizeof(ICCOMPRESS
))
1450 return ICERR_BADPARAM
;
1451 if (!lpic
->lpbiOutput
|| !lpic
->lpOutput
||
1452 !lpic
->lpbiInput
|| !lpic
->lpInput
)
1453 return ICERR_BADPARAM
;
1455 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
);
1457 if (! pi
->bCompress
) {
1458 LRESULT hr
= CompressBegin(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
);
1461 } else if (CompressQuery(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
) != ICERR_OK
)
1462 return ICERR_BADFORMAT
;
1464 if (lpic
->lFrameNum
>= pi
->nPrevFrame
+ 1) {
1465 /* we continue in the sequence so we need to initialize
1466 * our internal framedata */
1468 computeInternalFrame(pi
, lpic
->lpbiInput
, lpic
->lpInput
);
1469 } else if (lpic
->lFrameNum
== pi
->nPrevFrame
) {
1470 /* Oops, compress same frame again ? Okay, as you wish.
1471 * No need to recompute internal framedata, because we only swapped buffers */
1472 LPWORD pTmp
= pi
->pPrevFrame
;
1474 pi
->pPrevFrame
= pi
->pCurFrame
;
1475 pi
->pCurFrame
= pTmp
;
1476 } else if ((lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1479 WARN(": prev=%d cur=%d gone back? -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1480 if (lpic
->lpbiPrev
== NULL
|| lpic
->lpPrev
== NULL
)
1481 return ICERR_GOTOKEYFRAME
; /* Need a keyframe if you go back */
1482 if (CompressQuery(pi
, lpic
->lpbiPrev
, lpic
->lpbiOutput
) != ICERR_OK
)
1483 return ICERR_BADFORMAT
;
1485 WARN(": prev=%d cur=%d compute swapped -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1486 computeInternalFrame(pi
, lpic
->lpbiPrev
, lpic
->lpPrev
);
1488 /* swap buffers for current and previous frame */
1489 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1490 pTmp
= pi
->pPrevFrame
;
1491 pi
->pPrevFrame
= pi
->pCurFrame
;
1492 pi
->pCurFrame
= pTmp
;
1493 pi
->nPrevFrame
= lpic
->lFrameNum
;
1496 for (i
= 0; i
< 3; i
++) {
1497 SetQuality(pi
, lpic
->dwQuality
);
1499 lpic
->lpbiOutput
->biSizeImage
= 0;
1501 if (lpic
->lpbiOutput
->biBitCount
== 4)
1502 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, lpic
->lpInput
,
1503 lpic
->lpbiOutput
, lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1505 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, lpic
->lpInput
,
1506 lpic
->lpbiOutput
, lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1508 if (lpic
->dwFrameSize
== 0 ||
1509 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
)
1512 if ((*lpic
->lpdwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1513 if (lpic
->lpbiOutput
->biBitCount
== 4)
1514 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, lpic
->lpInput
,
1515 lpic
->lpbiOutput
, lpic
->lpOutput
, TRUE
);
1517 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, lpic
->lpInput
,
1518 lpic
->lpbiOutput
, lpic
->lpOutput
, TRUE
);
1520 if (lpic
->dwFrameSize
== 0 ||
1521 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
) {
1522 WARN("switched to keyframe, was small enough!\n");
1523 *lpic
->lpdwFlags
|= ICCOMPRESS_KEYFRAME
;
1524 *lpic
->lpckid
= MAKEAVICKID(cktypeDIBbits
,
1525 StreamFromFOURCC(*lpic
->lpckid
));
1530 if (lpic
->dwQuality
< 1000)
1533 lpic
->dwQuality
-= 1000; /* reduce quality by 10% */
1536 { /* swap buffer for current and previous frame */
1537 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1538 register LPWORD pTmp
= pi
->pPrevFrame
;
1540 pi
->pPrevFrame
= pi
->pCurFrame
;
1541 pi
->pCurFrame
= pTmp
;
1542 pi
->nPrevFrame
= lpic
->lFrameNum
;
1548 static LRESULT
CompressEnd(CodecInfo
*pi
)
1553 if (pi
->pPrevFrame
!= NULL
)
1555 GlobalUnlock(GlobalHandle(pi
->pPrevFrame
));
1556 GlobalFree(GlobalHandle(pi
->pPrevFrame
));
1558 if (pi
->pCurFrame
!= NULL
)
1560 GlobalUnlock(GlobalHandle(pi
->pCurFrame
));
1561 GlobalFree(GlobalHandle(pi
->pCurFrame
));
1563 pi
->pPrevFrame
= NULL
;
1564 pi
->pCurFrame
= NULL
;
1565 pi
->nPrevFrame
= -1;
1566 pi
->bCompress
= FALSE
;
1572 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1573 LPBITMAPINFOHEADER lpbiOut
)
1577 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1583 return (lpbiOut
!= NULL
? ICERR_BADPARAM
: 0);
1585 if (DecompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1586 return (lpbiOut
!= NULL
? ICERR_BADFORMAT
: 0);
1588 size
= lpbiIn
->biSize
;
1590 if (lpbiIn
->biBitCount
<= 8)
1591 size
+= lpbiIn
->biClrUsed
* sizeof(RGBQUAD
);
1593 if (lpbiOut
!= NULL
) {
1594 memcpy(lpbiOut
, lpbiIn
, size
);
1595 lpbiOut
->biCompression
= BI_RGB
;
1596 lpbiOut
->biSizeImage
= DIBWIDTHBYTES(*lpbiOut
) * lpbiOut
->biHeight
;
1603 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1604 LPCBITMAPINFOHEADER lpbiOut
)
1606 LRESULT hr
= ICERR_OK
;
1608 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1613 /* need at least one format */
1614 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1615 return ICERR_BADPARAM
;
1617 /* check input format if given */
1618 if (lpbiIn
!= NULL
) {
1619 if (!isSupportedMRLE(lpbiIn
))
1620 return ICERR_BADFORMAT
;
1623 /* check output format if given */
1624 if (lpbiOut
!= NULL
) {
1625 if (!isSupportedDIB(lpbiOut
))
1626 hr
= ICERR_BADFORMAT
;
1628 if (lpbiIn
!= NULL
) {
1629 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1630 hr
= ICERR_UNSUPPORTED
;
1631 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1632 hr
= ICERR_UNSUPPORTED
;
1633 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1634 hr
= ICERR_UNSUPPORTED
;
1641 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1642 LPCBITMAPINFOHEADER lpbiOut
)
1644 const RGBQUAD
*rgbIn
;
1645 const RGBQUAD
*rgbOut
;
1648 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1653 /* check parameters */
1654 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1655 return ICERR_BADPARAM
;
1656 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1657 return ICERR_BADFORMAT
;
1659 /* FIXME: cannot compress and decompress at a time! */
1660 if (pi
->bCompress
) {
1661 FIXME("cannot compress and decompress at same time!\n");
1665 if (pi
->bDecompress
)
1668 rgbIn
= (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
1669 rgbOut
= (const RGBQUAD
*)((const BYTE
*)lpbiOut
+ lpbiOut
->biSize
);
1671 switch (lpbiOut
->biBitCount
) {
1674 pi
->palette_map
= LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1675 if (pi
->palette_map
== NULL
)
1676 return ICERR_MEMORY
;
1678 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1679 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1684 pi
->palette_map
= LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* 2);
1685 if (pi
->palette_map
== NULL
)
1686 return ICERR_MEMORY
;
1688 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1691 if (lpbiOut
->biBitCount
== 15)
1692 color
= ((rgbIn
[i
].rgbRed
>> 3) << 10)
1693 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1695 color
= ((rgbIn
[i
].rgbRed
>> 3) << 11)
1696 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1698 pi
->palette_map
[i
* 2 + 1] = color
>> 8;
1699 pi
->palette_map
[i
* 2 + 0] = color
& 0xFF;
1704 pi
->palette_map
= LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1705 if (pi
->palette_map
== NULL
)
1706 return ICERR_MEMORY
;
1707 memcpy(pi
->palette_map
, rgbIn
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1711 pi
->bDecompress
= TRUE
;
1716 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
)
1718 TRACE("(%p,%p,%u)\n",pi
,pic
,dwSize
);
1723 /* check parameters */
1725 return ICERR_BADPARAM
;
1726 if (pic
->lpbiInput
== NULL
|| pic
->lpInput
== NULL
||
1727 pic
->lpbiOutput
== NULL
|| pic
->lpOutput
== NULL
)
1728 return ICERR_BADPARAM
;
1731 if (! pi
->bDecompress
) {
1732 LRESULT hr
= DecompressBegin(pi
, pic
->lpbiInput
, pic
->lpbiOutput
);
1735 } else if (DecompressQuery(pi
, pic
->lpbiInput
, pic
->lpbiOutput
) != ICERR_OK
)
1736 return ICERR_BADFORMAT
;
1738 assert(pic
->lpbiInput
->biWidth
== pic
->lpbiOutput
->biWidth
);
1739 assert(pic
->lpbiInput
->biHeight
== pic
->lpbiOutput
->biHeight
);
1741 pic
->lpbiOutput
->biSizeImage
= DIBWIDTHBYTES(*pic
->lpbiOutput
) * pic
->lpbiOutput
->biHeight
;
1742 if (pic
->lpbiInput
->biBitCount
== 4)
1743 return MSRLE32_DecompressRLE4(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1745 return MSRLE32_DecompressRLE8(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1748 static LRESULT
DecompressEnd(CodecInfo
*pi
)
1755 pi
->bDecompress
= FALSE
;
1757 if (pi
->palette_map
!= NULL
) {
1758 LocalFree(pi
->palette_map
);
1759 pi
->palette_map
= NULL
;
1765 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1766 LPBITMAPINFOHEADER lpbiOut
)
1770 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1775 /* check parameters */
1776 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1777 return ICERR_BADPARAM
;
1779 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1780 return ICERR_BADFORMAT
;
1782 if (lpbiOut
->biBitCount
> 8)
1785 if (lpbiIn
->biBitCount
<= 8) {
1786 if (lpbiIn
->biClrUsed
> 0)
1787 size
= lpbiIn
->biClrUsed
;
1789 size
= (1 << lpbiIn
->biBitCount
);
1791 lpbiOut
->biClrUsed
= size
;
1793 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
, (const BYTE
*)lpbiIn
+ lpbiIn
->biSize
, size
* sizeof(RGBQUAD
));
1794 } /* else could never occur ! */
1799 /* DriverProc - entry point for an installable driver */
1800 LRESULT CALLBACK
MSRLE32_DriverProc(DWORD_PTR dwDrvID
, HDRVR hDrv
, UINT uMsg
,
1801 LPARAM lParam1
, LPARAM lParam2
)
1803 CodecInfo
*pi
= (CodecInfo
*)dwDrvID
;
1805 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID
, hDrv
, uMsg
, lParam1
, lParam2
);
1808 /* standard driver messages */
1812 return (LRESULT
)Open((ICOPEN
*)lParam2
);
1814 if (dwDrvID
!= 0xFFFF0000 && (LPVOID
)dwDrvID
!= NULL
)
1822 case DRV_QUERYCONFIGURE
:
1823 return DRVCNF_CANCEL
; /* FIXME */
1825 return DRVCNF_OK
; /* FIXME */
1830 /* installable compression manager messages */
1832 FIXME("ICM_CONFIGURE (%ld)\n",lParam1
);
1834 return ICERR_UNSUPPORTED
; /* FIXME */
1836 return Configure(pi
, (HWND
)lParam1
);
1841 return About(pi
, (HWND
)lParam1
);
1844 return 0; /* no state */
1846 return GetInfo(pi
, (ICINFO
*)lParam1
, (DWORD
)lParam2
);
1847 case ICM_GETDEFAULTQUALITY
:
1848 if ((LPVOID
)lParam1
!= NULL
) {
1849 *((LPDWORD
)lParam1
) = MSRLE32_DEFAULTQUALITY
;
1853 case ICM_GETQUALITY
:
1854 if ((LPVOID
)lParam1
!= NULL
) {
1855 *((LPDWORD
)lParam1
) = pi
->dwQuality
;
1859 case ICM_SETQUALITY
:
1860 return SetQuality(pi
, *(LPLONG
)lParam1
);
1861 case ICM_COMPRESS_GET_FORMAT
:
1862 return CompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1863 (LPBITMAPINFOHEADER
)lParam2
);
1864 case ICM_COMPRESS_GET_SIZE
:
1865 return CompressGetSize(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1866 (LPCBITMAPINFOHEADER
)lParam2
);
1867 case ICM_COMPRESS_QUERY
:
1868 return CompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1869 (LPCBITMAPINFOHEADER
)lParam2
);
1870 case ICM_COMPRESS_BEGIN
:
1871 return CompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1872 (LPCBITMAPINFOHEADER
)lParam2
);
1874 return Compress(pi
, (ICCOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1875 case ICM_COMPRESS_END
:
1876 return CompressEnd(pi
);
1877 case ICM_DECOMPRESS_GET_FORMAT
:
1878 return DecompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1879 (LPBITMAPINFOHEADER
)lParam2
);
1880 case ICM_DECOMPRESS_QUERY
:
1881 return DecompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1882 (LPCBITMAPINFOHEADER
)lParam2
);
1883 case ICM_DECOMPRESS_BEGIN
:
1884 return DecompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1885 (LPCBITMAPINFOHEADER
)lParam2
);
1886 case ICM_DECOMPRESS
:
1887 return Decompress(pi
, (ICDECOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1888 case ICM_DECOMPRESS_END
:
1889 return DecompressEnd(pi
);
1890 case ICM_DECOMPRESS_SET_PALETTE
:
1891 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi
, (LPVOID
)lParam1
, (LPVOID
)lParam2
);
1892 return ICERR_UNSUPPORTED
;
1893 case ICM_DECOMPRESS_GET_PALETTE
:
1894 return DecompressGetPalette(pi
, (LPBITMAPINFOHEADER
)lParam1
,
1895 (LPBITMAPINFOHEADER
)lParam2
);
1896 case ICM_GETDEFAULTKEYFRAMERATE
:
1897 if ((LPVOID
)lParam1
!= NULL
)
1898 *(LPDWORD
)lParam1
= 15;
1901 if (uMsg
< DRV_USER
)
1902 return DefDriverProc(dwDrvID
, hDrv
, uMsg
, lParam1
, lParam2
);
1904 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg
,lParam1
,lParam2
);
1907 return ICERR_UNSUPPORTED
;
1910 /* DllMain - library initialization code */
1911 BOOL WINAPI
DllMain(HINSTANCE hModule
, DWORD dwReason
, LPVOID lpReserved
)
1913 TRACE("(%p,%d,%p)\n",hModule
,dwReason
,lpReserved
);
1916 case DLL_PROCESS_ATTACH
:
1917 DisableThreadLibraryCalls(hModule
);
1918 MSRLE32_hModule
= hModule
;
1921 case DLL_PROCESS_DETACH
: