| /* | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| /* TODO: | |
| * - some improvements possible | |
| * - implement DecompressSetPalette? -- does we need it for anything? | |
| */ | |
| #include <assert.h> | |
| #include "msrle_private.h" | |
| #include "winnls.h" | |
| #include "winuser.h" | |
| #include "windowsx.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(msrle32); | |
| static HINSTANCE MSRLE32_hModule = 0; | |
| #define ABS(a) ((a) < 0 ? -(a) : (a)) | |
| #define SQR(a) ((a) * (a)) | |
| #define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q) | |
| inline WORD ColorCmp(WORD clr1, WORD clr2) | |
| { | |
| register UINT a = (clr1-clr2); | |
| return SQR(a); | |
| } | |
| inline WORD Intensity(RGBQUAD clr) | |
| { | |
| return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4; | |
| } | |
| #define GetRawPixel(lpbi,lp,x) \ | |
| ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \ | |
| ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x])) | |
| /*****************************************************************************/ | |
| /* utility functions */ | |
| static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi); | |
| static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi); | |
| static void LoadWideString(UINT id, LPWSTR str, INT len); | |
| static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr); | |
| /* compression functions */ | |
| static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn); | |
| static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi); | |
| static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey); | |
| static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey); | |
| /* decompression functions */ | |
| static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, | |
| LPBYTE lpIn, LPBYTE lpOut); | |
| static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, | |
| LPBYTE lpIn, LPBYTE lpOut); | |
| /* API functions */ | |
| static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPBITMAPINFOHEADER lpbiOut); | |
| static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPCBITMAPINFOHEADER lpbiOut); | |
| static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPCBITMAPINFOHEADER lpbiOut); | |
| static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPCBITMAPINFOHEADER lpbiOut); | |
| static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize); | |
| static LRESULT CompressEnd(CodecInfo *pi); | |
| static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPBITMAPINFOHEADER lpbiOut); | |
| static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPCBITMAPINFOHEADER lpbiOut); | |
| static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPCBITMAPINFOHEADER lpbiOut); | |
| static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize); | |
| static LRESULT DecompressEnd(CodecInfo *pi); | |
| static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPBITMAPINFOHEADER lpbiOut); | |
| /*****************************************************************************/ | |
| static void LoadWideString(UINT id, LPWSTR str, INT len) | |
| { | |
| char szTemp[80]; | |
| LoadStringA(MSRLE32_hModule, id, szTemp, sizeof(szTemp)); | |
| MultiByteToWideChar(CP_ACP, 0, szTemp, -1, str, len); | |
| } | |
| static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi) | |
| { | |
| /* pre-conditions */ | |
| assert(lpbi != NULL); | |
| if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \ | |
| lpbi->biPlanes != 1) | |
| return FALSE; | |
| if (lpbi->biCompression == BI_RLE4) { | |
| if (lpbi->biBitCount != 4 || \ | |
| (lpbi->biWidth % 2) != 0) | |
| return FALSE; | |
| } else if (lpbi->biCompression == BI_RLE8) { | |
| if (lpbi->biBitCount != 8) | |
| return FALSE; | |
| } else | |
| return FALSE; | |
| return TRUE; | |
| } | |
| static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi) | |
| { | |
| /* pre-conditions */ | |
| assert(lpbi != NULL); | |
| /* check structure version/planes/compression */ | |
| if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || | |
| lpbi->biPlanes != 1) | |
| return FALSE; | |
| if (lpbi->biCompression != BI_RGB && | |
| lpbi->biCompression != BI_BITFIELDS) | |
| return FALSE; | |
| /* check bit-depth */ | |
| if (lpbi->biBitCount != 1 && | |
| lpbi->biBitCount != 4 && | |
| lpbi->biBitCount != 8 && | |
| lpbi->biBitCount != 15 && | |
| lpbi->biBitCount != 16 && | |
| lpbi->biBitCount != 24 && | |
| lpbi->biBitCount != 32) | |
| return FALSE; | |
| /* check for size(s) */ | |
| if (!lpbi->biWidth || !lpbi->biHeight) | |
| return FALSE; /* image with zero size, makes no sense so error ! */ | |
| if (DIBWIDTHBYTES(*lpbi) * (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, LPBYTE 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(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width) | |
| { | |
| INT count; | |
| WORD clr1, clr2; | |
| /* pre-conditions */ | |
| assert(lpA && lpB && lDist >= 0 && width > 0); | |
| if (pos >= width) | |
| return 0; | |
| if (pos+1 == width) | |
| return 1; | |
| clr1 = lpB[pos++]; | |
| clr2 = lpB[pos]; | |
| count = 2; | |
| while (pos + 1 < width) { | |
| WORD clr3, clr4; | |
| clr3 = lpB[++pos]; | |
| if (pos + 1 >= width) | |
| return count + 1; | |
| clr4 = lpB[++pos]; | |
| if (ColorCmp(clr1, clr3) <= lDist && | |
| ColorCmp(clr2, clr4) <= lDist) { | |
| /* diff at end? -- look-ahead for 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(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width) | |
| { | |
| INT count; | |
| for (count = 0; pos < width; pos++, count++) { | |
| if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) { | |
| /* diff at end? -- look-ahead for 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(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage) | |
| { | |
| LPBYTE lpOut = *ppOut; | |
| INT count, pos; | |
| WORD clr1, clr2; | |
| /* try to encode as many pixel as possible */ | |
| count = 1; | |
| pos = x; | |
| clr1 = lpC[pos++]; | |
| if (pos < lpbi->biWidth) { | |
| clr2 = lpC[pos]; | |
| for (++count; pos + 1 < lpbi->biWidth; ) { | |
| ++pos; | |
| if (ColorCmp(clr1, lpC[pos]) > lDist) | |
| break; | |
| count++; | |
| if (pos + 1 >= lpbi->biWidth) | |
| break; | |
| ++pos; | |
| if (ColorCmp(clr2, lpC[pos]) > lDist) | |
| break; | |
| count++; | |
| } | |
| } | |
| if (count < 4) { | |
| /* add some pixel for absoluting if possible */ | |
| count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); | |
| 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; | |
| BOOL 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(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage) | |
| { | |
| LPBYTE lpOut = *ppOut; | |
| INT count, pos; | |
| WORD clr; | |
| assert(lpbi->biBitCount <= 8); | |
| assert(lpbi->biCompression == BI_RGB); | |
| /* try to encode as much as possible */ | |
| pos = x; | |
| clr = lpC[pos++]; | |
| for (count = 1; pos < lpbi->biWidth; count++) { | |
| if (ColorCmp(clr, lpC[pos++]) > lDist) | |
| break; | |
| } | |
| if (count < 2) { | |
| /* add some more pixels for absoluting if possible */ | |
| count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); | |
| 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); | |
| BOOL extra_byte = size % 2; | |
| *lpSizeImage += 2 + size + extra_byte; | |
| count -= size; | |
| *lpOut++ = 0; | |
| *lpOut++ = size; | |
| for (i = 0; i < size; i++) { | |
| *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; | |
| x++; | |
| } | |
| if (extra_byte) | |
| *lpOut++ = 0; | |
| } | |
| if (count > 0) { | |
| /* too 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(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE 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(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE 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 a 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(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, | |
| LPBYTE lpIn, LPBYTE lpOut) | |
| { | |
| int bytes_per_pixel; | |
| int line_size; | |
| int pixel_ptr = 0; | |
| int i; | |
| BOOL bEndFlag = FALSE; | |
| assert(pi != NULL); | |
| assert(lpbi != NULL && lpbi->biCompression == BI_RGB); | |
| assert(lpIn != NULL && lpOut != NULL); | |
| bytes_per_pixel = (lpbi->biBitCount + 1) / 8; | |
| line_size = DIBWIDTHBYTES(*lpbi); | |
| do { | |
| BYTE code0, code1; | |
| code0 = *lpIn++; | |
| code1 = *lpIn++; | |
| if (code0 == 0) { | |
| int extra_byte; | |
| switch (code1) { | |
| case 0: /* EOL - end of line */ | |
| pixel_ptr = 0; | |
| lpOut += line_size; | |
| break; | |
| case 1: /* EOI - end of image */ | |
| bEndFlag = TRUE; | |
| break; | |
| case 2: /* skip */ | |
| pixel_ptr += *lpIn++ * bytes_per_pixel; | |
| lpOut += *lpIn++ * line_size; | |
| if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) { | |
| pixel_ptr = 0; | |
| lpOut += line_size; | |
| } | |
| break; | |
| default: /* absolute mode */ | |
| extra_byte = (((code1 + 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(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, | |
| LPBYTE lpIn, LPBYTE lpOut) | |
| { | |
| int bytes_per_pixel; | |
| int line_size; | |
| int pixel_ptr = 0; | |
| BOOL bEndFlag = FALSE; | |
| assert(pi != NULL); | |
| assert(lpbi != NULL && lpbi->biCompression == BI_RGB); | |
| assert(lpIn != NULL && lpOut != NULL); | |
| bytes_per_pixel = (lpbi->biBitCount + 1) / 8; | |
| line_size = DIBWIDTHBYTES(*lpbi); | |
| do { | |
| BYTE code0, code1; | |
| code0 = *lpIn++; | |
| code1 = *lpIn++; | |
| if (code0 == 0) { | |
| int extra_byte; | |
| switch (code1) { | |
| case 0: /* EOL - end of line */ | |
| pixel_ptr = 0; | |
| lpOut += line_size; | |
| break; | |
| case 1: /* EOI - end of image */ | |
| bEndFlag = TRUE; | |
| break; | |
| case 2: /* skip */ | |
| pixel_ptr += *lpIn++ * bytes_per_pixel; | |
| lpOut += *lpIn++ * line_size; | |
| if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) { | |
| pixel_ptr = 0; | |
| lpOut += line_size; | |
| } | |
| break; | |
| default: /* absolute mode */ | |
| if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) { | |
| WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth); | |
| return ICERR_ERROR; | |
| } | |
| extra_byte = code1 & 0x01; | |
| code0 = code1; | |
| while (code0--) { | |
| code1 = *lpIn++; | |
| if (bytes_per_pixel == 1) { | |
| lpOut[pixel_ptr] = pi->palette_map[code1]; | |
| } else if (bytes_per_pixel == 2) { | |
| lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0]; | |
| lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1]; | |
| } else { | |
| lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; | |
| lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; | |
| lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; | |
| } | |
| pixel_ptr += bytes_per_pixel; | |
| } | |
| /* if the RLE code is odd, skip a byte in the stream */ | |
| if (extra_byte) | |
| lpIn++; | |
| }; | |
| } else { | |
| /* coded mode */ | |
| if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) { | |
| WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth); | |
| return ICERR_ERROR; | |
| } | |
| if (bytes_per_pixel == 1) { | |
| code1 = pi->palette_map[code1]; | |
| while (code0--) | |
| lpOut[pixel_ptr++] = code1; | |
| } else if (bytes_per_pixel == 2) { | |
| BYTE hi = pi->palette_map[code1 * 2 + 0]; | |
| BYTE lo = pi->palette_map[code1 * 2 + 1]; | |
| while (code0--) { | |
| lpOut[pixel_ptr + 0] = hi; | |
| lpOut[pixel_ptr + 1] = lo; | |
| pixel_ptr += bytes_per_pixel; | |
| } | |
| } else { | |
| BYTE r = pi->palette_map[code1 * 4 + 2]; | |
| BYTE g = pi->palette_map[code1 * 4 + 1]; | |
| BYTE b = pi->palette_map[code1 * 4 + 0]; | |
| while (code0--) { | |
| lpOut[pixel_ptr + 0] = b; | |
| lpOut[pixel_ptr + 1] = g; | |
| lpOut[pixel_ptr + 2] = r; | |
| pixel_ptr += bytes_per_pixel; | |
| } | |
| } | |
| } | |
| } while (! bEndFlag); | |
| return ICERR_OK; | |
| } | |
| /*****************************************************************************/ | |
| static CodecInfo* Open(LPICOPEN icinfo) | |
| { | |
| CodecInfo* pi = NULL; | |
| if (icinfo == NULL) { | |
| TRACE("(NULL)\n"); | |
| return (LPVOID)0xFFFF0000; | |
| } | |
| TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo, | |
| icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType, | |
| icinfo->fccHandler, (char*)&icinfo->fccHandler, | |
| icinfo->dwVersion,icinfo->dwFlags); | |
| if (icinfo->fccType != ICTYPE_VIDEO) | |
| return NULL; | |
| switch (icinfo->fccHandler) { | |
| case FOURCC_RLE: | |
| case FOURCC_RLE4: | |
| case FOURCC_RLE8: | |
| case FOURCC_MRLE: | |
| break; | |
| case mmioFOURCC('m','r','l','e'): | |
| icinfo->fccHandler = FOURCC_MRLE; | |
| break; | |
| default: | |
| WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n", | |
| icinfo->fccHandler,(char*)&icinfo->fccHandler); | |
| return NULL; | |
| } | |
| pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo)); | |
| if (pi != NULL) { | |
| pi->fccHandler = icinfo->fccHandler; | |
| pi->bCompress = FALSE; | |
| pi->dwQuality = MSRLE32_DEFAULTQUALITY; | |
| pi->nPrevFrame = -1; | |
| pi->pPrevFrame = pi->pCurFrame = NULL; | |
| pi->bDecompress = FALSE; | |
| pi->palette_map = NULL; | |
| } | |
| icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY); | |
| return pi; | |
| } | |
| static LRESULT Close(CodecInfo *pi) | |
| { | |
| TRACE("(%p)\n", pi); | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL) | |
| CompressEnd(pi); | |
| LocalFree((HLOCAL)pi); | |
| return 1; | |
| } | |
| static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize) | |
| { | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| /* check parameters */ | |
| if (icinfo == NULL) | |
| return sizeof(ICINFO); | |
| if (dwSize < sizeof(ICINFO)) | |
| return 0; | |
| icinfo->dwSize = sizeof(ICINFO); | |
| icinfo->fccType = streamtypeVIDEO; | |
| icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE); | |
| icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC; | |
| icinfo->dwVersion = MSRLE32_VERSION; | |
| icinfo->dwVersionICM = 0x01040000; /* Version 1.4 build 0 */ | |
| LoadWideString(IDS_NAME, icinfo->szName, sizeof(icinfo->szName)); | |
| LoadWideString(IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)); | |
| return sizeof(ICINFO); | |
| } | |
| static LRESULT SetQuality(CodecInfo *pi, LONG lQuality) | |
| { | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| if (lQuality == -1) | |
| lQuality = MSRLE32_DEFAULTQUALITY; | |
| else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH) | |
| return ICERR_BADPARAM; | |
| pi->dwQuality = (DWORD)lQuality; | |
| return ICERR_OK; | |
| } | |
| static LRESULT Configure(CodecInfo *pi, HWND hWnd) | |
| { | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| /* FIXME */ | |
| return ICERR_OK; | |
| } | |
| static LRESULT About(CodecInfo *pi, HWND hWnd) | |
| { | |
| CHAR szTitle[20]; | |
| CHAR szAbout[128]; | |
| /* pre-condition */ | |
| assert(MSRLE32_hModule != 0); | |
| LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)); | |
| LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)); | |
| MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION); | |
| return ICERR_OK; | |
| } | |
| static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPBITMAPINFOHEADER lpbiOut) | |
| { | |
| LRESULT size; | |
| TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| /* check parameters -- need 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(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 = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD)); | |
| if (pi->pPrevFrame == NULL) | |
| return ICERR_MEMORY; | |
| pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD)); | |
| if (pi->pCurFrame == NULL) { | |
| CompressEnd(pi); | |
| return ICERR_MEMORY; | |
| } | |
| pi->nPrevFrame = -1; | |
| pi->bCompress = TRUE; | |
| rgbIn = (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 = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed); | |
| if (pi->palette_map == NULL) { | |
| CompressEnd(pi); | |
| return ICERR_MEMORY; | |
| } | |
| for (i = 0; i < lpbiIn->biClrUsed; i++) { | |
| pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]); | |
| } | |
| break; | |
| }; | |
| return ICERR_OK; | |
| } | |
| static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize) | |
| { | |
| int i; | |
| TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize); | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| /* check parameters */ | |
| if (lpic == NULL || dwSize < sizeof(ICCOMPRESS)) | |
| return ICERR_BADPARAM; | |
| if (!lpic->lpbiOutput || !lpic->lpOutput || | |
| !lpic->lpbiInput || !lpic->lpInput) | |
| return ICERR_BADPARAM; | |
| TRACE("lpic={0x%lX,%p,%p,%p,%p,%p,%p,%ld,%lu,%lu,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev); | |
| if (! pi->bCompress) { | |
| LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput); | |
| if (hr != ICERR_OK) | |
| return hr; | |
| } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK) | |
| return ICERR_BADFORMAT; | |
| if (lpic->lFrameNum >= pi->nPrevFrame + 1) { | |
| /* we continue in the sequence so we need to initialize | |
| * our internal framedata */ | |
| computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput); | |
| } else if (lpic->lFrameNum == pi->nPrevFrame) { | |
| /* Oops, compress same frame again ? Okay, as you wish. | |
| * No need to recompute internal framedata, because we only swapped buffers */ | |
| LPWORD pTmp = pi->pPrevFrame; | |
| pi->pPrevFrame = pi->pCurFrame; | |
| pi->pCurFrame = pTmp; | |
| } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) { | |
| LPWORD pTmp; | |
| WARN(": prev=%ld cur=%ld 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=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum); | |
| computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev); | |
| /* swap buffers for current and previous frame */ | |
| /* Don't free and alloc new -- costs to much time and they are of equal size ! */ | |
| pTmp = pi->pPrevFrame; | |
| pi->pPrevFrame = pi->pCurFrame; | |
| pi->pCurFrame = pTmp; | |
| pi->nPrevFrame = lpic->lFrameNum; | |
| } | |
| for (i = 0; i < 3; i++) { | |
| SetQuality(pi, lpic->dwQuality); | |
| lpic->lpbiOutput->biSizeImage = 0; | |
| if (lpic->lpbiOutput->biBitCount == 4) | |
| MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, | |
| lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0); | |
| else | |
| MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, | |
| lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0); | |
| if (lpic->dwFrameSize == 0 || | |
| lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) | |
| break; | |
| if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) { | |
| if (lpic->lpbiOutput->biBitCount == 4) | |
| MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, | |
| lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE); | |
| else | |
| MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, | |
| lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE); | |
| if (lpic->dwFrameSize == 0 || | |
| lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) { | |
| WARN("switched to keyframe, was small enough!\n"); | |
| *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME; | |
| *lpic->lpckid = MAKEAVICKID(cktypeDIBbits, | |
| StreamFromFOURCC(*lpic->lpckid)); | |
| break; | |
| } | |
| } | |
| if (lpic->dwQuality < 1000) | |
| break; | |
| lpic->dwQuality -= 1000; /* reduce quality by 10% */ | |
| } | |
| { /* swap buffer for current and previous frame */ | |
| /* Don't free and alloc new -- costs to much time and they are of equal size ! */ | |
| register LPWORD pTmp = pi->pPrevFrame; | |
| pi->pPrevFrame = pi->pCurFrame; | |
| pi->pCurFrame = pTmp; | |
| pi->nPrevFrame = lpic->lFrameNum; | |
| } | |
| return ICERR_OK; | |
| } | |
| static LRESULT CompressEnd(CodecInfo *pi) | |
| { | |
| TRACE("(%p)\n",pi); | |
| if (pi != NULL) { | |
| if (pi->pPrevFrame != NULL) | |
| GlobalFreePtr(pi->pPrevFrame); | |
| if (pi->pCurFrame != NULL) | |
| GlobalFreePtr(pi->pCurFrame); | |
| pi->pPrevFrame = NULL; | |
| pi->pCurFrame = NULL; | |
| pi->nPrevFrame = -1; | |
| pi->bCompress = FALSE; | |
| } | |
| return ICERR_OK; | |
| } | |
| static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPBITMAPINFOHEADER lpbiOut) | |
| { | |
| 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 = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed); | |
| if (pi->palette_map == NULL) | |
| return ICERR_MEMORY; | |
| for (i = 0; i < lpbiIn->biClrUsed; i++) { | |
| pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]); | |
| } | |
| break; | |
| case 15: | |
| case 16: | |
| pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2); | |
| if (pi->palette_map == NULL) | |
| return ICERR_MEMORY; | |
| for (i = 0; i < lpbiIn->biClrUsed; i++) { | |
| WORD color; | |
| if (lpbiOut->biBitCount == 15) | |
| color = ((rgbIn[i].rgbRed >> 3) << 10) | |
| | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3); | |
| else | |
| color = ((rgbIn[i].rgbRed >> 3) << 11) | |
| | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3); | |
| pi->palette_map[i * 2 + 1] = color >> 8; | |
| pi->palette_map[i * 2 + 0] = color & 0xFF; | |
| }; | |
| break; | |
| case 24: | |
| case 32: | |
| pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD)); | |
| if (pi->palette_map == NULL) | |
| return ICERR_MEMORY; | |
| memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD)); | |
| break; | |
| }; | |
| pi->bDecompress = TRUE; | |
| return ICERR_OK; | |
| } | |
| static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize) | |
| { | |
| TRACE("(%p,%p,%lu)\n",pi,pic,dwSize); | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| /* check parameters */ | |
| if (pic == NULL) | |
| return ICERR_BADPARAM; | |
| if (pic->lpbiInput == NULL || pic->lpInput == NULL || | |
| pic->lpbiOutput == NULL || pic->lpOutput == NULL) | |
| return ICERR_BADPARAM; | |
| /* check formats */ | |
| if (! pi->bDecompress) { | |
| LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput); | |
| if (hr != ICERR_OK) | |
| return hr; | |
| } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK) | |
| return ICERR_BADFORMAT; | |
| assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth); | |
| assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight); | |
| pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight; | |
| if (pic->lpbiInput->biBitCount == 4) | |
| return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput); | |
| else | |
| return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput); | |
| } | |
| static LRESULT DecompressEnd(CodecInfo *pi) | |
| { | |
| TRACE("(%p)\n",pi); | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| pi->bDecompress = FALSE; | |
| if (pi->palette_map != NULL) { | |
| LocalFree((HLOCAL)pi->palette_map); | |
| pi->palette_map = NULL; | |
| } | |
| return ICERR_OK; | |
| } | |
| static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, | |
| LPBITMAPINFOHEADER lpbiOut) | |
| { | |
| int size; | |
| TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); | |
| /* pre-condition */ | |
| assert(pi != NULL); | |
| /* check parameters */ | |
| if (lpbiIn == NULL || lpbiOut == NULL) | |
| return ICERR_BADPARAM; | |
| if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) | |
| return ICERR_BADFORMAT; | |
| if (lpbiOut->biBitCount > 8) | |
| return ICERR_ERROR; | |
| if (lpbiIn->biBitCount <= 8) { | |
| if (lpbiIn->biClrUsed > 0) | |
| size = lpbiIn->biClrUsed; | |
| else | |
| size = (1 << lpbiIn->biBitCount); | |
| lpbiOut->biClrUsed = size; | |
| memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (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 dwDrvID, HDRVR hDrv, UINT uMsg, | |
| LPARAM lParam1, LPARAM lParam2) | |
| { | |
| CodecInfo *pi = (CodecInfo*)dwDrvID; | |
| TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID)dwDrvID, (LPVOID)hDrv, | |
| uMsg, lParam1, lParam2); | |
| switch (uMsg) { | |
| /* standard driver messages */ | |
| case DRV_LOAD: | |
| return DRVCNF_OK; | |
| case DRV_OPEN: | |
| if (lParam2 == 0) | |
| return (LRESULT)0xFFFF0000; | |
| else | |
| return (LRESULT)Open((ICOPEN*)lParam2); | |
| case DRV_CLOSE: | |
| if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL) | |
| Close(pi); | |
| return DRVCNF_OK; | |
| case DRV_ENABLE: | |
| case DRV_DISABLE: | |
| return DRVCNF_OK; | |
| case DRV_FREE: | |
| return DRVCNF_OK; | |
| case DRV_QUERYCONFIGURE: | |
| return DRVCNF_CANCEL; /* FIXME */ | |
| case DRV_CONFIGURE: | |
| return DRVCNF_OK; /* FIXME */ | |
| case DRV_INSTALL: | |
| case DRV_REMOVE: | |
| return DRVCNF_OK; | |
| /* installable compression manager messages */ | |
| case ICM_CONFIGURE: | |
| FIXME("ICM_CONFIGURE (%ld)\n",lParam1); | |
| if (lParam1 == -1) | |
| return ICERR_UNSUPPORTED; /* FIXME */ | |
| else | |
| return Configure(pi, (HWND)lParam1); | |
| case ICM_ABOUT: | |
| if (lParam1 == -1) | |
| return ICERR_OK; | |
| else | |
| return About(pi, (HWND)lParam1); | |
| case ICM_GETSTATE: | |
| case ICM_SETSTATE: | |
| return 0; /* no state */ | |
| case ICM_GETINFO: | |
| return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2); | |
| case ICM_GETDEFAULTQUALITY: | |
| if ((LPVOID)lParam1 != NULL) { | |
| *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY; | |
| return ICERR_OK; | |
| } | |
| break; | |
| case ICM_GETQUALITY: | |
| if ((LPVOID)lParam1 != NULL) { | |
| *((LPDWORD)lParam1) = pi->dwQuality; | |
| return ICERR_OK; | |
| } | |
| break; | |
| case ICM_SETQUALITY: | |
| return SetQuality(pi, *(LPLONG)lParam1); | |
| 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,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved); | |
| switch (dwReason) { | |
| case DLL_PROCESS_ATTACH: | |
| DisableThreadLibraryCalls(hModule); | |
| MSRLE32_hModule = hModule; | |
| break; | |
| case DLL_PROCESS_DETACH: | |
| break; | |
| }; | |
| return TRUE; | |
| } |