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? -- do 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 BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
);
63 /* compression functions */
64 static void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
);
65 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
);
66 static LRESULT
MSRLE32_CompressRLE4(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
);
67 static LRESULT
MSRLE32_CompressRLE8(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
);
69 /* decompression functions */
70 static LRESULT
MSRLE32_DecompressRLE4(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
71 LPBYTE lpIn
, LPBYTE lpOut
);
72 static LRESULT
MSRLE32_DecompressRLE8(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
73 LPBYTE lpIn
, LPBYTE lpOut
);
76 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
77 LPBITMAPINFOHEADER lpbiOut
);
78 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
79 LPCBITMAPINFOHEADER lpbiOut
);
80 static LRESULT
CompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
81 LPCBITMAPINFOHEADER lpbiOut
);
82 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
83 LPCBITMAPINFOHEADER lpbiOut
);
84 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
);
85 static LRESULT
CompressEnd(CodecInfo
*pi
);
87 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
88 LPBITMAPINFOHEADER lpbiOut
);
89 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
90 LPCBITMAPINFOHEADER lpbiOut
);
91 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
92 LPCBITMAPINFOHEADER lpbiOut
);
93 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
);
94 static LRESULT
DecompressEnd(CodecInfo
*pi
);
95 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
96 LPBITMAPINFOHEADER lpbiOut
);
98 /*****************************************************************************/
100 static BOOL
isSupportedMRLE(LPCBITMAPINFOHEADER lpbi
)
103 assert(lpbi
!= NULL
);
105 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) || \
109 if (lpbi
->biCompression
== BI_RLE4
) {
110 if (lpbi
->biBitCount
!= 4 || \
111 (lpbi
->biWidth
% 2) != 0)
113 } else if (lpbi
->biCompression
== BI_RLE8
) {
114 if (lpbi
->biBitCount
!= 8)
122 static BOOL
isSupportedDIB(LPCBITMAPINFOHEADER lpbi
)
125 assert(lpbi
!= NULL
);
127 /* check structure version/planes/compression */
128 if (lpbi
->biSize
< sizeof(BITMAPINFOHEADER
) ||
131 if (lpbi
->biCompression
!= BI_RGB
&&
132 lpbi
->biCompression
!= BI_BITFIELDS
)
135 /* check bit-depth */
136 if (lpbi
->biBitCount
!= 1 &&
137 lpbi
->biBitCount
!= 4 &&
138 lpbi
->biBitCount
!= 8 &&
139 lpbi
->biBitCount
!= 15 &&
140 lpbi
->biBitCount
!= 16 &&
141 lpbi
->biBitCount
!= 24 &&
142 lpbi
->biBitCount
!= 32)
145 /* check for size(s) */
146 if (!lpbi
->biWidth
|| !lpbi
->biHeight
)
147 return FALSE
; /* image with zero size, makes no sense so error ! */
148 if (DIBWIDTHBYTES(*lpbi
) * (DWORD
)lpbi
->biHeight
>= (1UL << 31) - 1)
149 return FALSE
; /* image too big ! */
151 /* check for nonexistent colortable for hi- and true-color DIB's */
152 if (lpbi
->biBitCount
>= 15 && lpbi
->biClrUsed
> 0)
158 static BYTE
MSRLE32_GetNearestPaletteIndex(UINT count
, const RGBQUAD
*clrs
, RGBQUAD clr
)
160 INT diff
= 0x00FFFFFF;
165 assert(clrs
!= NULL
);
167 for (i
= 0; i
< count
; i
++) {
168 int r
= ((int)clrs
[i
].rgbRed
- (int)clr
.rgbRed
);
169 int g
= ((int)clrs
[i
].rgbGreen
- (int)clr
.rgbGreen
);
170 int b
= ((int)clrs
[i
].rgbBlue
- (int)clr
.rgbBlue
);
185 /*****************************************************************************/
187 void computeInternalFrame(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
)
189 WORD wIntensityTbl
[256];
190 DWORD lInLine
, lOutLine
;
196 assert(pi
!= NULL
&& lpbiIn
!= NULL
&& lpIn
!= NULL
);
197 assert(pi
->pCurFrame
!= NULL
);
199 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
200 lOutLine
= WIDTHBYTES((WORD
)lpbiIn
->biWidth
* 8u * sizeof(WORD
)) / 2u;
201 lpOut
= pi
->pCurFrame
;
203 assert(lpbiIn
->biClrUsed
!= 0);
207 (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
209 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++)
210 wIntensityTbl
[i
] = Intensity(lp
[i
]);
213 for (y
= 0; y
< lpbiIn
->biHeight
; y
++) {
216 switch (lpbiIn
->biBitCount
) {
218 for (x
= 0; x
< lpbiIn
->biWidth
/ 8; x
++) {
219 for (i
= 0; i
< 7; i
++)
220 lpOut
[8 * x
+ i
] = wIntensityTbl
[(lpIn
[x
] >> (7 - i
)) & 1];
224 for (x
= 0; x
< lpbiIn
->biWidth
/ 2; x
++) {
225 lpOut
[2 * x
+ 0] = wIntensityTbl
[(lpIn
[x
] >> 4)];
226 lpOut
[2 * x
+ 1] = wIntensityTbl
[(lpIn
[x
] & 0x0F)];
230 for (x
= 0; x
< lpbiIn
->biWidth
; x
++)
231 lpOut
[x
] = wIntensityTbl
[lpIn
[x
]];
240 static LONG
MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi
)
245 assert(lpbi
!= NULL
);
247 a
= lpbi
->biWidth
/ 255;
248 b
= lpbi
->biWidth
% 255;
249 if (lpbi
->biBitCount
<= 4) {
254 size
= (2 + a
* (2 + ((a
+ 2) & ~2)) + b
* (2 + ((b
+ 2) & ~2)));
255 return size
* lpbi
->biHeight
;
258 /* lpP => current pos in previous frame
259 * lpA => previous pos in current frame
260 * lpB => current pos in current frame
262 static INT
countDiffRLE4(LPWORD lpP
, LPWORD lpA
, LPWORD lpB
, INT pos
, LONG lDist
, LONG width
)
268 assert(lpA
&& lpB
&& lDist
>= 0 && width
> 0);
279 while (pos
+ 1 < width
) {
283 if (pos
+ 1 >= width
)
287 if (ColorCmp(clr1
, clr3
) <= lDist
&&
288 ColorCmp(clr2
, clr4
) <= lDist
) {
289 /* diff at end? -- look-ahead for at least ?? more encodable pixels */
290 if (pos
+ 2 < width
&& ColorCmp(clr1
,lpB
[pos
+1]) <= lDist
&&
291 ColorCmp(clr2
,lpB
[pos
+2]) <= lDist
) {
292 if (pos
+ 4 < width
&& ColorCmp(lpB
[pos
+1],lpB
[pos
+3]) <= lDist
&&
293 ColorCmp(lpB
[pos
+2],lpB
[pos
+4]) <= lDist
)
294 return count
- 3; /* followed by at least 4 encodable pixels */
297 } else if (lpP
!= NULL
&& ColorCmp(lpP
[pos
], lpB
[pos
]) <= lDist
) {
298 /* 'compare' with previous frame for end of diff */
317 /* lpP => current pos in previous frame
318 * lpA => previous pos in current frame
319 * lpB => current pos in current frame
321 static INT
countDiffRLE8(LPWORD lpP
, LPWORD lpA
, LPWORD lpB
, INT pos
, LONG lDist
, LONG width
)
325 for (count
= 0; pos
< width
; pos
++, count
++) {
326 if (ColorCmp(lpA
[pos
], lpB
[pos
]) <= lDist
) {
327 /* diff at end? -- look-ahead for some more encodable pixel */
328 if (pos
+ 1 < width
&& ColorCmp(lpB
[pos
], lpB
[pos
+1]) <= lDist
)
330 if (pos
+ 2 < width
&& ColorCmp(lpB
[pos
+1], lpB
[pos
+2]) <= lDist
)
332 } else if (lpP
!= NULL
&& ColorCmp(lpP
[pos
], lpB
[pos
]) <= lDist
) {
333 /* 'compare' with previous frame for end of diff */
336 for (count2
= 0, pos
++; pos
< width
&& count2
<= 5; pos
++, count2
++) {
337 if (ColorCmp(lpP
[pos
], lpB
[pos
]) > lDist
)
350 static INT
MSRLE32_CompressRLE4Line(CodecInfo
*pi
, LPWORD lpP
, LPWORD lpC
, LPCBITMAPINFOHEADER lpbi
, BYTE
*lpIn
, LONG lDist
, INT x
, LPBYTE
*ppOut
, DWORD
*lpSizeImage
)
352 LPBYTE lpOut
= *ppOut
;
356 /* try to encode as many pixel as possible */
360 if (pos
< lpbi
->biWidth
) {
362 for (++count
; pos
+ 1 < lpbi
->biWidth
; ) {
364 if (ColorCmp(clr1
, lpC
[pos
]) > lDist
)
367 if (pos
+ 1 >= lpbi
->biWidth
)
370 if (ColorCmp(clr2
, lpC
[pos
]) > lDist
)
377 /* add some pixel for absoluting if possible */
378 count
+= countDiffRLE4(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
382 /* check for near end of line */
383 if (x
+ count
> lpbi
->biWidth
)
384 count
= lpbi
->biWidth
- x
;
386 /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
389 INT size
= min(count
, 254);
390 int bytes
= ((size
+ 1) & (~1)) / 2;
391 BOOL extra_byte
= bytes
& 0x01;
393 *lpSizeImage
+= 2 + bytes
+ extra_byte
;
394 assert(((*lpSizeImage
) % 2) == 0);
398 for (i
= 0; i
< size
; i
+= 2) {
399 clr1
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
402 clr2
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
407 *lpOut
++ = (clr1
<< 4) | clr2
;
414 /* too little for absoluting so we must encode them */
418 clr1
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
421 clr2
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
426 *lpOut
++ = (clr1
<< 4) | clr2
;
429 /* encode count pixel(s) */
430 clr1
= ((pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)] << 4) |
431 pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
+ 1)]);
435 INT size
= min(count
, 254);
449 static INT
MSRLE32_CompressRLE8Line(CodecInfo
*pi
, LPWORD lpP
, LPWORD lpC
, LPCBITMAPINFOHEADER lpbi
, BYTE
*lpIn
, LONG lDist
, INT x
, LPBYTE
*ppOut
, DWORD
*lpSizeImage
)
451 LPBYTE lpOut
= *ppOut
;
455 assert(lpbi
->biBitCount
<= 8);
456 assert(lpbi
->biCompression
== BI_RGB
);
458 /* try to encode as much as possible */
461 for (count
= 1; pos
< lpbi
->biWidth
; count
++) {
462 if (ColorCmp(clr
, lpC
[pos
++]) > lDist
)
467 /* add some more pixels for absoluting if possible */
468 count
+= countDiffRLE8(lpP
, lpC
- 1, lpC
, pos
-1, lDist
, lpbi
->biWidth
);
472 /* check for over end of line */
473 if (x
+ count
> lpbi
->biWidth
)
474 count
= lpbi
->biWidth
- x
;
476 /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
479 INT size
= min(count
, 255);
480 BOOL extra_byte
= size
% 2;
482 *lpSizeImage
+= 2 + size
+ extra_byte
;
486 for (i
= 0; i
< size
; i
++) {
487 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
494 /* too little for absoluting so we must encode them even if it's expensive! */
497 *lpSizeImage
+= 2 * count
;
499 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
504 *lpOut
++ = pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
509 /* encode count pixel(s) */
510 clr
= pi
->palette_map
[GetRawPixel(lpbi
,lpIn
,x
)];
512 /* optimize end of line */
513 if (x
+ count
+ 1 == lpbi
->biWidth
)
518 INT size
= min(count
, 255);
532 LRESULT
MSRLE32_CompressRLE4(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
)
535 LONG lLine
, lInLine
, lDist
;
536 LPBYTE lpOutStart
= lpOut
;
539 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
540 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
541 assert(pi
->pCurFrame
!= NULL
);
544 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
545 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
546 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
548 lpbiOut
->biSizeImage
= 0;
550 /* keyframe -- convert internal frame to output format */
553 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
557 x
= MSRLE32_CompressRLE4Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
558 &lpOut
, &lpbiOut
->biSizeImage
);
559 } while (x
< lpbiOut
->biWidth
);
564 /* add EOL -- end of line */
565 lpbiOut
->biSizeImage
+= 2;
567 lpOut
+= sizeof(WORD
);
568 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
571 /* delta-frame -- compute delta between last and this internal frame */
576 assert(pi
->pPrevFrame
!= NULL
);
578 lpP
= pi
->pPrevFrame
;
582 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
590 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
591 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
595 if (pos
== lpbiOut
->biWidth
&& count
> 8) {
596 /* (count > 8) secures that we will save space */
599 } else if (jumpy
|| jumpx
!= pos
) {
604 /* can only jump in positive direction -- jump until EOL, EOL */
605 INT w
= lpbiOut
->biWidth
- jumpx
;
612 /* if (w % 255 == 2) then equal costs
613 * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
614 * else it will be cheaper
617 lpbiOut
->biSizeImage
+= 4;
620 *lpOut
= min(w
, 255);
624 /* add EOL -- end of line */
625 lpbiOut
->biSizeImage
+= 2;
626 *((LPWORD
)lpOut
) = 0;
627 lpOut
+= sizeof(WORD
);
630 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
632 /* write out real jump(s) */
633 while (jumpy
|| pos
!= jumpx
) {
634 lpbiOut
->biSizeImage
+= 4;
637 *lpOut
= min(pos
- jumpx
, 255);
640 *lpOut
= min(jumpy
, 255);
649 if (x
< lpbiOut
->biWidth
) {
650 /* skipped the 'same' things corresponding to previous frame */
651 x
= MSRLE32_CompressRLE4Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
652 &lpOut
, &lpbiOut
->biSizeImage
);
654 } while (x
< lpbiOut
->biWidth
);
663 /* add EOL -- end of line */
664 lpbiOut
->biSizeImage
+= 2;
665 *((LPWORD
)lpOut
) = 0;
666 lpOut
+= sizeof(WORD
);
667 assert(lpOut
== lpOutStart
+ lpbiOut
->biSizeImage
);
671 /* add EOL -- will be changed to EOI */
672 lpbiOut
->biSizeImage
+= 2;
673 *((LPWORD
)lpOut
) = 0;
674 lpOut
+= sizeof(WORD
);
677 /* change EOL to EOI -- end of image */
679 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
684 LRESULT
MSRLE32_CompressRLE8(CodecInfo
*pi
, LPBITMAPINFOHEADER lpbiIn
, LPBYTE lpIn
, LPBITMAPINFOHEADER lpbiOut
, LPBYTE lpOut
, BOOL isKey
)
687 LONG lDist
, lInLine
, lLine
;
688 LPBYTE lpOutStart
= lpOut
;
690 assert(pi
!= NULL
&& lpbiOut
!= NULL
);
691 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
692 assert(pi
->pCurFrame
!= NULL
);
695 lDist
= QUALITY_to_DIST(pi
->dwQuality
);
696 lInLine
= DIBWIDTHBYTES(*lpbiIn
);
697 lLine
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2;
699 lpbiOut
->biSizeImage
= 0;
701 /* keyframe -- convert internal frame to output format */
704 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
708 x
= MSRLE32_CompressRLE8Line(pi
, NULL
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
709 &lpOut
, &lpbiOut
->biSizeImage
);
710 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
711 } while (x
< lpbiOut
->biWidth
);
716 /* add EOL -- end of line */
717 lpbiOut
->biSizeImage
+= 2;
718 *((LPWORD
)lpOut
) = 0;
719 lpOut
+= sizeof(WORD
);
720 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
723 /* delta-frame -- compute delta between last and this internal frame */
728 assert(pi
->pPrevFrame
!= NULL
);
730 lpP
= pi
->pPrevFrame
;
734 for (y
= 0; y
< lpbiOut
->biHeight
; y
++) {
742 for (count
= 0, pos
= x
; pos
< lpbiOut
->biWidth
; pos
++, count
++) {
743 if (ColorCmp(lpP
[pos
], lpC
[pos
]) > lDist
)
747 if (pos
== lpbiOut
->biWidth
&& count
> 4) {
748 /* (count > 4) secures that we will save space */
751 } else if (jumpy
|| jumpx
!= pos
) {
756 /* can only jump in positive direction -- do an EOL then jump */
762 /* add EOL -- end of line */
763 lpbiOut
->biSizeImage
+= 2;
764 *((LPWORD
)lpOut
) = 0;
765 lpOut
+= sizeof(WORD
);
766 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
769 /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
771 /* write out real jump(s) */
772 while (jumpy
|| pos
!= jumpx
) {
773 lpbiOut
->biSizeImage
+= 4;
776 *lpOut
= min(pos
- jumpx
, 255);
778 *lpOut
= min(jumpy
, 255);
788 if (x
< lpbiOut
->biWidth
) {
789 /* skip the 'same' things corresponding to previous frame */
790 x
= MSRLE32_CompressRLE8Line(pi
, lpP
, lpC
, lpbiIn
, lpIn
, lDist
, x
,
791 &lpOut
, &lpbiOut
->biSizeImage
);
792 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
794 } while (x
< lpbiOut
->biWidth
);
801 /* add EOL -- end of line */
802 lpbiOut
->biSizeImage
+= 2;
803 *((LPWORD
)lpOut
) = 0;
804 lpOut
+= sizeof(WORD
);
805 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
809 /* add EOL -- will be changed to EOI */
810 lpbiOut
->biSizeImage
+= 2;
811 *((LPWORD
)lpOut
) = 0;
812 lpOut
+= sizeof(WORD
);
815 /* change EOL to EOI -- end of image */
817 assert(lpOut
== (lpOutStart
+ lpbiOut
->biSizeImage
));
822 /*****************************************************************************/
824 static LRESULT
MSRLE32_DecompressRLE4(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
825 LPBYTE lpIn
, LPBYTE lpOut
)
831 BOOL bEndFlag
= FALSE
;
834 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
835 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
837 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
838 line_size
= DIBWIDTHBYTES(*lpbi
);
850 case 0: /* EOL - end of line */
854 case 1: /* EOI - end of image */
858 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
859 lpOut
+= *lpIn
++ * line_size
;
860 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
865 default: /* absolute mode */
866 extra_byte
= (((code1
+ 1) & (~1)) / 2) & 0x01;
868 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
)
872 for (i
= 0; i
< code0
/ 2; i
++) {
873 if (bytes_per_pixel
== 1) {
875 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
876 if (2 * i
+ 1 <= code0
)
877 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
& 0x0F)];
878 } else if (bytes_per_pixel
== 2) {
879 code1
= lpIn
[i
] >> 4;
880 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
881 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
883 if (2 * i
+ 1 <= code0
) {
884 code1
= lpIn
[i
] & 0x0F;
885 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
886 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
889 code1
= lpIn
[i
] >> 4;
890 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
891 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
892 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
893 pixel_ptr
+= bytes_per_pixel
;
895 if (2 * i
+ 1 <= code0
) {
896 code1
= lpIn
[i
] & 0x0F;
897 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
898 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
899 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
900 pixel_ptr
+= bytes_per_pixel
;
905 if (bytes_per_pixel
== 1) {
907 lpOut
[pixel_ptr
++] = pi
->palette_map
[(code1
>> 4)];
908 } else if (bytes_per_pixel
== 2) {
909 code1
= lpIn
[i
] >> 4;
910 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 0];
911 lpOut
[pixel_ptr
++] = pi
->palette_map
[code1
* 2 + 1];
913 code1
= lpIn
[i
] >> 4;
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
;
923 /* if the RLE code is odd, skip a byte in the stream */
929 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
)
932 if (bytes_per_pixel
== 1) {
933 BYTE c1
= pi
->palette_map
[(code1
>> 4)];
934 BYTE c2
= pi
->palette_map
[(code1
& 0x0F)];
936 for (i
= 0; i
< code0
; i
++) {
938 lpOut
[pixel_ptr
++] = c1
;
940 lpOut
[pixel_ptr
++] = c2
;
942 } else if (bytes_per_pixel
== 2) {
943 BYTE hi1
= pi
->palette_map
[(code1
>> 4) * 2 + 0];
944 BYTE lo1
= pi
->palette_map
[(code1
>> 4) * 2 + 1];
946 BYTE hi2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 0];
947 BYTE lo2
= pi
->palette_map
[(code1
& 0x0F) * 2 + 1];
949 for (i
= 0; i
< code0
; i
++) {
951 lpOut
[pixel_ptr
++] = hi1
;
952 lpOut
[pixel_ptr
++] = lo1
;
954 lpOut
[pixel_ptr
++] = hi2
;
955 lpOut
[pixel_ptr
++] = lo2
;
959 BYTE b1
= pi
->palette_map
[(code1
>> 4) * 4 + 0];
960 BYTE g1
= pi
->palette_map
[(code1
>> 4) * 4 + 1];
961 BYTE r1
= pi
->palette_map
[(code1
>> 4) * 4 + 2];
963 BYTE b2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 0];
964 BYTE g2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 1];
965 BYTE r2
= pi
->palette_map
[(code1
& 0x0F) * 4 + 2];
967 for (i
= 0; i
< code0
; i
++) {
969 lpOut
[pixel_ptr
+ 0] = b1
;
970 lpOut
[pixel_ptr
+ 1] = g1
;
971 lpOut
[pixel_ptr
+ 2] = r1
;
973 lpOut
[pixel_ptr
+ 0] = b2
;
974 lpOut
[pixel_ptr
+ 1] = g2
;
975 lpOut
[pixel_ptr
+ 2] = r2
;
977 pixel_ptr
+= bytes_per_pixel
;
981 } while (! bEndFlag
);
986 static LRESULT
MSRLE32_DecompressRLE8(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbi
,
987 LPBYTE lpIn
, LPBYTE lpOut
)
992 BOOL bEndFlag
= FALSE
;
995 assert(lpbi
!= NULL
&& lpbi
->biCompression
== BI_RGB
);
996 assert(lpIn
!= NULL
&& lpOut
!= NULL
);
998 bytes_per_pixel
= (lpbi
->biBitCount
+ 1) / 8;
999 line_size
= DIBWIDTHBYTES(*lpbi
);
1011 case 0: /* EOL - end of line */
1015 case 1: /* EOI - end of image */
1019 pixel_ptr
+= *lpIn
++ * bytes_per_pixel
;
1020 lpOut
+= *lpIn
++ * line_size
;
1021 if (pixel_ptr
>= lpbi
->biWidth
* bytes_per_pixel
) {
1026 default: /* absolute mode */
1027 if (pixel_ptr
/bytes_per_pixel
+ code1
> lpbi
->biWidth
) {
1028 WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1031 extra_byte
= code1
& 0x01;
1036 if (bytes_per_pixel
== 1) {
1037 lpOut
[pixel_ptr
] = pi
->palette_map
[code1
];
1038 } else if (bytes_per_pixel
== 2) {
1039 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 2 + 0];
1040 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 2 + 1];
1042 lpOut
[pixel_ptr
+ 0] = pi
->palette_map
[code1
* 4 + 0];
1043 lpOut
[pixel_ptr
+ 1] = pi
->palette_map
[code1
* 4 + 1];
1044 lpOut
[pixel_ptr
+ 2] = pi
->palette_map
[code1
* 4 + 2];
1046 pixel_ptr
+= bytes_per_pixel
;
1049 /* if the RLE code is odd, skip a byte in the stream */
1055 if (pixel_ptr
/bytes_per_pixel
+ code0
> lpbi
->biWidth
) {
1056 WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr
/bytes_per_pixel
+ code1
,pixel_ptr
,bytes_per_pixel
,code1
,lpbi
->biWidth
);
1060 if (bytes_per_pixel
== 1) {
1061 code1
= pi
->palette_map
[code1
];
1063 lpOut
[pixel_ptr
++] = code1
;
1064 } else if (bytes_per_pixel
== 2) {
1065 BYTE hi
= pi
->palette_map
[code1
* 2 + 0];
1066 BYTE lo
= pi
->palette_map
[code1
* 2 + 1];
1069 lpOut
[pixel_ptr
+ 0] = hi
;
1070 lpOut
[pixel_ptr
+ 1] = lo
;
1071 pixel_ptr
+= bytes_per_pixel
;
1074 BYTE r
= pi
->palette_map
[code1
* 4 + 2];
1075 BYTE g
= pi
->palette_map
[code1
* 4 + 1];
1076 BYTE b
= pi
->palette_map
[code1
* 4 + 0];
1079 lpOut
[pixel_ptr
+ 0] = b
;
1080 lpOut
[pixel_ptr
+ 1] = g
;
1081 lpOut
[pixel_ptr
+ 2] = r
;
1082 pixel_ptr
+= bytes_per_pixel
;
1086 } while (! bEndFlag
);
1091 /*****************************************************************************/
1093 static CodecInfo
* Open(LPICOPEN icinfo
)
1095 CodecInfo
* pi
= NULL
;
1097 if (icinfo
== NULL
) {
1099 return (LPVOID
)0xFFFF0000;
1102 if (icinfo
->fccType
!= ICTYPE_VIDEO
) return NULL
;
1104 TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo
,
1105 icinfo
->dwSize
, icinfo
->fccType
, (char*)&icinfo
->fccType
,
1106 icinfo
->fccHandler
, (char*)&icinfo
->fccHandler
,
1107 icinfo
->dwVersion
,icinfo
->dwFlags
);
1109 switch (icinfo
->fccHandler
) {
1115 case mmioFOURCC('m','r','l','e'):
1116 icinfo
->fccHandler
= FOURCC_MRLE
;
1119 WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1120 icinfo
->fccHandler
,(char*)&icinfo
->fccHandler
);
1124 pi
= (CodecInfo
*)LocalAlloc(LPTR
, sizeof(CodecInfo
));
1127 pi
->fccHandler
= icinfo
->fccHandler
;
1129 pi
->bCompress
= FALSE
;
1130 pi
->dwQuality
= MSRLE32_DEFAULTQUALITY
;
1131 pi
->nPrevFrame
= -1;
1132 pi
->pPrevFrame
= pi
->pCurFrame
= NULL
;
1134 pi
->bDecompress
= FALSE
;
1135 pi
->palette_map
= NULL
;
1138 icinfo
->dwError
= (pi
!= NULL
? ICERR_OK
: ICERR_MEMORY
);
1143 static LRESULT
Close(CodecInfo
*pi
)
1145 TRACE("(%p)\n", pi
);
1150 if (pi
->pPrevFrame
!= NULL
|| pi
->pCurFrame
!= NULL
)
1153 LocalFree((HLOCAL
)pi
);
1157 static LRESULT
GetInfo(CodecInfo
*pi
, ICINFO
*icinfo
, DWORD dwSize
)
1162 /* check parameters */
1164 return sizeof(ICINFO
);
1165 if (dwSize
< sizeof(ICINFO
))
1168 icinfo
->dwSize
= sizeof(ICINFO
);
1169 icinfo
->fccType
= ICTYPE_VIDEO
;
1170 icinfo
->fccHandler
= (pi
!= NULL
? pi
->fccHandler
: FOURCC_MRLE
);
1171 icinfo
->dwFlags
= VIDCF_QUALITY
| VIDCF_TEMPORAL
| VIDCF_CRUNCH
| VIDCF_FASTTEMPORALC
;
1172 icinfo
->dwVersion
= ICVERSION
;
1173 icinfo
->dwVersionICM
= ICVERSION
;
1175 LoadStringW(MSRLE32_hModule
, IDS_NAME
, icinfo
->szName
, sizeof(icinfo
->szName
)/sizeof(WCHAR
));
1176 LoadStringW(MSRLE32_hModule
, IDS_DESCRIPTION
, icinfo
->szDescription
, sizeof(icinfo
->szDescription
)/sizeof(WCHAR
));
1178 return sizeof(ICINFO
);
1181 static LRESULT
SetQuality(CodecInfo
*pi
, LONG lQuality
)
1187 lQuality
= MSRLE32_DEFAULTQUALITY
;
1188 else if (ICQUALITY_LOW
> lQuality
|| lQuality
> ICQUALITY_HIGH
)
1189 return ICERR_BADPARAM
;
1191 pi
->dwQuality
= (DWORD
)lQuality
;
1196 static LRESULT
Configure(CodecInfo
*pi
, HWND hWnd
)
1205 static LRESULT
About(CodecInfo
*pi
, HWND hWnd
)
1211 assert(MSRLE32_hModule
!= 0);
1213 LoadStringA(MSRLE32_hModule
, IDS_NAME
, szTitle
, sizeof(szTitle
));
1214 LoadStringA(MSRLE32_hModule
, IDS_ABOUT
, szAbout
, sizeof(szAbout
));
1216 MessageBoxA(hWnd
, szAbout
, szTitle
, MB_OK
|MB_ICONINFORMATION
);
1221 static LRESULT
CompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1222 LPBITMAPINFOHEADER lpbiOut
)
1226 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1231 /* check parameters -- need at least input format */
1232 if (lpbiIn
== NULL
) {
1233 if (lpbiOut
!= NULL
)
1234 return ICERR_BADPARAM
;
1238 /* handle unsupported input format */
1239 if (CompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1240 return (lpbiOut
== NULL
? ICERR_BADFORMAT
: 0);
1242 assert(0 < lpbiIn
->biBitCount
&& lpbiIn
->biBitCount
<= 8);
1244 switch (pi
->fccHandler
) {
1253 size
= (lpbiIn
->biBitCount
<= 4 ? 1 << 4 : 1 << 8);
1259 if (lpbiIn
->biClrUsed
!= 0)
1260 size
= lpbiIn
->biClrUsed
;
1262 size
= sizeof(BITMAPINFOHEADER
) + size
* sizeof(RGBQUAD
);
1264 if (lpbiOut
!= NULL
) {
1265 lpbiOut
->biSize
= sizeof(BITMAPINFOHEADER
);
1266 lpbiOut
->biWidth
= lpbiIn
->biWidth
;
1267 lpbiOut
->biHeight
= lpbiIn
->biHeight
;
1268 lpbiOut
->biPlanes
= 1;
1269 if (pi
->fccHandler
== FOURCC_RLE4
||
1270 lpbiIn
->biBitCount
<= 4) {
1271 lpbiOut
->biCompression
= BI_RLE4
;
1272 lpbiOut
->biBitCount
= 4;
1274 lpbiOut
->biCompression
= BI_RLE8
;
1275 lpbiOut
->biBitCount
= 8;
1277 lpbiOut
->biSizeImage
= MSRLE32_GetMaxCompressedSize(lpbiOut
);
1278 lpbiOut
->biXPelsPerMeter
= lpbiIn
->biXPelsPerMeter
;
1279 lpbiOut
->biYPelsPerMeter
= lpbiIn
->biYPelsPerMeter
;
1280 if (lpbiIn
->biClrUsed
== 0)
1281 size
= 1<<lpbiIn
->biBitCount
;
1283 size
= lpbiIn
->biClrUsed
;
1284 lpbiOut
->biClrUsed
= min(size
, 1 << lpbiOut
->biBitCount
);
1285 lpbiOut
->biClrImportant
= 0;
1287 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
,
1288 (const BYTE
*)lpbiIn
+ lpbiIn
->biSize
, lpbiOut
->biClrUsed
* sizeof(RGBQUAD
));
1295 static LRESULT
CompressGetSize(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1296 LPCBITMAPINFOHEADER lpbiOut
)
1301 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1303 /* check parameter -- need at least one format */
1304 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1306 /* check if the given format is supported */
1307 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1310 /* the worst case is coding the complete image in absolute mode. */
1312 return MSRLE32_GetMaxCompressedSize(lpbiIn
);
1314 return MSRLE32_GetMaxCompressedSize(lpbiOut
);
1317 static LRESULT
CompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1318 LPCBITMAPINFOHEADER lpbiOut
)
1323 /* need at least one format */
1324 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1325 return ICERR_BADPARAM
;
1327 /* check input format if given */
1328 if (lpbiIn
!= NULL
) {
1329 if (!isSupportedDIB(lpbiIn
))
1330 return ICERR_BADFORMAT
;
1332 /* for 4-bit need an even width */
1333 if (lpbiIn
->biBitCount
<= 4 && (lpbiIn
->biWidth
% 2))
1334 return ICERR_BADFORMAT
;
1336 if (pi
->fccHandler
== FOURCC_RLE4
&& lpbiIn
->biBitCount
> 4)
1337 return ICERR_UNSUPPORTED
;
1338 else if (lpbiIn
->biBitCount
> 8)
1339 return ICERR_UNSUPPORTED
;
1342 /* check output format if given */
1343 if (lpbiOut
!= NULL
) {
1344 if (!isSupportedMRLE(lpbiOut
))
1345 return ICERR_BADFORMAT
;
1347 if (lpbiIn
!= NULL
) {
1348 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1349 return ICERR_UNSUPPORTED
;
1350 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1351 return ICERR_UNSUPPORTED
;
1352 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1353 return ICERR_UNSUPPORTED
;
1360 static LRESULT
CompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1361 LPCBITMAPINFOHEADER lpbiOut
)
1363 const RGBQUAD
*rgbIn
;
1364 const RGBQUAD
*rgbOut
;
1368 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1373 /* check parameters -- need both formats */
1374 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1375 return ICERR_BADPARAM
;
1376 /* And both must be supported */
1377 if (CompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1378 return ICERR_BADFORMAT
;
1380 /* FIXME: cannot compress and decompress at same time! */
1381 if (pi
->bDecompress
) {
1382 FIXME("cannot compress and decompress at same time!\n");
1389 size
= WIDTHBYTES(lpbiOut
->biWidth
* 16) / 2 * lpbiOut
->biHeight
;
1390 pi
->pPrevFrame
= (LPWORD
)GlobalAllocPtr(GPTR
, size
* sizeof(WORD
));
1391 if (pi
->pPrevFrame
== NULL
)
1392 return ICERR_MEMORY
;
1393 pi
->pCurFrame
= (LPWORD
)GlobalAllocPtr(GPTR
, size
* sizeof(WORD
));
1394 if (pi
->pCurFrame
== NULL
) {
1396 return ICERR_MEMORY
;
1398 pi
->nPrevFrame
= -1;
1399 pi
->bCompress
= TRUE
;
1401 rgbIn
= (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
1402 rgbOut
= (const RGBQUAD
*)((const BYTE
*)lpbiOut
+ lpbiOut
->biSize
);
1404 switch (lpbiOut
->biBitCount
) {
1407 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1408 if (pi
->palette_map
== NULL
) {
1410 return ICERR_MEMORY
;
1413 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1414 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1422 static LRESULT
Compress(CodecInfo
*pi
, ICCOMPRESS
* lpic
, DWORD dwSize
)
1426 TRACE("(%p,%p,%lu)\n",pi
,lpic
,dwSize
);
1431 /* check parameters */
1432 if (lpic
== NULL
|| dwSize
< sizeof(ICCOMPRESS
))
1433 return ICERR_BADPARAM
;
1434 if (!lpic
->lpbiOutput
|| !lpic
->lpOutput
||
1435 !lpic
->lpbiInput
|| !lpic
->lpInput
)
1436 return ICERR_BADPARAM
;
1438 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
);
1440 if (! pi
->bCompress
) {
1441 LRESULT hr
= CompressBegin(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
);
1444 } else if (CompressQuery(pi
, lpic
->lpbiInput
, lpic
->lpbiOutput
) != ICERR_OK
)
1445 return ICERR_BADFORMAT
;
1447 if (lpic
->lFrameNum
>= pi
->nPrevFrame
+ 1) {
1448 /* we continue in the sequence so we need to initialize
1449 * our internal framedata */
1451 computeInternalFrame(pi
, lpic
->lpbiInput
, lpic
->lpInput
);
1452 } else if (lpic
->lFrameNum
== pi
->nPrevFrame
) {
1453 /* Oops, compress same frame again ? Okay, as you wish.
1454 * No need to recompute internal framedata, because we only swapped buffers */
1455 LPWORD pTmp
= pi
->pPrevFrame
;
1457 pi
->pPrevFrame
= pi
->pCurFrame
;
1458 pi
->pCurFrame
= pTmp
;
1459 } else if ((lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1462 WARN(": prev=%ld cur=%ld gone back? -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1463 if (lpic
->lpbiPrev
== NULL
|| lpic
->lpPrev
== NULL
)
1464 return ICERR_GOTOKEYFRAME
; /* Need a keyframe if you go back */
1465 if (CompressQuery(pi
, lpic
->lpbiPrev
, lpic
->lpbiOutput
) != ICERR_OK
)
1466 return ICERR_BADFORMAT
;
1468 WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi
->nPrevFrame
,lpic
->lFrameNum
);
1469 computeInternalFrame(pi
, lpic
->lpbiPrev
, lpic
->lpPrev
);
1471 /* swap buffers for current and previous frame */
1472 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1473 pTmp
= pi
->pPrevFrame
;
1474 pi
->pPrevFrame
= pi
->pCurFrame
;
1475 pi
->pCurFrame
= pTmp
;
1476 pi
->nPrevFrame
= lpic
->lFrameNum
;
1479 for (i
= 0; i
< 3; i
++) {
1480 SetQuality(pi
, lpic
->dwQuality
);
1482 lpic
->lpbiOutput
->biSizeImage
= 0;
1484 if (lpic
->lpbiOutput
->biBitCount
== 4)
1485 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1486 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1488 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1489 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, (lpic
->dwFlags
& ICCOMPRESS_KEYFRAME
) != 0);
1491 if (lpic
->dwFrameSize
== 0 ||
1492 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
)
1495 if ((*lpic
->lpdwFlags
& ICCOMPRESS_KEYFRAME
) == 0) {
1496 if (lpic
->lpbiOutput
->biBitCount
== 4)
1497 MSRLE32_CompressRLE4(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1498 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1500 MSRLE32_CompressRLE8(pi
, lpic
->lpbiInput
, (LPBYTE
)lpic
->lpInput
,
1501 lpic
->lpbiOutput
, (LPBYTE
)lpic
->lpOutput
, TRUE
);
1503 if (lpic
->dwFrameSize
== 0 ||
1504 lpic
->lpbiOutput
->biSizeImage
< lpic
->dwFrameSize
) {
1505 WARN("switched to keyframe, was small enough!\n");
1506 *lpic
->lpdwFlags
|= ICCOMPRESS_KEYFRAME
;
1507 *lpic
->lpckid
= MAKEAVICKID(cktypeDIBbits
,
1508 StreamFromFOURCC(*lpic
->lpckid
));
1513 if (lpic
->dwQuality
< 1000)
1516 lpic
->dwQuality
-= 1000; /* reduce quality by 10% */
1519 { /* swap buffer for current and previous frame */
1520 /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1521 register LPWORD pTmp
= pi
->pPrevFrame
;
1523 pi
->pPrevFrame
= pi
->pCurFrame
;
1524 pi
->pCurFrame
= pTmp
;
1525 pi
->nPrevFrame
= lpic
->lFrameNum
;
1531 static LRESULT
CompressEnd(CodecInfo
*pi
)
1536 if (pi
->pPrevFrame
!= NULL
)
1537 GlobalFreePtr(pi
->pPrevFrame
);
1538 if (pi
->pCurFrame
!= NULL
)
1539 GlobalFreePtr(pi
->pCurFrame
);
1540 pi
->pPrevFrame
= NULL
;
1541 pi
->pCurFrame
= NULL
;
1542 pi
->nPrevFrame
= -1;
1543 pi
->bCompress
= FALSE
;
1549 static LRESULT
DecompressGetFormat(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1550 LPBITMAPINFOHEADER lpbiOut
)
1554 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1560 return (lpbiOut
!= NULL
? ICERR_BADPARAM
: 0);
1562 if (DecompressQuery(pi
, lpbiIn
, NULL
) != ICERR_OK
)
1563 return (lpbiOut
!= NULL
? ICERR_BADFORMAT
: 0);
1565 size
= lpbiIn
->biSize
;
1567 if (lpbiIn
->biBitCount
<= 8)
1568 size
+= lpbiIn
->biClrUsed
* sizeof(RGBQUAD
);
1570 if (lpbiOut
!= NULL
) {
1571 memcpy(lpbiOut
, lpbiIn
, size
);
1572 lpbiOut
->biCompression
= BI_RGB
;
1573 lpbiOut
->biSizeImage
= DIBWIDTHBYTES(*lpbiOut
) * lpbiOut
->biHeight
;
1580 static LRESULT
DecompressQuery(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1581 LPCBITMAPINFOHEADER lpbiOut
)
1583 LRESULT hr
= ICERR_OK
;
1585 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1590 /* need at least one format */
1591 if (lpbiIn
== NULL
&& lpbiOut
== NULL
)
1592 return ICERR_BADPARAM
;
1594 /* check input format if given */
1595 if (lpbiIn
!= NULL
) {
1596 if (!isSupportedMRLE(lpbiIn
))
1597 return ICERR_BADFORMAT
;
1600 /* check output format if given */
1601 if (lpbiOut
!= NULL
) {
1602 if (!isSupportedDIB(lpbiOut
))
1603 hr
= ICERR_BADFORMAT
;
1605 if (lpbiIn
!= NULL
) {
1606 if (lpbiIn
->biWidth
!= lpbiOut
->biWidth
)
1607 hr
= ICERR_UNSUPPORTED
;
1608 if (lpbiIn
->biHeight
!= lpbiOut
->biHeight
)
1609 hr
= ICERR_UNSUPPORTED
;
1610 if (lpbiIn
->biBitCount
> lpbiOut
->biBitCount
)
1611 hr
= ICERR_UNSUPPORTED
;
1618 static LRESULT
DecompressBegin(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1619 LPCBITMAPINFOHEADER lpbiOut
)
1621 const RGBQUAD
*rgbIn
;
1622 const RGBQUAD
*rgbOut
;
1625 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1630 /* check parameters */
1631 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1632 return ICERR_BADPARAM
;
1633 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1634 return ICERR_BADFORMAT
;
1636 /* FIXME: cannot compress and decompress at a time! */
1637 if (pi
->bCompress
) {
1638 FIXME("cannot compress and decompress at same time!\n");
1642 if (pi
->bDecompress
)
1645 rgbIn
= (const RGBQUAD
*)((const BYTE
*)lpbiIn
+ lpbiIn
->biSize
);
1646 rgbOut
= (const RGBQUAD
*)((const BYTE
*)lpbiOut
+ lpbiOut
->biSize
);
1648 switch (lpbiOut
->biBitCount
) {
1651 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
);
1652 if (pi
->palette_map
== NULL
)
1653 return ICERR_MEMORY
;
1655 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1656 pi
->palette_map
[i
] = MSRLE32_GetNearestPaletteIndex(lpbiOut
->biClrUsed
, rgbOut
, rgbIn
[i
]);
1661 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* 2);
1662 if (pi
->palette_map
== NULL
)
1663 return ICERR_MEMORY
;
1665 for (i
= 0; i
< lpbiIn
->biClrUsed
; i
++) {
1668 if (lpbiOut
->biBitCount
== 15)
1669 color
= ((rgbIn
[i
].rgbRed
>> 3) << 10)
1670 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1672 color
= ((rgbIn
[i
].rgbRed
>> 3) << 11)
1673 | ((rgbIn
[i
].rgbGreen
>> 3) << 5) | (rgbIn
[i
].rgbBlue
>> 3);
1675 pi
->palette_map
[i
* 2 + 1] = color
>> 8;
1676 pi
->palette_map
[i
* 2 + 0] = color
& 0xFF;
1681 pi
->palette_map
= (LPBYTE
)LocalAlloc(LPTR
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1682 if (pi
->palette_map
== NULL
)
1683 return ICERR_MEMORY
;
1684 memcpy(pi
->palette_map
, rgbIn
, lpbiIn
->biClrUsed
* sizeof(RGBQUAD
));
1688 pi
->bDecompress
= TRUE
;
1693 static LRESULT
Decompress(CodecInfo
*pi
, ICDECOMPRESS
*pic
, DWORD dwSize
)
1695 TRACE("(%p,%p,%lu)\n",pi
,pic
,dwSize
);
1700 /* check parameters */
1702 return ICERR_BADPARAM
;
1703 if (pic
->lpbiInput
== NULL
|| pic
->lpInput
== NULL
||
1704 pic
->lpbiOutput
== NULL
|| pic
->lpOutput
== NULL
)
1705 return ICERR_BADPARAM
;
1708 if (! pi
->bDecompress
) {
1709 LRESULT hr
= DecompressBegin(pi
, pic
->lpbiInput
, pic
->lpbiOutput
);
1712 } else if (DecompressQuery(pi
, pic
->lpbiInput
, pic
->lpbiOutput
) != ICERR_OK
)
1713 return ICERR_BADFORMAT
;
1715 assert(pic
->lpbiInput
->biWidth
== pic
->lpbiOutput
->biWidth
);
1716 assert(pic
->lpbiInput
->biHeight
== pic
->lpbiOutput
->biHeight
);
1718 pic
->lpbiOutput
->biSizeImage
= DIBWIDTHBYTES(*pic
->lpbiOutput
) * pic
->lpbiOutput
->biHeight
;
1719 if (pic
->lpbiInput
->biBitCount
== 4)
1720 return MSRLE32_DecompressRLE4(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1722 return MSRLE32_DecompressRLE8(pi
, pic
->lpbiOutput
, pic
->lpInput
, pic
->lpOutput
);
1725 static LRESULT
DecompressEnd(CodecInfo
*pi
)
1732 pi
->bDecompress
= FALSE
;
1734 if (pi
->palette_map
!= NULL
) {
1735 LocalFree((HLOCAL
)pi
->palette_map
);
1736 pi
->palette_map
= NULL
;
1742 static LRESULT
DecompressGetPalette(CodecInfo
*pi
, LPCBITMAPINFOHEADER lpbiIn
,
1743 LPBITMAPINFOHEADER lpbiOut
)
1747 TRACE("(%p,%p,%p)\n",pi
,lpbiIn
,lpbiOut
);
1752 /* check parameters */
1753 if (lpbiIn
== NULL
|| lpbiOut
== NULL
)
1754 return ICERR_BADPARAM
;
1756 if (DecompressQuery(pi
, lpbiIn
, lpbiOut
) != ICERR_OK
)
1757 return ICERR_BADFORMAT
;
1759 if (lpbiOut
->biBitCount
> 8)
1762 if (lpbiIn
->biBitCount
<= 8) {
1763 if (lpbiIn
->biClrUsed
> 0)
1764 size
= lpbiIn
->biClrUsed
;
1766 size
= (1 << lpbiIn
->biBitCount
);
1768 lpbiOut
->biClrUsed
= size
;
1770 memcpy((LPBYTE
)lpbiOut
+ lpbiOut
->biSize
, (const BYTE
*)lpbiIn
+ lpbiIn
->biSize
, size
* sizeof(RGBQUAD
));
1771 } /* else could never occur ! */
1776 /* DriverProc - entry point for an installable driver */
1777 LRESULT CALLBACK
MSRLE32_DriverProc(DWORD_PTR dwDrvID
, HDRVR hDrv
, UINT uMsg
,
1778 LPARAM lParam1
, LPARAM lParam2
)
1780 CodecInfo
*pi
= (CodecInfo
*)dwDrvID
;
1782 TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID
, hDrv
, uMsg
, lParam1
, lParam2
);
1785 /* standard driver messages */
1789 return (LRESULT
)Open((ICOPEN
*)lParam2
);
1791 if (dwDrvID
!= 0xFFFF0000 && (LPVOID
)dwDrvID
!= NULL
)
1799 case DRV_QUERYCONFIGURE
:
1800 return DRVCNF_CANCEL
; /* FIXME */
1802 return DRVCNF_OK
; /* FIXME */
1807 /* installable compression manager messages */
1809 FIXME("ICM_CONFIGURE (%ld)\n",lParam1
);
1811 return ICERR_UNSUPPORTED
; /* FIXME */
1813 return Configure(pi
, (HWND
)lParam1
);
1818 return About(pi
, (HWND
)lParam1
);
1821 return 0; /* no state */
1823 return GetInfo(pi
, (ICINFO
*)lParam1
, (DWORD
)lParam2
);
1824 case ICM_GETDEFAULTQUALITY
:
1825 if ((LPVOID
)lParam1
!= NULL
) {
1826 *((LPDWORD
)lParam1
) = MSRLE32_DEFAULTQUALITY
;
1830 case ICM_GETQUALITY
:
1831 if ((LPVOID
)lParam1
!= NULL
) {
1832 *((LPDWORD
)lParam1
) = pi
->dwQuality
;
1836 case ICM_SETQUALITY
:
1837 return SetQuality(pi
, *(LPLONG
)lParam1
);
1838 case ICM_COMPRESS_GET_FORMAT
:
1839 return CompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1840 (LPBITMAPINFOHEADER
)lParam2
);
1841 case ICM_COMPRESS_GET_SIZE
:
1842 return CompressGetSize(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1843 (LPCBITMAPINFOHEADER
)lParam2
);
1844 case ICM_COMPRESS_QUERY
:
1845 return CompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1846 (LPCBITMAPINFOHEADER
)lParam2
);
1847 case ICM_COMPRESS_BEGIN
:
1848 return CompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1849 (LPCBITMAPINFOHEADER
)lParam2
);
1851 return Compress(pi
, (ICCOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1852 case ICM_COMPRESS_END
:
1853 return CompressEnd(pi
);
1854 case ICM_DECOMPRESS_GET_FORMAT
:
1855 return DecompressGetFormat(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1856 (LPBITMAPINFOHEADER
)lParam2
);
1857 case ICM_DECOMPRESS_QUERY
:
1858 return DecompressQuery(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1859 (LPCBITMAPINFOHEADER
)lParam2
);
1860 case ICM_DECOMPRESS_BEGIN
:
1861 return DecompressBegin(pi
, (LPCBITMAPINFOHEADER
)lParam1
,
1862 (LPCBITMAPINFOHEADER
)lParam2
);
1863 case ICM_DECOMPRESS
:
1864 return Decompress(pi
, (ICDECOMPRESS
*)lParam1
, (DWORD
)lParam2
);
1865 case ICM_DECOMPRESS_END
:
1866 return DecompressEnd(pi
);
1867 case ICM_DECOMPRESS_SET_PALETTE
:
1868 FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi
, (LPVOID
)lParam1
, (LPVOID
)lParam2
);
1869 return ICERR_UNSUPPORTED
;
1870 case ICM_DECOMPRESS_GET_PALETTE
:
1871 return DecompressGetPalette(pi
, (LPBITMAPINFOHEADER
)lParam1
,
1872 (LPBITMAPINFOHEADER
)lParam2
);
1873 case ICM_GETDEFAULTKEYFRAMERATE
:
1874 if ((LPVOID
)lParam1
!= NULL
)
1875 *(LPDWORD
)lParam1
= 15;
1878 if (uMsg
< DRV_USER
)
1879 return DefDriverProc(dwDrvID
, hDrv
, uMsg
, lParam1
, lParam2
);
1881 FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg
,lParam1
,lParam2
);
1884 return ICERR_UNSUPPORTED
;
1887 /* DllMain - library initialization code */
1888 BOOL WINAPI
DllMain(HINSTANCE hModule
, DWORD dwReason
, LPVOID lpReserved
)
1890 TRACE("(%p,%ld,%p)\n",(LPVOID
)hModule
,dwReason
,lpReserved
);
1893 case DLL_PROCESS_ATTACH
:
1894 DisableThreadLibraryCalls(hModule
);
1895 MSRLE32_hModule
= hModule
;
1898 case DLL_PROCESS_DETACH
: