[MSRLE32] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / msrle32 / msrle32.c
index e157027..5b17b25 100644 (file)
@@ -36,14 +36,10 @@ static HINSTANCE MSRLE32_hModule = 0;
 
 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
 
-#define ABS(a)                ((a) < 0 ? -(a) : (a))
-#define SQR(a)                ((a) * (a))
-
-#define QUALITY_to_DIST(q)    (ICQUALITY_HIGH - q)
 static inline WORD ColorCmp(WORD clr1, WORD clr2)
 {
-  register UINT a = (clr1-clr2);
-  return SQR(a);
+  UINT a = clr1 - clr2;
+  return a * a;
 }
 static inline WORD Intensity(RGBQUAD clr)
 {
@@ -257,7 +253,7 @@ static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
   }
 
   size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
-  return size * lpbi->biHeight;
+  return size * lpbi->biHeight + 2;
 }
 
 /* lpP => current  pos in previous frame
@@ -457,8 +453,7 @@ static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP,
 
 static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
                                     const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
-                                    const BYTE *lpIn, LONG lDist,
-                                    INT x, LPBYTE *ppOut,
+                                    const BYTE *lpIn, INT x, LPBYTE *ppOut,
                                     DWORD *lpSizeImage)
 {
   LPBYTE lpOut = *ppOut;
@@ -472,13 +467,13 @@ static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
   pos = x;
   clr = lpC[pos++];
   for (count = 1; pos < lpbi->biWidth; count++) {
-    if (ColorCmp(clr, lpC[pos++]) > lDist)
+    if (ColorCmp(clr, lpC[pos++]) > 0)
       break;
   }
 
   if (count < 2) {
     /* add some more pixels for absoluting if possible */
-    count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
+    count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, 0, lpbi->biWidth);
 
     assert(count > 0);
 
@@ -547,7 +542,7 @@ LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
                              LPBYTE lpOut, BOOL isKey)
 {
   LPWORD lpC;
-  LONG   lLine, lInLine, lDist;
+  LONG   lLine, lInLine;
   LPBYTE lpOutStart = lpOut;
 
   /* pre-conditions */
@@ -556,7 +551,6 @@ LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
   assert(pi->pCurFrame != NULL);
 
   lpC      = pi->pCurFrame;
-  lDist    = QUALITY_to_DIST(pi->dwQuality);
   lInLine  = DIBWIDTHBYTES(*lpbiIn);
   lLine    = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
 
@@ -569,7 +563,7 @@ LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
       x = 0;
 
       do {
-       x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
+       x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, 0, x,
                                     &lpOut, &lpbiOut->biSizeImage);
       } while (x < lpbiOut->biWidth);
 
@@ -603,7 +597,7 @@ LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
        if (jumpx == -1)
          jumpx = x;
        for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
-         if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
+         if (ColorCmp(lpP[pos], lpC[pos]) > 0)
            break;
        }
 
@@ -663,7 +657,7 @@ LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
 
        if (x < lpbiOut->biWidth) {
          /* skipped the 'same' things corresponding to previous frame */
-         x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
+         x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, 0, x,
                               &lpOut, &lpbiOut->biSizeImage);
        }
       } while (x < lpbiOut->biWidth);
@@ -701,7 +695,7 @@ LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
                              LPBYTE lpOut, BOOL isKey)
 {
   LPWORD lpC;
-  LONG   lDist, lInLine, lLine;
+  LONG   lInLine, lLine;
   LPBYTE lpOutStart = lpOut;
 
   assert(pi != NULL && lpbiOut != NULL);
@@ -709,7 +703,6 @@ LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
   assert(pi->pCurFrame != NULL);
 
   lpC     = pi->pCurFrame;
-  lDist   = QUALITY_to_DIST(pi->dwQuality);
   lInLine = DIBWIDTHBYTES(*lpbiIn);
   lLine   = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
 
@@ -722,7 +715,7 @@ LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
       x = 0;
 
       do {
-       x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
+       x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, x,
                             &lpOut, &lpbiOut->biSizeImage);
        assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
       } while (x < lpbiOut->biWidth);
@@ -757,7 +750,7 @@ LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
        if (jumpx == -1)
          jumpx = x;
        for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
-         if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
+         if (ColorCmp(lpP[pos], lpC[pos]) > 0)
            break;
        }
 
@@ -804,7 +797,7 @@ LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
 
        if (x < lpbiOut->biWidth) {
          /* skip the 'same' things corresponding to previous frame */
-         x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
+          x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, x,
                               &lpOut, &lpbiOut->biSizeImage);
          assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
        }
@@ -823,14 +816,16 @@ LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
       }
     }
 
-    /* add EOL -- will be changed to EOI */
+    /* add EOL */
     lpbiOut->biSizeImage += 2;
     *((LPWORD)lpOut) = 0;
     lpOut += sizeof(WORD);
   }
 
-  /* change EOL to EOI -- end of image */
-  lpOut[-1] = 1;
+  /* add EOI -- end of image */
+  lpbiOut->biSizeImage += 2;
+  *lpOut++ = 0;
+  *lpOut++ = 1;
   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
 
   return ICERR_OK;
@@ -1144,7 +1139,6 @@ static CodecInfo* Open(LPICOPEN icinfo)
     pi->fccHandler  = icinfo->fccHandler;
 
     pi->bCompress   = FALSE;
-    pi->dwQuality   = MSRLE32_DEFAULTQUALITY;
     pi->nPrevFrame  = -1;
     pi->pPrevFrame  = pi->pCurFrame = NULL;
 
@@ -1189,27 +1183,12 @@ static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
   icinfo->dwVersion    = ICVERSION;
   icinfo->dwVersionICM = ICVERSION;
 
-  LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
-  LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
+  LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName));
+  LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(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(const CodecInfo *pi, HWND hWnd)
 {
   /* pre-condition */
@@ -1227,8 +1206,8 @@ static LRESULT About(CodecInfo *pi, HWND hWnd)
   /* pre-condition */
   assert(MSRLE32_hModule != 0);
 
-  LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
-  LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)/sizeof(szAbout[0]));
+  LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, ARRAY_SIZE(szTitle));
+  LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, ARRAY_SIZE(szAbout));
 
   MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
 
@@ -1438,6 +1417,7 @@ static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
 
 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
 {
+  BOOL is_key;
   int i;
 
   TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
@@ -1486,24 +1466,22 @@ static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
     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 ! */
+    /* Don't free and alloc new -- costs too 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);
+  is_key = (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0;
 
+  for (i = 0; i < 3; i++) {
     lpic->lpbiOutput->biSizeImage = 0;
 
     if (lpic->lpbiOutput->biBitCount == 4)
-      MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
-                   lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
+      MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput, lpic->lpbiOutput, lpic->lpOutput, is_key);
     else
-      MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
-                   lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
+      MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput, lpic->lpbiOutput, lpic->lpOutput, is_key);
 
     if (lpic->dwFrameSize == 0 ||
        lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
@@ -1520,7 +1498,7 @@ static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
       if (lpic->dwFrameSize == 0 ||
          lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
        WARN("switched to keyframe, was small enough!\n");
-       *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
+        is_key = TRUE;
        *lpic->lpckid    = MAKEAVICKID(cktypeDIBbits,
                                       StreamFromFOURCC(*lpic->lpckid));
        break;
@@ -1534,14 +1512,16 @@ static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
   }
 
   { /* 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;
+    /* Don't free and alloc new -- costs too much time and they are of equal size ! */
+    LPWORD pTmp = pi->pPrevFrame;
 
     pi->pPrevFrame = pi->pCurFrame;
     pi->pCurFrame  = pTmp;
     pi->nPrevFrame = lpic->lFrameNum;
   }
 
+  /* FIXME: What is AVIIF_TWOCC? */
+  *lpic->lpdwFlags |= AVIIF_TWOCC | (is_key ? AVIIF_KEYFRAME : 0);
   return ICERR_OK;
 }
 
@@ -1564,6 +1544,11 @@ static LRESULT CompressEnd(CodecInfo *pi)
     pi->pCurFrame  = NULL;
     pi->nPrevFrame = -1;
     pi->bCompress  = FALSE;
+
+    if (pi->palette_map != NULL) {
+        LocalFree(pi->palette_map);
+        pi->palette_map = NULL;
+    }
   }
 
   return ICERR_OK;
@@ -1587,8 +1572,16 @@ static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
 
   size = lpbiIn->biSize;
 
-  if (lpbiIn->biBitCount <= 8)
-    size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
+  if (lpbiIn->biBitCount <= 8) {
+    int colors;
+
+    if (lpbiIn->biClrUsed == 0)
+      colors = 1 << lpbiIn->biBitCount;
+    else
+      colors = lpbiIn->biClrUsed;
+
+    size += colors * sizeof(RGBQUAD);
+  }
 
   if (lpbiOut != NULL) {
     memcpy(lpbiOut, lpbiIn, size);
@@ -1616,7 +1609,7 @@ static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
 
   /* check input format if given */
   if (lpbiIn != NULL) {
-    if (!isSupportedMRLE(lpbiIn))
+    if (!isSupportedMRLE(lpbiIn) && !isSupportedDIB(lpbiIn))
       return ICERR_BADFORMAT;
   }
 
@@ -1627,11 +1620,11 @@ static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
 
     if (lpbiIn != NULL) {
       if (lpbiIn->biWidth  != lpbiOut->biWidth)
-       hr = ICERR_UNSUPPORTED;
+        hr = ICERR_UNSUPPORTED;
       if (lpbiIn->biHeight != lpbiOut->biHeight)
-       hr = ICERR_UNSUPPORTED;
+        hr = ICERR_UNSUPPORTED;
       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
-       hr = ICERR_UNSUPPORTED;
+        hr = ICERR_UNSUPPORTED;
     }
   }
 
@@ -1665,49 +1658,57 @@ static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
   if (pi->bDecompress)
     DecompressEnd(pi);
 
-  rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
-  rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
-
-  switch (lpbiOut->biBitCount) {
-  case 4:
-  case 8:
-    pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
-    if (pi->palette_map == NULL)
-      return ICERR_MEMORY;
+  if (lpbiIn->biCompression != BI_RGB)
+  {
+    int colors;
 
-    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 = LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
-    if (pi->palette_map == NULL)
-      return ICERR_MEMORY;
+    if (lpbiIn->biBitCount <= 8 && lpbiIn->biClrUsed == 0)
+      colors = 1 << lpbiIn->biBitCount;
+    else
+      colors = lpbiIn->biClrUsed;
 
-    for (i = 0; i < lpbiIn->biClrUsed; i++) {
-      WORD color;
+    rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
+    rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
 
-      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);
+    switch (lpbiOut->biBitCount) {
+    case 4:
+    case 8:
+      pi->palette_map = LocalAlloc(LPTR, colors);
+      if (pi->palette_map == NULL)
+        return ICERR_MEMORY;
 
-      pi->palette_map[i * 2 + 1] = color >> 8;
-      pi->palette_map[i * 2 + 0] = color & 0xFF;
+      for (i = 0; i < colors; i++)
+        pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(colors, rgbOut, rgbIn[i]);
+      break;
+    case 15:
+    case 16:
+      pi->palette_map = LocalAlloc(LPTR, colors * 2);
+      if (pi->palette_map == NULL)
+        return ICERR_MEMORY;
+
+      for (i = 0; i < colors; 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 = LocalAlloc(LPTR, colors * sizeof(RGBQUAD));
+      if (pi->palette_map == NULL)
+        return ICERR_MEMORY;
+      memcpy(pi->palette_map, rgbIn, colors * sizeof(RGBQUAD));
+      break;
     };
-    break;
-  case 24:
-  case 32:
-    pi->palette_map = 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;
@@ -1738,6 +1739,14 @@ static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
   assert(pic->lpbiInput->biWidth  == pic->lpbiOutput->biWidth);
   assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
 
+  /* Uncompressed frame? */
+  if (pic->lpbiInput->biCompression == BI_RGB)
+  {
+    pic->lpbiOutput->biSizeImage = pic->lpbiInput->biSizeImage;
+    memcpy(pic->lpOutput, pic->lpInput, pic->lpbiOutput->biSizeImage);
+    return ICERR_OK;
+  }
+
   pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
   if (pic->lpbiInput->biBitCount == 4)
     return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
@@ -1850,14 +1859,6 @@ LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
       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);
   case ICM_COMPRESS_GET_FORMAT:
     return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
                             (LPBITMAPINFOHEADER)lParam2);
@@ -1917,9 +1918,6 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
     DisableThreadLibraryCalls(hModule);
     MSRLE32_hModule = hModule;
     break;
-
-  case DLL_PROCESS_DETACH:
-    break;
   }
 
   return TRUE;