diff --git a/configure b/configure index 01e67850448..6948245eab3 100755 --- a/configure +++ b/configure @@ -14207,7 +14207,7 @@ MAKE_TEST_RULES=dlls/Maketest.rules MAKE_PROG_RULES=programs/Makeprog.rules -ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile unicode/Makefile" +ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile unicode/Makefile" cat >confcache <<\_ACEOF @@ -14728,10 +14728,10 @@ do "dlls/msimg32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msimg32/Makefile" ;; "dlls/msisys/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msisys/Makefile" ;; "dlls/msnet32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msnet32/Makefile" ;; - "dlls/msrle32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msrle32/Makefile" ;; "dlls/msvcrt/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msvcrt/Makefile" ;; "dlls/msvcrt20/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msvcrt20/Makefile" ;; "dlls/msvideo/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msvideo/Makefile" ;; + "dlls/msvideo/msrle32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/msvideo/msrle32/Makefile" ;; "dlls/netapi32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/netapi32/Makefile" ;; "dlls/netapi32/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/netapi32/tests/Makefile" ;; "dlls/ntdll/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/ntdll/Makefile" ;; diff --git a/configure.ac b/configure.ac index c042513c62e..ee10f788e0b 100644 --- a/configure.ac +++ b/configure.ac @@ -1412,10 +1412,10 @@ dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile -dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile +dlls/msvideo/msrle32/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile diff --git a/dlls/Makefile.in b/dlls/Makefile.in index e83e549329d..6ef9ddfcb18 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -47,10 +47,10 @@ BASEDIRS = \ msimg32 \ msisys \ msnet32 \ - msrle32 \ msvcrt \ msvcrt20 \ msvideo \ + msvideo/msrle32 \ netapi32 \ ntdll \ odbc32 \ @@ -396,8 +396,8 @@ msisys.ocx$(DLLEXT): msisys/msisys.ocx$(DLLEXT) msnet32.dll$(DLLEXT): msnet32/msnet32.dll$(DLLEXT) $(RM) $@ && $(LN_S) msnet32/msnet32.dll$(DLLEXT) $@ -msrle32.dll$(DLLEXT): msrle32/msrle32.dll$(DLLEXT) - $(RM) $@ && $(LN_S) msrle32/msrle32.dll$(DLLEXT) $@ +msrle32.dll$(DLLEXT): msvideo/msrle32/msrle32.dll$(DLLEXT) + $(RM) $@ && $(LN_S) msvideo/msrle32/msrle32.dll$(DLLEXT) $@ msvcrt.dll$(DLLEXT): msvcrt/msvcrt.dll$(DLLEXT) $(RM) $@ && $(LN_S) msvcrt/msvcrt.dll$(DLLEXT) $@ @@ -605,7 +605,7 @@ msacm/msg711/msg711.acm$(DLLEXT): msacm/msg711 msimg32/msimg32.dll$(DLLEXT): msimg32 msisys/msisys.ocx$(DLLEXT): msisys msnet32/msnet32.dll$(DLLEXT): msnet32 -msrle32/msrle32.dll$(DLLEXT): msrle32 +msvideo/msrle32/msrle32.dll$(DLLEXT): msvideo/msrle32 msvcrt/msvcrt.dll$(DLLEXT): msvcrt msvcrt20/msvcrt20.dll$(DLLEXT): msvcrt20 msvideo/msvfw32.dll$(DLLEXT): msvideo @@ -704,7 +704,7 @@ msacm/msg711/__install__: msg711.acm$(DLLEXT) msimg32/__install__: msimg32.dll$(DLLEXT) msisys/__install__: msisys.ocx$(DLLEXT) msnet32/__install__: msnet32.dll$(DLLEXT) -msrle32/__install__: msrle32.dll$(DLLEXT) +msvideo/msrle32/__install__: msrle32.dll$(DLLEXT) msvcrt/__install__: msvcrt.dll$(DLLEXT) msvcrt20/__install__: msvcrt20.dll$(DLLEXT) msvideo/__install__: msvfw32.dll$(DLLEXT) @@ -762,7 +762,7 @@ x11drv/__install__: x11drv.dll$(DLLEXT) # Inter-dll dependencies advapi32: kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT) -avicap32: kernel32.dll$(DLLEXT) +avicap32: ntdll.dll$(DLLEXT) avifil32: msvfw32.dll$(DLLEXT) kernel32.dll$(DLLEXT) comcat: ole32.dll$(DLLEXT) user32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) comctl32: user32.dll$(DLLEXT) gdi32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) \ @@ -799,9 +799,9 @@ msdmo: kernel32.dll$(DLLEXT) msimg32: kernel32.dll$(DLLEXT) msisys: kernel32.dll$(DLLEXT) msnet32: kernel32.dll$(DLLEXT) -msrle32: kernel32.dll$(DLLEXT) msvcrt20: msvcrt.dll$(DLLEXT) msvcrt: kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT) +msvideo/msrle32: winmm.dll$(DLLEXT) user32.dll$(DLLEXT) kernel32.dll$(DLLEXT) msvideo: winmm.dll$(DLLEXT) comctl32.dll$(DLLEXT) version.dll$(DLLEXT) user32.dll$(DLLEXT) \ gdi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) netapi32: advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) diff --git a/dlls/msrle32/msrle32.c b/dlls/msrle32/msrle32.c deleted file mode 100644 index f67dd033a4d..00000000000 --- a/dlls/msrle32/msrle32.c +++ /dev/null @@ -1 +0,0 @@ -/* all codes are removed by author */ diff --git a/dlls/msrle32/msrle32.spec b/dlls/msrle32/msrle32.spec deleted file mode 100644 index 345368e4bbc..00000000000 --- a/dlls/msrle32/msrle32.spec +++ /dev/null @@ -1 +0,0 @@ -@ stub DriverProc #(long long long long long) diff --git a/dlls/msrle32/.cvsignore b/dlls/msvideo/msrle32/.cvsignore similarity index 82% rename from dlls/msrle32/.cvsignore rename to dlls/msvideo/msrle32/.cvsignore index 7ee5ee5cb8b..95fd6c46f00 100644 --- a/dlls/msrle32/.cvsignore +++ b/dlls/msvideo/msrle32/.cvsignore @@ -1,3 +1,4 @@ Makefile msrle32.dll.dbg.c msrle32.spec.c +rsrc.res diff --git a/dlls/msrle32/Makefile.in b/dlls/msvideo/msrle32/Makefile.in similarity index 73% rename from dlls/msrle32/Makefile.in rename to dlls/msvideo/msrle32/Makefile.in index 0717476c57b..2dd74b949d6 100644 --- a/dlls/msrle32/Makefile.in +++ b/dlls/msvideo/msrle32/Makefile.in @@ -1,14 +1,17 @@ TOPSRCDIR = @top_srcdir@ -TOPOBJDIR = ../.. +TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msrle32.dll +IMPORTS = winmm user32 kernel32 LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = msrle32.c +RC_SRCS = rsrc.rc + @MAKE_DLL_RULES@ ### Dependencies: diff --git a/dlls/msvideo/msrle32/msrle32.c b/dlls/msvideo/msrle32/msrle32.c new file mode 100644 index 00000000000..039f7cf7676 --- /dev/null +++ b/dlls/msvideo/msrle32/msrle32.c @@ -0,0 +1,1877 @@ +/* + * Copyright 2002 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: + * - compression of RLE4 is buggy -- see FIXME's + * - many improvements possible + * - implement DecompressSetPalette? -- does we need it for anything? + */ + +#include + +#include "msrle_private.h" + +#include "winnls.h" +#include "winuser.h" +#include "windowsx.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msrle32); + +static HINSTANCE MSRLE32_hModule = 0; + +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#define SQR(a) ((a) * (a)) + +#define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q) +inline WORD ColorCmp(WORD clr1, WORD clr2) +{ + register UINT a = (clr1-clr2); + return SQR(a); +} +inline WORD Intensity(RGBQUAD clr) +{ + return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4; +} + +#define GetRawPixel(lpbi,lp,x) \ + ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \ + ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x])) + +/*****************************************************************************/ + +/* utility functions */ +static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi); +static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi); +static void LoadWideString(UINT id, LPWSTR str, INT len); +static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr); + +/* compression functions */ +static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn); +static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi); +static LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey); +static LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey); + +/* decompression functions */ +static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, + LPBYTE lpIn, LPBYTE lpOut); +static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, + LPBYTE lpIn, LPBYTE lpOut); + +/* API functions */ +static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPBITMAPINFOHEADER lpbiOut); +static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut); +static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut); +static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut); +static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize); +static LRESULT CompressEnd(CodecInfo *pi); + +static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPBITMAPINFOHEADER lpbiOut); +static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut); +static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut); +static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize); +static LRESULT DecompressEnd(CodecInfo *pi); +static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPBITMAPINFOHEADER lpbiOut); + +/*****************************************************************************/ + +static void LoadWideString(UINT id, LPWSTR str, INT len) +{ + char szTemp[80]; + + LoadStringA(MSRLE32_hModule, id, szTemp, sizeof(szTemp)); + MultiByteToWideChar(CP_ACP, 0, szTemp, -1, str, len); +} + +static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi) +{ + /* pre-conditions */ + assert(lpbi != NULL); + + if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || \ + lpbi->biPlanes != 1) + return FALSE; + + if (lpbi->biCompression == BI_RLE4) { + if (lpbi->biBitCount != 4 || \ + (lpbi->biWidth % 2) != 0) + return FALSE; + } else if (lpbi->biCompression == BI_RLE8) { + if (lpbi->biBitCount != 8) + return FALSE; + } else + return FALSE; + + return TRUE; +} + +static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi) +{ + /* pre-conditions */ + assert(lpbi != NULL); + + /* check structure version/planes/compression */ + if (lpbi->biSize < sizeof(BITMAPINFOHEADER) || + lpbi->biPlanes != 1) + return FALSE; + if (lpbi->biCompression != BI_RGB && + lpbi->biCompression != BI_BITFIELDS) + return FALSE; + + /* check bit-depth */ + if (lpbi->biBitCount != 1 && + lpbi->biBitCount != 4 && + lpbi->biBitCount != 8 && + lpbi->biBitCount != 15 && + lpbi->biBitCount != 16 && + lpbi->biBitCount != 24 && + lpbi->biBitCount != 32) + return FALSE; + + /* check for size(s) */ + if (!lpbi->biWidth || !lpbi->biHeight) + return FALSE; /* image with zero size, makes no sense so error ! */ + if (DIBWIDTHBYTES(*lpbi) * lpbi->biHeight >= (1UL << 31) - 1) + return FALSE; /* image too big ! */ + + /* check for non existing colortable for hi- and true-color DIB's */ + if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0) + return FALSE; + + return TRUE; +} + +static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr) +{ + INT diff = 0x00FFFFFF; + UINT i; + UINT index = 0; + + /* pre-conditions */ + assert(clrs != NULL); + + for (i = 0; i < count; i++) { + int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed); + int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen); + int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue); + + r = r*r + g*g + b*b; + + if (r < diff) { + index = i; + diff = r; + if (diff == 0) + break; + } + } + + return index; +} + +/*****************************************************************************/ + +void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, LPBYTE lpIn) +{ + WORD wIntensityTbl[256]; + LONG lInLine, lOutLine; + LPWORD lpOut; + int i, y; + + /* pre-conditions */ + assert(pi != NULL && lpbiIn != NULL && lpIn != NULL); + assert(pi->pCurFrame != NULL); + + lInLine = DIBWIDTHBYTES(*lpbiIn); + lOutLine = WIDTHBYTES(lpbiIn->biWidth * 8*sizeof(WORD)) / 2; + lpOut = pi->pCurFrame; + + assert(lpbiIn->biClrUsed != 0); + + { + const RGBQUAD *lp = (LPRGBQUAD)((LPBYTE)lpbiIn + lpbiIn->biSize); + + for (i = 0; i < lpbiIn->biClrUsed; i++) + wIntensityTbl[i] = Intensity(lp[i]); + } + + for (y = 0; y < lpbiIn->biHeight; y++) { + int x; + + switch (lpbiIn->biBitCount) { + case 1: + for (x = 0; x < lpbiIn->biWidth; x += 8) { + for (i = 0; i < 7; i++) + lpOut[x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1]; + } + break; + case 4: + for (x = 0; x < lpbiIn->biWidth; x += 2) { + lpOut[x + 0] = wIntensityTbl[(lpIn[x] >> 4)]; + lpOut[x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)]; + } + break; + case 8: + for (x = 0; x < lpbiIn->biWidth; x++) + lpOut[x] = wIntensityTbl[lpIn[x]]; + break; + } + + lpIn += lInLine; + lpOut += lOutLine; + } +} + +static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi) +{ + LONG a, b, size; + + /* pre-condition */ + assert(lpbi != NULL); + + a = lpbi->biWidth / 255; + b = lpbi->biWidth % 255; + if (lpbi->biBitCount <= 4) { + a /= 2; + b /= 2; + } + + size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2))); + return size * lpbi->biHeight; +} + +/* lpP => current pos in previous frame + * lpA => previous pos in current frame + * lpB => current pos in current frame + */ +static INT countDiffRLE4(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width) +{ + INT count; + WORD clr1, clr2; + + /* pre-conditions */ + assert(lpA && lpB && lDist >= 0 && width > 0); + + if (pos >= width) + return 0; + if (pos+1 == width) + return 1; + + clr1 = lpB[pos++]; + clr2 = lpB[pos]; + + count = 2; + while (pos + 1 < width) { + WORD clr3, clr4; + + clr3 = lpB[++pos]; + if (pos + 1 >= width) + return count + 1; + + clr4 = lpB[++pos]; + if (ColorCmp(clr1, clr3) <= lDist && + ColorCmp(clr2, clr4) <= lDist) { + /* diff at end? -- look-ahead for atleast ?? more encodable pixel */ + + /* FIXME */ + + return count; + } else if (lpP && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { + /* 'compare' with previous frame for end of diff */ + INT count2 = 0; + + /* FIXME */ + + if (count2 >= 4) + return count; + + pos -= count2; + } + + count += 2; + clr1 = clr3; + clr2 = clr4; + } + + return count; +} + +/* lpP => current pos in previous frame + * lpA => previous pos in current frame + * lpB => current pos in current frame + */ +static INT countDiffRLE8(LPWORD lpP, LPWORD lpA, LPWORD lpB, INT pos, LONG lDist, LONG width) +{ + INT count; + + for (count = 0; pos < width; pos++, count++) { + if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) { + /* diff at end? -- look-ahead for atleast one more encodable pixel */ + if (pos + 1 < width && ColorCmp(lpA[pos], lpB[pos+1]) <= lDist) + return count; + } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) { + /* 'compare' with previous frame for end of diff */ + INT count2 = 0; + + for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) { + if (ColorCmp(lpP[pos], lpB[pos]) > lDist) + break; + } + if (count2 > 4) + return count; + + pos -= count2; + } + } + + return count; +} + +static INT MSRLE32_CompressRLE4Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage) +{ + LPBYTE lpOut = *ppOut; + INT count, pos; + WORD clr1, clr2; + + /* try to encode as many pixel as possible */ + count = 1; + pos = x; + clr1 = lpC[pos++]; + if (pos < lpbi->biWidth) { + clr2 = lpC[pos]; + for (++count; pos + 1 < lpbi->biWidth; ) { + ++pos; + if (ColorCmp(clr1, lpC[pos]) > lDist) + break; + count++; + if (pos + 1 >= lpbi->biWidth) + break; + ++pos; + if (ColorCmp(clr2, lpC[pos]) > lDist) + break; + count++; + } + } + + if (count < 4) { + /* add some pixel for absoluting if possible */ + count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); + + /* check for near end of line */ + if (x + count > lpbi->biWidth) + count = lpbi->biWidth - x; + + /* absolute pixel(s) in groups of atleast 3 and maximal 254 pixel */ + while (count > 2) { + INT i; + INT size = min(count, 254); + BOOL extra_byte = size % 2; + + *lpSizeImage += 2 + size + extra_byte; + count -= size; + *lpOut++ = 0; + *lpOut++ = size; + for (i = 0; i < size; i += 2) { + clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + if (i + 1 < size) { + clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + } else + clr2 = 0; + + *lpOut++ = (clr1 << 4) | clr2; + } + if (extra_byte) + *lpOut++ = 0; + } + + if (count > 0) { + /* too less for absoluting so we must encode them */ + assert(count <= 2); + + *lpSizeImage += 2; + clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + if (count == 2) { + clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + } else + clr2 = 0; + *lpOut++ = count; + *lpOut++ = (clr1 << 4) | clr2; + } + } else { + /* encode count pixel(s) */ + clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) | + pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]); + + x += count; + while (count > 0) { + INT size = min(count, 254); + + *lpSizeImage += 2; + count -= size; + *lpOut++ = size; + *lpOut++ = clr1; + } + } + + *ppOut = lpOut; + + return x; +} + +static INT MSRLE32_CompressRLE8Line(CodecInfo *pi, LPWORD lpP, LPWORD lpC, LPCBITMAPINFOHEADER lpbi, BYTE *lpIn, LONG lDist, INT x, LPBYTE *ppOut, DWORD *lpSizeImage) +{ + LPBYTE lpOut = *ppOut; + INT count, pos; + WORD clr; + + assert(lpbi->biBitCount <= 8); + assert(lpbi->biCompression == BI_RGB); + + /* try to encode as much as possible */ + pos = x; + clr = lpC[pos++]; + for (count = 1; pos < lpbi->biWidth; count++) { + if (ColorCmp(clr, lpC[pos++]) > lDist) + break; + } + + if (count < 2) { + /* add some more pixels for absoluting if possible */ + count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth); + + /* check for over end of line */ + if (x + count > lpbi->biWidth) + count = lpbi->biWidth - x; + + /* absolute pixel(s) in groups of atleast 3 and maximal 255 pixels */ + while (count > 2) { + INT i; + INT size = min(count, 255); + BOOL extra_byte = size % 2; + + *lpSizeImage += 2 + size + extra_byte; + count -= size; + *lpOut++ = 0; + *lpOut++ = size; + for (i = 0; i < size; i++) { + *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + } + if (extra_byte) + *lpOut++ = 0; + } + if (count > 0) { + /* too less for absoluting so we must encode them even if it's expensive! */ + assert(count <= 2); + + *lpSizeImage += 2 * count; + *lpOut++ = 1; + *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + + if (count == 2) { + *lpOut++ = 1; + *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + x++; + } + } + } else { + /* encode count pixel(s) */ + clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)]; + + /* optimize end of line */ + if (x + count + 1 == lpbi->biWidth) + count++; + + x += count; + while (count > 0) { + INT size = min(count, 255); + + *lpSizeImage += 2; + count -= size; + *lpOut++ = size; + *lpOut++ = clr; + } + } + + *ppOut = lpOut; + + return x; +} + +LRESULT MSRLE32_CompressRLE4(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey) +{ + LPWORD lpC; + LONG lLine, lInLine, lDist; + + /* pre-conditions */ + assert(pi != NULL && lpbiOut != NULL); + assert(lpIn != NULL && lpOut != NULL); + assert(pi->pCurFrame != NULL); + + lpC = pi->pCurFrame; + lDist = QUALITY_to_DIST(pi->dwQuality); + lInLine = DIBWIDTHBYTES(*lpbiIn); + lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2; + + lpbiOut->biSizeImage = 0; + if (isKey) { + /* keyframe -- convert internal frame to output format */ + INT x, y; + + for (y = 0; y < lpbiOut->biHeight; y++) { + x = 0; + + do { + x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x, + &lpOut, &lpbiOut->biSizeImage); + } while (x < lpbiOut->biWidth); + + lpC += lLine; + lpIn += lInLine; + + /* add EOL -- end of line */ + lpbiOut->biSizeImage += 2; + *((LPWORD)lpOut)++ = 0; + } + } else { + /* delta-frame -- compute delta between last and this internal frame */ + LPWORD lpP; + INT x, y; + INT jumpx, jumpy; + + assert(pi->pPrevFrame != NULL); + + lpP = pi->pPrevFrame; + jumpy = 0; + jumpx = -1; + + for (y = 0; y < lpbiOut->biHeight; y++) { + x = 0; + + do { + INT count, pos; + + if (jumpx == -1) + jumpx = x; + for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) { + if (ColorCmp(lpP[pos], lpC[pos]) > lDist) + break; + } + + if (pos == lpbiOut->biWidth && count > 8) { + /* (count > 8) secures that we will save space */ + jumpy++; + break; + } else if (jumpy || jumpx != pos) { + /* time to jump */ + assert(jumpx != -1); + + if (pos < jumpx) { + /* can only jump in positive direction -- jump until EOL, EOL */ + INT w = lpbiOut->biWidth - jumpx; + + assert(jumpy > 0); + assert(w >= 4); + + jumpx = 0; + jumpy--; + /* if (w % 255 == 2) then equal costs + * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive + * else it will be cheaper + */ + while (w > 0) { + lpbiOut->biSizeImage += 4; + *lpOut++ = 0; + *lpOut++ = 2; + *lpOut = min(w, 255); + w -= *lpOut++; + *lpOut++ = 0; + } + /* add EOL -- end of line */ + lpbiOut->biSizeImage += 2; + *((LPWORD)lpOut)++ = 0; + } + + /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */ + + /* write out real jump(s) */ + while (jumpy || pos != jumpx) { + lpbiOut->biSizeImage += 4; + *lpOut++ = 0; + *lpOut++ = 2; + *lpOut = min(pos - jumpx, 255); + x += *lpOut; + jumpx += *lpOut++; + *lpOut = min(jumpy, 255); + jumpy -= *lpOut++; + } + + jumpy = 0; + } + + jumpx = -1; + + if (x < lpbiOut->biWidth) { + /* skipped the 'same' things corresponding to previous frame */ + x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x, + &lpOut, &lpbiOut->biSizeImage); + } + } while (x < lpbiOut->biWidth); + + lpP += lLine; + lpC += lLine; + lpIn += lInLine; + + if (jumpy == 0) { + assert(jumpx == -1); + + /* add EOL -- end of line */ + lpbiOut->biSizeImage += 2; + *((LPWORD)lpOut)++ = 0; + } + } + } + + /* add EOI -- end of image */ + lpbiOut->biSizeImage += 2; + *lpOut++ = 0; + *lpOut++ = 1; + + return ICERR_OK; +} + +LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey) +{ + LPWORD lpC; + LONG lDist, lInLine, lLine; + + assert(pi != NULL && lpbiOut != NULL); + assert(lpIn != NULL && lpOut != NULL); + assert(pi->pCurFrame != NULL); + + lpC = pi->pCurFrame; + lDist = QUALITY_to_DIST(pi->dwQuality); + lInLine = DIBWIDTHBYTES(*lpbiIn); + lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2; + + lpbiOut->biSizeImage = 0; + if (isKey) { + /* keyframe -- convert internal frame to output format */ + INT x, y; + + for (y = 0; y < lpbiOut->biHeight; y++) { + x = 0; + + do { + x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x, + &lpOut, &lpbiOut->biSizeImage); + } while (x < lpbiOut->biWidth); + + lpC += lLine; + lpIn += lInLine; + + /* add EOL -- end of line */ + lpbiOut->biSizeImage += 2; + *((LPWORD)lpOut)++ = 0; + } + } else { + /* delta-frame -- compute delta between last and this internal frame */ + LPWORD lpP; + INT x, y; + INT jumpx, jumpy; + + assert(pi->pPrevFrame != NULL); + + lpP = pi->pPrevFrame; + jumpx = -1; + jumpy = 0; + + for (y = 0; y < lpbiOut->biHeight; y++) { + x = 0; + + do { + INT count, pos; + + if (jumpx == -1) + jumpx = x; + for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) { + if (ColorCmp(lpP[pos], lpC[pos]) > lDist) + break; + } + + if (pos == lpbiOut->biWidth && count > 4) { + /* (count > 4) secures that we will save space */ + jumpy++; + break; + } else if (jumpy || jumpx != pos) { + /* time to jump */ + assert(jumpx != -1); + + if (pos < jumpx) { + /* can only jump in positive direction -- do a EOL then jump */ + assert(jumpy > 0); + + jumpx = 0; + jumpy--; + + /* add EOL -- end of line */ + lpbiOut->biSizeImage += 2; + *((LPWORD)lpOut)++ = 0; + } + + /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */ + + /* write out real jump(s) */ + while (jumpy || pos != jumpx) { + lpbiOut->biSizeImage += 4; + *lpOut++ = 0; + *lpOut++ = 2; + *lpOut = min(pos - jumpx, 255); + jumpx += *lpOut++; + *lpOut = min(jumpy, 255); + jumpy -= *lpOut++; + } + x = pos; + + jumpy = 0; + } + + jumpx = -1; + + if (x < lpbiOut->biWidth) { + /* skip the 'same' things corresponding to previous frame */ + x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x, + &lpOut, &lpbiOut->biSizeImage); + } + } while (x < lpbiOut->biWidth); + + lpP += lLine; + lpC += lLine; + lpIn += lInLine; + + if (jumpy == 0) { + /* add EOL -- end of line */ + lpbiOut->biSizeImage += 2; + *lpOut++ = 0; + *lpOut++ = 0; + } + } + } + + /* add EOI -- end of image */ + lpbiOut->biSizeImage += 2; + *lpOut++ = 0; + *lpOut++ = 1; + + return ICERR_OK; +} + +/*****************************************************************************/ + +static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, + LPBYTE lpIn, LPBYTE lpOut) +{ + int bytes_per_pixel; + int line_size; + int pixel_ptr = 0; + int i; + BOOL bEndFlag = FALSE; + + assert(pi != NULL); + assert(lpbi != NULL && lpbi->biCompression == BI_RGB); + assert(lpIn != NULL && lpOut != NULL); + + bytes_per_pixel = (lpbi->biBitCount + 1) / 8; + line_size = DIBWIDTHBYTES(*lpbi); + + do { + BYTE code0, code1; + + code0 = *lpIn++; + code1 = *lpIn++; + + if (code0 == 0) { + int extra_byte; + + switch (code1) { + case 0: /* EOL - end of line */ + pixel_ptr = 0; + lpOut += line_size; + break; + case 1: /* EOI - end of image */ + bEndFlag = TRUE; + break; + case 2: /* skip */ + pixel_ptr += *lpIn++ * bytes_per_pixel; + lpOut += *lpIn++ * line_size; + if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) { + pixel_ptr = 0; + lpOut += line_size; + } + break; + default: /* absolute mode */ + extra_byte = (code1 / 2) & 0x01; + + if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) + return ICERR_ERROR; + + code0 = code1; + for (i = 0; i < code0 / 2; i++) { + if (bytes_per_pixel == 1) { + code1 = lpIn[i]; + lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)]; + if (2 * i <= code0) + lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)]; + } else if (bytes_per_pixel == 2) { + code1 = lpIn[i] >> 4; + lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0]; + lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1]; + + if (2 * i <= code0) { + code1 = lpIn[i] & 0x0F; + lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0]; + lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1]; + } + } else { + code1 = lpIn[i] >> 4; + lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; + lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; + lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; + pixel_ptr += bytes_per_pixel; + + if (2 * i <= code0) { + code1 = lpIn[i] & 0x0F; + lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; + lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; + lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; + pixel_ptr += bytes_per_pixel; + } + } + } + lpIn += code0 / 2; + + /* if the RLE code is odd, skip a byte in the stream */ + if (extra_byte) + lpIn++; + }; + } else { + /* coded mode */ + if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) + return ICERR_ERROR; + + if (bytes_per_pixel == 1) { + BYTE c1 = pi->palette_map[(code1 >> 4)]; + BYTE c2 = pi->palette_map[(code1 & 0x0F)]; + + for (i = 0; i < code0; i++) { + if ((i & 1) == 0) + lpOut[pixel_ptr++] = c1; + else + lpOut[pixel_ptr++] = c2; + } + } else if (bytes_per_pixel == 2) { + BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0]; + BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1]; + + BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0]; + BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1]; + + for (i = 0; i < code0; i++) { + if ((i & 1) == 0) { + lpOut[pixel_ptr++] = hi1; + lpOut[pixel_ptr++] = lo1; + } else { + lpOut[pixel_ptr++] = hi2; + lpOut[pixel_ptr++] = lo2; + } + } + } else { + BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0]; + BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1]; + BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2]; + + BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0]; + BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1]; + BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2]; + + for (i = 0; i < code0; i++) { + if ((i & 1) == 0) { + lpOut[pixel_ptr + 0] = b1; + lpOut[pixel_ptr + 1] = g1; + lpOut[pixel_ptr + 2] = r1; + } else { + lpOut[pixel_ptr + 0] = b2; + lpOut[pixel_ptr + 1] = g2; + lpOut[pixel_ptr + 2] = r2; + } + pixel_ptr += bytes_per_pixel; + } + } + } + } while (! bEndFlag); + + return ICERR_OK; +} + +static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi, + LPBYTE lpIn, LPBYTE lpOut) +{ + int bytes_per_pixel; + int line_size; + int pixel_ptr = 0; + BOOL bEndFlag = FALSE; + + assert(pi != NULL); + assert(lpbi != NULL && lpbi->biCompression == BI_RGB); + assert(lpIn != NULL && lpOut != NULL); + + bytes_per_pixel = (lpbi->biBitCount + 1) / 8; + line_size = DIBWIDTHBYTES(*lpbi); + + do { + BYTE code0, code1; + + code0 = *lpIn++; + code1 = *lpIn++; + + if (code0 == 0) { + int extra_byte; + + switch (code1) { + case 0: /* EOL - end of line */ + pixel_ptr = 0; + lpOut += line_size; + break; + case 1: /* EOI - end of image */ + bEndFlag = TRUE; + break; + case 2: /* skip */ + pixel_ptr += *lpIn++ * bytes_per_pixel; + lpOut += *lpIn++ * line_size; + if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) { + pixel_ptr = 0; + lpOut += line_size; + } + break; + default: /* absolute mode */ + if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) { + WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth); + return ICERR_ERROR; + } + extra_byte = code1 & 0x01; + + code0 = code1; + while (code0--) { + code1 = *lpIn++; + if (bytes_per_pixel == 1) { + lpOut[pixel_ptr] = pi->palette_map[code1]; + } else if (bytes_per_pixel == 2) { + lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0]; + lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1]; + } else { + lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0]; + lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1]; + lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2]; + } + pixel_ptr += bytes_per_pixel; + } + + /* if the RLE code is odd, skip a byte in the stream */ + if (extra_byte) + lpIn++; + }; + } else { + /* coded mode */ + if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) { + WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth); + return ICERR_ERROR; + } + + if (bytes_per_pixel == 1) { + code1 = pi->palette_map[code1]; + while (code0--) + lpOut[pixel_ptr++] = code1; + } else if (bytes_per_pixel == 2) { + BYTE hi = pi->palette_map[code1 * 2 + 0]; + BYTE lo = pi->palette_map[code1 * 2 + 1]; + + while (code0--) { + lpOut[pixel_ptr + 0] = hi; + lpOut[pixel_ptr + 1] = lo; + pixel_ptr += bytes_per_pixel; + } + } else { + BYTE r = pi->palette_map[code1 * 4 + 2]; + BYTE g = pi->palette_map[code1 * 4 + 1]; + BYTE b = pi->palette_map[code1 * 4 + 0]; + + while (code0--) { + lpOut[pixel_ptr + 0] = b; + lpOut[pixel_ptr + 1] = g; + lpOut[pixel_ptr + 2] = r; + pixel_ptr += bytes_per_pixel; + } + } + } + } while (! bEndFlag); + + return ICERR_OK; +} + +/*****************************************************************************/ + +static CodecInfo* Open(LPICOPEN icinfo) +{ + CodecInfo* pi = NULL; + + if (icinfo == NULL) { + TRACE("(NULL)\n"); + return (LPVOID)0xFFFF0000; + } + + TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo, + icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType, + icinfo->fccHandler, (char*)&icinfo->fccHandler, + icinfo->dwVersion,icinfo->dwFlags); + + if (icinfo->fccType != ICTYPE_VIDEO) + return NULL; + + switch (icinfo->fccHandler) { + case FOURCC_RLE: + case FOURCC_RLE4: + case FOURCC_RLE8: + case FOURCC_MRLE: + break; + case mmioFOURCC('m','r','l','e'): + icinfo->fccHandler = FOURCC_MRLE; + break; + default: + WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n", + icinfo->fccHandler,(char*)&icinfo->fccHandler); + return NULL; + } + + pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo)); + + if (pi != NULL) { + pi->fccHandler = icinfo->fccHandler; + + pi->bCompress = FALSE; + pi->dwQuality = MSRLE32_DEFAULTQUALITY; + pi->nPrevFrame = -1; + pi->pPrevFrame = pi->pCurFrame = NULL; + + pi->bDecompress = FALSE; + pi->palette_map = NULL; + } + + icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY); + + return pi; +} + +static LRESULT Close(CodecInfo *pi) +{ + TRACE("(%p)\n", pi); + + /* pre-condition */ + assert(pi != NULL); + + if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL) + CompressEnd(pi); + + LocalFree((HLOCAL)pi); + return 1; +} + +static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize) +{ + /* pre-condition */ + assert(pi != NULL); + + /* check parameters */ + if (icinfo == NULL) + return sizeof(ICINFO); + if (dwSize < sizeof(ICINFO)) + return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = streamtypeVIDEO; + icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE); + icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC; + icinfo->dwVersion = MSRLE32_VERSION; + icinfo->dwVersionICM = 0x01040000; /* Version 1.4 build 0 */ + + LoadWideString(IDS_NAME, icinfo->szName, sizeof(icinfo->szName)); + LoadWideString(IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)); + + return sizeof(ICINFO); +} + +static LRESULT SetQuality(CodecInfo *pi, LONG lQuality) +{ + /* pre-condition */ + assert(pi != NULL); + + if (lQuality == -1) + lQuality = MSRLE32_DEFAULTQUALITY; + else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH) + return ICERR_BADPARAM; + + pi->dwQuality = (DWORD)lQuality; + + return ICERR_OK; +} + +static LRESULT Configure(CodecInfo *pi, HWND hWnd) +{ + /* pre-condition */ + assert(pi != NULL); + + /* FIXME */ + return ICERR_OK; +} + +static LRESULT About(CodecInfo *pi, HWND hWnd) +{ + CHAR szTitle[20]; + CHAR szAbout[128]; + + /* pre-condition */ + assert(MSRLE32_hModule != 0); + + LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)); + LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)); + + MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION); + + return ICERR_OK; +} + +static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPBITMAPINFOHEADER lpbiOut) +{ + LRESULT size; + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* pre-condition */ + assert(pi != NULL); + + /* check parameters -- need atleast input format */ + if (lpbiIn == NULL) { + if (lpbiOut != NULL) + return ICERR_BADPARAM; + return 0; + } + + /* handle unsupported input format */ + if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK) + return (lpbiOut == NULL ? ICERR_BADFORMAT : 0); + + assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8); + + switch (pi->fccHandler) { + case FOURCC_RLE4: + size = 1 << 4; + break; + case FOURCC_RLE8: + size = 1 << 8; + break; + case FOURCC_RLE: + case FOURCC_MRLE: + size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8); + break; + default: + return ICERR_ERROR; + } + + if (lpbiIn->biClrUsed != 0) + size = lpbiIn->biClrUsed; + + size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD); + + if (lpbiOut != NULL) { + lpbiOut->biSize = sizeof(BITMAPINFOHEADER); + lpbiOut->biWidth = lpbiIn->biWidth; + lpbiOut->biHeight = lpbiIn->biHeight; + lpbiOut->biPlanes = 1; + if (pi->fccHandler == FOURCC_RLE4 || + lpbiIn->biBitCount <= 4) { + lpbiOut->biCompression = BI_RLE4; + lpbiOut->biBitCount = 4; + } else { + lpbiOut->biCompression = BI_RLE8; + lpbiOut->biBitCount = 8; + } + lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut); + lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter; + lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter; + if (lpbiIn->biClrUsed == 0) + size = 1<biBitCount; + else + size = lpbiIn->biClrUsed; + lpbiOut->biClrUsed = min(size, 1u << lpbiOut->biBitCount); + lpbiOut->biClrImportant = 0; + + memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, + (LPBYTE)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD)); + + return ICERR_OK; + } else + return size; +} + +static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut) +{ + /* pre-condition */ + assert(pi != NULL); + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* check parameter -- need atleast one format */ + if (lpbiIn == NULL && lpbiOut == NULL) + return 0; + /* check if the given format is supported */ + if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) + return 0; + + /* the worst case is coding the complete image in absolute mode. */ + if (lpbiIn) + return MSRLE32_GetMaxCompressedSize(lpbiIn); + else + return MSRLE32_GetMaxCompressedSize(lpbiOut); +} + +static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut) +{ + /* pre-condition */ + assert(pi != NULL); + + /* need atleast one format */ + if (lpbiIn == NULL && lpbiOut == NULL) + return ICERR_BADPARAM; + + /* check input format if given */ + if (lpbiIn != NULL) { + if (!isSupportedDIB(lpbiIn)) + return ICERR_BADFORMAT; + + /* for 4-bit need an even width */ + if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2)) + return ICERR_BADFORMAT; + + if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4) + return ICERR_UNSUPPORTED; + else if (lpbiIn->biBitCount > 8) + return ICERR_UNSUPPORTED; + } + + /* check output format if given */ + if (lpbiOut != NULL) { + if (!isSupportedMRLE(lpbiOut)) + return ICERR_BADFORMAT; + + if (lpbiIn != NULL) { + if (lpbiIn->biWidth != lpbiOut->biWidth) + return ICERR_UNSUPPORTED; + if (lpbiIn->biHeight != lpbiOut->biHeight) + return ICERR_UNSUPPORTED; + if (lpbiIn->biBitCount > lpbiOut->biBitCount) + return ICERR_UNSUPPORTED; + } + } + + return ICERR_OK; +} + +static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut) +{ + RGBQUAD *rgbIn; + RGBQUAD *rgbOut; + int i; + size_t size; + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* pre-condition */ + assert(pi != NULL); + + /* check parameters -- need both formats */ + if (lpbiIn == NULL || lpbiOut == NULL) + return ICERR_BADPARAM; + /* And both must be supported */ + if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) + return ICERR_BADFORMAT; + + /* FIXME: cannot compress and decompress at a time! */ + if (pi->bDecompress) { + FIXME("cannot compress and decompress at same time!\n"); + return ICERR_ERROR; + } + + if (pi->bCompress) + CompressEnd(pi); + + size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight; + pi->pPrevFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD)); + if (pi->pPrevFrame == NULL) + return ICERR_MEMORY; + pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD)); + if (pi->pCurFrame == NULL) { + CompressEnd(pi); + return ICERR_MEMORY; + } + pi->nPrevFrame = -1; + pi->bCompress = TRUE; + + rgbIn = (RGBQUAD*)((LPBYTE)lpbiIn + lpbiIn->biSize); + rgbOut = (RGBQUAD*)((LPBYTE)lpbiOut + lpbiOut->biSize); + + switch (lpbiOut->biBitCount) { + case 4: + case 8: + pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed); + if (pi->palette_map == NULL) { + CompressEnd(pi); + return ICERR_MEMORY; + } + + for (i = 0; i < lpbiIn->biClrUsed; i++) { + pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]); + } + break; + }; + + return ICERR_OK; +} + +static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize) +{ + int i; + + TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize); + + /* pre-condition */ + assert(pi != NULL); + + /* check parameters */ + if (lpic == NULL || dwSize < sizeof(ICCOMPRESS)) + return ICERR_BADPARAM; + if (!lpic->lpbiOutput || !lpic->lpOutput || + !lpic->lpbiInput || !lpic->lpInput) + return ICERR_BADPARAM; + + TRACE("lpic={0x%lX,%p,%p,%p,%p,%p,%p,%ld,%lu,%lu,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev); + + if (! pi->bCompress) { + LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput); + if (hr != ICERR_OK) + return hr; + } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK) + return ICERR_BADFORMAT; + + if (lpic->lFrameNum >= pi->nPrevFrame + 1) { + /* we continue in the sequence so we need to initialize + * our internal framedata */ + + computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput); + } else if (lpic->lFrameNum == pi->nPrevFrame) { + /* Oops, compress same frame again ? Okay, as you wish. + * No need to recompute internal framedata, because we only swapped buffers */ + LPWORD pTmp = pi->pPrevFrame; + + FIXME(": prev=%ld cur=%ld swap\n",pi->nPrevFrame,lpic->lFrameNum); + pi->pPrevFrame = pi->pCurFrame; + pi->pCurFrame = pTmp; + } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) { + LPWORD pTmp; + + WARN(": prev=%ld cur=%ld gone back? -- untested",pi->nPrevFrame,lpic->lFrameNum); + if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL) + return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */ + if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK) + return ICERR_BADFORMAT; + + WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum); + computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev); + + /* swap buffers for current and previous frame */ + /* Don't free and alloc new -- costs to much time and they are of equal size ! */ + pTmp = pi->pPrevFrame; + pi->pPrevFrame = pi->pCurFrame; + pi->pCurFrame = pTmp; + pi->nPrevFrame = lpic->lFrameNum; + } + + for (i = 0; i < 3; i++) { + SetQuality(pi, lpic->dwQuality); + + lpic->lpbiOutput->biSizeImage = 0; + + if (lpic->lpbiOutput->biBitCount == 4) + MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, + lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE); + /*MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, + lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);*/ + else + MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, + lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0); + + if (lpic->dwFrameSize == 0 || + lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) + break; + + if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) { + if (lpic->lpbiOutput->biBitCount == 4) + MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, + lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE); + else + MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput, + lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE); + + if (lpic->dwFrameSize == 0 || + lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) { + WARN("switched to keyframe, was small enough!\n"); + *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME; + *lpic->lpckid = MAKEAVICKID(cktypeDIBbits, + StreamFromFOURCC(*lpic->lpckid)); + break; + } + } + + if (lpic->dwQuality < 1000) + break; + + lpic->dwQuality -= 1000; /* reduce quality by 10% */ + } + + { /* swap buffer for current and previous frame */ + /* Don't free and alloc new -- costs to much time and they are of equal size ! */ + register LPWORD pTmp = pi->pPrevFrame; + + pi->pPrevFrame = pi->pCurFrame; + pi->pCurFrame = pTmp; + pi->nPrevFrame = lpic->lFrameNum; + } + + return ICERR_OK; +} + +static LRESULT CompressEnd(CodecInfo *pi) +{ + TRACE("(%p)\n",pi); + + if (pi != NULL) { + if (pi->pPrevFrame != NULL) + GlobalFreePtr(pi->pPrevFrame); + if (pi->pCurFrame != NULL) + GlobalFreePtr(pi->pCurFrame); + pi->pPrevFrame = NULL; + pi->pCurFrame = NULL; + pi->nPrevFrame = -1; + pi->bCompress = FALSE; + } + + return ICERR_OK; +} + +static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPBITMAPINFOHEADER lpbiOut) +{ + int size; + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* pre-condition */ + assert(pi != NULL); + + if (lpbiIn == NULL) + return (lpbiOut != NULL ? ICERR_BADPARAM : 0); + + if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK) + return (lpbiOut != NULL ? ICERR_BADFORMAT : 0); + + size = lpbiIn->biSize; + + if (lpbiOut != NULL) { + memcpy(lpbiOut, lpbiIn, size); + lpbiOut->biBitCount = 32; + lpbiOut->biCompression = BI_RGB; + lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight; + lpbiOut->biClrImportant = 0; + + if (lpbiOut->biBitCount <= 8 && lpbiOut->biClrUsed == 0) + lpbiOut->biClrUsed = 1 << lpbiOut->biBitCount; + else + lpbiOut->biClrUsed = 0; + + return size; + } else + return size; +} + +static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut) +{ + LRESULT hr = ICERR_OK; + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* pre-condition */ + assert(pi != NULL); + + /* need atleast one format */ + if (lpbiIn == NULL && lpbiOut == NULL) + return ICERR_BADPARAM; + + /* check input format if given */ + if (lpbiIn != NULL) { + if (!isSupportedMRLE(lpbiIn)) + return ICERR_BADFORMAT; + } + + /* check output format if given */ + if (lpbiOut != NULL) { + if (!isSupportedDIB(lpbiOut)) + hr = ICERR_BADFORMAT; + + if (lpbiIn != NULL) { + if (lpbiIn->biWidth != lpbiOut->biWidth) + hr = ICERR_UNSUPPORTED; + if (lpbiIn->biHeight != lpbiOut->biHeight) + hr = ICERR_UNSUPPORTED; + if (lpbiIn->biBitCount > lpbiOut->biBitCount) + hr = ICERR_UNSUPPORTED; + } + } + + return hr; +} + +static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPCBITMAPINFOHEADER lpbiOut) +{ + RGBQUAD *rgbIn; + RGBQUAD *rgbOut; + int i; + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* pre-condition */ + assert(pi != NULL); + + /* check parameters */ + if (lpbiIn == NULL || lpbiOut == NULL) + return ICERR_BADPARAM; + if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) + return ICERR_BADFORMAT; + + /* FIXME: cannot compress and decompress at a time! */ + if (pi->bCompress) { + FIXME("cannot compress and decompress at same time!\n"); + return ICERR_ERROR; + } + + if (pi->bDecompress) + DecompressEnd(pi); + + rgbIn = (RGBQUAD*)((LPBYTE)lpbiIn + lpbiIn->biSize); + rgbOut = (RGBQUAD*)((LPBYTE)lpbiOut + lpbiOut->biSize); + + switch (lpbiOut->biBitCount) { + case 4: + case 8: + pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed); + if (pi->palette_map == NULL) + return ICERR_MEMORY; + + for (i = 0; i < lpbiIn->biClrUsed; i++) { + pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]); + } + break; + case 15: + case 16: + pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2); + if (pi->palette_map == NULL) + return ICERR_MEMORY; + + for (i = 0; i < lpbiIn->biClrUsed; i++) { + WORD color; + + if (lpbiOut->biBitCount == 15) + color = ((rgbIn[i].rgbRed >> 3) << 10) + | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3); + else + color = ((rgbIn[i].rgbRed >> 3) << 11) + | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3); + + pi->palette_map[i * 2 + 1] = color >> 8; + pi->palette_map[i * 2 + 0] = color & 0xFF; + }; + break; + case 24: + case 32: + pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD)); + if (pi->palette_map == NULL) + return ICERR_MEMORY; + memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD)); + break; + }; + + pi->bDecompress = TRUE; + + return ICERR_OK; +} + +static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize) +{ + TRACE("(%p,%p,%lu)\n",pi,pic,dwSize); + + /* pre-condition */ + assert(pi != NULL); + + /* check parameters */ + if (pic == NULL) + return ICERR_BADPARAM; + if (pic->lpbiInput == NULL || pic->lpInput == NULL || + pic->lpbiOutput == NULL || pic->lpOutput == NULL) + return ICERR_BADPARAM; + + /* check formats */ + if (! pi->bDecompress) { + LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput); + if (hr != ICERR_OK) + return hr; + } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK) + return ICERR_BADFORMAT; + + assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth); + assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight); + + pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight; + if (pic->lpbiInput->biBitCount == 4) + return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput); + else + return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput); +} + +static LRESULT DecompressEnd(CodecInfo *pi) +{ + TRACE("(%p)\n",pi); + + /* pre-condition */ + assert(pi != NULL); + + pi->bDecompress = FALSE; + + if (pi->palette_map != NULL) { + LocalFree((HLOCAL)pi->palette_map); + pi->palette_map = NULL; + } + + return ICERR_OK; +} + +static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, + LPBITMAPINFOHEADER lpbiOut) +{ + int size; + + TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut); + + /* pre-condition */ + assert(pi != NULL); + + /* check parameters */ + if (lpbiIn == NULL || lpbiOut == NULL) + return ICERR_BADPARAM; + + if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK) + return ICERR_BADFORMAT; + + if (lpbiOut->biBitCount > 8) + return ICERR_ERROR; + + if (lpbiIn->biBitCount <= 8) { + if (lpbiIn->biClrUsed > 0) + size = lpbiIn->biClrUsed; + else + size = (1 << lpbiIn->biBitCount); + + lpbiOut->biClrUsed = size; + + memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (LPBYTE)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD)); + } /* else could never occur ! */ + + return ICERR_OK; +} + +/* DriverProc - entry point for an installable driver */ +LRESULT CALLBACK MSRLE32_DriverProc(DWORD dwDrvID, HDRVR hDrv, UINT uMsg, + LPARAM lParam1, LPARAM lParam2) +{ + CodecInfo *pi = (CodecInfo*)dwDrvID; + + TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID)dwDrvID, (LPVOID)hDrv, + uMsg, lParam1, lParam2); + + switch (uMsg) { + /* standard driver messages */ + case DRV_LOAD: + return DRVCNF_OK; + case DRV_OPEN: + if (lParam2 == 0) + return (LRESULT)0xFFFF0000; + else + return (LRESULT)Open((ICOPEN*)lParam2); + case DRV_CLOSE: + if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL) + Close(pi); + return DRVCNF_OK; + case DRV_ENABLE: + case DRV_DISABLE: + return DRVCNF_OK; + case DRV_FREE: + return DRVCNF_OK; + case DRV_QUERYCONFIGURE: + return DRVCNF_CANCEL; /* FIXME */ + case DRV_CONFIGURE: + return DRVCNF_OK; /* FIXME */ + case DRV_INSTALL: + case DRV_REMOVE: + return DRVCNF_OK; + + /* installable compression manager messages */ + case ICM_CONFIGURE: + FIXME("ICM_CONFIGURE (%ld)\n",lParam1); + if (lParam1 == -1) + return ICERR_UNSUPPORTED; /* FIXME */ + else + return Configure(pi, (HWND)lParam1); + case ICM_ABOUT: + if (lParam1 == -1) + return ICERR_OK; + else + return About(pi, (HWND)lParam1); + case ICM_GETSTATE: + case ICM_SETSTATE: + return 0; /* no state */ + case ICM_GETINFO: + return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2); + case ICM_GETDEFAULTQUALITY: + if ((LPVOID)lParam1 != NULL) { + *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY; + return ICERR_OK; + } + break; + case ICM_GETQUALITY: + if ((LPVOID)lParam1 != NULL) { + *((LPDWORD)lParam1) = pi->dwQuality; + return ICERR_OK; + } + break; + case ICM_SETQUALITY: + return SetQuality(pi, *(LPLONG)lParam1); + break; + case ICM_COMPRESS_GET_FORMAT: + return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPBITMAPINFOHEADER)lParam2); + case ICM_COMPRESS_GET_SIZE: + return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPCBITMAPINFOHEADER)lParam2); + case ICM_COMPRESS_QUERY: + return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPCBITMAPINFOHEADER)lParam2); + case ICM_COMPRESS_BEGIN: + return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPCBITMAPINFOHEADER)lParam2); + case ICM_COMPRESS: + return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2); + case ICM_COMPRESS_END: + return CompressEnd(pi); + case ICM_DECOMPRESS_GET_FORMAT: + return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPBITMAPINFOHEADER)lParam2); + case ICM_DECOMPRESS_QUERY: + return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPCBITMAPINFOHEADER)lParam2); + case ICM_DECOMPRESS_BEGIN: + return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1, + (LPCBITMAPINFOHEADER)lParam2); + case ICM_DECOMPRESS: + return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2); + case ICM_DECOMPRESS_END: + return DecompressEnd(pi); + case ICM_DECOMPRESS_SET_PALETTE: + FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2); + return ICERR_UNSUPPORTED; + case ICM_DECOMPRESS_GET_PALETTE: + return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1, + (LPBITMAPINFOHEADER)lParam2); + case ICM_GETDEFAULTKEYFRAMERATE: + if ((LPVOID)lParam1 != NULL) + *(LPDWORD)lParam1 = 15; + return ICERR_OK; + default: + if (uMsg < DRV_USER) + return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2); + else + FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2); + }; + + return ICERR_UNSUPPORTED; +} + +/* DllMain - library initialization code */ +BOOL WINAPI MSRLE32_DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) +{ + TRACE("(%p,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved); + + switch (dwReason) { + case DLL_PROCESS_ATTACH: + if (MSRLE32_hModule == 0) + MSRLE32_hModule = hModule; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + break; + }; + + return TRUE; +} diff --git a/dlls/msvideo/msrle32/msrle32.spec b/dlls/msvideo/msrle32/msrle32.spec new file mode 100644 index 00000000000..b137eb37c65 --- /dev/null +++ b/dlls/msvideo/msrle32/msrle32.spec @@ -0,0 +1,3 @@ +init MSRLE32_DllMain + +@ stdcall DriverProc(long long long long long) MSRLE32_DriverProc diff --git a/dlls/msvideo/msrle32/msrle_De.rc b/dlls/msvideo/msrle32/msrle_De.rc new file mode 100644 index 00000000000..35dba7e5416 --- /dev/null +++ b/dlls/msvideo/msrle32/msrle_De.rc @@ -0,0 +1,28 @@ +/* + * German resource file for MS-RLE + * + * Copyright 2002 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 + */ + +LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_NAME "WINE-MS-RLE" + IDS_DESCRIPTION "Wine MS-RLE Videodekoder" + IDS_ABOUT "Wine MS-RLE Videodekoder\nCopyright 2002 by Michael Günnewig" +} diff --git a/dlls/msvideo/msrle32/msrle_En.rc b/dlls/msvideo/msrle32/msrle_En.rc new file mode 100644 index 00000000000..3061f71471d --- /dev/null +++ b/dlls/msvideo/msrle32/msrle_En.rc @@ -0,0 +1,28 @@ +/* + * English resource file for MS-RLE + * + * Copyright 2002 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 + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_NAME "WINE-MS-RLE" + IDS_DESCRIPTION "Wine MS-RLE video codec" + IDS_ABOUT "Wine MS-RLE video codec\nCopyright 2002 by Michael Günnewig" +} diff --git a/dlls/msvideo/msrle32/msrle_Fr.rc b/dlls/msvideo/msrle32/msrle_Fr.rc new file mode 100644 index 00000000000..0faa81c8499 --- /dev/null +++ b/dlls/msvideo/msrle32/msrle_Fr.rc @@ -0,0 +1,28 @@ +/* + * French resource file for MS-RLE + * + * Copyright 2002 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 + */ + +LANGUAGE LANG_FRENCH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_NAME "WINE-MS-RLE" + IDS_DESCRIPTION "Wine: décodeur/encodeur vidéo MS-RLE" + IDS_ABOUT "Wine: décodeur/encodeur vidéo MS-RLE\nCopyright 2002 par Michael Günnewig" +} diff --git a/dlls/msvideo/msrle32/msrle_private.h b/dlls/msvideo/msrle32/msrle_private.h new file mode 100644 index 00000000000..a78976d5d68 --- /dev/null +++ b/dlls/msvideo/msrle32/msrle_private.h @@ -0,0 +1,56 @@ +/* + * Copyright 2002 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 + */ + +#ifndef __MSRLE32_PRIVATE_H +#define __MSRLE32_PRIVATE_H + +#include "winbase.h" +#include "mmsystem.h" +#include "vfw.h" + +#define IDS_NAME 100 +#define IDS_DESCRIPTION 101 +#define IDS_ABOUT 102 + +#define MSRLE32_VERSION 0x00010000 /* Version 1.0 build 0 */ +#define MSRLE32_DEFAULTQUALITY (75 * ICQUALITY_HIGH) / 100 + +#define FOURCC_RLE mmioFOURCC('R','L','E',' ') +#define FOURCC_RLE4 mmioFOURCC('R','L','E','4') +#define FOURCC_RLE8 mmioFOURCC('R','L','E','8') +#define FOURCC_MRLE mmioFOURCC('M','R','L','E') + +#define WIDTHBYTES(i) ((WORD)((i+31)&(~31))/8) /* ULONG aligned ! */ +#define DIBWIDTHBYTES(bi) WIDTHBYTES((WORD)(bi).biWidth * (WORD)(bi).biBitCount) + +typedef struct _CodecInfo { + FOURCC fccHandler; + DWORD dwQuality; + + BOOL bCompress; + LONG nPrevFrame; + LPWORD pPrevFrame; + LPWORD pCurFrame; + + BOOL bDecompress; + LPBYTE palette_map; +} CodecInfo; + +typedef const BITMAPINFOHEADER * LPCBITMAPINFOHEADER; + +#endif diff --git a/dlls/msvideo/msrle32/rsrc.rc b/dlls/msvideo/msrle32/rsrc.rc new file mode 100644 index 00000000000..7790221e47e --- /dev/null +++ b/dlls/msvideo/msrle32/rsrc.rc @@ -0,0 +1,35 @@ +/* + * Top level resource file for MS-RLE + * + * Copyright 2002 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 + */ + +#include "windef.h" + +#include "msrle_private.h" + +/* + * Everything specific to any language goes + * in one of the specific files. + * Note that you can and may override resources + * which also have a neutral version. This is to + * get localized bitmaps for example. + */ + +#include "msrle_En.rc" +#include "msrle_De.rc" +#include "msrle_Fr.rc"