2 * Copyright 2002-2003 Michael Günnewig
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * - some improvements possible
21 * - implement DecompressSetPalette? -- does we need it for anything?
26 #include "msrle_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(msrle32
);
36 static HINSTANCE MSRLE32_hModule
= 0;
38 #define ABS(a) ((a) < 0 ? -(a) : (a))
39 #define SQR(a) ((a) * (a))
41 #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
42 inline WORD
ColorCmp(WORD clr1
, WORD clr2
)
44 register UINT a
= (clr1
-clr2
);
47 inline WORD
Intensity(RGBQUAD clr
)
49 return (30 * clr
.rgbRed
+ 59 * clr
.rgbGreen
+ 11 * clr
.rgbBlue
)/4;
52 #define GetRawPixel(lpbi,lp,x) \
53 ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
54 ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
56 /*****************************************************************************/
58 /* utility functions */
59 static BOOL
isSupportedDIB(LPCBITMAPINFOHEADER lpbi
);
60 static BOOL
isSupportedMRLE(LPCBITMAPINFOHEADER lpbi
);
61 static void LoadWideString(UINT id
, LPWSTR str
, INT len
);
62 static BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
);
64 /* compression functions */
65 static void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
);
66 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
);
67 static LRESULT
MSRLE32_CompressRLE4(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
);
68 static LRESULT
MSRLE32_CompressRLE8(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
);
70 /* decompression functions */
71 static LRESULT
MSRLE32_DecompressRLE4(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
72 LPBYTE lpIn
, LPBYTE lpOut
);
73 static LRESULT
MSRLE32_DecompressRLE8(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
74 LPBYTE lpIn
, LPBYTE lpOut
);
77 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
78 LPBITMAPINFOHEADER lpbiOut
);
79 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
80 LPCBITMAPINFOHEADER lpbiOut
);
81 static LRESULT
CompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
82 LPCBITMAPINFOHEADER lpbiOut
);
83 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
84 LPCBITMAPINFOHEADER lpbiOut
);
85 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
);
86 static LRESULT
CompressEnd(CodecInfo
*pi
);
88 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
89 LPBITMAPINFOHEADER lpbiOut
);
90 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
91 LPCBITMAPINFOHEADER lpbiOut
);
92 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
93 LPCBITMAPINFOHEADER lpbiOut
);
94 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
);
95 static LRESULT
DecompressEnd(CodecInfo
*pi
);
96 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
97 LPBITMAPINFOHEADER lpbiOut
);
99 /*****************************************************************************/
101 static void LoadWideString(UINT id
, LPWSTR str
, INT len
)
105 LoadStringA(MSRLE32_hModule
, id
, szTemp
, sizeof(szTemp
));
106 MultiByteToWideChar(CP_ACP
, 0, szTemp
, -1, str
, len
);
109 static BOOL
isSupportedMRLE(LPCBITMAPINFOHEADER lpbi
)
112 assert(lpbi
!= NULL
);
114 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) || \
118 if (lpbi
->biCompression
== BI_RLE4
) {
119 if (lpbi
->biBitCount
!= 4 || \
120 (lpbi
->biWidth
% 2) != 0)
122 } else if (lpbi
->biCompression
== BI_RLE8
) {
123 if (lpbi
->biBitCount
!= 8)
131 static BOOL
isSupportedDIB(LPCBITMAPINFOHEADER lpbi
)
134 assert(lpbi
!= NULL
);
136 /* check structure version/planes/compression */
137 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) ||
140 if (lpbi
->biCompression
!= BI_RGB
&&
141 lpbi
->biCompression
!= BI_BITFIELDS
)
144 /* check bit-depth */
145 if (lpbi
->biBitCount
!= 1 &&
146 lpbi
->biBitCount
!= 4 &&
147 lpbi
->biBitCount
!= 8 &&
148 lpbi
->biBitCount
!= 15 &&
149 lpbi
->biBitCount
!= 16 &&
150 lpbi
->biBitCount
!= 24 &&
151 lpbi
->biBitCount
!= 32)
154 /* check for size(s) */
155 if (!lpbi
->biWidth
|| !lpbi
->biHeight
)
156 return FALSE
; /* image with zero size, makes no sense so error ! */
157 if (DIBWIDTHBYTES(*lpbi
) * (DWORD
)lpbi
->biHeight
>= (1UL << 31) - 1)
158 return FALSE
; /* image too big ! */
160 /* check for nonexistent colortable for hi- and true-color DIB's */
161 if (lpbi
->biBitCount
>= 15 && lpbi
->biClrUsed
> 0)
167 static BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
)
169 INT diff
= 0x00FFFFFF;
174 assert(clrs
!= NULL
);
176 for (i
= 0; i
< count
; i
++) {
177 int r
= ((int)clrs
[i
].rgbRed
- (int)clr
.rgbRed
);
178 int g
= ((int)clrs
[i
].rgbGreen
- (int)clr
.rgbGreen
);
179 int b
= ((int)clrs
[i
].rgbBlue
- (int)clr
.rgbBlue
);
194 /*****************************************************************************/
196 void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
)
198 WORD wIntensityTbl
[256];
199 DWORD lInLine
, lOutLine
;
205 assert(pi
!= NULL
&& lpbiIn
!= NULL
&& lpIn
!= NULL
);
206 assert(pi
->pCurFrame
!= NULL
);
208 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
209 lOutLine
= WIDTHBYTES((WORD
)lpbiIn
->biWidth
* 8u * sizeof(WORD
)) / 2u;
210 lpOut
= pi
->pCurFrame
;
212 assert(lpbiIn
->biClrUsed
!= 0);
216 (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
218 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++)
219 wIntensityTbl
[i
] = Intensity(lp
[i
]);
222 for (y
= 0; y
< lpbiIn
->biHeight
; y
++) {
225 switch (lpbiIn
->biBitCount
) {
227 for (x
= 0; x
< lpbiIn
->biWidth
/ 8; x
++) {
228 for (i
= 0; i
< 7; i
++)
229 lpOut
[8 * x
+ i
] = wIntensityTbl
[(lpIn
[x
] >> (7 - i
)) & 1];
233 for (x
= 0; x
< lpbiIn
->biWidth
/ 2; x
++) {
234 lpOut
[2 * x
+ 0] = wIntensityTbl
[(lpIn
[x
] >> 4)];
235 lpOut
[2 * x
+ 1] = wIntensityTbl
[(lpIn
[x
] & 0x0F)];
239 for (x
= 0; x
< lpbiIn
->biWidth
; x
++)
240 lpOut
[x
] = wIntensityTbl
[lpIn
[x
]];
249 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
)
254 assert(lpbi
!= NULL
);
256 a
= lpbi
->biWidth
/ 255;
257 b
= lpbi
->biWidth
% 255;
258 if (lpbi
->biBitCount
<= 4) {
263 size
= (2 + a
* (2 + ((a
+ 2) & ~2)) + b
* (2 + ((b
+ 2) & ~2)));
264 return size
* lpbi
->biHeight
;
267 /* lpP => current pos in previous frame
268 * lpA => previous pos in current frame
269 * lpB => current pos in current frame
271 static INT
countDiffRLE4(LPWORD lpP
, LPWORD lpA
, LPWORD lpB
, INT pos
, LONG lDist
, LONG width
)
277 assert(lpA
&& lpB
&& lDist
>= 0 && width
> 0);
288 while (pos
+ 1 < width
) {
292 if (pos
+ 1 >= width
)
296 if (ColorCmp(clr1
, clr3
) <= lDist
&&
297 ColorCmp(clr2
, clr4
) <= lDist
) {
298 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
299 if (pos
+ 2 < width
&& ColorCmp(clr1
,lpB
[pos
+1]) <= lDist
&&
300 ColorCmp(clr2
,lpB
[pos
+2]) <= lDist
) {
301 if (pos
+ 4 < width
&& ColorCmp(lpB
[pos
+1],lpB
[pos
+3]) <= lDist
&&
302 ColorCmp(lpB
[pos
+2],lpB
[pos
+4]) <= lDist
)
303 return count
- 3; /* followed by at least 4 encodable pixels */
306 } else if (lpP
!= NULL
&& ColorCmp(lpP
[pos
], lpB
[pos
]) <= lDist
) {
307 /* 'compare' with previous frame for end of diff */
326 /* lpP => current pos in previous frame
327 * lpA => previous pos in current frame
328 * lpB => current pos in current frame
330 static INT
countDiffRLE8(LPWORD lpP
, LPWORD lpA
, LPWORD lpB
, INT pos
, LONG lDist
, LONG width
)
334 for (count
= 0; pos
< width
; pos
++, count
++) {
335 if (ColorCmp(lpA
[pos
], lpB
[pos
]) <= lDist
) {
336 /* diff at end? -- look-ahead for some more encodable pixel */
337 if (pos
+ 1 < width
&& ColorCmp(lpB
[pos
], lpB
[pos
+1]) <= lDist
)
339 if (pos
+ 2 < width
&& ColorCmp(lpB
[pos
+1], lpB
[pos
+2]) <= lDist
)
341 } else if (lpP
!= NULL
&& ColorCmp(lpP
[pos
], lpB
[pos
]) <= lDist
) {
342 /* 'compare' with previous frame for end of diff */
345 for (count2
= 0, pos
++; pos
< width
&& count2
<= 5; pos
++, count2
++) {
346 if (ColorCmp(lpP
[pos
], lpB
[pos
]) > lDist
)
359 static INT
MSRLE32_CompressRLE4Line(CodecInfo
*pi
, LPWORD lpP
, LPWORD lpC
, LPCBITMAPINFOHEADER lpbi
, BYTE
*lpIn
, LONG lDist
, INT x
, LPBYTE
*ppOut
, DWORD
*lpSizeImage
)
361 LPBYTE lpOut
= *ppOut
;
365 /* try to encode as many pixel as possible */
369 if (pos
< lpbi
->biWidth
) {
371 for (++count
; pos
+ 1 < lpbi
->biWidth
; ) {
373 if (ColorCmp(clr1
, lpC
[pos
]) > lDist
)
376 if (pos
+ 1 >= lpbi
->biWidth
)
379 if (ColorCmp(clr2
, lpC
[pos
]) > lDist
)
386 /* add some pixel for absoluting if possible */
387 count
+= countDiffRLE4(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
391 /* check for near end of line */
392 if (x
+ count
> lpbi
->biWidth
)
393 count
= lpbi
->biWidth
- x
;
395 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
398 INT size
= min(count
, 254);
399 int bytes
= ((size
+ 1) & (~1)) / 2;
400 BOOL extra_byte
= bytes
& 0x01;
402 *lpSizeImage
+= 2 + bytes
+ extra_byte
;
403 assert(((*lpSizeImage
) % 2) == 0);
407 for (i
= 0; i
< size
; i
+= 2) {
408 clr1
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
411 clr2
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
416 *lpOut
++ = (clr1
<< 4) | clr2
;
423 /* too 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(CodecInfo
*pi
, LPWORD lpP
, LPWORD lpC
, LPCBITMAPINFOHEADER lpbi
, BYTE
*lpIn
, LONG lDist
, INT x
, LPBYTE
*ppOut
, DWORD
*lpSizeImage
)
460 LPBYTE lpOut
= *ppOut
;
464 assert(lpbi
->biBitCount
<= 8);
465 assert(lpbi
->biCompression
== BI_RGB
);
467 /* try to encode as much as possible */
470 for (count
= 1; pos
< lpbi
->biWidth
; count
++) {
471 if (ColorCmp(clr
, lpC
[pos
++]) > lDist
)
476 /* add some more pixels for absoluting if possible */
477 count
+= countDiffRLE8(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
481 /* check for over end of line */
482 if (x
+ count
> lpbi
->biWidth
)
483 count
= lpbi
->biWidth
- x
;
485 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
488 INT size
= min(count
, 255);
489 BOOL extra_byte
= size
% 2;
491 *lpSizeImage
+= 2 + size
+ extra_byte
;
495 for (i
= 0; i
< size
; i
++) {
496 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
503 /* too little for absoluting so we must encode them even if it's expensive! */
506 *lpSizeImage
+= 2 * count
;
508 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
513 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
518 /* encode count pixel(s) */
519 clr
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
521 /* optimize end of line */
522 if (x
+ count
+ 1 == lpbi
->biWidth
)
527 INT size
= min(count
, 255);
541 LRESULT
MSRLE32_CompressRLE4(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
)
544 LONG lLine
, lInLine
, lDist
;
545 LPBYTE lpOutStart
= lpOut
;
548 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
549 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
550 assert(pi
->pCurFrame
!= NULL
);
553 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
554 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
555 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
557 lpbiOut
->biSizeImage
= 0;
559 /* keyframe -- convert internal frame to output format */
562 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
566 x
= MSRLE32_CompressRLE4Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
567 &lpOut
, &lpbiOut
->biSizeImage
);
568 } while (x
< lpbiOut
->biWidth
);
573 /* add EOL -- end of line */
574 lpbiOut
->biSizeImage
+= 2;
576 lpOut
+= sizeof(WORD
);
577 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
580 /* delta-frame -- compute delta between last and this internal frame */
585 assert(pi
->pPrevFrame
!= NULL
);
587 lpP
= pi
->pPrevFrame
;
591 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
599 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
600 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
604 if (pos
== lpbiOut
->biWidth
&& count
> 8) {
605 /* (count > 8) secures that we will save space */
608 } else if (jumpy
|| jumpx
!= pos
) {
613 /* can only jump in positive direction -- jump until EOL, EOL */
614 INT w
= lpbiOut
->biWidth
- jumpx
;
621 /* if (w % 255 == 2) then equal costs
622 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
623 * else it will be cheaper
626 lpbiOut
->biSizeImage
+= 4;
629 *lpOut
= min(w
, 255);
633 /* add EOL -- end of line */
634 lpbiOut
->biSizeImage
+= 2;
635 *((LPWORD
)lpOut
) = 0;
636 lpOut
+= sizeof(WORD
);
639 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
641 /* write out real jump(s) */
642 while (jumpy
|| pos
!= jumpx
) {
643 lpbiOut
->biSizeImage
+= 4;
646 *lpOut
= min(pos
- jumpx
, 255);
649 *lpOut
= min(jumpy
, 255);
658 if (x
< lpbiOut
->biWidth
) {
659 /* skipped the 'same' things corresponding to previous frame */
660 x
= MSRLE32_CompressRLE4Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
661 &lpOut
, &lpbiOut
->biSizeImage
);
663 } while (x
< lpbiOut
->biWidth
);
672 /* add EOL -- end of line */
673 lpbiOut
->biSizeImage
+= 2;
674 *((LPWORD
)lpOut
) = 0;
675 lpOut
+= sizeof(WORD
);
676 assert(lpOut
== lpOutStart
+ lpbiOut
->biSizeImage
);
680 /* add EOL -- will be changed to EOI */
681 lpbiOut
->biSizeImage
+= 2;
682 *((LPWORD
)lpOut
) = 0;
683 lpOut
+= sizeof(WORD
);
686 /* change EOL to EOI -- end of image */
688 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
693 LRESULT
MSRLE32_CompressRLE8(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
)
696 LONG lDist
, lInLine
, lLine
;
697 LPBYTE lpOutStart
= lpOut
;
699 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
700 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
701 assert(pi
->pCurFrame
!= NULL
);
704 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
705 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
706 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
708 lpbiOut
->biSizeImage
= 0;
710 /* keyframe -- convert internal frame to output format */
713 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
717 x
= MSRLE32_CompressRLE8Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
718 &lpOut
, &lpbiOut
->biSizeImage
);
719 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
720 } while (x
< lpbiOut
->biWidth
);
725 /* add EOL -- end of line */
726 lpbiOut
->biSizeImage
+= 2;
727 *((LPWORD
)lpOut
) = 0;
728 lpOut
+= sizeof(WORD
);
729 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
732 /* delta-frame -- compute delta between last and this internal frame */
737 assert(pi
->pPrevFrame
!= NULL
);
739 lpP
= pi
->pPrevFrame
;
743 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
751 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
752 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
756 if (pos
== lpbiOut
->biWidth
&& count
> 4) {
757 /* (count > 4) secures that we will save space */
760 } else if (jumpy
|| jumpx
!= pos
) {
765 /* can only jump in positive direction -- do an EOL then jump */
771 /* add EOL -- end of line */
772 lpbiOut
->biSizeImage
+= 2;
773 *((LPWORD
)lpOut
) = 0;
774 lpOut
+= sizeof(WORD
);
775 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
778 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
780 /* write out real jump(s) */
781 while (jumpy
|| pos
!= jumpx
) {
782 lpbiOut
->biSizeImage
+= 4;
785 *lpOut
= min(pos
- jumpx
, 255);
787 *lpOut
= min(jumpy
, 255);
797 if (x
< lpbiOut
->biWidth
) {
798 /* skip the 'same' things corresponding to previous frame */
799 x
= MSRLE32_CompressRLE8Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
800 &lpOut
, &lpbiOut
->biSizeImage
);
801 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
803 } while (x
< lpbiOut
->biWidth
);
810 /* add EOL -- end of line */
811 lpbiOut
->biSizeImage
+= 2;
812 *((LPWORD
)lpOut
) = 0;
813 lpOut
+= sizeof(WORD
);
814 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
818 /* add EOL -- will be changed to EOI */
819 lpbiOut
->biSizeImage
+= 2;
820 *((LPWORD
)lpOut
) = 0;
821 lpOut
+= sizeof(WORD
);
824 /* change EOL to EOI -- end of image */
826 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
831 /*****************************************************************************/
833 static LRESULT
MSRLE32_DecompressRLE4(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
834 LPBYTE lpIn
, LPBYTE lpOut
)
840 BOOL bEndFlag
= FALSE
;
843 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
844 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
846 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
847 line_size
= DIBWIDTHBYTES(*lpbi
);
859 case 0: /* EOL - end of line */
863 case 1: /* EOI - end of image */
867 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
868 lpOut
+= *lpIn
++ * line_size
;
869 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
874 default: /* absolute mode */
875 extra_byte
= (((code1
+ 1) & (~1)) / 2) & 0x01;
877 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
)
881 for (i
= 0; i
< code0
/ 2; i
++) {
882 if (bytes_per_pixel
== 1) {
884 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
885 if (2 * i
+ 1 <= code0
)
886 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
& 0x0F)];
887 } else if (bytes_per_pixel
== 2) {
888 code1
= lpIn
[i
] >> 4;
889 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
890 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
892 if (2 * i
+ 1 <= code0
) {
893 code1
= lpIn
[i
] & 0x0F;
894 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
895 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
898 code1
= lpIn
[i
] >> 4;
899 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
900 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
901 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
902 pixel_ptr
+= bytes_per_pixel
;
904 if (2 * i
+ 1 <= code0
) {
905 code1
= lpIn
[i
] & 0x0F;
906 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
907 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
908 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
909 pixel_ptr
+= bytes_per_pixel
;
914 if (bytes_per_pixel
== 1) {
916 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
917 } else if (bytes_per_pixel
== 2) {
918 code1
= lpIn
[i
] >> 4;
919 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
920 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
922 code1
= lpIn
[i
] >> 4;
923 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
924 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
925 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
926 pixel_ptr
+= bytes_per_pixel
;
932 /* if the RLE code is odd, skip a byte in the stream */
938 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
)
941 if (bytes_per_pixel
== 1) {
942 BYTE c1
= pi
->palette_map
[(code1
>> 4)];
943 BYTE c2
= pi
->palette_map
[(code1
& 0x0F)];
945 for (i
= 0; i
< code0
; i
++) {
947 lpOut
[pixel_ptr
++] = c1
;
949 lpOut
[pixel_ptr
++] = c2
;
951 } else if (bytes_per_pixel
== 2) {
952 BYTE hi1
= pi
->palette_map
[(code1
>> 4) * 2 + 0];
953 BYTE lo1
= pi
->palette_map
[(code1
>> 4) * 2 + 1];
955 BYTE hi2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 0];
956 BYTE lo2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 1];
958 for (i
= 0; i
< code0
; i
++) {
960 lpOut
[pixel_ptr
++] = hi1
;
961 lpOut
[pixel_ptr
++] = lo1
;
963 lpOut
[pixel_ptr
++] = hi2
;
964 lpOut
[pixel_ptr
++] = lo2
;
968 BYTE b1
= pi
->palette_map
[(code1
>> 4) * 4 + 0];
969 BYTE g1
= pi
->palette_map
[(code1
>> 4) * 4 + 1];
970 BYTE r1
= pi
->palette_map
[(code1
>> 4) * 4 + 2];
972 BYTE b2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 0];
973 BYTE g2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 1];
974 BYTE r2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 2];
976 for (i
= 0; i
< code0
; i
++) {
978 lpOut
[pixel_ptr
+ 0] = b1
;
979 lpOut
[pixel_ptr
+ 1] = g1
;
980 lpOut
[pixel_ptr
+ 2] = r1
;
982 lpOut
[pixel_ptr
+ 0] = b2
;
983 lpOut
[pixel_ptr
+ 1] = g2
;
984 lpOut
[pixel_ptr
+ 2] = r2
;
986 pixel_ptr
+= bytes_per_pixel
;
990 } while (! bEndFlag
);
995 static LRESULT
MSRLE32_DecompressRLE8(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
996 LPBYTE lpIn
, LPBYTE lpOut
)
1001 BOOL bEndFlag
= FALSE
;
1004 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
1005 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
1007 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
1008 line_size
= DIBWIDTHBYTES(*lpbi
);
1020 case 0: /* EOL - end of line */
1024 case 1: /* EOI - end of image */
1028 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
1029 lpOut
+= *lpIn
++ * line_size
;
1030 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
1035 default: /* absolute mode */
1036 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
) {
1037 WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1040 extra_byte
= code1
& 0x01;
1045 if (bytes_per_pixel
== 1) {
1046 lpOut
[pixel_ptr
] = pi
->palette_map
[code1
];
1047 } else if (bytes_per_pixel
== 2) {
1048 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 2 + 0];
1049 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 2 + 1];
1051 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
1052 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
1053 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
1055 pixel_ptr
+= bytes_per_pixel
;
1058 /* if the RLE code is odd, skip a byte in the stream */
1064 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
) {
1065 WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1069 if (bytes_per_pixel
== 1) {
1070 code1
= pi
->palette_map
[code1
];
1072 lpOut
[pixel_ptr
++] = code1
;
1073 } else if (bytes_per_pixel
== 2) {
1074 BYTE hi
= pi
->palette_map
[code1
* 2 + 0];
1075 BYTE lo
= pi
->palette_map
[code1
* 2 + 1];
1078 lpOut
[pixel_ptr
+ 0] = hi
;
1079 lpOut
[pixel_ptr
+ 1] = lo
;
1080 pixel_ptr
+= bytes_per_pixel
;
1083 BYTE r
= pi
->palette_map
[code1
* 4 + 2];
1084 BYTE g
= pi
->palette_map
[code1
* 4 + 1];
1085 BYTE b
= pi
->palette_map
[code1
* 4 + 0];
1088 lpOut
[pixel_ptr
+ 0] = b
;
1089 lpOut
[pixel_ptr
+ 1] = g
;
1090 lpOut
[pixel_ptr
+ 2] = r
;
1091 pixel_ptr
+= bytes_per_pixel
;
1095 } while (! bEndFlag
);
1100 /*****************************************************************************/
1102 static CodecInfo
* Open(LPICOPEN icinfo
)
1104 CodecInfo
* pi
= NULL
;
1106 if (icinfo
== NULL
) {
1108 return (LPVOID
)0xFFFF0000;
1111 TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo
,
1112 icinfo
->dwSize
, icinfo
->fccType
, (char*)&icinfo
->fccType
,
1113 icinfo
->fccHandler
, (char*)&icinfo
->fccHandler
,
1114 icinfo
->dwVersion
,icinfo
->dwFlags
);
1116 if (icinfo
->fccType
!= ICTYPE_VIDEO
)
1119 switch (icinfo
->fccHandler
) {
1125 case mmioFOURCC('m','r','l','e'):
1126 icinfo
->fccHandler
= FOURCC_MRLE
;
1129 WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1130 icinfo
->fccHandler
,(char*)&icinfo
->fccHandler
);
1134 pi
= (CodecInfo
*)LocalAlloc(LPTR
, sizeof(CodecInfo
));
1137 pi
->fccHandler
= icinfo
->fccHandler
;
1139 pi
->bCompress
= FALSE
;
1140 pi
->dwQuality
= MSRLE32_DEFAULTQUALITY
;
1141 pi
->nPrevFrame
= -1;
1142 pi
->pPrevFrame
= pi
->pCurFrame
= NULL
;
1144 pi
->bDecompress
= FALSE
;
1145 pi
->palette_map
= NULL
;
1148 icinfo
->dwError
= (pi
!= NULL
? ICERR_OK
: ICERR_MEMORY
);
1153 static LRESULT
Close(CodecInfo
*pi
)
1155 TRACE("(%p)\n", pi
);
1160 if (pi
->pPrevFrame
!= NULL
|| pi
->pCurFrame
!= NULL
)
1163 LocalFree((HLOCAL
)pi
);
1167 static LRESULT
GetInfo(CodecInfo
*pi
, ICINFO
*icinfo
, DWORD dwSize
)
1172 /* check parameters */
1174 return sizeof(ICINFO
);
1175 if (dwSize
< sizeof(ICINFO
))
1178 icinfo
->dwSize
= sizeof(ICINFO
);
1179 icinfo
->fccType
= streamtypeVIDEO
;
1180 icinfo
->fccHandler
= (pi
!= NULL
? pi
->fccHandler
: FOURCC_MRLE
);
1181 icinfo
->dwFlags
= VIDCF_QUALITY
| VIDCF_TEMPORAL
| VIDCF_CRUNCH
| VIDCF_FASTTEMPORALC
;
1182 icinfo
->dwVersion
= MSRLE32_VERSION
;
1183 icinfo
->dwVersionICM
= 0x01040000; /* Version 1.4 build 0 */
1185 LoadWideString(IDS_NAME
, icinfo
->szName
, sizeof(icinfo
->szName
));
1186 LoadWideString(IDS_DESCRIPTION
, icinfo
->szDescription
, sizeof(icinfo
->szDescription
));
1188 return sizeof(ICINFO
);
1191 static LRESULT
SetQuality(CodecInfo
*pi
, LONG lQuality
)
1197 lQuality
= MSRLE32_DEFAULTQUALITY
;
1198 else if (ICQUALITY_LOW
> lQuality
|| lQuality
> ICQUALITY_HIGH
)
1199 return ICERR_BADPARAM
;
1201 pi
->dwQuality
= (DWORD
)lQuality
;
1206 static LRESULT
Configure(CodecInfo
*pi
, HWND hWnd
)
1215 static LRESULT
About(CodecInfo
*pi
, HWND hWnd
)
1221 assert(MSRLE32_hModule
!= 0);
1223 LoadStringA(MSRLE32_hModule
, IDS_NAME
, szTitle
, sizeof(szTitle
));
1224 LoadStringA(MSRLE32_hModule
, IDS_ABOUT
, szAbout
, sizeof(szAbout
));
1226 MessageBoxA(hWnd
, szAbout
, szTitle
, MB_OK
|MB_ICONINFORMATION
);
1231 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1232 LPBITMAPINFOHEADER lpbiOut
)
1236 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1241 /* check parameters -- need at least input format */
1242 if (lpbiIn
== NULL
) {
1243 if (lpbiOut
!= NULL
)
1244 return ICERR_BADPARAM
;
1248 /* handle unsupported input format */
1249 if (CompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1250 return (lpbiOut
== NULL
? ICERR_BADFORMAT
: 0);
1252 assert(0 < lpbiIn
->biBitCount
&& lpbiIn
->biBitCount
<= 8);
1254 switch (pi
->fccHandler
) {
1263 size
= (lpbiIn
->biBitCount
<= 4 ? 1 << 4 : 1 << 8);
1269 if (lpbiIn
->biClrUsed
!= 0)
1270 size
= lpbiIn
->biClrUsed
;
1272 size
= sizeof(BITMAPINFOHEADER
) + size
* sizeof(RGBQUAD
);
1274 if (lpbiOut
!= NULL
) {
1275 lpbiOut
->biSize
= sizeof(BITMAPINFOHEADER
);
1276 lpbiOut
->biWidth
= lpbiIn
->biWidth
;
1277 lpbiOut
->biHeight
= lpbiIn
->biHeight
;
1278 lpbiOut
->biPlanes
= 1;
1279 if (pi
->fccHandler
== FOURCC_RLE4
||
1280 lpbiIn
->biBitCount
<= 4) {
1281 lpbiOut
->biCompression
= BI_RLE4
;
1282 lpbiOut
->biBitCount
= 4;
1284 lpbiOut
->biCompression
= BI_RLE8
;
1285 lpbiOut
->biBitCount
= 8;
1287 lpbiOut
->biSizeImage
= MSRLE32_GetMaxCompressedSize(lpbiOut
);
1288 lpbiOut
->biXPelsPerMeter
= lpbiIn
->biXPelsPerMeter
;
1289 lpbiOut
->biYPelsPerMeter
= lpbiIn
->biYPelsPerMeter
;
1290 if (lpbiIn
->biClrUsed
== 0)
1291 size
= 1<<lpbiIn
->biBitCount
;
1293 size
= lpbiIn
->biClrUsed
;
1294 lpbiOut
->biClrUsed
= min(size
, 1 << lpbiOut
->biBitCount
);
1295 lpbiOut
->biClrImportant
= 0;
1297 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
,
1298 (const BYTE
*)lpbiIn
+ lpbiIn
->biSize
, lpbiOut
->biClrUsed
* sizeof(RGBQUAD
));
1305 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1306 LPCBITMAPINFOHEADER lpbiOut
)
1311 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1313 /* check parameter -- need at least one format */
1314 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1316 /* check if the given format is supported */
1317 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1320 /* the worst case is coding the complete image in absolute mode. */
1322 return MSRLE32_GetMaxCompressedSize(lpbiIn
);
1324 return MSRLE32_GetMaxCompressedSize(lpbiOut
);
1327 static LRESULT
CompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1328 LPCBITMAPINFOHEADER lpbiOut
)
1333 /* need at least one format */
1334 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1335 return ICERR_BADPARAM
;
1337 /* check input format if given */
1338 if (lpbiIn
!= NULL
) {
1339 if (!isSupportedDIB(lpbiIn
))
1340 return ICERR_BADFORMAT
;
1342 /* for 4-bit need an even width */
1343 if (lpbiIn
->biBitCount
<= 4 && (lpbiIn
->biWidth
% 2))
1344 return ICERR_BADFORMAT
;
1346 if (pi
->fccHandler
== FOURCC_RLE4
&& lpbiIn
->biBitCount
> 4)
1347 return ICERR_UNSUPPORTED
;
1348 else if (lpbiIn
->biBitCount
> 8)
1349 return ICERR_UNSUPPORTED
;
1352 /* check output format if given */
1353 if (lpbiOut
!= NULL
) {
1354 if (!isSupportedMRLE(lpbiOut
))
1355 return ICERR_BADFORMAT
;
1357 if (lpbiIn
!= NULL
) {
1358 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1359 return ICERR_UNSUPPORTED
;
1360 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1361 return ICERR_UNSUPPORTED
;
1362 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1363 return ICERR_UNSUPPORTED
;
1370 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1371 LPCBITMAPINFOHEADER lpbiOut
)
1373 const RGBQUAD
*rgbIn
;
1374 const RGBQUAD
*rgbOut
;
1378 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1383 /* check parameters -- need both formats */
1384 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1385 return ICERR_BADPARAM
;
1386 /* And both must be supported */
1387 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1388 return ICERR_BADFORMAT
;
1390 /* FIXME: cannot compress and decompress at same time! */
1391 if (pi
->bDecompress
) {
1392 FIXME("cannot compress and decompress at same time!\n");
1399 size
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2 * lpbiOut
->biHeight
;
1400 pi
->pPrevFrame
= (LPWORD
)GlobalAllocPtr(GPTR
, size
* sizeof(WORD
));
1401 if (pi
->pPrevFrame
== NULL
)
1402 return ICERR_MEMORY
;
1403 pi
->pCurFrame
= (LPWORD
)GlobalAllocPtr(GPTR
, size
* sizeof(WORD
));
1404 if (pi
->pCurFrame
== NULL
) {
1406 return ICERR_MEMORY
;
1408 pi
->nPrevFrame
= -1;
1409 pi
->bCompress
= TRUE
;
1411 rgbIn
= (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
1412 rgbOut
= (const RGBQUAD
*)((const BYTE
*)lpbiOut
+ lpbiOut
->biSize
);
1414 switch (lpbiOut
->biBitCount
) {
1417 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1418 if (pi
->palette_map
== NULL
) {
1420 return ICERR_MEMORY
;
1423 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1424 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1432 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
)
1436 TRACE("(%p,%p,%lu)\n",pi
,lpic
,dwSize
);
1441 /* check parameters */
1442 if (lpic
== NULL
|| dwSize
< sizeof(ICCOMPRESS
))
1443 return ICERR_BADPARAM
;
1444 if (!lpic
->lpbiOutput
|| !lpic
->lpOutput
||
1445 !lpic
->lpbiInput
|| !lpic
->lpInput
)
1446 return ICERR_BADPARAM
;
1448 TRACE("lpic={0x%lX,%p,%p,%p,%p,%p,%p,%ld,%lu,%lu,%p,%p}\n",lpic
->dwFlags
,lpic
->lpbiOutput
,lpic
->lpOutput
,lpic
->lpbiInput
,lpic
->lpInput
,lpic
->lpckid
,lpic
->lpdwFlags
,lpic
->lFrameNum
,lpic
->dwFrameSize
,lpic
->dwQuality
,lpic
->lpbiPrev
,lpic
->lpPrev
);
1450 if (! pi
->bCompress
) {
1451 LRESULT hr
= CompressBegin(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
);
1454 } else if (CompressQuery(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
) != ICERR_OK
)
1455 return ICERR_BADFORMAT
;
1457 if (lpic
->lFrameNum
>= pi
->nPrevFrame
+ 1) {
1458 /* we continue in the sequence so we need to initialize
1459 * our internal framedata */
1461 computeInternalFrame(pi
, lpic
->lpbiInput
, lpic
->lpInput
);
1462 } else if (lpic
->lFrameNum
== pi
->nPrevFrame
) {
1463 /* Oops, compress same frame again ? Okay, as you wish.
1464 * No need to recompute internal framedata, because we only swapped buffers */
1465 LPWORD pTmp
= pi
->pPrevFrame
;
1467 pi
->pPrevFrame
= pi
->pCurFrame
;
1468 pi
->pCurFrame
= pTmp
;
1469 } else if ((lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1472 WARN(": prev=%ld cur=%ld gone back? -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1473 if (lpic
->lpbiPrev
== NULL
|| lpic
->lpPrev
== NULL
)
1474 return ICERR_GOTOKEYFRAME
; /* Need a keyframe if you go back */
1475 if (CompressQuery(pi
, lpic
->lpbiPrev
, lpic
->lpbiOutput
) != ICERR_OK
)
1476 return ICERR_BADFORMAT
;
1478 WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1479 computeInternalFrame(pi
, lpic
->lpbiPrev
, lpic
->lpPrev
);
1481 /* swap buffers for current and previous frame */
1482 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1483 pTmp
= pi
->pPrevFrame
;
1484 pi
->pPrevFrame
= pi
->pCurFrame
;
1485 pi
->pCurFrame
= pTmp
;
1486 pi
->nPrevFrame
= lpic
->lFrameNum
;
1489 for (i
= 0; i
< 3; i
++) {
1490 SetQuality(pi
, lpic
->dwQuality
);
1492 lpic
->lpbiOutput
->biSizeImage
= 0;
1494 if (lpic
->lpbiOutput
->biBitCount
== 4)
1495 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1496 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1498 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1499 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1501 if (lpic
->dwFrameSize
== 0 ||
1502 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
)
1505 if ((*lpic
->lpdwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1506 if (lpic
->lpbiOutput
->biBitCount
== 4)
1507 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1508 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1510 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1511 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1513 if (lpic
->dwFrameSize
== 0 ||
1514 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
) {
1515 WARN("switched to keyframe, was small enough!\n");
1516 *lpic
->lpdwFlags
|= ICCOMPRESS_KEYFRAME
;
1517 *lpic
->lpckid
= MAKEAVICKID(cktypeDIBbits
,
1518 StreamFromFOURCC(*lpic
->lpckid
));
1523 if (lpic
->dwQuality
< 1000)
1526 lpic
->dwQuality
-= 1000; /* reduce quality by 10% */
1529 { /* swap buffer for current and previous frame */
1530 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1531 register LPWORD pTmp
= pi
->pPrevFrame
;
1533 pi
->pPrevFrame
= pi
->pCurFrame
;
1534 pi
->pCurFrame
= pTmp
;
1535 pi
->nPrevFrame
= lpic
->lFrameNum
;
1541 static LRESULT
CompressEnd(CodecInfo
*pi
)
1546 if (pi
->pPrevFrame
!= NULL
)
1547 GlobalFreePtr(pi
->pPrevFrame
);
1548 if (pi
->pCurFrame
!= NULL
)
1549 GlobalFreePtr(pi
->pCurFrame
);
1550 pi
->pPrevFrame
= NULL
;
1551 pi
->pCurFrame
= NULL
;
1552 pi
->nPrevFrame
= -1;
1553 pi
->bCompress
= FALSE
;
1559 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1560 LPBITMAPINFOHEADER lpbiOut
)
1564 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1570 return (lpbiOut
!= NULL
? ICERR_BADPARAM
: 0);
1572 if (DecompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1573 return (lpbiOut
!= NULL
? ICERR_BADFORMAT
: 0);
1575 size
= lpbiIn
->biSize
;
1577 if (lpbiIn
->biBitCount
<= 8)
1578 size
+= lpbiIn
->biClrUsed
* sizeof(RGBQUAD
);
1580 if (lpbiOut
!= NULL
) {
1581 memcpy(lpbiOut
, lpbiIn
, size
);
1582 lpbiOut
->biCompression
= BI_RGB
;
1583 lpbiOut
->biSizeImage
= DIBWIDTHBYTES(*lpbiOut
) * lpbiOut
->biHeight
;
1590 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1591 LPCBITMAPINFOHEADER lpbiOut
)
1593 LRESULT hr
= ICERR_OK
;
1595 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1600 /* need at least one format */
1601 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1602 return ICERR_BADPARAM
;
1604 /* check input format if given */
1605 if (lpbiIn
!= NULL
) {
1606 if (!isSupportedMRLE(lpbiIn
))
1607 return ICERR_BADFORMAT
;
1610 /* check output format if given */
1611 if (lpbiOut
!= NULL
) {
1612 if (!isSupportedDIB(lpbiOut
))
1613 hr
= ICERR_BADFORMAT
;
1615 if (lpbiIn
!= NULL
) {
1616 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1617 hr
= ICERR_UNSUPPORTED
;
1618 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1619 hr
= ICERR_UNSUPPORTED
;
1620 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1621 hr
= ICERR_UNSUPPORTED
;
1628 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1629 LPCBITMAPINFOHEADER lpbiOut
)
1631 const RGBQUAD
*rgbIn
;
1632 const RGBQUAD
*rgbOut
;
1635 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1640 /* check parameters */
1641 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1642 return ICERR_BADPARAM
;
1643 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1644 return ICERR_BADFORMAT
;
1646 /* FIXME: cannot compress and decompress at a time! */
1647 if (pi
->bCompress
) {
1648 FIXME("cannot compress and decompress at same time!\n");
1652 if (pi
->bDecompress
)
1655 rgbIn
= (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
1656 rgbOut
= (const RGBQUAD
*)((const BYTE
*)lpbiOut
+ lpbiOut
->biSize
);
1658 switch (lpbiOut
->biBitCount
) {
1661 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1662 if (pi
->palette_map
== NULL
)
1663 return ICERR_MEMORY
;
1665 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1666 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1671 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* 2);
1672 if (pi
->palette_map
== NULL
)
1673 return ICERR_MEMORY
;
1675 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1678 if (lpbiOut
->biBitCount
== 15)
1679 color
= ((rgbIn
[i
].rgbRed
>> 3) << 10)
1680 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1682 color
= ((rgbIn
[i
].rgbRed
>> 3) << 11)
1683 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1685 pi
->palette_map
[i
* 2 + 1] = color
>> 8;
1686 pi
->palette_map
[i
* 2 + 0] = color
& 0xFF;
1691 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1692 if (pi
->palette_map
== NULL
)
1693 return ICERR_MEMORY
;
1694 memcpy(pi
->palette_map
, rgbIn
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1698 pi
->bDecompress
= TRUE
;
1703 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
)
1705 TRACE("(%p,%p,%lu)\n",pi
,pic
,dwSize
);
1710 /* check parameters */
1712 return ICERR_BADPARAM
;
1713 if (pic
->lpbiInput
== NULL
|| pic
->lpInput
== NULL
||
1714 pic
->lpbiOutput
== NULL
|| pic
->lpOutput
== NULL
)
1715 return ICERR_BADPARAM
;
1718 if (! pi
->bDecompress
) {
1719 LRESULT hr
= DecompressBegin(pi
, pic
->lpbiInput
, pic
->lpbiOutput
);
1722 } else if (DecompressQuery(pi
, pic
->lpbiInput
, pic
->lpbiOutput
) != ICERR_OK
)
1723 return ICERR_BADFORMAT
;
1725 assert(pic
->lpbiInput
->biWidth
== pic
->lpbiOutput
->biWidth
);
1726 assert(pic
->lpbiInput
->biHeight
== pic
->lpbiOutput
->biHeight
);
1728 pic
->lpbiOutput
->biSizeImage
= DIBWIDTHBYTES(*pic
->lpbiOutput
) * pic
->lpbiOutput
->biHeight
;
1729 if (pic
->lpbiInput
->biBitCount
== 4)
1730 return MSRLE32_DecompressRLE4(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1732 return MSRLE32_DecompressRLE8(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1735 static LRESULT
DecompressEnd(CodecInfo
*pi
)
1742 pi
->bDecompress
= FALSE
;
1744 if (pi
->palette_map
!= NULL
) {
1745 LocalFree((HLOCAL
)pi
->palette_map
);
1746 pi
->palette_map
= NULL
;
1752 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1753 LPBITMAPINFOHEADER lpbiOut
)
1757 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1762 /* check parameters */
1763 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1764 return ICERR_BADPARAM
;
1766 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1767 return ICERR_BADFORMAT
;
1769 if (lpbiOut
->biBitCount
> 8)
1772 if (lpbiIn
->biBitCount
<= 8) {
1773 if (lpbiIn
->biClrUsed
> 0)
1774 size
= lpbiIn
->biClrUsed
;
1776 size
= (1 << lpbiIn
->biBitCount
);
1778 lpbiOut
->biClrUsed
= size
;
1780 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
, (const BYTE
*)lpbiIn
+ lpbiIn
->biSize
, size
* sizeof(RGBQUAD
));
1781 } /* else could never occur ! */
1786 /* DriverProc - entry point for an installable driver */
1787 LRESULT CALLBACK
MSRLE32_DriverProc(DWORD dwDrvID
, HDRVR hDrv
, UINT uMsg
,
1788 LPARAM lParam1
, LPARAM lParam2
)
1790 CodecInfo
*pi
= (CodecInfo
*)dwDrvID
;
1792 TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID
)dwDrvID
, (LPVOID
)hDrv
,
1793 uMsg
, lParam1
, lParam2
);
1796 /* standard driver messages */
1801 return (LRESULT
)0xFFFF0000;
1803 return (LRESULT
)Open((ICOPEN
*)lParam2
);
1805 if (dwDrvID
!= 0xFFFF0000 && (LPVOID
)dwDrvID
!= NULL
)
1813 case DRV_QUERYCONFIGURE
:
1814 return DRVCNF_CANCEL
; /* FIXME */
1816 return DRVCNF_OK
; /* FIXME */
1821 /* installable compression manager messages */
1823 FIXME("ICM_CONFIGURE (%ld)\n",lParam1
);
1825 return ICERR_UNSUPPORTED
; /* FIXME */
1827 return Configure(pi
, (HWND
)lParam1
);
1832 return About(pi
, (HWND
)lParam1
);
1835 return 0; /* no state */
1837 return GetInfo(pi
, (ICINFO
*)lParam1
, (DWORD
)lParam2
);
1838 case ICM_GETDEFAULTQUALITY
:
1839 if ((LPVOID
)lParam1
!= NULL
) {
1840 *((LPDWORD
)lParam1
) = MSRLE32_DEFAULTQUALITY
;
1844 case ICM_GETQUALITY
:
1845 if ((LPVOID
)lParam1
!= NULL
) {
1846 *((LPDWORD
)lParam1
) = pi
->dwQuality
;
1850 case ICM_SETQUALITY
:
1851 return SetQuality(pi
, *(LPLONG
)lParam1
);
1852 case ICM_COMPRESS_GET_FORMAT
:
1853 return CompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1854 (LPBITMAPINFOHEADER
)lParam2
);
1855 case ICM_COMPRESS_GET_SIZE
:
1856 return CompressGetSize(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1857 (LPCBITMAPINFOHEADER
)lParam2
);
1858 case ICM_COMPRESS_QUERY
:
1859 return CompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1860 (LPCBITMAPINFOHEADER
)lParam2
);
1861 case ICM_COMPRESS_BEGIN
:
1862 return CompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1863 (LPCBITMAPINFOHEADER
)lParam2
);
1865 return Compress(pi
, (ICCOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1866 case ICM_COMPRESS_END
:
1867 return CompressEnd(pi
);
1868 case ICM_DECOMPRESS_GET_FORMAT
:
1869 return DecompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1870 (LPBITMAPINFOHEADER
)lParam2
);
1871 case ICM_DECOMPRESS_QUERY
:
1872 return DecompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1873 (LPCBITMAPINFOHEADER
)lParam2
);
1874 case ICM_DECOMPRESS_BEGIN
:
1875 return DecompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1876 (LPCBITMAPINFOHEADER
)lParam2
);
1877 case ICM_DECOMPRESS
:
1878 return Decompress(pi
, (ICDECOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1879 case ICM_DECOMPRESS_END
:
1880 return DecompressEnd(pi
);
1881 case ICM_DECOMPRESS_SET_PALETTE
:
1882 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi
, (LPVOID
)lParam1
, (LPVOID
)lParam2
);
1883 return ICERR_UNSUPPORTED
;
1884 case ICM_DECOMPRESS_GET_PALETTE
:
1885 return DecompressGetPalette(pi
, (LPBITMAPINFOHEADER
)lParam1
,
1886 (LPBITMAPINFOHEADER
)lParam2
);
1887 case ICM_GETDEFAULTKEYFRAMERATE
:
1888 if ((LPVOID
)lParam1
!= NULL
)
1889 *(LPDWORD
)lParam1
= 15;
1892 if (uMsg
< DRV_USER
)
1893 return DefDriverProc(dwDrvID
, hDrv
, uMsg
, lParam1
, lParam2
);
1895 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg
,lParam1
,lParam2
);
1898 return ICERR_UNSUPPORTED
;
1901 /* DllMain - library initialization code */
1902 BOOL WINAPI
DllMain(HINSTANCE hModule
, DWORD dwReason
, LPVOID lpReserved
)
1904 TRACE("(%p,%ld,%p)\n",(LPVOID
)hModule
,dwReason
,lpReserved
);
1907 case DLL_PROCESS_ATTACH
:
1908 DisableThreadLibraryCalls(hModule
);
1909 MSRLE32_hModule
= hModule
;
1912 case DLL_PROCESS_DETACH
: