ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

msrle32.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2002-2003 Michael Günnewig
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 /* TODO:
00020  *   - some improvements possible
00021  *   - implement DecompressSetPalette? -- do we need it for anything?
00022  */
00023 
00024 #include <assert.h>
00025 
00026 #include "msrle_private.h"
00027 
00028 #include "winnls.h"
00029 #include "winuser.h"
00030 
00031 #include "wine/debug.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
00034 
00035 static HINSTANCE MSRLE32_hModule = 0;
00036 
00037 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
00038 
00039 #define ABS(a)                ((a) < 0 ? -(a) : (a))
00040 #define SQR(a)                ((a) * (a))
00041 
00042 #define QUALITY_to_DIST(q)    (ICQUALITY_HIGH - q)
00043 static inline WORD ColorCmp(WORD clr1, WORD clr2)
00044 {
00045   register UINT a = (clr1-clr2);
00046   return SQR(a);
00047 }
00048 static inline WORD Intensity(RGBQUAD clr)
00049 {
00050   return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
00051 }
00052 
00053 #define GetRawPixel(lpbi,lp,x) \
00054   ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
00055    ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
00056 
00057 /*****************************************************************************/
00058 
00059 /* utility functions */
00060 static BOOL    isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
00061 static BOOL    isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
00062 static BYTE    MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
00063 
00064 /* compression functions */
00065 static void    computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn);
00066 static LONG    MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
00067 static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00068                                     const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
00069                                     LPBYTE lpOut, BOOL isKey);
00070 static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00071                                     const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
00072                                     LPBYTE lpOut, BOOL isKey);
00073 
00074 /* decompression functions */
00075 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
00076                       const BYTE *lpIn, LPBYTE lpOut);
00077 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
00078                       const BYTE *lpIn, LPBYTE lpOut);
00079 
00080 /* API functions */
00081 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00082                  LPBITMAPINFOHEADER lpbiOut);
00083 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00084                    LPCBITMAPINFOHEADER lpbiOut);
00085 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00086                  LPCBITMAPINFOHEADER lpbiOut);
00087 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00088                  LPCBITMAPINFOHEADER lpbiOut);
00089 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
00090 static LRESULT CompressEnd(CodecInfo *pi);
00091 
00092 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00093                    LPBITMAPINFOHEADER lpbiOut);
00094 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00095                    LPCBITMAPINFOHEADER lpbiOut);
00096 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00097                    LPCBITMAPINFOHEADER lpbiOut);
00098 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
00099 static LRESULT DecompressEnd(CodecInfo *pi);
00100 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00101                     LPBITMAPINFOHEADER lpbiOut);
00102 
00103 /*****************************************************************************/
00104 
00105 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
00106 {
00107   /* pre-conditions */
00108   assert(lpbi != NULL);
00109 
00110   if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
00111       lpbi->biPlanes != 1)
00112     return FALSE;
00113 
00114   if (lpbi->biCompression == BI_RLE4) {
00115     if (lpbi->biBitCount != 4 ||
00116     (lpbi->biWidth % 2) != 0)
00117       return FALSE;
00118   } else if (lpbi->biCompression == BI_RLE8) {
00119     if (lpbi->biBitCount != 8)
00120       return FALSE;
00121   } else
00122     return FALSE;
00123 
00124   return TRUE;
00125 }
00126 
00127 static BOOL  isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
00128 {
00129   /* pre-conditions */
00130   assert(lpbi != NULL);
00131 
00132   /* check structure version/planes/compression */
00133   if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
00134       lpbi->biPlanes != 1)
00135     return FALSE;
00136   if (lpbi->biCompression != BI_RGB &&
00137       lpbi->biCompression != BI_BITFIELDS)
00138     return FALSE;
00139 
00140   /* check bit-depth */
00141   if (lpbi->biBitCount != 1 &&
00142       lpbi->biBitCount != 4 &&
00143       lpbi->biBitCount != 8 &&
00144       lpbi->biBitCount != 15 &&
00145       lpbi->biBitCount != 16 &&
00146       lpbi->biBitCount != 24 &&
00147       lpbi->biBitCount != 32)
00148     return FALSE;
00149 
00150   /* check for size(s) */
00151   if (!lpbi->biWidth || !lpbi->biHeight)
00152     return FALSE; /* image with zero size, makes no sense so error ! */
00153   if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
00154     return FALSE; /* image too big ! */
00155 
00156   /* check for nonexistent colortable for hi- and true-color DIB's */
00157   if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
00158     return FALSE;
00159 
00160   return TRUE;
00161 }
00162 
00163 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
00164 {
00165   INT  diff = 0x00FFFFFF;
00166   UINT i;
00167   UINT idx = 0;
00168 
00169   /* pre-conditions */
00170   assert(clrs != NULL);
00171 
00172   for (i = 0; i < count; i++) {
00173     int r = ((int)clrs[i].rgbRed   - (int)clr.rgbRed);
00174     int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
00175     int b = ((int)clrs[i].rgbBlue  - (int)clr.rgbBlue);
00176 
00177     r = r*r + g*g + b*b;
00178 
00179     if (r < diff) {
00180       idx  = i;
00181       diff = r;
00182       if (diff == 0)
00183     break;
00184     }
00185   }
00186 
00187   return idx;
00188 }
00189 
00190 /*****************************************************************************/
00191 
00192 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn)
00193 {
00194   WORD   wIntensityTbl[256];
00195   DWORD  lInLine, lOutLine;
00196   LPWORD lpOut;
00197   UINT   i;
00198   LONG   y;
00199 
00200   /* pre-conditions */
00201   assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
00202   assert(pi->pCurFrame != NULL);
00203 
00204   lInLine  = DIBWIDTHBYTES(*lpbiIn);
00205   lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
00206   lpOut    = pi->pCurFrame;
00207 
00208   assert(lpbiIn->biClrUsed != 0);
00209 
00210   {
00211     const RGBQUAD *lp =
00212       (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
00213 
00214     for (i = 0; i < lpbiIn->biClrUsed; i++)
00215       wIntensityTbl[i] = Intensity(lp[i]);
00216   }
00217 
00218   for (y = 0; y < lpbiIn->biHeight; y++) {
00219     LONG x;
00220 
00221     switch (lpbiIn->biBitCount) {
00222     case 1:
00223       for (x = 0; x < lpbiIn->biWidth / 8; x++) {
00224     for (i = 0; i < 7; i++)
00225       lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
00226       }
00227       break;
00228     case 4:
00229       for (x = 0; x < lpbiIn->biWidth / 2; x++) {
00230     lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
00231     lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
00232       }
00233       break;
00234     case 8:
00235       for (x = 0; x < lpbiIn->biWidth; x++)
00236     lpOut[x] = wIntensityTbl[lpIn[x]];
00237       break;
00238     }
00239 
00240     lpIn  += lInLine;
00241     lpOut += lOutLine;
00242   }
00243 }
00244 
00245 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
00246 {
00247   LONG a, b, size;
00248 
00249   /* pre-condition */
00250   assert(lpbi != NULL);
00251 
00252   a = lpbi->biWidth / 255;
00253   b = lpbi->biWidth % 255;
00254   if (lpbi->biBitCount <= 4) {
00255     a /= 2;
00256     b /= 2;
00257   }
00258 
00259   size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
00260   return size * lpbi->biHeight;
00261 }
00262 
00263 /* lpP => current  pos in previous frame
00264  * lpA => previous pos in current  frame
00265  * lpB => current  pos in current  frame
00266  */
00267 static INT countDiffRLE4(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
00268 {
00269   INT  count;
00270   WORD clr1, clr2;
00271 
00272   /* pre-conditions */
00273   assert(lpA && lpB && lDist >= 0 && width > 0);
00274 
00275   if (pos >= width)
00276     return 0;
00277   if (pos+1 == width)
00278     return 1;
00279 
00280   clr1 = lpB[pos++];
00281   clr2 = lpB[pos];
00282 
00283   count = 2;
00284   while (pos + 1 < width) {
00285     WORD clr3, clr4;
00286 
00287     clr3 = lpB[++pos];
00288     if (pos + 1 >= width)
00289       return count + 1;
00290 
00291     clr4 = lpB[++pos];
00292     if (ColorCmp(clr1, clr3) <= lDist &&
00293     ColorCmp(clr2, clr4) <= lDist) {
00294       /* diff at end? -- look-ahead for at least ?? more encodable pixels */
00295       if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
00296       ColorCmp(clr2,lpB[pos+2]) <= lDist) {
00297     if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
00298         ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
00299       return count - 3; /* followed by at least 4 encodable pixels */
00300     return count - 2;
00301       }
00302     } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
00303       /* 'compare' with previous frame for end of diff */
00304       INT count2 = 0;
00305 
00306       /* FIXME */
00307 
00308       if (count2 >= 8)
00309     return count;
00310 
00311       pos -= count2;
00312     }
00313 
00314     count += 2;
00315     clr1 = clr3;
00316     clr2 = clr4;
00317   }
00318 
00319   return count;
00320 }
00321 
00322 /* lpP => current  pos in previous frame
00323  * lpA => previous pos in current  frame
00324  * lpB => current  pos in current  frame
00325  */
00326 static INT countDiffRLE8(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
00327 {
00328   INT count;
00329 
00330   for (count = 0; pos < width; pos++, count++) {
00331     if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
00332       /* diff at end? -- look-ahead for some more encodable pixel */
00333       if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
00334     return count - 1;
00335       if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
00336     return count - 1;
00337     } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
00338       /* 'compare' with previous frame for end of diff */
00339       INT count2 = 0;
00340 
00341       for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
00342     if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
00343       break;
00344       }
00345       if (count2 > 4)
00346     return count;
00347 
00348       pos -= count2;
00349     }
00350   }
00351 
00352   return count;
00353 }
00354 
00355 static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP,
00356                                     const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
00357                                     const BYTE *lpIn, LONG lDist,
00358                                     INT x, LPBYTE *ppOut,
00359                                     DWORD *lpSizeImage)
00360 {
00361   LPBYTE lpOut = *ppOut;
00362   INT    count, pos;
00363   WORD   clr1, clr2;
00364 
00365   /* try to encode as many pixel as possible */
00366   count = 1;
00367   pos   = x;
00368   clr1  = lpC[pos++];
00369   if (pos < lpbi->biWidth) {
00370     clr2 = lpC[pos];
00371     for (++count; pos + 1 < lpbi->biWidth; ) {
00372       ++pos;
00373       if (ColorCmp(clr1, lpC[pos]) > lDist)
00374     break;
00375       count++;
00376       if (pos + 1 >= lpbi->biWidth)
00377     break;
00378       ++pos;
00379       if (ColorCmp(clr2, lpC[pos]) > lDist)
00380     break;
00381       count++;
00382     }
00383   }
00384 
00385   if (count < 4) {
00386     /* add some pixel for absoluting if possible */
00387     count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
00388 
00389     assert(count > 0);
00390 
00391     /* check for near end of line */
00392     if (x + count > lpbi->biWidth)
00393       count = lpbi->biWidth - x;
00394 
00395     /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
00396     while (count > 2) {
00397       INT  i;
00398       INT  size       = min(count, 254);
00399       int  bytes      = ((size + 1) & (~1)) / 2;
00400       int  extra_byte = bytes & 0x01;
00401 
00402       *lpSizeImage += 2 + bytes + extra_byte;
00403       assert(((*lpSizeImage) % 2) == 0);
00404       count -= size;
00405       *lpOut++ = 0;
00406       *lpOut++ = size;
00407       for (i = 0; i < size; i += 2) {
00408     clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00409     x++;
00410     if (i + 1 < size) {
00411       clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00412       x++;
00413     } else
00414       clr2 = 0;
00415 
00416     *lpOut++ = (clr1 << 4) | clr2;
00417       }
00418       if (extra_byte)
00419     *lpOut++ = 0;
00420     }
00421 
00422     if (count > 0) {
00423       /* too little for absoluting so we must encode them */
00424       assert(count <= 2);
00425 
00426       *lpSizeImage += 2;
00427       clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00428       x++;
00429       if (count == 2) {
00430     clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00431     x++;
00432       } else
00433     clr2 = 0;
00434       *lpOut++ = count;
00435       *lpOut++ = (clr1 << 4) | clr2;
00436     }
00437   } else {
00438     /* encode count pixel(s) */
00439     clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
00440         pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
00441 
00442     x += count;
00443     while (count > 0) {
00444       INT size = min(count, 254);
00445 
00446       *lpSizeImage += 2;
00447       count    -= size;
00448       *lpOut++  = size;
00449       *lpOut++  = clr1;
00450     }
00451   }
00452 
00453   *ppOut = lpOut;
00454 
00455   return x;
00456 }
00457 
00458 static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
00459                                     const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
00460                                     const BYTE *lpIn, LONG lDist,
00461                                     INT x, LPBYTE *ppOut,
00462                                     DWORD *lpSizeImage)
00463 {
00464   LPBYTE lpOut = *ppOut;
00465   INT    count, pos;
00466   WORD   clr;
00467 
00468   assert(lpbi->biBitCount <= 8);
00469   assert(lpbi->biCompression == BI_RGB);
00470 
00471   /* try to encode as much as possible */
00472   pos = x;
00473   clr = lpC[pos++];
00474   for (count = 1; pos < lpbi->biWidth; count++) {
00475     if (ColorCmp(clr, lpC[pos++]) > lDist)
00476       break;
00477   }
00478 
00479   if (count < 2) {
00480     /* add some more pixels for absoluting if possible */
00481     count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
00482 
00483     assert(count > 0);
00484 
00485     /* check for over end of line */
00486     if (x + count > lpbi->biWidth)
00487       count = lpbi->biWidth - x;
00488 
00489     /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
00490     while (count > 2) {
00491       INT  i;
00492       INT  size       = min(count, 255);
00493       int  extra_byte = size % 2;
00494 
00495       *lpSizeImage += 2 + size + extra_byte;
00496       count -= size;
00497       *lpOut++ = 0;
00498       *lpOut++ = size;
00499       for (i = 0; i < size; i++) {
00500     *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00501     x++;
00502       }
00503       if (extra_byte)
00504     *lpOut++ = 0;
00505     }
00506     if (count > 0) {
00507       /* too little for absoluting so we must encode them even if it's expensive! */
00508       assert(count <= 2);
00509 
00510       *lpSizeImage += 2 * count;
00511       *lpOut++ = 1;
00512       *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00513       x++;
00514 
00515       if (count == 2) {
00516     *lpOut++ = 1;
00517     *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00518     x++;
00519       }
00520     }
00521   } else {
00522     /* encode count pixel(s) */
00523     clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
00524 
00525     /* optimize end of line */
00526     if (x + count + 1 == lpbi->biWidth)
00527       count++;
00528 
00529     x += count;
00530     while (count > 0) {
00531       INT size = min(count, 255);
00532 
00533       *lpSizeImage += 2;
00534       count    -= size;
00535       *lpOut++  = size;
00536       *lpOut++  = clr;
00537     }
00538   }
00539 
00540   *ppOut = lpOut;
00541 
00542   return x;
00543 }
00544 
00545 LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00546                              const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
00547                              LPBYTE lpOut, BOOL isKey)
00548 {
00549   LPWORD lpC;
00550   LONG   lLine, lInLine, lDist;
00551   LPBYTE lpOutStart = lpOut;
00552 
00553   /* pre-conditions */
00554   assert(pi != NULL && lpbiOut != NULL);
00555   assert(lpIn != NULL && lpOut != NULL);
00556   assert(pi->pCurFrame != NULL);
00557 
00558   lpC      = pi->pCurFrame;
00559   lDist    = QUALITY_to_DIST(pi->dwQuality);
00560   lInLine  = DIBWIDTHBYTES(*lpbiIn);
00561   lLine    = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
00562 
00563   lpbiOut->biSizeImage = 0;
00564   if (isKey) {
00565     /* keyframe -- convert internal frame to output format */
00566     INT x, y;
00567 
00568     for (y = 0; y < lpbiOut->biHeight; y++) {
00569       x = 0;
00570 
00571       do {
00572     x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
00573                      &lpOut, &lpbiOut->biSizeImage);
00574       } while (x < lpbiOut->biWidth);
00575 
00576       lpC   += lLine;
00577       lpIn  += lInLine;
00578 
00579       /* add EOL -- end of line */
00580       lpbiOut->biSizeImage += 2;
00581       *(LPWORD)lpOut = 0;
00582       lpOut += sizeof(WORD);
00583       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00584     }
00585   } else {
00586     /* delta-frame -- compute delta between last and this internal frame */
00587     LPWORD lpP;
00588     INT    x, y;
00589     INT    jumpx, jumpy;
00590 
00591     assert(pi->pPrevFrame != NULL);
00592 
00593     lpP   = pi->pPrevFrame;
00594     jumpy = 0;
00595     jumpx = -1;
00596 
00597     for (y = 0; y < lpbiOut->biHeight; y++) {
00598       x = 0;
00599 
00600       do {
00601     INT count, pos;
00602 
00603     if (jumpx == -1)
00604       jumpx = x;
00605     for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
00606       if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
00607         break;
00608     }
00609 
00610     if (pos == lpbiOut->biWidth && count > 8) {
00611       /* (count > 8) secures that we will save space */
00612       jumpy++;
00613       break;
00614     } else if (jumpy || jumpx != pos) {
00615       /* time to jump */
00616       assert(jumpx != -1);
00617 
00618       if (pos < jumpx) {
00619         /* can only jump in positive direction -- jump until EOL, EOL */
00620         INT w = lpbiOut->biWidth - jumpx;
00621 
00622         assert(jumpy > 0);
00623         assert(w >= 4);
00624 
00625         jumpx = 0;
00626         jumpy--;
00627         /* if (w % 255 == 2) then equal costs
00628          * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
00629          * else it will be cheaper
00630          */
00631         while (w > 0) {
00632           lpbiOut->biSizeImage += 4;
00633           *lpOut++ = 0;
00634           *lpOut++ = 2;
00635           *lpOut   = min(w, 255);
00636           w       -= *lpOut++;
00637           *lpOut++ = 0;
00638         }
00639         /* add EOL -- end of line */
00640         lpbiOut->biSizeImage += 2;
00641         *((LPWORD)lpOut) = 0;
00642         lpOut += sizeof(WORD);
00643       }
00644 
00645       /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
00646 
00647       /* write out real jump(s) */
00648       while (jumpy || pos != jumpx) {
00649         lpbiOut->biSizeImage += 4;
00650         *lpOut++ = 0;
00651         *lpOut++ = 2;
00652         *lpOut   = min(pos - jumpx, 255);
00653         x       += *lpOut;
00654         jumpx   += *lpOut++;
00655         *lpOut   = min(jumpy, 255);
00656         jumpy   -= *lpOut++;
00657       }
00658 
00659       jumpy = 0;
00660     }
00661 
00662     jumpx = -1;
00663 
00664     if (x < lpbiOut->biWidth) {
00665       /* skipped the 'same' things corresponding to previous frame */
00666       x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
00667                    &lpOut, &lpbiOut->biSizeImage);
00668     }
00669       } while (x < lpbiOut->biWidth);
00670 
00671       lpP   += lLine;
00672       lpC   += lLine;
00673       lpIn  += lInLine;
00674 
00675       if (jumpy == 0) {
00676     assert(jumpx == -1);
00677 
00678     /* add EOL -- end of line */
00679     lpbiOut->biSizeImage += 2;
00680     *((LPWORD)lpOut) = 0;
00681         lpOut += sizeof(WORD);
00682     assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
00683       }
00684     }
00685 
00686     /* add EOL -- will be changed to EOI */
00687     lpbiOut->biSizeImage += 2;
00688     *((LPWORD)lpOut) = 0;
00689     lpOut += sizeof(WORD);
00690   }
00691 
00692   /* change EOL to EOI -- end of image */
00693   lpOut[-1] = 1;
00694   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00695 
00696   return ICERR_OK;
00697 }
00698 
00699 LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
00700                              const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
00701                              LPBYTE lpOut, BOOL isKey)
00702 {
00703   LPWORD lpC;
00704   LONG   lDist, lInLine, lLine;
00705   LPBYTE lpOutStart = lpOut;
00706 
00707   assert(pi != NULL && lpbiOut != NULL);
00708   assert(lpIn != NULL && lpOut != NULL);
00709   assert(pi->pCurFrame != NULL);
00710 
00711   lpC     = pi->pCurFrame;
00712   lDist   = QUALITY_to_DIST(pi->dwQuality);
00713   lInLine = DIBWIDTHBYTES(*lpbiIn);
00714   lLine   = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
00715 
00716   lpbiOut->biSizeImage = 0;
00717   if (isKey) {
00718     /* keyframe -- convert internal frame to output format */
00719     INT x, y;
00720 
00721     for (y = 0; y < lpbiOut->biHeight; y++) {
00722       x = 0;
00723 
00724       do {
00725     x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
00726                  &lpOut, &lpbiOut->biSizeImage);
00727     assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00728       } while (x < lpbiOut->biWidth);
00729 
00730       lpC  += lLine;
00731       lpIn += lInLine;
00732 
00733       /* add EOL -- end of line */
00734       lpbiOut->biSizeImage += 2;
00735       *((LPWORD)lpOut) = 0;
00736       lpOut += sizeof(WORD);
00737       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00738     }
00739   } else {
00740     /* delta-frame -- compute delta between last and this internal frame */
00741     LPWORD lpP;
00742     INT    x, y;
00743     INT    jumpx, jumpy;
00744 
00745     assert(pi->pPrevFrame != NULL);
00746 
00747     lpP   = pi->pPrevFrame;
00748     jumpx = -1;
00749     jumpy = 0;
00750 
00751     for (y = 0; y < lpbiOut->biHeight; y++) {
00752       x = 0;
00753 
00754       do {
00755     INT count, pos;
00756 
00757     if (jumpx == -1)
00758       jumpx = x;
00759     for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
00760       if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
00761         break;
00762     }
00763 
00764     if (pos == lpbiOut->biWidth && count > 4) {
00765       /* (count > 4) secures that we will save space */
00766       jumpy++;
00767       break;
00768     } else if (jumpy || jumpx != pos) {
00769       /* time to jump */
00770       assert(jumpx != -1);
00771 
00772       if (pos < jumpx) {
00773         /* can only jump in positive direction -- do an EOL then jump */
00774         assert(jumpy > 0);
00775 
00776         jumpx = 0;
00777         jumpy--;
00778 
00779         /* add EOL -- end of line */
00780         lpbiOut->biSizeImage += 2;
00781         *((LPWORD)lpOut) = 0;
00782         lpOut += sizeof(WORD);
00783         assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00784       }
00785 
00786       /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
00787 
00788       /* write out real jump(s) */
00789       while (jumpy || pos != jumpx) {
00790         lpbiOut->biSizeImage += 4;
00791         *lpOut++ = 0;
00792         *lpOut++ = 2;
00793         *lpOut   = min(pos - jumpx, 255);
00794         jumpx   += *lpOut++;
00795         *lpOut   = min(jumpy, 255);
00796         jumpy   -= *lpOut++;
00797       }
00798       x = pos;
00799 
00800       jumpy = 0;
00801     }
00802 
00803     jumpx = -1;
00804 
00805     if (x < lpbiOut->biWidth) {
00806       /* skip the 'same' things corresponding to previous frame */
00807       x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
00808                    &lpOut, &lpbiOut->biSizeImage);
00809       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00810     }
00811       } while (x < lpbiOut->biWidth);
00812 
00813       lpP  += lLine;
00814       lpC  += lLine;
00815       lpIn += lInLine;
00816 
00817       if (jumpy == 0) {
00818     /* add EOL -- end of line */
00819     lpbiOut->biSizeImage += 2;
00820     *((LPWORD)lpOut) = 0;
00821     lpOut += sizeof(WORD);
00822     assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00823       }
00824     }
00825 
00826     /* add EOL -- will be changed to EOI */
00827     lpbiOut->biSizeImage += 2;
00828     *((LPWORD)lpOut) = 0;
00829     lpOut += sizeof(WORD);
00830   }
00831 
00832   /* change EOL to EOI -- end of image */
00833   lpOut[-1] = 1;
00834   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
00835 
00836   return ICERR_OK;
00837 }
00838 
00839 /*****************************************************************************/
00840 
00841 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
00842                       const BYTE *lpIn, LPBYTE lpOut)
00843 {
00844   int  bytes_per_pixel;
00845   int  line_size;
00846   int  pixel_ptr  = 0;
00847   int  i;
00848   BOOL bEndFlag   = FALSE;
00849 
00850   assert(pi != NULL);
00851   assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
00852   assert(lpIn != NULL && lpOut != NULL);
00853 
00854   bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
00855   line_size       = DIBWIDTHBYTES(*lpbi);
00856 
00857   do {
00858     BYTE code0, code1;
00859 
00860     code0 = *lpIn++;
00861     code1 = *lpIn++;
00862 
00863     if (code0 == 0) {
00864       int  extra_byte;
00865 
00866       switch (code1) {
00867       case  0: /* EOL - end of line  */
00868     pixel_ptr = 0;
00869     lpOut += line_size;
00870     break;
00871       case  1: /* EOI - end of image */
00872     bEndFlag = TRUE;
00873     break;
00874       case  2: /* skip */
00875     pixel_ptr += *lpIn++ * bytes_per_pixel;
00876     lpOut     += *lpIn++ * line_size;
00877     if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
00878       pixel_ptr = 0;
00879       lpOut    += line_size;
00880     }
00881     break;
00882       default: /* absolute mode */
00883     extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
00884 
00885     if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
00886       return ICERR_ERROR;
00887 
00888     code0 = code1;
00889     for (i = 0; i < code0 / 2; i++) {
00890       if (bytes_per_pixel == 1) {
00891         code1 = lpIn[i];
00892         lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
00893         if (2 * i + 1 <= code0)
00894           lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
00895       } else if (bytes_per_pixel == 2) {
00896         code1 = lpIn[i] >> 4;
00897         lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
00898         lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
00899 
00900         if (2 * i + 1 <= code0) {
00901           code1 = lpIn[i] & 0x0F;
00902           lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
00903           lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
00904         }
00905       } else {
00906         code1 = lpIn[i] >> 4;
00907         lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
00908         lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
00909         lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
00910         pixel_ptr += bytes_per_pixel;
00911 
00912         if (2 * i + 1 <= code0) {
00913           code1 = lpIn[i] & 0x0F;
00914           lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
00915           lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
00916           lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
00917           pixel_ptr += bytes_per_pixel;
00918         }
00919       }
00920     }
00921     if (code0 & 0x01) {
00922       if (bytes_per_pixel == 1) {
00923         code1 = lpIn[i];
00924         lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
00925       } else if (bytes_per_pixel == 2) {
00926         code1 = lpIn[i] >> 4;
00927         lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
00928         lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
00929       } else {
00930         code1 = lpIn[i] >> 4;
00931         lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
00932         lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
00933         lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
00934         pixel_ptr += bytes_per_pixel;
00935       }
00936       lpIn++;
00937     }
00938     lpIn += code0 / 2;
00939 
00940     /* if the RLE code is odd, skip a byte in the stream */
00941     if (extra_byte)
00942       lpIn++;
00943       };
00944     } else {
00945       /* coded mode */
00946       if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
00947     return ICERR_ERROR;
00948 
00949       if (bytes_per_pixel == 1) {
00950     BYTE c1 = pi->palette_map[(code1 >> 4)];
00951     BYTE c2 = pi->palette_map[(code1 & 0x0F)];
00952 
00953     for (i = 0; i < code0; i++) {
00954       if ((i & 1) == 0)
00955         lpOut[pixel_ptr++] = c1;
00956       else
00957         lpOut[pixel_ptr++] = c2;
00958     }
00959       } else if (bytes_per_pixel == 2) {
00960     BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
00961     BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
00962 
00963     BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
00964     BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
00965 
00966     for (i = 0; i < code0; i++) {
00967       if ((i & 1) == 0) {
00968         lpOut[pixel_ptr++] = hi1;
00969         lpOut[pixel_ptr++] = lo1;
00970       } else {
00971         lpOut[pixel_ptr++] = hi2;
00972         lpOut[pixel_ptr++] = lo2;
00973       }
00974     }
00975       } else {
00976     BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
00977     BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
00978     BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
00979 
00980     BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
00981     BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
00982     BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
00983 
00984     for (i = 0; i < code0; i++) {
00985       if ((i & 1) == 0) {
00986         lpOut[pixel_ptr + 0] = b1;
00987         lpOut[pixel_ptr + 1] = g1;
00988         lpOut[pixel_ptr + 2] = r1;
00989       } else {
00990         lpOut[pixel_ptr + 0] = b2;
00991         lpOut[pixel_ptr + 1] = g2;
00992         lpOut[pixel_ptr + 2] = r2;
00993       }
00994       pixel_ptr += bytes_per_pixel;
00995     }
00996       }
00997     }
00998   } while (! bEndFlag);
00999 
01000   return ICERR_OK;
01001 }
01002 
01003 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
01004                       const BYTE *lpIn, LPBYTE lpOut)
01005 {
01006   int  bytes_per_pixel;
01007   int  line_size;
01008   int  pixel_ptr  = 0;
01009   BOOL bEndFlag   = FALSE;
01010 
01011   assert(pi != NULL);
01012   assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
01013   assert(lpIn != NULL && lpOut != NULL);
01014 
01015   bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
01016   line_size       = DIBWIDTHBYTES(*lpbi);
01017 
01018   do {
01019     BYTE code0, code1;
01020 
01021     code0 = *lpIn++;
01022     code1 = *lpIn++;
01023 
01024     if (code0 == 0) {
01025       int  extra_byte;
01026 
01027       switch (code1) {
01028       case  0: /* EOL - end of line  */
01029     pixel_ptr = 0;
01030     lpOut += line_size;
01031     break;
01032       case  1: /* EOI - end of image */
01033     bEndFlag = TRUE;
01034     break;
01035       case  2: /* skip */
01036     pixel_ptr += *lpIn++ * bytes_per_pixel;
01037     lpOut     += *lpIn++ * line_size;
01038     if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
01039       pixel_ptr = 0;
01040       lpOut    += line_size;
01041     }
01042     break;
01043       default: /* absolute mode */
01044     if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
01045           WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
01046       return ICERR_ERROR;
01047     }
01048     extra_byte = code1 & 0x01;
01049 
01050     code0 = code1;
01051     while (code0--) {
01052       code1 = *lpIn++;
01053       if (bytes_per_pixel == 1) {
01054         lpOut[pixel_ptr] = pi->palette_map[code1];
01055       } else if (bytes_per_pixel == 2) {
01056         lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
01057         lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
01058       } else {
01059         lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
01060         lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
01061         lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
01062       }
01063       pixel_ptr += bytes_per_pixel;
01064     }
01065 
01066     /* if the RLE code is odd, skip a byte in the stream */
01067     if (extra_byte)
01068       lpIn++;
01069       };
01070     } else {
01071       /* coded mode */
01072       if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
01073     WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
01074     return ICERR_ERROR;
01075       }
01076 
01077       if (bytes_per_pixel == 1) {
01078     code1 = pi->palette_map[code1];
01079     while (code0--)
01080       lpOut[pixel_ptr++] = code1;
01081       } else if (bytes_per_pixel == 2) {
01082     BYTE hi = pi->palette_map[code1 * 2 + 0];
01083     BYTE lo = pi->palette_map[code1 * 2 + 1];
01084 
01085     while (code0--) {
01086       lpOut[pixel_ptr + 0] = hi;
01087       lpOut[pixel_ptr + 1] = lo;
01088       pixel_ptr += bytes_per_pixel;
01089     }
01090       } else {
01091     BYTE r = pi->palette_map[code1 * 4 + 2];
01092     BYTE g = pi->palette_map[code1 * 4 + 1];
01093     BYTE b = pi->palette_map[code1 * 4 + 0];
01094 
01095     while (code0--) {
01096       lpOut[pixel_ptr + 0] = b;
01097       lpOut[pixel_ptr + 1] = g;
01098       lpOut[pixel_ptr + 2] = r;
01099       pixel_ptr += bytes_per_pixel;
01100     }
01101       }
01102     }
01103   } while (! bEndFlag);
01104 
01105   return ICERR_OK;
01106 }
01107 
01108 /*****************************************************************************/
01109 
01110 static CodecInfo* Open(LPICOPEN icinfo)
01111 {
01112   CodecInfo* pi = NULL;
01113 
01114   if (icinfo == NULL) {
01115     TRACE("(NULL)\n");
01116     return (LPVOID)0xFFFF0000;
01117   }
01118 
01119   if (compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return NULL;
01120 
01121   TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo,
01122     icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
01123     icinfo->fccHandler, (char*)&icinfo->fccHandler,
01124     icinfo->dwVersion,icinfo->dwFlags);
01125 
01126   switch (icinfo->fccHandler) {
01127   case FOURCC_RLE:
01128   case FOURCC_RLE4:
01129   case FOURCC_RLE8:
01130   case FOURCC_MRLE:
01131     break;
01132   case mmioFOURCC('m','r','l','e'):
01133     icinfo->fccHandler = FOURCC_MRLE;
01134     break;
01135   default:
01136     WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
01137      icinfo->fccHandler,(char*)&icinfo->fccHandler);
01138     return NULL;
01139   }
01140 
01141   pi = LocalAlloc(LPTR, sizeof(CodecInfo));
01142 
01143   if (pi != NULL) {
01144     pi->fccHandler  = icinfo->fccHandler;
01145 
01146     pi->bCompress   = FALSE;
01147     pi->dwQuality   = MSRLE32_DEFAULTQUALITY;
01148     pi->nPrevFrame  = -1;
01149     pi->pPrevFrame  = pi->pCurFrame = NULL;
01150 
01151     pi->bDecompress = FALSE;
01152     pi->palette_map = NULL;
01153   }
01154 
01155   icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
01156 
01157   return pi;
01158 }
01159 
01160 static LRESULT Close(CodecInfo *pi)
01161 {
01162   TRACE("(%p)\n", pi);
01163 
01164   /* pre-condition */
01165   assert(pi != NULL);
01166 
01167   if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
01168     CompressEnd(pi);
01169 
01170   LocalFree(pi);
01171   return 1;
01172 }
01173 
01174 static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
01175 {
01176   /* pre-condition */
01177   assert(pi != NULL);
01178 
01179   /* check parameters */
01180   if (icinfo == NULL)
01181     return sizeof(ICINFO);
01182   if (dwSize < sizeof(ICINFO))
01183     return 0;
01184 
01185   icinfo->dwSize       = sizeof(ICINFO);
01186   icinfo->fccType      = ICTYPE_VIDEO;
01187   icinfo->fccHandler   = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
01188   icinfo->dwFlags      = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
01189   icinfo->dwVersion    = ICVERSION;
01190   icinfo->dwVersionICM = ICVERSION;
01191 
01192   LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
01193   LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
01194 
01195   return sizeof(ICINFO);
01196 }
01197 
01198 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
01199 {
01200   /* pre-condition */
01201   assert(pi != NULL);
01202 
01203   if (lQuality == -1)
01204     lQuality = MSRLE32_DEFAULTQUALITY;
01205   else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
01206     return ICERR_BADPARAM;
01207 
01208   pi->dwQuality = (DWORD)lQuality;
01209 
01210   return ICERR_OK;
01211 }
01212 
01213 static LRESULT Configure(const CodecInfo *pi, HWND hWnd)
01214 {
01215   /* pre-condition */
01216   assert(pi != NULL);
01217 
01218   /* FIXME */
01219   return ICERR_OK;
01220 }
01221 
01222 static LRESULT About(CodecInfo *pi, HWND hWnd)
01223 {
01224   WCHAR szTitle[20];
01225   WCHAR szAbout[128];
01226 
01227   /* pre-condition */
01228   assert(MSRLE32_hModule != 0);
01229 
01230   LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
01231   LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)/sizeof(szAbout[0]));
01232 
01233   MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
01234 
01235   return ICERR_OK;
01236 }
01237 
01238 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01239                  LPBITMAPINFOHEADER lpbiOut)
01240 {
01241   LRESULT size;
01242 
01243   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01244 
01245   /* pre-condition */
01246   assert(pi != NULL);
01247 
01248   /* check parameters -- need at least input format */
01249   if (lpbiIn == NULL) {
01250     if (lpbiOut != NULL)
01251       return ICERR_BADPARAM;
01252     return 0;
01253   }
01254 
01255   /* handle unsupported input format */
01256   if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
01257     return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
01258 
01259   assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
01260 
01261   switch (pi->fccHandler) {
01262   case FOURCC_RLE4:
01263     size = 1 << 4;
01264     break;
01265   case FOURCC_RLE8:
01266     size = 1 << 8;
01267     break;
01268   case FOURCC_RLE:
01269   case FOURCC_MRLE:
01270     size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
01271     break;
01272   default:
01273     return ICERR_ERROR;
01274   }
01275 
01276   if (lpbiIn->biClrUsed != 0)
01277     size = lpbiIn->biClrUsed;
01278 
01279   size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
01280 
01281   if (lpbiOut != NULL) {
01282     lpbiOut->biSize          = sizeof(BITMAPINFOHEADER);
01283     lpbiOut->biWidth         = lpbiIn->biWidth;
01284     lpbiOut->biHeight        = lpbiIn->biHeight;
01285     lpbiOut->biPlanes        = 1;
01286     if (pi->fccHandler == FOURCC_RLE4 ||
01287     lpbiIn->biBitCount <= 4) {
01288       lpbiOut->biCompression = BI_RLE4;
01289       lpbiOut->biBitCount    = 4;
01290     } else {
01291       lpbiOut->biCompression = BI_RLE8;
01292       lpbiOut->biBitCount    = 8;
01293     }
01294     lpbiOut->biSizeImage     = MSRLE32_GetMaxCompressedSize(lpbiOut);
01295     lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
01296     lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
01297     if (lpbiIn->biClrUsed == 0)
01298       size = 1<<lpbiIn->biBitCount;
01299     else
01300       size = lpbiIn->biClrUsed;
01301     lpbiOut->biClrUsed       = min(size, 1 << lpbiOut->biBitCount);
01302     lpbiOut->biClrImportant  = 0;
01303 
01304     memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
01305        (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
01306 
01307     return ICERR_OK;
01308   } else
01309     return size;
01310 }
01311 
01312 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01313                    LPCBITMAPINFOHEADER lpbiOut)
01314 {
01315   /* pre-condition */
01316   assert(pi != NULL);
01317 
01318   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01319 
01320   /* check parameter -- need at least one format */
01321   if (lpbiIn == NULL && lpbiOut == NULL)
01322     return 0;
01323   /* check if the given format is supported */
01324   if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
01325     return 0;
01326 
01327   /* the worst case is coding the complete image in absolute mode. */
01328   if (lpbiIn)
01329     return MSRLE32_GetMaxCompressedSize(lpbiIn);
01330   else
01331     return MSRLE32_GetMaxCompressedSize(lpbiOut);
01332 }
01333 
01334 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01335                  LPCBITMAPINFOHEADER lpbiOut)
01336 {
01337   /* pre-condition */
01338   assert(pi != NULL);
01339 
01340   /* need at least one format */
01341   if (lpbiIn == NULL && lpbiOut == NULL)
01342     return ICERR_BADPARAM;
01343 
01344   /* check input format if given */
01345   if (lpbiIn != NULL) {
01346     if (!isSupportedDIB(lpbiIn))
01347       return ICERR_BADFORMAT;
01348 
01349     /* for 4-bit need an even width */
01350     if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
01351       return ICERR_BADFORMAT;
01352 
01353     if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
01354       return ICERR_UNSUPPORTED;
01355     else if (lpbiIn->biBitCount > 8)
01356       return ICERR_UNSUPPORTED;
01357   }
01358 
01359   /* check output format if given */
01360   if (lpbiOut != NULL) {
01361     if (!isSupportedMRLE(lpbiOut))
01362       return ICERR_BADFORMAT;
01363 
01364     if (lpbiIn != NULL) {
01365       if (lpbiIn->biWidth  != lpbiOut->biWidth)
01366     return ICERR_UNSUPPORTED;
01367       if (lpbiIn->biHeight != lpbiOut->biHeight)
01368     return ICERR_UNSUPPORTED;
01369       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
01370     return ICERR_UNSUPPORTED;
01371     }
01372   }
01373 
01374   return ICERR_OK;
01375 }
01376 
01377 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01378                  LPCBITMAPINFOHEADER lpbiOut)
01379 {
01380   const RGBQUAD *rgbIn;
01381   const RGBQUAD *rgbOut;
01382   UINT   i;
01383   size_t size;
01384 
01385   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01386 
01387   /* pre-condition */
01388   assert(pi != NULL);
01389 
01390   /* check parameters -- need both formats */
01391   if (lpbiIn == NULL || lpbiOut == NULL)
01392     return ICERR_BADPARAM;
01393   /* And both must be supported */
01394   if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
01395     return ICERR_BADFORMAT;
01396 
01397   /* FIXME: cannot compress and decompress at same time! */
01398   if (pi->bDecompress) {
01399     FIXME("cannot compress and decompress at same time!\n");
01400     return ICERR_ERROR;
01401   }
01402 
01403   if (pi->bCompress)
01404     CompressEnd(pi);
01405 
01406   size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
01407   pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
01408   if (pi->pPrevFrame == NULL)
01409     return ICERR_MEMORY;
01410   pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
01411   if (pi->pCurFrame == NULL) {
01412     CompressEnd(pi);
01413     return ICERR_MEMORY;
01414   }
01415   pi->nPrevFrame = -1;
01416   pi->bCompress  = TRUE;
01417 
01418   rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
01419   rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
01420 
01421   switch (lpbiOut->biBitCount) {
01422   case 4:
01423   case 8:
01424     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
01425     if (pi->palette_map == NULL) {
01426       CompressEnd(pi);
01427       return ICERR_MEMORY;
01428     }
01429 
01430     for (i = 0; i < lpbiIn->biClrUsed; i++) {
01431       pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
01432     }
01433     break;
01434   };
01435 
01436   return ICERR_OK;
01437 }
01438 
01439 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
01440 {
01441   int i;
01442 
01443   TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
01444 
01445   /* pre-condition */
01446   assert(pi != NULL);
01447 
01448   /* check parameters */
01449   if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
01450     return ICERR_BADPARAM;
01451   if (!lpic->lpbiOutput || !lpic->lpOutput ||
01452       !lpic->lpbiInput  || !lpic->lpInput)
01453     return ICERR_BADPARAM;
01454 
01455   TRACE("lpic={0x%X,%p,%p,%p,%p,%p,%p,%d,%u,%u,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev);
01456 
01457   if (! pi->bCompress) {
01458     LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
01459     if (hr != ICERR_OK)
01460       return hr;
01461   } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
01462     return ICERR_BADFORMAT;
01463 
01464   if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
01465     /* we continue in the sequence so we need to initialize 
01466      * our internal framedata */
01467 
01468     computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
01469   } else if (lpic->lFrameNum == pi->nPrevFrame) {
01470     /* Oops, compress same frame again ? Okay, as you wish.
01471      * No need to recompute internal framedata, because we only swapped buffers */
01472     LPWORD pTmp = pi->pPrevFrame;
01473 
01474     pi->pPrevFrame = pi->pCurFrame;
01475     pi->pCurFrame  = pTmp;
01476   } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
01477     LPWORD pTmp;
01478 
01479     WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
01480     if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
01481       return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
01482     if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
01483       return ICERR_BADFORMAT;
01484 
01485     WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
01486     computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
01487 
01488     /* swap buffers for current and previous frame */
01489     /* Don't free and alloc new -- costs to much time and they are of equal size ! */
01490     pTmp = pi->pPrevFrame;
01491     pi->pPrevFrame = pi->pCurFrame;
01492     pi->pCurFrame  = pTmp;
01493     pi->nPrevFrame = lpic->lFrameNum;
01494   }
01495 
01496   for (i = 0; i < 3; i++) {
01497     SetQuality(pi, lpic->dwQuality);
01498 
01499     lpic->lpbiOutput->biSizeImage = 0;
01500 
01501     if (lpic->lpbiOutput->biBitCount == 4)
01502       MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
01503                    lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
01504     else
01505       MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
01506                    lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
01507 
01508     if (lpic->dwFrameSize == 0 ||
01509     lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
01510       break;
01511 
01512     if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
01513       if (lpic->lpbiOutput->biBitCount == 4)
01514         MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
01515                              lpic->lpbiOutput, lpic->lpOutput, TRUE);
01516       else
01517         MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
01518                              lpic->lpbiOutput, lpic->lpOutput, TRUE);
01519 
01520       if (lpic->dwFrameSize == 0 ||
01521       lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
01522     WARN("switched to keyframe, was small enough!\n");
01523     *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
01524     *lpic->lpckid    = MAKEAVICKID(cktypeDIBbits,
01525                        StreamFromFOURCC(*lpic->lpckid));
01526     break;
01527       }
01528     }
01529 
01530     if (lpic->dwQuality < 1000)
01531       break;
01532 
01533     lpic->dwQuality -= 1000; /* reduce quality by 10% */
01534   }
01535 
01536   { /* swap buffer for current and previous frame */
01537     /* Don't free and alloc new -- costs to much time and they are of equal size ! */
01538     register LPWORD pTmp = pi->pPrevFrame;
01539 
01540     pi->pPrevFrame = pi->pCurFrame;
01541     pi->pCurFrame  = pTmp;
01542     pi->nPrevFrame = lpic->lFrameNum;
01543   }
01544 
01545   return ICERR_OK;
01546 }
01547 
01548 static LRESULT CompressEnd(CodecInfo *pi)
01549 {
01550   TRACE("(%p)\n",pi);
01551 
01552   if (pi != NULL) {
01553     if (pi->pPrevFrame != NULL)
01554     {
01555       GlobalUnlock(GlobalHandle(pi->pPrevFrame));
01556       GlobalFree(GlobalHandle(pi->pPrevFrame));
01557     }
01558     if (pi->pCurFrame != NULL)
01559     {
01560       GlobalUnlock(GlobalHandle(pi->pCurFrame));
01561       GlobalFree(GlobalHandle(pi->pCurFrame));
01562     }
01563     pi->pPrevFrame = NULL;
01564     pi->pCurFrame  = NULL;
01565     pi->nPrevFrame = -1;
01566     pi->bCompress  = FALSE;
01567   }
01568 
01569   return ICERR_OK;
01570 }
01571 
01572 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01573                    LPBITMAPINFOHEADER lpbiOut)
01574 {
01575   DWORD size;
01576 
01577   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01578 
01579   /* pre-condition */
01580   assert(pi != NULL);
01581 
01582   if (lpbiIn == NULL)
01583     return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
01584 
01585   if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
01586     return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
01587 
01588   size = lpbiIn->biSize;
01589 
01590   if (lpbiIn->biBitCount <= 8)
01591     size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
01592 
01593   if (lpbiOut != NULL) {
01594     memcpy(lpbiOut, lpbiIn, size);
01595     lpbiOut->biCompression  = BI_RGB;
01596     lpbiOut->biSizeImage    = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
01597 
01598     return ICERR_OK;
01599   } else
01600     return size;
01601 }
01602 
01603 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01604                    LPCBITMAPINFOHEADER lpbiOut)
01605 {
01606   LRESULT hr = ICERR_OK;
01607 
01608   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01609 
01610   /* pre-condition */
01611   assert(pi != NULL);
01612 
01613   /* need at least one format */
01614   if (lpbiIn == NULL && lpbiOut == NULL)
01615     return ICERR_BADPARAM;
01616 
01617   /* check input format if given */
01618   if (lpbiIn != NULL) {
01619     if (!isSupportedMRLE(lpbiIn))
01620       return ICERR_BADFORMAT;
01621   }
01622 
01623   /* check output format if given */
01624   if (lpbiOut != NULL) {
01625     if (!isSupportedDIB(lpbiOut))
01626       hr = ICERR_BADFORMAT;
01627 
01628     if (lpbiIn != NULL) {
01629       if (lpbiIn->biWidth  != lpbiOut->biWidth)
01630     hr = ICERR_UNSUPPORTED;
01631       if (lpbiIn->biHeight != lpbiOut->biHeight)
01632     hr = ICERR_UNSUPPORTED;
01633       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
01634     hr = ICERR_UNSUPPORTED;
01635     }
01636   }
01637 
01638   return hr;
01639 }
01640 
01641 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01642                    LPCBITMAPINFOHEADER lpbiOut)
01643 {
01644   const RGBQUAD *rgbIn;
01645   const RGBQUAD *rgbOut;
01646   UINT  i;
01647 
01648   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01649 
01650   /* pre-condition */
01651   assert(pi != NULL);
01652 
01653   /* check parameters */
01654   if (lpbiIn == NULL || lpbiOut == NULL)
01655     return ICERR_BADPARAM;
01656   if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
01657     return ICERR_BADFORMAT;
01658 
01659   /* FIXME: cannot compress and decompress at a time! */
01660   if (pi->bCompress) {
01661     FIXME("cannot compress and decompress at same time!\n");
01662     return ICERR_ERROR;
01663   }
01664 
01665   if (pi->bDecompress)
01666     DecompressEnd(pi);
01667 
01668   rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
01669   rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
01670 
01671   switch (lpbiOut->biBitCount) {
01672   case 4:
01673   case 8:
01674     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
01675     if (pi->palette_map == NULL)
01676       return ICERR_MEMORY;
01677 
01678     for (i = 0; i < lpbiIn->biClrUsed; i++) {
01679       pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
01680     }
01681     break;
01682   case 15:
01683   case 16:
01684     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
01685     if (pi->palette_map == NULL)
01686       return ICERR_MEMORY;
01687 
01688     for (i = 0; i < lpbiIn->biClrUsed; i++) {
01689       WORD color;
01690 
01691       if (lpbiOut->biBitCount == 15)
01692     color = ((rgbIn[i].rgbRed >> 3) << 10)
01693       | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
01694       else
01695     color = ((rgbIn[i].rgbRed >> 3) << 11)
01696       | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
01697 
01698       pi->palette_map[i * 2 + 1] = color >> 8;
01699       pi->palette_map[i * 2 + 0] = color & 0xFF;
01700     };
01701     break;
01702   case 24:
01703   case 32:
01704     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
01705     if (pi->palette_map == NULL)
01706       return ICERR_MEMORY;
01707     memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
01708     break;
01709   };
01710 
01711   pi->bDecompress = TRUE;
01712 
01713   return ICERR_OK;
01714 }
01715 
01716 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
01717 {
01718   TRACE("(%p,%p,%u)\n",pi,pic,dwSize);
01719 
01720   /* pre-condition */
01721   assert(pi != NULL);
01722 
01723   /* check parameters */
01724   if (pic == NULL)
01725     return ICERR_BADPARAM;
01726   if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
01727       pic->lpbiOutput == NULL || pic->lpOutput == NULL)
01728     return ICERR_BADPARAM;
01729 
01730   /* check formats */
01731   if (! pi->bDecompress) {
01732     LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
01733     if (hr != ICERR_OK)
01734       return hr;
01735   } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
01736     return ICERR_BADFORMAT;
01737 
01738   assert(pic->lpbiInput->biWidth  == pic->lpbiOutput->biWidth);
01739   assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
01740 
01741   pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
01742   if (pic->lpbiInput->biBitCount == 4)
01743     return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
01744   else
01745     return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
01746 }
01747 
01748 static LRESULT DecompressEnd(CodecInfo *pi)
01749 {
01750   TRACE("(%p)\n",pi);
01751 
01752   /* pre-condition */
01753   assert(pi != NULL);
01754 
01755   pi->bDecompress = FALSE;
01756 
01757   if (pi->palette_map != NULL) {
01758     LocalFree(pi->palette_map);
01759     pi->palette_map = NULL;
01760   }
01761 
01762   return ICERR_OK;
01763 }
01764 
01765 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
01766                     LPBITMAPINFOHEADER lpbiOut)
01767 {
01768   int size;
01769 
01770   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
01771 
01772   /* pre-condition */
01773   assert(pi != NULL);
01774 
01775   /* check parameters */
01776   if (lpbiIn == NULL || lpbiOut == NULL)
01777     return ICERR_BADPARAM;
01778 
01779   if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
01780     return ICERR_BADFORMAT;
01781 
01782   if (lpbiOut->biBitCount > 8)
01783     return ICERR_ERROR;
01784 
01785   if (lpbiIn->biBitCount <= 8) {
01786     if (lpbiIn->biClrUsed > 0)
01787       size = lpbiIn->biClrUsed;
01788     else
01789       size = (1 << lpbiIn->biBitCount);
01790 
01791     lpbiOut->biClrUsed = size;
01792 
01793     memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
01794   } /* else could never occur ! */
01795 
01796   return ICERR_OK;
01797 }
01798 
01799 /* DriverProc - entry point for an installable driver */
01800 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
01801                     LPARAM lParam1, LPARAM lParam2)
01802 {
01803   CodecInfo *pi = (CodecInfo*)dwDrvID;
01804 
01805   TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
01806 
01807   switch (uMsg) {
01808     /* standard driver messages */
01809   case DRV_LOAD:
01810     return DRVCNF_OK;
01811   case DRV_OPEN:
01812       return (LRESULT)Open((ICOPEN*)lParam2);
01813   case DRV_CLOSE:
01814     if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
01815       Close(pi);
01816     return DRVCNF_OK;
01817   case DRV_ENABLE:
01818   case DRV_DISABLE:
01819     return DRVCNF_OK;
01820   case DRV_FREE:
01821     return DRVCNF_OK;
01822   case DRV_QUERYCONFIGURE:
01823     return DRVCNF_CANCEL; /* FIXME */
01824   case DRV_CONFIGURE:
01825     return DRVCNF_OK;     /* FIXME */
01826   case DRV_INSTALL:
01827   case DRV_REMOVE:
01828     return DRVCNF_OK;
01829 
01830     /* installable compression manager messages */
01831   case ICM_CONFIGURE:
01832     FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
01833     if (lParam1 == -1)
01834       return ICERR_UNSUPPORTED; /* FIXME */
01835     else
01836       return Configure(pi, (HWND)lParam1);
01837   case ICM_ABOUT:
01838     if (lParam1 == -1)
01839       return ICERR_OK;
01840     else
01841       return About(pi, (HWND)lParam1);
01842   case ICM_GETSTATE:
01843   case ICM_SETSTATE:
01844     return 0; /* no state */
01845   case ICM_GETINFO:
01846     return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
01847   case ICM_GETDEFAULTQUALITY:
01848     if ((LPVOID)lParam1 != NULL) {
01849       *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
01850       return ICERR_OK;
01851     }
01852     break;
01853   case ICM_GETQUALITY:
01854     if ((LPVOID)lParam1 != NULL) {
01855       *((LPDWORD)lParam1) = pi->dwQuality;
01856       return ICERR_OK;
01857     }
01858     break;
01859   case ICM_SETQUALITY:
01860     return SetQuality(pi, *(LPLONG)lParam1);
01861   case ICM_COMPRESS_GET_FORMAT:
01862     return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
01863                  (LPBITMAPINFOHEADER)lParam2);
01864   case ICM_COMPRESS_GET_SIZE:
01865     return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
01866                (LPCBITMAPINFOHEADER)lParam2);
01867   case ICM_COMPRESS_QUERY:
01868     return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
01869              (LPCBITMAPINFOHEADER)lParam2);
01870   case ICM_COMPRESS_BEGIN:
01871     return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
01872              (LPCBITMAPINFOHEADER)lParam2);
01873   case ICM_COMPRESS:
01874     return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
01875   case ICM_COMPRESS_END:
01876     return CompressEnd(pi);
01877   case ICM_DECOMPRESS_GET_FORMAT:
01878     return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
01879                    (LPBITMAPINFOHEADER)lParam2);
01880   case ICM_DECOMPRESS_QUERY:
01881     return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
01882                (LPCBITMAPINFOHEADER)lParam2);
01883   case ICM_DECOMPRESS_BEGIN:
01884     return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
01885                (LPCBITMAPINFOHEADER)lParam2);
01886   case ICM_DECOMPRESS:
01887     return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
01888   case ICM_DECOMPRESS_END:
01889     return DecompressEnd(pi);
01890   case ICM_DECOMPRESS_SET_PALETTE:
01891     FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
01892     return ICERR_UNSUPPORTED;
01893   case ICM_DECOMPRESS_GET_PALETTE:
01894     return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
01895                 (LPBITMAPINFOHEADER)lParam2);
01896   case ICM_GETDEFAULTKEYFRAMERATE:
01897     if ((LPVOID)lParam1 != NULL)
01898       *(LPDWORD)lParam1 = 15;
01899     return ICERR_OK;
01900   default:
01901     if (uMsg < DRV_USER)
01902       return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
01903     else
01904       FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
01905   };
01906 
01907   return ICERR_UNSUPPORTED;
01908 }
01909 
01910 /* DllMain - library initialization code */
01911 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
01912 {
01913   TRACE("(%p,%d,%p)\n",hModule,dwReason,lpReserved);
01914 
01915   switch (dwReason) {
01916   case DLL_PROCESS_ATTACH:
01917     DisableThreadLibraryCalls(hModule);
01918     MSRLE32_hModule = hModule;
01919     break;
01920 
01921   case DLL_PROCESS_DETACH:
01922     break;
01923   }
01924 
01925   return TRUE;
01926 }

Generated on Sat May 26 2012 04:23:53 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.