| /* |
| * Copyright 2002-2003 Michael Günnewig |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| /* TODO: |
| * - some improvements possible |
| * - implement DecompressSetPalette? -- do we need it for anything? |
| */ |
| |
| #include <assert.h> |
| |
| #include "msrle_private.h" |
| |
| #include "winnls.h" |
| #include "winuser.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msrle32); |
| |
| 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); |
| } |
| static 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 BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr); |
| |
| /* compression functions */ |
| static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn); |
| static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi); |
| static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, |
| const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, |
| LPBYTE lpOut, BOOL isKey); |
| static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, |
| const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, |
| LPBYTE lpOut, BOOL isKey); |
| |
| /* decompression functions */ |
| static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, |
| const BYTE *lpIn, LPBYTE lpOut); |
| static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, |
| const BYTE *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(const 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 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) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1) |
| return FALSE; /* image too big ! */ |
| |
| /* check for nonexistent 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 idx = 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) { |
| idx = i; |
| diff = r; |
| if (diff == 0) |
| break; |
| } |
| } |
| |
| return idx; |
| } |
| |
| /*****************************************************************************/ |
| |
| void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn) |
| { |
| WORD wIntensityTbl[256]; |
| DWORD lInLine, lOutLine; |
| LPWORD lpOut; |
| UINT i; |
| LONG y; |
| |
| /* pre-conditions */ |
| assert(pi != NULL && lpbiIn != NULL && lpIn != NULL); |
| assert(pi->pCurFrame != NULL); |
| |
| lInLine = DIBWIDTHBYTES(*lpbiIn); |
| lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u; |
| lpOut = pi->pCurFrame; |
| |
| assert(lpbiIn->biClrUsed != 0); |
| |
| { |
| const RGBQUAD *lp = |
| (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize); |
| |
| for (i = 0; i < lpbiIn->biClrUsed; i++) |
| wIntensityTbl[i] = Intensity(lp[i]); |
| } |
| |
| for (y = 0; y < lpbiIn->biHeight; y++) { |
| LONG x; |
| |
| switch (lpbiIn->biBitCount) { |
| case 1: |
| for (x = 0; x < lpbiIn->biWidth / 8; x++) { |
| for (i = 0; i < 7; i++) |
| lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1]; |
| } |
| break; |
| case 4: |
| for (x = 0; x < lpbiIn->biWidth / 2; x++) { |
| lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)]; |
| lpOut[2 * 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(const WORD *lpP, const WORD *lpA, const WORD *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 at least ?? more encodable pixels */ |
| if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist && |
| ColorCmp(clr2,lpB[pos+2]) <= lDist) { |
| if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist && |
| ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist) |
| return count - 3; /* followed by at least 4 encodable pixels */ |
| return count - 2; |
| } |
| } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { |
| /* 'compare' with previous frame for end of diff */ |
| INT count2 = 0; |
| |
| /* FIXME */ |
| |
| if (count2 >= 8) |
| 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(const WORD *lpP, const WORD *lpA, const WORD *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 some more encodable pixel */ |
| if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist) |
| return count - 1; |
| if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist) |
| return count - 1; |
| } 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(const CodecInfo *pi, const WORD *lpP, |
| const WORD *lpC, LPCBITMAPINFOHEADER lpbi, |
| const 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); |
| |
| assert(count > 0); |
| |
| /* check for near end of line */ |
| if (x + count > lpbi->biWidth) |
| count = lpbi->biWidth - x; |
| |
| /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */ |
| while (count > 2) { |
| INT i; |
| INT size = min(count, 254); |
| int bytes = ((size + 1) & (~1)) / 2; |
| int extra_byte = bytes & 0x01; |
| |
| *lpSizeImage += 2 + bytes + extra_byte; |
| assert(((*lpSizeImage) % 2) == 0); |
| 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 little 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(const CodecInfo *pi, const WORD *lpP, |
| const WORD *lpC, LPCBITMAPINFOHEADER lpbi, |
| const 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); |
| |
| assert(count > 0); |
| |
| /* check for over end of line */ |
| if (x + count > lpbi->biWidth) |
| count = lpbi->biWidth - x; |
| |
| /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */ |
| while (count > 2) { |
| INT i; |
| INT size = min(count, 255); |
| int 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 little 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(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, |
| const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, |
| LPBYTE lpOut, BOOL isKey) |
| { |
| LPWORD lpC; |
| LONG lLine, lInLine, lDist; |
| LPBYTE lpOutStart = lpOut; |
| |
| /* 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; |
| lpOut += sizeof(WORD); |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| } |
| } 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; |
| lpOut += sizeof(WORD); |
| } |
| |
| /* 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; |
| lpOut += sizeof(WORD); |
| assert(lpOut == lpOutStart + lpbiOut->biSizeImage); |
| } |
| } |
| |
| /* add EOL -- will be changed to EOI */ |
| lpbiOut->biSizeImage += 2; |
| *((LPWORD)lpOut) = 0; |
| lpOut += sizeof(WORD); |
| } |
| |
| /* change EOL to EOI -- end of image */ |
| lpOut[-1] = 1; |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| |
| return ICERR_OK; |
| } |
| |
| LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, |
| const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut, |
| LPBYTE lpOut, BOOL isKey) |
| { |
| LPWORD lpC; |
| LONG lDist, lInLine, lLine; |
| LPBYTE lpOutStart = lpOut; |
| |
| 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); |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| } while (x < lpbiOut->biWidth); |
| |
| lpC += lLine; |
| lpIn += lInLine; |
| |
| /* add EOL -- end of line */ |
| lpbiOut->biSizeImage += 2; |
| *((LPWORD)lpOut) = 0; |
| lpOut += sizeof(WORD); |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| } |
| } 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 an EOL then jump */ |
| assert(jumpy > 0); |
| |
| jumpx = 0; |
| jumpy--; |
| |
| /* add EOL -- end of line */ |
| lpbiOut->biSizeImage += 2; |
| *((LPWORD)lpOut) = 0; |
| lpOut += sizeof(WORD); |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| } |
| |
| /* 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); |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| } |
| } while (x < lpbiOut->biWidth); |
| |
| lpP += lLine; |
| lpC += lLine; |
| lpIn += lInLine; |
| |
| if (jumpy == 0) { |
| /* add EOL -- end of line */ |
| lpbiOut->biSizeImage += 2; |
| *((LPWORD)lpOut) = 0; |
| lpOut += sizeof(WORD); |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| } |
| } |
| |
| /* add EOL -- will be changed to EOI */ |
| lpbiOut->biSizeImage += 2; |
| *((LPWORD)lpOut) = 0; |
| lpOut += sizeof(WORD); |
| } |
| |
| /* change EOL to EOI -- end of image */ |
| lpOut[-1] = 1; |
| assert(lpOut == (lpOutStart + lpbiOut->biSizeImage)); |
| |
| return ICERR_OK; |
| } |
| |
| /*****************************************************************************/ |
| |
| static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, |
| const BYTE *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 + 1) & (~1)) / 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 + 1 <= 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 + 1 <= 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 + 1 <= 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; |
| } |
| } |
| } |
| if (code0 & 0x01) { |
| if (bytes_per_pixel == 1) { |
| code1 = lpIn[i]; |
| lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)]; |
| } 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]; |
| } 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; |
| } |
| lpIn++; |
| } |
| 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(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, |
| const BYTE *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) > %d\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) > %d\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; |
| } |
| |
| if (compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return NULL; |
| |
| TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo, |
| icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType, |
| icinfo->fccHandler, (char*)&icinfo->fccHandler, |
| icinfo->dwVersion,icinfo->dwFlags); |
| |
| 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%08X(%4.4s) !\n", |
| icinfo->fccHandler,(char*)&icinfo->fccHandler); |
| return NULL; |
| } |
| |
| pi = 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(pi); |
| return 1; |
| } |
| |
| static LRESULT GetInfo(const 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 = ICTYPE_VIDEO; |
| icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE); |
| icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC; |
| 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)); |
| |
| 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 */ |
| assert(pi != NULL); |
| |
| /* FIXME */ |
| return ICERR_OK; |
| } |
| |
| static LRESULT About(CodecInfo *pi, HWND hWnd) |
| { |
| WCHAR szTitle[20]; |
| WCHAR szAbout[128]; |
| |
| /* 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])); |
| |
| MessageBoxW(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 at least 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, 1 << lpbiOut->biBitCount); |
| lpbiOut->biClrImportant = 0; |
| |
| memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, |
| (const BYTE*)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 at least 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(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, |
| LPCBITMAPINFOHEADER lpbiOut) |
| { |
| /* pre-condition */ |
| assert(pi != NULL); |
| |
| /* need at least 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) |
| { |
| const RGBQUAD *rgbIn; |
| const RGBQUAD *rgbOut; |
| UINT 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 same 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 = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD))); |
| if (pi->pPrevFrame == NULL) |
| return ICERR_MEMORY; |
| pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD))); |
| if (pi->pCurFrame == NULL) { |
| CompressEnd(pi); |
| return ICERR_MEMORY; |
| } |
| pi->nPrevFrame = -1; |
| pi->bCompress = TRUE; |
| |
| 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) { |
| 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,%u)\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%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); |
| |
| 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; |
| |
| pi->pPrevFrame = pi->pCurFrame; |
| pi->pCurFrame = pTmp; |
| } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) { |
| LPWORD pTmp; |
| |
| WARN(": prev=%d cur=%d gone back? -- untested\n",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=%d cur=%d 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, lpic->lpInput, |
| lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0); |
| else |
| MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput, |
| lpic->lpbiOutput, 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, lpic->lpInput, |
| lpic->lpbiOutput, lpic->lpOutput, TRUE); |
| else |
| MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput, |
| lpic->lpbiOutput, 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) |
| { |
| GlobalUnlock(GlobalHandle(pi->pPrevFrame)); |
| GlobalFree(GlobalHandle(pi->pPrevFrame)); |
| } |
| if (pi->pCurFrame != NULL) |
| { |
| GlobalUnlock(GlobalHandle(pi->pCurFrame)); |
| GlobalFree(GlobalHandle(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) |
| { |
| DWORD 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 (lpbiIn->biBitCount <= 8) |
| size += lpbiIn->biClrUsed * sizeof(RGBQUAD); |
| |
| if (lpbiOut != NULL) { |
| memcpy(lpbiOut, lpbiIn, size); |
| lpbiOut->biCompression = BI_RGB; |
| lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight; |
| |
| return ICERR_OK; |
| } 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 at least 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) |
| { |
| const RGBQUAD *rgbIn; |
| const RGBQUAD *rgbOut; |
| UINT 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 = (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; |
| |
| 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; |
| |
| 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 = 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,%u)\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(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, (const BYTE*)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_PTR dwDrvID, HDRVR hDrv, UINT uMsg, |
| LPARAM lParam1, LPARAM lParam2) |
| { |
| CodecInfo *pi = (CodecInfo*)dwDrvID; |
| |
| TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2); |
| |
| switch (uMsg) { |
| /* standard driver messages */ |
| case DRV_LOAD: |
| return DRVCNF_OK; |
| case DRV_OPEN: |
| 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); |
| 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 DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) |
| { |
| TRACE("(%p,%d,%p)\n",hModule,dwReason,lpReserved); |
| |
| switch (dwReason) { |
| case DLL_PROCESS_ATTACH: |
| DisableThreadLibraryCalls(hModule); |
| MSRLE32_hModule = hModule; |
| break; |
| |
| case DLL_PROCESS_DETACH: |
| break; |
| } |
| |
| return TRUE; |
| } |