RLE decoder

Eric Pouech eric.pouech at wanadoo.fr
Mon Oct 7 16:02:07 CDT 2002


Michael Günnewig submitted this RLE decoder to rewind... so wine can
benefit from it

Alexandre, the patch implies that the dlls/msrle32 directory is removed
and this new stuff is installed in dlls/msvideo/msrle32 instead
I think it's better to have video codecs under the dlls/msvideo dir (as
we have audio codecs under dlls/msacm)

A+
-------------- next part --------------
Name:          msrle
ChangeLog:     Michael Günnewig: implemented the MS RLE video codec
License:       X11
GenDate:       2002/10/07 20:57:42 UTC
ModifiedFiles: configure.ac dlls/Makefile.in
AddedFiles:    dlls/msvideom/msrle32/Makefile.in dlls/msvideo/msrle32/.cvsignore dlls/msvideo/msrle32/msrle32.c dlls/msvideo/msrle32/msrle32.spec dlls/msvideo/msrle32/msrle_private.h dlls/msvideo/msrle32/rsrc.rc dlls/msvideo/msrle32/msrle_En.rc dlls/msvideo/msrle32/msrle_De.rc dlls/msvideo/msrle32/msrle_Fr.rc
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/configure.ac,v
retrieving revision 1.81
diff -u -u -r1.81 configure.ac
--- configure.ac	2 Oct 2002 19:58:27 -0000	1.81
+++ configure.ac	5 Oct 2002 07:24:30 -0000
@@ -1412,10 +1413,10 @@
 dlls/msimg32/Makefile
 dlls/msisys/Makefile
 dlls/msnet32/Makefile
-dlls/msrle32/Makefile
 dlls/msvcrt/Makefile
 dlls/msvcrt20/Makefile
 dlls/msvideo/Makefile
+dlls/msvideo/msrle32/Makefile
 dlls/netapi32/Makefile
 dlls/netapi32/tests/Makefile
 dlls/ntdll/Makefile
Index: dlls/Makefile.in
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/Makefile.in,v
retrieving revision 1.153
diff -u -u -r1.153 Makefile.in
--- dlls/Makefile.in	2 Oct 2002 02:34:10 -0000	1.153
+++ dlls/Makefile.in	5 Oct 2002 07:27:31 -0000
 	msisys \
 	msnet32 \
-	msrle32 \
 	msvcrt \
 	msvcrt20 \
 	msvideo \
+	msvideo/msrle32 \
 	netapi32 \
 	ntdll \
 	odbc32 \
@@ -396,8 +401,8 @@
 msnet32.dll$(DLLEXT): msnet32/msnet32.dll$(DLLEXT)
 	$(RM) $@ && $(LN_S) msnet32/msnet32.dll$(DLLEXT) $@
 
-msrle32.dll$(DLLEXT): msrle32/msrle32.dll$(DLLEXT)
-	$(RM) $@ && $(LN_S) msrle32/msrle32.dll$(DLLEXT) $@
+msrle32.dll$(DLLEXT): msvideo/msrle32/msrle32.dll$(DLLEXT)
+	$(RM) $@ && $(LN_S) msvideo/msrle32/msrle32.dll$(DLLEXT) $@
 
 msvcrt.dll$(DLLEXT): msvcrt/msvcrt.dll$(DLLEXT)
 	$(RM) $@ && $(LN_S) msvcrt/msvcrt.dll$(DLLEXT) $@
@@ -605,7 +611,7 @@
 msimg32/msimg32.dll$(DLLEXT): msimg32
 msisys/msisys.ocx$(DLLEXT): msisys
 msnet32/msnet32.dll$(DLLEXT): msnet32
-msrle32/msrle32.dll$(DLLEXT): msrle32
+msvideo/msrle32/msrle32.dll$(DLLEXT): msvideo/msrle32
 msvcrt/msvcrt.dll$(DLLEXT): msvcrt
 msvcrt20/msvcrt20.dll$(DLLEXT): msvcrt20
 msvideo/msvfw32.dll$(DLLEXT): msvideo
@@ -704,7 +711,7 @@
 msimg32/__install__: msimg32.dll$(DLLEXT)
 msisys/__install__: msisys.ocx$(DLLEXT)
 msnet32/__install__: msnet32.dll$(DLLEXT)
-msrle32/__install__: msrle32.dll$(DLLEXT)
+msvideo/msrle32/__install__: msrle32.dll$(DLLEXT)
 msvcrt/__install__: msvcrt.dll$(DLLEXT)
 msvcrt20/__install__: msvcrt20.dll$(DLLEXT)
 msvideo/__install__: msvfw32.dll$(DLLEXT)
@@ -799,9 +807,9 @@
 msimg32:  kernel32.dll$(DLLEXT)
 msisys:   kernel32.dll$(DLLEXT)
 msnet32:  kernel32.dll$(DLLEXT)
-msrle32:  kernel32.dll$(DLLEXT)
 msvcrt20: msvcrt.dll$(DLLEXT)
 msvcrt:   kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT)
+msvideo/msrle32: kernel32.dll$(DLLEXT) user32.dll$(DLLEXT) winmm.dll$(DLLEXT)
 msvideo:  winmm.dll$(DLLEXT) comctl32.dll$(DLLEXT) version.dll$(DLLEXT) user32.dll$(DLLEXT) \
           gdi32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
 netapi32: advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/.cvsignore	Mon Oct  7 22:12:49 2002
@@ -0,0 +1,3 @@
+Makefile
+msrle32.dll.dbg.c
+msrle32.spec.c
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/msrle32.c	Mon Oct  7 22:08:20 2002
@@ -0,0 +1,1871 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* TODO:
+ *   - compression of RLE4 is buggy -- see FIXME's
+ *   - many improvements possible
+ *   - implement DecompressSetPalette? -- does we need it for anything?
+ */
+
+#include <assert.h>
+
+#include "msrle_private.h"
+
+#include "winnls.h"
+#include "winuser.h"
+#include "windowsx.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
+
+static HINSTANCE MSRLE32_hModule = 0;
+
+#define ABS(a)                ((a) < 0 ? -(a) : (a))
+#define SQR(a)                ((a) * (a))
+
+#define QUALITY_to_DIST(q)    (ICQUALITY_HIGH - q)
+inline WORD ColorCmp(WORD clr1, WORD clr2)
+{
+  register UINT a = (clr1-clr2);
+  return SQR(a);
+}
+inline WORD Intensity(RGBQUAD clr)
+{
+  return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
+}
+
+#define GetRawPixel(lpbi,lp,x) \
+  ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
+   ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
+
+/*****************************************************************************/
+
+/* utility functions */
+static BOOL    isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
+static BOOL    isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
+static void    LoadWideString(UINT id, LPWSTR str, INT len);
+static BYTE    MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
+
+/* compression functions */
+static void    computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn);
+static LONG    MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
+static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
+static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey);
+
+/* decompression functions */
+static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+				      LPBYTE lpIn, LPBYTE lpOut);
+static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+				      LPBYTE lpIn, LPBYTE lpOut);
+
+/* API functions */
+static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+				 LPBITMAPINFOHEADER lpbiOut);
+static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			       LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			     LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			     LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
+static LRESULT CompressEnd(CodecInfo *pi);
+
+static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+				   LPBITMAPINFOHEADER lpbiOut);
+static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			       LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			       LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
+static LRESULT DecompressEnd(CodecInfo *pi);
+static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+				    LPBITMAPINFOHEADER lpbiOut);
+
+/*****************************************************************************/
+
+static void LoadWideString(UINT id, LPWSTR str, INT len)
+{
+  char szTemp[80];
+
+  LoadStringA(MSRLE32_hModule, id, szTemp, sizeof(szTemp));
+  MultiByteToWideChar(CP_ACP, 0, szTemp, -1, str, len);
+}
+
+static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
+{
+  /* pre-conditions */
+  assert(lpbi != NULL);
+
+  if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \
+      lpbi->biPlanes != 1)
+    return FALSE;
+
+  if (lpbi->biCompression == BI_RLE4) {
+    if (lpbi->biBitCount != 4 || \
+	(lpbi->biWidth % 2) != 0)
+      return FALSE;
+  } else if (lpbi->biCompression == BI_RLE8) {
+    if (lpbi->biBitCount != 8)
+      return FALSE;
+  } else
+    return FALSE;
+
+  return TRUE;
+}
+
+static BOOL  isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
+{
+  /* pre-conditions */
+  assert(lpbi != NULL);
+
+  /* check structure version/planes/compression */
+  if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
+      lpbi->biPlanes != 1)
+    return FALSE;
+  if (lpbi->biCompression != BI_RGB &&
+      lpbi->biCompression != BI_BITFIELDS)
+    return FALSE;
+
+  /* check bit-depth */
+  if (lpbi->biBitCount != 1 &&
+      lpbi->biBitCount != 4 &&
+      lpbi->biBitCount != 8 &&
+      lpbi->biBitCount != 15 &&
+      lpbi->biBitCount != 16 &&
+      lpbi->biBitCount != 24 &&
+      lpbi->biBitCount != 32)
+    return FALSE;
+
+  /* check for size(s) */
+  if (!lpbi->biWidth || !lpbi->biHeight)
+    return FALSE; /* image with zero size, makes no sense so error ! */
+  if (DIBWIDTHBYTES(*lpbi) * lpbi->biHeight >= (1UL << 31) - 1)
+    return FALSE; /* image too big ! */
+
+  /* check for non existing colortable for hi- and true-color DIB's */
+  if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
+{
+  INT  diff = 0x00FFFFFF;
+  UINT i;
+  UINT index = 0;
+
+  /* pre-conditions */
+  assert(clrs != NULL);
+
+  for (i = 0; i < count; i++) {
+    int r = ((int)clrs[i].rgbRed   - (int)clr.rgbRed);
+    int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
+    int b = ((int)clrs[i].rgbBlue  - (int)clr.rgbBlue);
+
+    r = r*r + g*g + b*b;
+
+    if (r < diff) {
+      index = i;
+      diff  = r;
+      if (diff == 0)
+	break;
+    }
+  }
+
+  return index;
+}
+
+/*****************************************************************************/
+
+void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn)
+{
+  WORD   wIntensityTbl[256];
+  LONG   lInLine, lOutLine;
+  LPWORD lpOut;
+  int i, y;
+
+  /* pre-conditions */
+  assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
+  assert(pi->pCurFrame != NULL);
+
+  lInLine  = DIBWIDTHBYTES(*lpbiIn);
+  lOutLine = WIDTHBYTES(lpbiIn->biWidth * 8*sizeof(WORD)) / 2;
+  lpOut    = pi->pCurFrame;
+
+  assert(lpbiIn->biClrUsed != 0);
+
+  {
+    const RGBQUAD *lp = (LPRGBQUAD)((LPBYTE)lpbiIn + lpbiIn->biSize);
+
+    for (i = 0; i < lpbiIn->biClrUsed; i++)
+      wIntensityTbl[i] = Intensity(lp[i]);
+  }
+
+  for (y = 0; y < lpbiIn->biHeight; y++) {
+    int x;
+
+    switch (lpbiIn->biBitCount) {
+    case 1:
+      for (x = 0; x < lpbiIn->biWidth; x += 8) {
+	for (i = 0; i < 7; i++)
+	  lpOut[x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
+      }
+      break;
+    case 4:
+      for (x = 0; x < lpbiIn->biWidth; x += 2) {
+	lpOut[x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
+	lpOut[x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
+      }
+      break;
+    case 8:
+      for (x = 0; x < lpbiIn->biWidth; x++)
+	lpOut[x] = wIntensityTbl[lpIn[x]];
+      break;
+    }
+
+    lpIn  += lInLine;
+    lpOut += lOutLine;
+  }
+}
+
+static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
+{
+  LONG a, b, size;
+
+  /* pre-condition */
+  assert(lpbi != NULL);
+
+  a = lpbi->biWidth / 255;
+  b = lpbi->biWidth % 255;
+  if (lpbi->biBitCount <= 4) {
+    a /= 2;
+    b /= 2;
+  }
+
+  size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
+  return size * lpbi->biHeight;
+}
+
+/* lpP => current  pos in previous frame
+ * lpA => previous pos in current  frame
+ * lpB => current  pos in current  frame
+ */
+static INT countDiffRLE4(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
+{
+  INT  count;
+  WORD clr1, clr2;
+
+  /* pre-conditions */
+  assert(lpA && lpB && lDist >= 0 && width > 0);
+
+  if (pos >= width)
+    return 0;
+  if (pos+1 == width)
+    return 1;
+
+  clr1 = lpB[pos++];
+  clr2 = lpB[pos];
+
+  count = 2;
+  while (pos + 1 < width) {
+    WORD clr3, clr4;
+
+    clr3 = lpB[++pos];
+    if (pos + 1 >= width)
+      return count + 1;
+
+    clr4 = lpB[++pos];
+    if (ColorCmp(clr1, clr3) <= lDist &&
+	ColorCmp(clr2, clr4) <= lDist) {
+      /* diff at end? -- look-ahead for atleast ?? more encodable pixel */
+
+      /* FIXME */
+
+      return count;
+    } else if (lpP && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
+      /* 'compare' with previous frame for end of diff */
+      INT count2 = 0;
+
+      /* FIXME */
+
+      if (count2 >= 4)
+	return count;
+
+      pos -= count2;
+    }
+
+    count += 2;
+    clr1 = clr3;
+    clr2 = clr4;
+  }
+
+  return count;
+}
+
+/* lpP => current  pos in previous frame
+ * lpA => previous pos in current  frame
+ * lpB => current  pos in current  frame
+ */
+static INT countDiffRLE8(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width)
+{
+  INT count;
+
+  for (count = 0; pos < width; pos++, count++) {
+    if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
+      /* diff at end? -- look-ahead for atleast one more encodable pixel */
+      if (pos + 1 < width && ColorCmp(lpA[pos], lpB[pos+1]) <= lDist)
+	return count;
+    } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
+      /* 'compare' with previous frame for end of diff */
+      INT count2 = 0;
+
+      for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
+	if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
+	  break;
+      }
+      if (count2 > 4)
+	return count;
+
+      pos -= count2;
+    }
+  }
+
+  return count;
+}
+
+static INT MSRLE32_CompressRLE4Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
+{
+  LPBYTE lpOut = *ppOut;
+  INT    count, pos;
+  WORD   clr1, clr2;
+
+  /* try to encode as many pixel as possible */
+  count = 1;
+  pos   = x;
+  clr1  = lpC[pos++];
+  if (pos < lpbi->biWidth) {
+    clr2 = lpC[pos];
+    for (++count; pos + 1 < lpbi->biWidth; ) {
+      ++pos;
+      if (ColorCmp(clr1, lpC[pos]) > lDist)
+	break;
+      count++;
+      if (pos + 1 >= lpbi->biWidth)
+	break;
+      ++pos;
+      if (ColorCmp(clr2, lpC[pos]) > lDist)
+	break;
+      count++;
+    }
+  }
+
+  if (count < 4) {
+    /* add some pixel for absoluting if possible */
+    count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
+
+    /* check for near end of line */
+    if (x + count > lpbi->biWidth)
+      count = lpbi->biWidth - x;
+
+    /* absolute pixel(s) in groups of atleast 3 and maximal 254 pixel */
+    while (count > 2) {
+      INT  i;
+      INT  size       = min(count, 254);
+      BOOL extra_byte = size % 2;
+
+      *lpSizeImage += 2 + size + extra_byte;
+      count -= size;
+      *lpOut++ = 0;
+      *lpOut++ = size;
+      for (i = 0; i < size; i += 2) {
+	clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+	x++;
+	if (i + 1 < size) {
+	  clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+	  x++;
+	} else
+	  clr2 = 0;
+
+	*lpOut++ = (clr1 << 4) | clr2;
+      }
+      if (extra_byte)
+	*lpOut++ = 0;
+    }
+
+    if (count > 0) {
+      /* too less for absoluting so we must encode them */
+      assert(count <= 2);
+
+      *lpSizeImage += 2;
+      clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+      x++;
+      if (count == 2) {
+	clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+	x++;
+      } else
+	clr2 = 0;
+      *lpOut++ = count;
+      *lpOut++ = (clr1 << 4) | clr2;
+    }
+  } else {
+    /* encode count pixel(s) */
+    clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
+	    pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
+
+    x += count;
+    while (count > 0) {
+      INT size = min(count, 254);
+
+      *lpSizeImage += 2;
+      count    -= size;
+      *lpOut++  = size;
+      *lpOut++  = clr1;
+    }
+  }
+
+  *ppOut = lpOut;
+
+  return x;
+}
+
+static INT MSRLE32_CompressRLE8Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage)
+{
+  LPBYTE lpOut = *ppOut;
+  INT    count, pos;
+  WORD   clr;
+
+  assert(lpbi->biBitCount <= 8);
+  assert(lpbi->biCompression == BI_RGB);
+
+  /* try to encode as much as possible */
+  pos = x;
+  clr = lpC[pos++];
+  for (count = 1; pos < lpbi->biWidth; count++) {
+    if (ColorCmp(clr, lpC[pos++]) > lDist)
+      break;
+  }
+
+  if (count < 2) {
+    /* add some more pixels for absoluting if possible */
+    count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
+
+    /* check for over end of line */
+    if (x + count > lpbi->biWidth)
+      count = lpbi->biWidth - x;
+
+    /* absolute pixel(s) in groups of atleast 3 and maximal 255 pixels */
+    while (count > 2) {
+      INT  i;
+      INT  size       = min(count, 255);
+      BOOL extra_byte = size % 2;
+
+      *lpSizeImage += 2 + size + extra_byte;
+      count -= size;
+      *lpOut++ = 0;
+      *lpOut++ = size;
+      for (i = 0; i < size; i++) {
+	*lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+	x++;
+      }
+      if (extra_byte)
+	*lpOut++ = 0;
+    }
+    if (count > 0) {
+      /* too less for absoluting so we must encode them even if it's expensive! */
+      assert(count <= 2);
+
+      *lpSizeImage += 2 * count;
+      *lpOut++ = 1;
+      *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+      x++;
+
+      if (count == 2) {
+	*lpOut++ = 1;
+	*lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+	x++;
+      }
+    }
+  } else {
+    /* encode count pixel(s) */
+    clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+
+    /* optimize end of line */
+    if (x + count + 1 == lpbi->biWidth)
+      count++;
+
+    x += count;
+    while (count > 0) {
+      INT size = min(count, 255);
+
+      *lpSizeImage += 2;
+      count    -= size;
+      *lpOut++  = size;
+      *lpOut++  = clr;
+    }
+  }
+
+  *ppOut = lpOut;
+
+  return x;
+}
+
+LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
+{
+  LPWORD lpC;
+  LONG   lLine, lInLine, lDist;
+
+  /* pre-conditions */
+  assert(pi != NULL && lpbiOut != NULL);
+  assert(lpIn != NULL && lpOut != NULL);
+  assert(pi->pCurFrame != NULL);
+
+  lpC      = pi->pCurFrame;
+  lDist    = QUALITY_to_DIST(pi->dwQuality);
+  lInLine  = DIBWIDTHBYTES(*lpbiIn);
+  lLine    = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
+
+  lpbiOut->biSizeImage = 0;
+  if (isKey) {
+    /* keyframe -- convert internal frame to output format */
+    INT x, y;
+
+    for (y = 0; y < lpbiOut->biHeight; y++) {
+      x = 0;
+
+      do {
+	x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
+				     &lpOut, &lpbiOut->biSizeImage);
+      } while (x < lpbiOut->biWidth);
+
+      lpC   += lLine;
+      lpIn  += lInLine;
+
+      /* add EOL -- end of line */
+      lpbiOut->biSizeImage += 2;
+      *((LPWORD)lpOut)++ = 0;
+    }
+  } else {
+    /* delta-frame -- compute delta between last and this internal frame */
+    LPWORD lpP;
+    INT    x, y;
+    INT    jumpx, jumpy;
+
+    assert(pi->pPrevFrame != NULL);
+
+    lpP   = pi->pPrevFrame;
+    jumpy = 0;
+    jumpx = -1;
+
+    for (y = 0; y < lpbiOut->biHeight; y++) {
+      x = 0;
+
+      do {
+	INT count, pos;
+
+	if (jumpx == -1)
+	  jumpx = x;
+	for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
+	  if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
+	    break;
+	}
+
+	if (pos == lpbiOut->biWidth && count > 8) {
+	  /* (count > 8) secures that we will save space */
+	  jumpy++;
+	  break;
+	} else if (jumpy || jumpx != pos) {
+	  /* time to jump */
+	  assert(jumpx != -1);
+
+	  if (pos < jumpx) {
+	    /* can only jump in positive direction -- jump until EOL, EOL */
+	    INT w = lpbiOut->biWidth - jumpx;
+
+	    assert(jumpy > 0);
+	    assert(w >= 4);
+
+	    jumpx = 0;
+	    jumpy--;
+	    /* if (w % 255 == 2) then equal costs
+	     * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
+	     * else it will be cheaper
+	     */
+	    while (w > 0) {
+	      lpbiOut->biSizeImage += 4;
+	      *lpOut++ = 0;
+	      *lpOut++ = 2;
+	      *lpOut   = min(w, 255);
+	      w       -= *lpOut++;
+	      *lpOut++ = 0;
+	    }
+	    /* add EOL -- end of line */
+	    lpbiOut->biSizeImage += 2;
+	    *((LPWORD)lpOut)++ = 0;
+	  }
+
+	  /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
+
+	  /* write out real jump(s) */
+	  while (jumpy || pos != jumpx) {
+	    lpbiOut->biSizeImage += 4;
+	    *lpOut++ = 0;
+	    *lpOut++ = 2;
+	    *lpOut   = min(pos - jumpx, 255);
+	    x       += *lpOut;
+	    jumpx   += *lpOut++;
+	    *lpOut   = min(jumpy, 255);
+	    jumpy   -= *lpOut++;
+	  }
+
+	  jumpy = 0;
+	}
+
+	jumpx = -1;
+
+	if (x < lpbiOut->biWidth) {
+	  /* skipped the 'same' things corresponding to previous frame */
+	  x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
+			       &lpOut, &lpbiOut->biSizeImage);
+	}
+      } while (x < lpbiOut->biWidth);
+
+      lpP   += lLine;
+      lpC   += lLine;
+      lpIn  += lInLine;
+
+      if (jumpy == 0) {
+	assert(jumpx == -1);
+
+	/* add EOL -- end of line */
+	lpbiOut->biSizeImage += 2;
+	*((LPWORD)lpOut)++ = 0;
+      }
+    }
+  }
+
+  /* add EOI -- end of image */
+  lpbiOut->biSizeImage += 2;
+  *lpOut++ = 0;
+  *lpOut++ = 1;
+
+  return ICERR_OK;
+}
+
+LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
+{
+  LPWORD lpC;
+  LONG   lDist, lInLine, lLine;
+
+  assert(pi != NULL && lpbiOut != NULL);
+  assert(lpIn != NULL && lpOut != NULL);
+  assert(pi->pCurFrame != NULL);
+
+  lpC     = pi->pCurFrame;
+  lDist   = QUALITY_to_DIST(pi->dwQuality);
+  lInLine = DIBWIDTHBYTES(*lpbiIn);
+  lLine   = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
+
+  lpbiOut->biSizeImage = 0;
+  if (isKey) {
+    /* keyframe -- convert internal frame to output format */
+    INT x, y;
+
+    for (y = 0; y < lpbiOut->biHeight; y++) {
+      x = 0;
+
+      do {
+	x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
+			     &lpOut, &lpbiOut->biSizeImage);
+      } while (x < lpbiOut->biWidth);
+
+      lpC  += lLine;
+      lpIn += lInLine;
+
+      /* add EOL -- end of line */
+      lpbiOut->biSizeImage += 2;
+      *((LPWORD)lpOut)++ = 0;
+    }
+  } else {
+    /* delta-frame -- compute delta between last and this internal frame */
+    LPWORD lpP;
+    INT    x, y;
+    INT    jumpx, jumpy;
+
+    assert(pi->pPrevFrame != NULL);
+
+    lpP   = pi->pPrevFrame;
+    jumpx = -1;
+    jumpy = 0;
+
+    for (y = 0; y < lpbiOut->biHeight; y++) {
+      x = 0;
+
+      do {
+	INT count, pos;
+
+	if (jumpx == -1)
+	  jumpx = x;
+	for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
+	  if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
+	    break;
+	}
+
+	if (pos == lpbiOut->biWidth && count > 4) {
+	  /* (count > 4) secures that we will save space */
+	  jumpy++;
+	  break;
+	} else if (jumpy || jumpx != pos) {
+	  /* time to jump */
+	  assert(jumpx != -1);
+
+	  if (pos < jumpx) {
+	    /* can only jump in positive direction -- do a EOL then jump */
+	    assert(jumpy > 0);
+
+	    jumpx = 0;
+	    jumpy--;
+
+	    /* add EOL -- end of line */
+	    lpbiOut->biSizeImage += 2;
+	    *((LPWORD)lpOut)++ = 0;
+	  }
+
+	  /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
+
+	  /* write out real jump(s) */
+	  while (jumpy || pos != jumpx) {
+	    lpbiOut->biSizeImage += 4;
+	    *lpOut++ = 0;
+	    *lpOut++ = 2;
+	    *lpOut   = min(pos - jumpx, 255);
+	    jumpx   += *lpOut++;
+	    *lpOut   = min(jumpy, 255);
+	    jumpy   -= *lpOut++;
+	  }
+	  x = pos;
+
+	  jumpy = 0;
+	}
+
+	jumpx = -1;
+
+	if (x < lpbiOut->biWidth) {
+	  /* skip the 'same' things corresponding to previous frame */
+	  x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
+			       &lpOut, &lpbiOut->biSizeImage);
+	}
+      } while (x < lpbiOut->biWidth);
+
+      lpP  += lLine;
+      lpC  += lLine;
+      lpIn += lInLine;
+
+      if (jumpy == 0) {
+	/* add EOL -- end of line */
+	lpbiOut->biSizeImage += 2;
+	*lpOut++ = 0;
+	*lpOut++ = 0;
+      }
+    }
+  }
+
+  /* add EOI -- end of image */
+  lpbiOut->biSizeImage += 2;
+  *lpOut++ = 0;
+  *lpOut++ = 1;
+
+  return ICERR_OK;
+}
+
+/*****************************************************************************/
+
+static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+				      LPBYTE lpIn, LPBYTE lpOut)
+{
+  int  bytes_per_pixel;
+  int  line_size;
+  int  pixel_ptr  = 0;
+  int  i;
+  BOOL bEndFlag   = FALSE;
+
+  assert(pi != NULL);
+  assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
+  assert(lpIn != NULL && lpOut != NULL);
+
+  bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
+  line_size       = DIBWIDTHBYTES(*lpbi);
+
+  do {
+    BYTE code0, code1;
+
+    code0 = *lpIn++;
+    code1 = *lpIn++;
+
+    if (code0 == 0) {
+      int  extra_byte;
+
+      switch (code1) {
+      case  0: /* EOL - end of line  */
+	pixel_ptr = 0;
+	lpOut += line_size;
+	break;
+      case  1: /* EOI - end of image */
+	bEndFlag = TRUE;
+	break;
+      case  2: /* skip */
+	pixel_ptr += *lpIn++ * bytes_per_pixel;
+	lpOut     += *lpIn++ * line_size;
+	if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
+	  pixel_ptr = 0;
+	  lpOut    += line_size;
+	}
+	break;
+      default: /* absolute mode */
+	extra_byte = (code1 / 2) & 0x01;
+
+	if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
+	  return ICERR_ERROR;
+
+	code0 = code1;
+	for (i = 0; i < code0 / 2; i++) {
+	  if (bytes_per_pixel == 1) {
+	    code1 = lpIn[i];
+	    lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
+	    if (2 * i <= code0)
+	      lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
+	  } else if (bytes_per_pixel == 2) {
+	    code1 = lpIn[i] >> 4;
+	    lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
+	    lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
+
+	    if (2 * i <= code0) {
+	      code1 = lpIn[i] & 0x0F;
+	      lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
+	      lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
+	    }
+	  } else {
+	    code1 = lpIn[i] >> 4;
+	    lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+	    lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+	    lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+	    pixel_ptr += bytes_per_pixel;
+
+	    if (2 * i <= code0) {
+	      code1 = lpIn[i] & 0x0F;
+	      lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+	      lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+	      lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+	      pixel_ptr += bytes_per_pixel;
+	    }
+	  }
+	}
+	lpIn += code0 / 2;
+
+	/* if the RLE code is odd, skip a byte in the stream */
+	if (extra_byte)
+	  lpIn++;
+      };
+    } else {
+      /* coded mode */
+      if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
+	return ICERR_ERROR;
+
+      if (bytes_per_pixel == 1) {
+	BYTE c1 = pi->palette_map[(code1 >> 4)];
+	BYTE c2 = pi->palette_map[(code1 & 0x0F)];
+
+	for (i = 0; i < code0; i++) {
+	  if ((i & 1) == 0)
+	    lpOut[pixel_ptr++] = c1;
+	  else
+	    lpOut[pixel_ptr++] = c2;
+	}
+      } else if (bytes_per_pixel == 2) {
+	BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
+	BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
+
+	BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
+	BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
+
+	for (i = 0; i < code0; i++) {
+	  if ((i & 1) == 0) {
+	    lpOut[pixel_ptr++] = hi1;
+	    lpOut[pixel_ptr++] = lo1;
+	  } else {
+	    lpOut[pixel_ptr++] = hi2;
+	    lpOut[pixel_ptr++] = lo2;
+	  }
+	}
+      } else {
+	BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
+	BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
+	BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
+
+	BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
+	BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
+	BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
+
+	for (i = 0; i < code0; i++) {
+	  if ((i & 1) == 0) {
+	    lpOut[pixel_ptr + 0] = b1;
+	    lpOut[pixel_ptr + 1] = g1;
+	    lpOut[pixel_ptr + 2] = r1;
+	  } else {
+	    lpOut[pixel_ptr + 0] = b2;
+	    lpOut[pixel_ptr + 1] = g2;
+	    lpOut[pixel_ptr + 2] = r2;
+	  }
+	  pixel_ptr += bytes_per_pixel;
+	}
+      }
+    }
+  } while (! bEndFlag);
+
+  return ICERR_OK;
+}
+
+static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+				      LPBYTE lpIn, LPBYTE lpOut)
+{
+  int  bytes_per_pixel;
+  int  line_size;
+  int  pixel_ptr  = 0;
+  BOOL bEndFlag   = FALSE;
+
+  assert(pi != NULL);
+  assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
+  assert(lpIn != NULL && lpOut != NULL);
+
+  bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
+  line_size       = DIBWIDTHBYTES(*lpbi);
+
+  do {
+    BYTE code0, code1;
+
+    code0 = *lpIn++;
+    code1 = *lpIn++;
+
+    if (code0 == 0) {
+      int  extra_byte;
+
+      switch (code1) {
+      case  0: /* EOL - end of line  */
+	pixel_ptr = 0;
+	lpOut += line_size;
+	break;
+      case  1: /* EOI - end of image */
+	bEndFlag = TRUE;
+	break;
+      case  2: /* skip */
+	pixel_ptr += *lpIn++ * bytes_per_pixel;
+	lpOut     += *lpIn++ * line_size;
+	if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
+	  pixel_ptr = 0;
+	  lpOut    += line_size;
+	}
+	break;
+      default: /* absolute mode */
+	if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
+	  WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
+	  return ICERR_ERROR;
+	}
+	extra_byte = code1 & 0x01;
+
+	code0 = code1;
+	while (code0--) {
+	  code1 = *lpIn++;
+	  if (bytes_per_pixel == 1) {
+	    lpOut[pixel_ptr] = pi->palette_map[code1];
+	  } else if (bytes_per_pixel == 2) {
+	    lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
+	    lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
+	  } else {
+	    lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+	    lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+	    lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+	  }
+	  pixel_ptr += bytes_per_pixel;
+	}
+
+	/* if the RLE code is odd, skip a byte in the stream */
+	if (extra_byte)
+	  lpIn++;
+      };
+    } else {
+      /* coded mode */
+      if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
+	WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
+	return ICERR_ERROR;
+      }
+
+      if (bytes_per_pixel == 1) {
+	code1 = pi->palette_map[code1];
+	while (code0--)
+	  lpOut[pixel_ptr++] = code1;
+      } else if (bytes_per_pixel == 2) {
+	BYTE hi = pi->palette_map[code1 * 2 + 0];
+	BYTE lo = pi->palette_map[code1 * 2 + 1];
+
+	while (code0--) {
+	  lpOut[pixel_ptr + 0] = hi;
+	  lpOut[pixel_ptr + 1] = lo;
+	  pixel_ptr += bytes_per_pixel;
+	}
+      } else {
+	BYTE r = pi->palette_map[code1 * 4 + 2];
+	BYTE g = pi->palette_map[code1 * 4 + 1];
+	BYTE b = pi->palette_map[code1 * 4 + 0];
+
+	while (code0--) {
+	  lpOut[pixel_ptr + 0] = b;
+	  lpOut[pixel_ptr + 1] = g;
+	  lpOut[pixel_ptr + 2] = r;
+	  pixel_ptr += bytes_per_pixel;
+	}
+      }
+    }
+  } while (! bEndFlag);
+
+  return ICERR_OK;
+}
+
+/*****************************************************************************/
+
+static CodecInfo* Open(LPICOPEN icinfo)
+{
+  CodecInfo* pi = NULL;
+
+  if (icinfo == NULL) {
+    TRACE("(NULL)\n");
+    return (LPVOID)0xFFFF0000;
+  }
+
+  TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo,
+	icinfo->dwSize,	icinfo->fccType, (char*)&icinfo->fccType,
+	icinfo->fccHandler, (char*)&icinfo->fccHandler,
+	icinfo->dwVersion,icinfo->dwFlags);
+
+  if (icinfo->fccType != ICTYPE_VIDEO)
+    return NULL;
+
+  switch (icinfo->fccHandler) {
+  case FOURCC_RLE:
+  case FOURCC_RLE4:
+  case FOURCC_RLE8:
+  case FOURCC_MRLE:
+    break;
+  case mmioFOURCC('m','r','l','e'):
+    icinfo->fccHandler = FOURCC_MRLE;
+    break;
+  default:
+    WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
+	 icinfo->fccHandler,(char*)&icinfo->fccHandler);
+    return NULL;
+  }
+
+  pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
+
+  if (pi != NULL) {
+    pi->fccHandler  = icinfo->fccHandler;
+
+    pi->bCompress   = FALSE;
+    pi->dwQuality   = MSRLE32_DEFAULTQUALITY;
+    pi->nPrevFrame  = -1;
+    pi->pPrevFrame  = pi->pCurFrame = NULL;
+
+    pi->bDecompress = FALSE;
+    pi->palette_map = NULL;
+  }
+
+  icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
+
+  return pi;
+}
+
+static LRESULT Close(CodecInfo *pi)
+{
+  TRACE("(%p)\n", pi);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
+    CompressEnd(pi);
+
+  LocalFree((HLOCAL)pi);
+  return 1;
+}
+
+static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
+{
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters */
+  if (icinfo == NULL)
+    return sizeof(ICINFO);
+  if (dwSize < sizeof(ICINFO))
+    return 0;
+
+  icinfo->dwSize       = sizeof(ICINFO);
+  icinfo->fccType      = streamtypeVIDEO;
+  icinfo->fccHandler   = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
+  icinfo->dwFlags      = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
+  icinfo->dwVersion    = MSRLE32_VERSION;
+  icinfo->dwVersionICM = 0x01040000; /* Version 1.4 build 0 */
+
+  LoadWideString(IDS_NAME, icinfo->szName, sizeof(icinfo->szName));
+  LoadWideString(IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription));
+
+  return sizeof(ICINFO);
+}
+
+static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
+{
+  /* pre-condition */
+  assert(pi != NULL);
+
+  if (lQuality == -1)
+    lQuality = MSRLE32_DEFAULTQUALITY;
+  else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
+    return ICERR_BADPARAM;
+
+  pi->dwQuality = (DWORD)lQuality;
+
+  return ICERR_OK;
+}
+
+static LRESULT Configure(CodecInfo *pi, HWND hWnd)
+{
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* FIXME */
+  return ICERR_OK;
+}
+
+static LRESULT About(CodecInfo *pi, HWND hWnd)
+{
+  CHAR szTitle[20];
+  CHAR szAbout[128];
+
+  /* pre-condition */
+  assert(MSRLE32_hModule != 0);
+
+  LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
+  LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
+
+  MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
+
+  return ICERR_OK;
+}
+
+static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+				 LPBITMAPINFOHEADER lpbiOut)
+{
+  LRESULT size;
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters -- need atleast input format */
+  if (lpbiIn == NULL) {
+    if (lpbiOut != NULL)
+      return ICERR_BADPARAM;
+    return 0;
+  }
+
+  /* handle unsupported input format */
+  if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
+    return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
+
+  assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
+
+  switch (pi->fccHandler) {
+  case FOURCC_RLE4:
+    size = 1 << 4;
+    break;
+  case FOURCC_RLE8:
+    size = 1 << 8;
+    break;
+  case FOURCC_RLE:
+  case FOURCC_MRLE:
+    size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
+    break;
+  default:
+    return ICERR_ERROR;
+  }
+
+  if (lpbiIn->biClrUsed != 0)
+    size = lpbiIn->biClrUsed;
+
+  size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
+
+  if (lpbiOut != NULL) {
+    lpbiOut->biSize          = sizeof(BITMAPINFOHEADER);
+    lpbiOut->biWidth         = lpbiIn->biWidth;
+    lpbiOut->biHeight        = lpbiIn->biHeight;
+    lpbiOut->biPlanes        = 1;
+    if (pi->fccHandler == FOURCC_RLE4 ||
+	lpbiIn->biBitCount <= 4) {
+      lpbiOut->biCompression = BI_RLE4;
+      lpbiOut->biBitCount    = 4;
+    } else {
+      lpbiOut->biCompression = BI_RLE8;
+      lpbiOut->biBitCount    = 8;
+    }
+    lpbiOut->biSizeImage     = MSRLE32_GetMaxCompressedSize(lpbiOut);
+    lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
+    lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
+    if (lpbiIn->biClrUsed == 0)
+      size = 1<<lpbiIn->biBitCount;
+    else
+      size = lpbiIn->biClrUsed;
+    lpbiOut->biClrUsed       = min(size, 1u << lpbiOut->biBitCount);
+    lpbiOut->biClrImportant  = 0;
+
+    memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
+	   (LPBYTE)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
+
+    return ICERR_OK;
+  } else
+    return size;
+}
+
+static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			       LPCBITMAPINFOHEADER lpbiOut)
+{
+  /* pre-condition */
+  assert(pi != NULL);
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* check parameter -- need atleast one format */
+  if (lpbiIn == NULL && lpbiOut == NULL)
+    return 0;
+  /* check if the given format is supported */
+  if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+    return 0;
+
+  /* the worst case is coding the complete image in absolute mode. */
+  if (lpbiIn)
+    return MSRLE32_GetMaxCompressedSize(lpbiIn);
+  else
+    return MSRLE32_GetMaxCompressedSize(lpbiOut);
+}
+
+static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			     LPCBITMAPINFOHEADER lpbiOut)
+{
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* need atleast one format */
+  if (lpbiIn == NULL && lpbiOut == NULL)
+    return ICERR_BADPARAM;
+
+  /* check input format if given */
+  if (lpbiIn != NULL) {
+    if (!isSupportedDIB(lpbiIn))
+      return ICERR_BADFORMAT;
+
+    /* for 4-bit need an even width */
+    if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
+      return ICERR_BADFORMAT;
+
+    if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
+      return ICERR_UNSUPPORTED;
+    else if (lpbiIn->biBitCount > 8)
+      return ICERR_UNSUPPORTED;
+  }
+
+  /* check output format if given */
+  if (lpbiOut != NULL) {
+    if (!isSupportedMRLE(lpbiOut))
+      return ICERR_BADFORMAT;
+
+    if (lpbiIn != NULL) {
+      if (lpbiIn->biWidth  != lpbiOut->biWidth)
+	return ICERR_UNSUPPORTED;
+      if (lpbiIn->biHeight != lpbiOut->biHeight)
+	return ICERR_UNSUPPORTED;
+      if (lpbiIn->biBitCount > lpbiOut->biBitCount)
+	return ICERR_UNSUPPORTED;
+    }
+  }
+
+  return ICERR_OK;
+}
+
+static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			     LPCBITMAPINFOHEADER lpbiOut)
+{
+  RGBQUAD *rgbIn;
+  RGBQUAD *rgbOut;
+  int      i;
+  size_t   size;
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters -- need both formats */
+  if (lpbiIn == NULL || lpbiOut == NULL)
+    return ICERR_BADPARAM;
+  /* And both must be supported */
+  if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+    return ICERR_BADFORMAT;
+
+  /* FIXME: cannot compress and decompress at a time! */
+  if (pi->bDecompress) {
+    FIXME("cannot compress and decompress at same time!\n");
+    return ICERR_ERROR;
+  }
+
+  if (pi->bCompress)
+    CompressEnd(pi);
+
+  size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
+  pi->pPrevFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
+  if (pi->pPrevFrame == NULL)
+    return ICERR_MEMORY;
+  pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
+  if (pi->pCurFrame == NULL) {
+    CompressEnd(pi);
+    return ICERR_MEMORY;
+  }
+  pi->nPrevFrame = -1;
+  pi->bCompress  = TRUE;
+
+  rgbIn  = (RGBQUAD*)((LPBYTE)lpbiIn  + lpbiIn->biSize);
+  rgbOut = (RGBQUAD*)((LPBYTE)lpbiOut + lpbiOut->biSize);
+
+  switch (lpbiOut->biBitCount) {
+  case 4:
+  case 8:
+    pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
+    if (pi->palette_map == NULL) {
+      CompressEnd(pi);
+      return ICERR_MEMORY;
+    }
+
+    for (i = 0; i < lpbiIn->biClrUsed; i++) {
+      pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
+    }
+    break;
+  };
+
+  return ICERR_OK;
+}
+
+static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
+{
+  int i;
+
+  TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters */
+  if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
+    return ICERR_BADPARAM;
+  if (!lpic->lpbiOutput || !lpic->lpOutput ||
+      !lpic->lpbiInput  || !lpic->lpInput)
+    return ICERR_BADPARAM;
+
+  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);
+
+  if (! pi->bCompress) {
+    LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
+    if (hr != ICERR_OK)
+      return hr;
+  } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
+    return ICERR_BADFORMAT;
+
+  if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
+    /* we continue in the sequence so we need to initialize 
+     * our internal framedata */
+
+    computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
+  } else if (lpic->lFrameNum == pi->nPrevFrame) {
+    /* Oops, compress same frame again ? Okay, as you wish.
+     * No need to recompute internal framedata, because we only swapped buffers */
+    LPWORD pTmp = pi->pPrevFrame;
+
+    FIXME(": prev=%ld cur=%ld swap\n",pi->nPrevFrame,lpic->lFrameNum);
+    pi->pPrevFrame = pi->pCurFrame;
+    pi->pCurFrame  = pTmp;
+  } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
+    LPWORD pTmp;
+
+    WARN(": prev=%ld cur=%ld gone back? -- untested",pi->nPrevFrame,lpic->lFrameNum);
+    if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
+      return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
+    if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
+      return ICERR_BADFORMAT;
+
+    WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
+    computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
+
+    /* swap buffers for current and previous frame */
+    /* Don't free and alloc new -- costs to much time and they are of equal size ! */
+    pTmp = pi->pPrevFrame;
+    pi->pPrevFrame = pi->pCurFrame;
+    pi->pCurFrame  = pTmp;
+    pi->nPrevFrame = lpic->lFrameNum;
+  }
+
+  for (i = 0; i < 3; i++) {
+    SetQuality(pi, lpic->dwQuality);
+
+    lpic->lpbiOutput->biSizeImage = 0;
+
+    if (lpic->lpbiOutput->biBitCount == 4)
+      MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
+		   lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
+    /*MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
+		   lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);*/
+    else
+      MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
+		   lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
+
+    if (lpic->dwFrameSize == 0 ||
+	lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
+      break;
+
+    if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
+      if (lpic->lpbiOutput->biBitCount == 4)
+	MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
+			     lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
+      else
+	MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
+			     lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
+
+      if (lpic->dwFrameSize == 0 ||
+	  lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
+	WARN("switched to keyframe, was small enough!\n");
+	*lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
+	*lpic->lpckid    = MAKEAVICKID(cktypeDIBbits,
+				       StreamFromFOURCC(*lpic->lpckid));
+	break;
+      }
+    }
+
+    if (lpic->dwQuality < 1000)
+      break;
+
+    lpic->dwQuality -= 1000; /* reduce quality by 10% */
+  }
+
+  { /* swap buffer for current and previous frame */
+    /* Don't free and alloc new -- costs to much time and they are of equal size ! */
+    register LPWORD pTmp = pi->pPrevFrame;
+
+    pi->pPrevFrame = pi->pCurFrame;
+    pi->pCurFrame  = pTmp;
+    pi->nPrevFrame = lpic->lFrameNum;
+  }
+
+  return ICERR_OK;
+}
+
+static LRESULT CompressEnd(CodecInfo *pi)
+{
+  TRACE("(%p)\n",pi);
+
+  if (pi != NULL) {
+    if (pi->pPrevFrame != NULL)
+      GlobalFreePtr(pi->pPrevFrame);
+    if (pi->pCurFrame != NULL)
+      GlobalFreePtr(pi->pCurFrame);
+    pi->pPrevFrame = NULL;
+    pi->pCurFrame  = NULL;
+    pi->nPrevFrame = -1;
+    pi->bCompress  = FALSE;
+  }
+
+  return ICERR_OK;
+}
+
+static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+				   LPBITMAPINFOHEADER lpbiOut)
+{
+  int size;
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  if (lpbiIn == NULL)
+    return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
+
+  if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
+    return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
+
+  size = lpbiIn->biSize;
+
+  if (lpbiOut != NULL) {
+    memcpy(lpbiOut, lpbiIn, size);
+    lpbiOut->biBitCount     = 32;
+    lpbiOut->biCompression  = BI_RGB;
+    lpbiOut->biSizeImage    = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
+    lpbiOut->biClrImportant = 0;
+
+    if (lpbiOut->biBitCount <= 8 && lpbiOut->biClrUsed == 0)
+      lpbiOut->biClrUsed = 1 << lpbiOut->biBitCount;
+    else
+      lpbiOut->biClrUsed = 0;
+
+    return size;
+  } else
+    return size;
+}
+
+static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			       LPCBITMAPINFOHEADER lpbiOut)
+{
+  LRESULT hr = ICERR_OK;
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* need atleast one format */
+  if (lpbiIn == NULL && lpbiOut == NULL)
+    return ICERR_BADPARAM;
+
+  /* check input format if given */
+  if (lpbiIn != NULL) {
+    if (!isSupportedMRLE(lpbiIn))
+      return ICERR_BADFORMAT;
+  }
+
+  /* check output format if given */
+  if (lpbiOut != NULL) {
+    if (!isSupportedDIB(lpbiOut))
+      hr = ICERR_BADFORMAT;
+
+    if (lpbiIn != NULL) {
+      if (lpbiIn->biWidth  != lpbiOut->biWidth)
+	hr = ICERR_UNSUPPORTED;
+      if (lpbiIn->biHeight != lpbiOut->biHeight)
+	hr = ICERR_UNSUPPORTED;
+      if (lpbiIn->biBitCount > lpbiOut->biBitCount)
+	hr = ICERR_UNSUPPORTED;
+    }
+  }
+
+  return hr;
+}
+
+static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+			       LPCBITMAPINFOHEADER lpbiOut)
+{
+  RGBQUAD *rgbIn;
+  RGBQUAD *rgbOut;
+  int      i;
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters */
+  if (lpbiIn == NULL || lpbiOut == NULL)
+    return ICERR_BADPARAM;
+  if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+    return ICERR_BADFORMAT;
+
+  /* FIXME: cannot compress and decompress at a time! */
+  if (pi->bCompress) {
+    FIXME("cannot compress and decompress at same time!\n");
+    return ICERR_ERROR;
+  }
+
+  if (pi->bDecompress)
+    DecompressEnd(pi);
+
+  rgbIn  = (RGBQUAD*)((LPBYTE)lpbiIn  + lpbiIn->biSize);
+  rgbOut = (RGBQUAD*)((LPBYTE)lpbiOut + lpbiOut->biSize);
+
+  switch (lpbiOut->biBitCount) {
+  case 4:
+  case 8:
+    pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
+    if (pi->palette_map == NULL)
+      return ICERR_MEMORY;
+
+    for (i = 0; i < lpbiIn->biClrUsed; i++) {
+      pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
+    }
+    break;
+  case 15:
+  case 16:
+    pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
+    if (pi->palette_map == NULL)
+      return ICERR_MEMORY;
+
+    for (i = 0; i < lpbiIn->biClrUsed; i++) {
+      WORD color;
+
+      if (lpbiOut->biBitCount == 15)
+	color = ((rgbIn[i].rgbRed >> 3) << 10)
+	  | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
+      else
+	color = ((rgbIn[i].rgbRed >> 3) << 11)
+	  | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
+
+      pi->palette_map[i * 2 + 1] = color >> 8;
+      pi->palette_map[i * 2 + 0] = color & 0xFF;
+    };
+    break;
+  case 24:
+  case 32:
+    pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
+    if (pi->palette_map == NULL)
+      return ICERR_MEMORY;
+    memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
+    break;
+  };
+
+  pi->bDecompress = TRUE;
+
+  return ICERR_OK;
+}
+
+static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
+{
+  TRACE("(%p,%p,%lu)\n",pi,pic,dwSize);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters */
+  if (pic == NULL)
+    return ICERR_BADPARAM;
+  if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
+      pic->lpbiOutput == NULL || pic->lpOutput == NULL)
+    return ICERR_BADPARAM;
+
+  /* check formats */
+  if (! pi->bDecompress) {
+    LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
+    if (hr != ICERR_OK)
+      return hr;
+  } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
+    return ICERR_BADFORMAT;
+
+  assert(pic->lpbiInput->biWidth  == pic->lpbiOutput->biWidth);
+  assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
+
+  pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
+  if (pic->lpbiInput->biBitCount == 4)
+    return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
+  else
+    return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
+}
+
+static LRESULT DecompressEnd(CodecInfo *pi)
+{
+  TRACE("(%p)\n",pi);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  pi->bDecompress = FALSE;
+
+  if (pi->palette_map != NULL) {
+    LocalFree((HLOCAL)pi->palette_map);
+    pi->palette_map = NULL;
+  }
+
+  return ICERR_OK;
+}
+
+static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+				    LPBITMAPINFOHEADER lpbiOut)
+{
+  int size;
+
+  TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+  /* pre-condition */
+  assert(pi != NULL);
+
+  /* check parameters */
+  if (lpbiIn == NULL || lpbiOut == NULL)
+    return ICERR_BADPARAM;
+
+  if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+    return ICERR_BADFORMAT;
+
+  if (lpbiOut->biBitCount > 8)
+    return ICERR_ERROR;
+
+  if (lpbiIn->biBitCount <= 8) {
+    if (lpbiIn->biClrUsed > 0)
+      size = lpbiIn->biClrUsed;
+    else
+      size = (1 << lpbiIn->biBitCount);
+
+    lpbiOut->biClrUsed = size;
+
+    memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (LPBYTE)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
+  } /* else could never occur ! */
+
+  return ICERR_OK;
+}
+
+/* DriverProc - entry point for an installable driver */
+LRESULT CALLBACK MSRLE32_DriverProc(DWORD dwDrvID, HDRVR hDrv, UINT uMsg,
+				    LPARAM lParam1, LPARAM lParam2)
+{
+  CodecInfo *pi = (CodecInfo*)dwDrvID;
+
+  TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID)dwDrvID, (LPVOID)hDrv,
+	uMsg, lParam1, lParam2);
+
+  switch (uMsg) {
+    /* standard driver messages */
+  case DRV_LOAD:
+    return DRVCNF_OK;
+  case DRV_OPEN:
+    if (lParam2 == 0)
+      return (LRESULT)0xFFFF0000;
+    else
+      return (LRESULT)Open((ICOPEN*)lParam2);
+  case DRV_CLOSE:
+    if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
+      Close(pi);
+    return DRVCNF_OK;
+  case DRV_ENABLE:
+  case DRV_DISABLE:
+    return DRVCNF_OK;
+  case DRV_FREE:
+    return DRVCNF_OK;
+  case DRV_QUERYCONFIGURE:
+    return DRVCNF_CANCEL; /* FIXME */
+  case DRV_CONFIGURE:
+    return DRVCNF_OK;     /* FIXME */
+  case DRV_INSTALL:
+  case DRV_REMOVE:
+    return DRVCNF_OK;
+
+    /* installable compression manager messages */
+  case ICM_CONFIGURE:
+    FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
+    if (lParam1 == -1)
+      return ICERR_UNSUPPORTED; /* FIXME */
+    else
+      return Configure(pi, (HWND)lParam1);
+  case ICM_ABOUT:
+    if (lParam1 == -1)
+      return ICERR_OK;
+    else
+      return About(pi, (HWND)lParam1);
+  case ICM_GETSTATE:
+  case ICM_SETSTATE:
+    return 0; /* no state */
+  case ICM_GETINFO:
+    return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
+  case ICM_GETDEFAULTQUALITY:
+    if ((LPVOID)lParam1 != NULL) {
+      *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
+      return ICERR_OK;
+    }
+    break;
+  case ICM_GETQUALITY:
+    if ((LPVOID)lParam1 != NULL) {
+      *((LPDWORD)lParam1) = pi->dwQuality;
+      return ICERR_OK;
+    }
+    break;
+  case ICM_SETQUALITY:
+    return SetQuality(pi, *(LPLONG)lParam1);
+    break;
+  case ICM_COMPRESS_GET_FORMAT:
+    return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
+			     (LPBITMAPINFOHEADER)lParam2);
+  case ICM_COMPRESS_GET_SIZE:
+    return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
+			   (LPCBITMAPINFOHEADER)lParam2);
+  case ICM_COMPRESS_QUERY:
+    return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
+			 (LPCBITMAPINFOHEADER)lParam2);
+  case ICM_COMPRESS_BEGIN:
+    return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
+			 (LPCBITMAPINFOHEADER)lParam2);
+  case ICM_COMPRESS:
+    return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
+  case ICM_COMPRESS_END:
+    return CompressEnd(pi);
+  case ICM_DECOMPRESS_GET_FORMAT:
+    return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
+			       (LPBITMAPINFOHEADER)lParam2);
+  case ICM_DECOMPRESS_QUERY:
+    return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
+			   (LPCBITMAPINFOHEADER)lParam2);
+  case ICM_DECOMPRESS_BEGIN:
+    return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
+			   (LPCBITMAPINFOHEADER)lParam2);
+  case ICM_DECOMPRESS:
+    return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
+  case ICM_DECOMPRESS_END:
+    return DecompressEnd(pi);
+  case ICM_DECOMPRESS_SET_PALETTE:
+    FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
+    return ICERR_UNSUPPORTED;
+  case ICM_DECOMPRESS_GET_PALETTE:
+    return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
+				(LPBITMAPINFOHEADER)lParam2);
+  case ICM_GETDEFAULTKEYFRAMERATE:
+    if ((LPVOID)lParam1 != NULL)
+      *(LPDWORD)lParam1 = 15;
+    return ICERR_OK;
+  default:
+    if (uMsg < DRV_USER)
+      return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
+    else
+      FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
+  };
+
+  return ICERR_UNSUPPORTED;
+}
+
+/* DllMain - library initialization code */
+BOOL WINAPI MSRLE32_DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
+{
+  TRACE("(%p,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
+
+  switch (dwReason) {
+  case DLL_PROCESS_ATTACH:
+    if (MSRLE32_hModule == 0)
+      MSRLE32_hModule = hModule;
+    break;
+  case DLL_THREAD_ATTACH:
+    break;
+  case DLL_THREAD_DETACH:
+    break;
+  case DLL_PROCESS_DETACH:
+    break;
+  };
+
+  return TRUE;
+}
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/msrle32.spec	Mon Oct  7 22:16:36 2002
@@ -0,0 +1,3 @@
+init MSRLE32_DllMain
+
+@ stdcall DriverProc(long long long long long) MSRLE32_DriverProc
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/msrle_private.h	Mon Oct  7 22:08:20 2002
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MSRLE32_PRIVATE_H
+#define __MSRLE32_PRIVATE_H
+
+#include "winbase.h"
+#include "mmsystem.h"
+#include "vfw.h"
+
+#define IDS_NAME        100
+#define IDS_DESCRIPTION 101
+#define IDS_ABOUT       102
+
+#define MSRLE32_VERSION  0x00010000 /* Version 1.0 build 0 */
+#define MSRLE32_DEFAULTQUALITY (75 * ICQUALITY_HIGH) / 100
+
+#define FOURCC_RLE   mmioFOURCC('R','L','E',' ')
+#define FOURCC_RLE4  mmioFOURCC('R','L','E','4')
+#define FOURCC_RLE8  mmioFOURCC('R','L','E','8')
+#define FOURCC_MRLE  mmioFOURCC('M','R','L','E')
+
+#define WIDTHBYTES(i)     ((WORD)((i+31)&(~31))/8) /* ULONG aligned ! */
+#define DIBWIDTHBYTES(bi) WIDTHBYTES((WORD)(bi).biWidth * (WORD)(bi).biBitCount)
+
+typedef struct _CodecInfo {
+  FOURCC  fccHandler;
+  DWORD   dwQuality;
+
+  BOOL    bCompress;
+  LONG    nPrevFrame;
+  LPWORD  pPrevFrame;
+  LPWORD  pCurFrame;
+
+  BOOL    bDecompress;
+  LPBYTE  palette_map;
+} CodecInfo;
+
+typedef const BITMAPINFOHEADER * LPCBITMAPINFOHEADER;
+
+#endif
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/rsrc.rc	Mon Oct  7 22:56:32 2002
@@ -0,0 +1,29 @@
+/*
+ * Top level resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "windef.h"
+
+#include "msrle_private.h"
+
+/*
+ * Everything specific to any language goes
+ * in one of the specific files.
+ * Note that you can and may override resources
+ * which also have a neutral version. This is to
+ * get localized bitmaps for example.
+ */
+
+#include "msrle_En.rc"
+#include "msrle_De.rc"
+#include "msrle_Fr.rc"
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/msrle_En.rc	Mon Oct  7 22:56:30 2002
@@ -0,0 +1,22 @@
+/*
+ * English resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+	IDS_NAME	"WINE-MS-RLE"
+	IDS_DESCRIPTION	"Wine MS-RLE video codec"
+	IDS_ABOUT       "Wine MS-RLE video codec\nCopyright 2002 by Michael Günnewig"
+}
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/msrle_De.rc	Mon Oct  7 22:56:29 2002
@@ -0,0 +1,22 @@
+/*
+ * German resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+	IDS_NAME	"WINE-MS-RLE"
+	IDS_DESCRIPTION	"Wine MS-RLE Videodekoder"
+	IDS_ABOUT       "Wine MS-RLE Videodekoder\nCopyright 2002 by Michael Günnewig"
+}
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/msvideo/msrle32/msrle_Fr.rc	Mon Oct  7 22:56:30 2002
@@ -0,0 +1,22 @@
+/*
+ * French resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+LANGUAGE LANG_FRENCH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+	IDS_NAME	"WINE-MS-RLE"
+	IDS_DESCRIPTION	"Wine: décodeur/encodeur vidéo MS-RLE"
+	IDS_ABOUT       "Wine: décodeur/encodeur vidéo MS-RLE\nCopyright 2002 par Michael Günnewig"
+}


More information about the wine-patches mailing list