diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..6baabc7 --- /dev/null +++ b/README.txt @@ -0,0 +1,49 @@ + + + + + Zoe Lossless Codec + +Zoe Lossless Codec is a video compression/decompression module to be used in AVI files under +the Video for Windows (VfW) framework. The encoded data will typically be stored inside AVI files. The +current version allows lossless compression of grayscale video data in the "Y8 " or "Y10 " formats, +as well as RGB24, RGB32 and UYVY. RGB formats are encoded per-channel without any color space conversion. +"Y10 " is a new FOURCC code representing 10 bits of grayscale data stored in the LSB of 16 bit words. + + + + Revision History: + 2014-04-15 E. Danvoye Initial Release + 2014-04-15 E. Danvoye 1.0.1 Fix crash with CRT allocator + 2014-05-02 E. Danvoye 1.0.2 Multi-channel, Support RGB24 and RGB32 + 2014-05-05 E. Danvoye 1.0.4 Add UYVY decompression directly to RGB24 + 2014-05-09 E. Danvoye 1.0.5 Fix playback in Windows Media Player and Adobe Premiere (by supporting negative height and RGB32 output) + 2014-05-12 E. Danvoye 1.0.6 Hack for Motionbuilder, forge RGB output for YUV formats + 2014-05-12 E. Danvoye 1.0.7 Fixed playback in Sony Vegas + 2015-07-07 E. Danvoye 1.1.1 Add 10 bit grayscale, 12 bit grayscale and 12bit packed grayscale + +========= + +Copyright (c) 2014,2015 Activision +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and + the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ZoeCodec.cpp b/ZoeCodec.cpp new file mode 100644 index 0000000..aeb5f67 --- /dev/null +++ b/ZoeCodec.cpp @@ -0,0 +1,1022 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Revision History: +// 2014-03-28 E. Danvoye Initial Release +// + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include "stdafx.h" +#include "ZoeCodec.h" +#include "codecs.h" + +//#define LOG_TO_FILE +//#define LOG_TO_STDOUT + +#define VERSION 0x00010100 // 1.1.1 + +#if _WIN64 + TCHAR szDescription[] = TEXT("Zoe Lossless Codec (64 bits) v1.1.1"); + TCHAR szName[] = TEXT("ZoeLosslessCodec64"); +#else + TCHAR szDescription[] = TEXT("Zoe Lossless Codec (32 bits) v1.1.1"); + TCHAR szName[] = TEXT("ZoeLosslessCodec32"); +#endif + +const char * fourCCStr(DWORD fourcc) +{ + static char buf[32]; + if (fourcc==BI_RGB) + strcpy_s(buf,"BI_RGB"); + else if (fourcc==BI_RLE8) + strcpy_s(buf,"BI_RLE8"); + else if (fourcc==BI_RLE4) + strcpy_s(buf,"BI_RLE4"); + else if (fourcc==BI_BITFIELDS) + strcpy_s(buf,"BI_BITFIELDS"); + else if (fourcc==BI_JPEG) + strcpy_s(buf,"BI_JPEG"); + else if (fourcc==BI_PNG) + strcpy_s(buf,"BI_PNG"); + else + { + buf[0] = (fourcc&0x000000FF); + buf[1] = (fourcc&0x0000FF00)>>8; + buf[2] = (fourcc&0x00FF0000)>>16; + buf[3] = (fourcc&0xFF000000)>>24; + buf[4] = 0; + } + return buf; +} + +enum eBufferTypes { + BTYPE_INVALID = 0xFF, + BTYPE_NONE = 0, + BTYPE_RGB24, + BTYPE_RGB32, + BTYPE_Y8, + BTYPE_Y10, + BTYPE_HY8, + BTYPE_HY10, + BTYPE_HRGB24, + BTYPE_HRGB32, + BTYPE_HUYVY, + + BTYPE_PY10, // Packed 10 bit grayscale data (16 pixels x 10 bit grouped in 20 bytes) + + BTYPE_Y12, + BTYPE_HY12, + + BTYPE_COUNT +}; + +struct ZoeCodecHeader +{ + unsigned char version; + unsigned char buffer_type; + unsigned char pad0; + unsigned char pad1; +}; + +BOOL IsValidType(int type) +{ + return type>BTYPE_NONE && type " << buffer << " (" << moduleName << ")" << std::endl; + } +#endif + + va_end(args); +} +#endif + +bool exeRequiresForceRGB() +{ + // Some applications don't properly handle YUV formats (ex.: Motionbuilder 2014), for those applications + // we force the output to RGB. Microsoft's documentation simply states that "the default format should be + // the one that preserves the greatest amount of information". Applications can still check a specific output format + // using DecompressQuery. + + char moduleName[MAX_PATH]; + GetModuleFileName(NULL, moduleName, MAX_PATH); + + // make lowercase + for(int i = 0; moduleName[i]; i++){ + moduleName[i] = tolower(moduleName[i]); + } + + if (strstr(moduleName,"motionbuilder.exe")!=0) + return true; + + return false; +} + +bool IsFormatSupported(LPBITMAPINFOHEADER lpbiIn) +{ + if (!lpbiIn) + return FALSE; + + // Formats supported by the Compressor + + if (lpbiIn->biCompression == BI_RGB && lpbiIn->biBitCount == 24) + return TRUE; + if (lpbiIn->biCompression == BI_RGB && lpbiIn->biBitCount == 32) + return TRUE; + if (lpbiIn->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && lpbiIn->biBitCount == 8) + return TRUE; + if (lpbiIn->biCompression == mmioFOURCC('Y', '1', '0', ' ') && lpbiIn->biBitCount == 16) + return TRUE; + if (lpbiIn->biCompression == mmioFOURCC('Y', '1', '2', ' ') && lpbiIn->biBitCount == 16) + return TRUE; + if (lpbiIn->biCompression == mmioFOURCC('P', 'Y', '1', '0') && lpbiIn->biBitCount == 16) + return TRUE; + if (lpbiIn->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && lpbiIn->biBitCount == 16) + return TRUE; + + return FALSE; +} + +void FillHeaderForInput(const LPBITMAPINFOHEADER lpbiIn, ZoeCodecHeader* header) +{ + header->version = 1; + header->buffer_type = BTYPE_NONE; + + if (lpbiIn->biCompression == BI_RGB && lpbiIn->biBitCount == 24) + header->buffer_type = BTYPE_HRGB24; // BTYPE_RGB24; + else if (lpbiIn->biCompression == BI_RGB && lpbiIn->biBitCount == 32) + header->buffer_type = BTYPE_HRGB32; // BTYPE_RGB32; + else if (lpbiIn->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && lpbiIn->biBitCount == 8) + header->buffer_type = BTYPE_HY8; // BTYPE_Y8 + else if (lpbiIn->biCompression == mmioFOURCC('Y', '1', '0', ' ') && lpbiIn->biBitCount == 16) + header->buffer_type = BTYPE_HY10; // BTYPE_Y10 + else if (lpbiIn->biCompression == mmioFOURCC('Y', '1', '2', ' ') && lpbiIn->biBitCount == 16) + header->buffer_type = BTYPE_HY12; // BTYPE_Y12 + else if (lpbiIn->biCompression == mmioFOURCC('P', 'Y', '1', '0') && lpbiIn->biBitCount == 16) + header->buffer_type = BTYPE_HY10; // BTYPE_PY10 + else if (lpbiIn->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && lpbiIn->biBitCount == 16) + header->buffer_type = BTYPE_HUYVY; // Compressed UYVY + + header->pad0 = 0; + header->pad1 = 0; +} + +BOOL QueryAbout() +{ + return FALSE; +} + +DWORD About(HWND hwnd) +{ + return ICERR_ERROR; +} + +BOOL QueryConfigure() +{ + return FALSE; +} + +DWORD Configure(HWND hwnd) +{ + return ICERR_ERROR; +} + +DWORD GetState(LPVOID pv, DWORD dwSize) +{ + return 0; // no state information +} + +DWORD SetState(LPVOID pv, DWORD dwSize) +{ + return 0; // no state information +} + +DWORD GetInfo(ICINFO* icinfo, DWORD dwSize) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("GetInfo"); +#endif + + if (icinfo == NULL) + return sizeof(ICINFO); + + if (dwSize < sizeof(ICINFO)) + return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = ICTYPE_VIDEO; + icinfo->fccHandler = FOURCC_AZCL; + icinfo->dwFlags = 0; + + icinfo->dwVersion = VERSION; + icinfo->dwVersionICM = ICVERSION; + MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR)); + + return sizeof(ICINFO); +} + +DWORD CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ + if (!lpbiIn) + return ICERR_BADFORMAT; + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("CompressQuery in FOURCC:%s bitCount:%d", fourCCStr(lpbiIn->biCompression), lpbiIn->biBitCount); + + if (lpbiOut) + logMessage("CompressQuery out FOURCC:%s bitCount:%d", fourCCStr(lpbiOut->biCompression), lpbiOut->biBitCount); +#endif + + return (IsFormatSupported(lpbiIn)) ? ICERR_OK : ICERR_BADFORMAT; +} + +DWORD CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("CompressGetFormat"); +#endif + + if (!IsFormatSupported(lpbiIn)) + return ICERR_BADFORMAT; + + if (!lpbiOut) + return sizeof(BITMAPINFOHEADER) + sizeof(ZoeCodecHeader); // size of returned structure + + // Fill output structure + lpbiOut->biSize = sizeof(BITMAPINFOHEADER) + sizeof(ZoeCodecHeader); + lpbiOut->biWidth = lpbiIn->biWidth; + lpbiOut->biHeight = lpbiIn->biHeight; + lpbiOut->biPlanes = 1; + lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter; + lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter; + lpbiOut->biClrUsed = 0; + lpbiOut->biClrImportant = 0; + + lpbiOut->biSizeImage = 0; // will be filled later in Compress + lpbiOut->biBitCount = 32; + lpbiOut->biCompression = FOURCC_AZCL; + + ZoeCodecHeader* header = (ZoeCodecHeader*)(&lpbiOut[1]); + FillHeaderForInput(lpbiIn, header); + + return ICERR_OK; +} + +DWORD CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("CompressBegin"); +#endif + + // Initialization + + return ICERR_OK; +} + +DWORD CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("CompressGetSize width:%d height:%d bits:%d", lpbiIn->biWidth, lpbiIn->biHeight, lpbiIn->biBitCount); +#endif + + // Worst case scenario is full uncompressed size + return (lpbiIn->biWidth * abs(lpbiIn->biHeight) * lpbiIn->biBitCount) / 8; +} + +DWORD Compress(ICCOMPRESS* icinfo, DWORD dwSize) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Compress"); +#endif + + // TODO, should we flip-y the image before compression if the input biHeight is negative ? + // See comment in Decompress + + if (!IsFormatSupported(icinfo->lpbiInput)) + return ICERR_BADFORMAT; + + const ZoeCodecHeader* header = (ZoeCodecHeader*)(&icinfo->lpbiOutput[1]); + + if (icinfo->lpckid) + *icinfo->lpckid = FOURCC_AZCL; + + if (header->version == 1) + { + const unsigned char* in_frame = (unsigned char*)icinfo->lpInput; + unsigned char* out_frame = (unsigned char*)icinfo->lpOutput; + + if (header->buffer_type == BTYPE_RGB24) + { + if (icinfo->lpbiInput->biCompression != BI_RGB || icinfo->lpbiInput->biBitCount != 24) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_RGB24_To_RGB24(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_RGB32) + { + if (icinfo->lpbiInput->biCompression != BI_RGB || icinfo->lpbiInput->biBitCount != 32) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_RGB32_To_RGB32(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_Y8) + { + if (icinfo->lpbiInput->biCompression != mmioFOURCC('Y', '8', ' ', ' ') || icinfo->lpbiInput->biBitCount != 8) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_Y8_To_Y8(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_HY8) + { + if (icinfo->lpbiInput->biCompression != mmioFOURCC('Y', '8', ' ', ' ') || icinfo->lpbiInput->biBitCount != 8) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_Y8_To_HY8(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_HY10) + { + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + if (icinfo->lpbiInput->biCompression == mmioFOURCC('Y', '1', '0', ' ') && icinfo->lpbiInput->biBitCount == 16) + { + DWORD size = Compress_Y10_To_HY10(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + } + else if (icinfo->lpbiInput->biCompression == mmioFOURCC('P', 'Y', '1', '0') && icinfo->lpbiInput->biBitCount == 16) + { + DWORD size = Compress_PY10_To_HY10(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + } + else + return ICERR_BADFORMAT; + + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_Y10) + { + if (icinfo->lpbiInput->biCompression != mmioFOURCC('Y', '1', '0', ' ') || icinfo->lpbiInput->biBitCount != 16) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_Y10_To_Y10(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_HY12) + { + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + if (icinfo->lpbiInput->biCompression == mmioFOURCC('Y', '1', '2', ' ') && icinfo->lpbiInput->biBitCount == 16) + { + DWORD size = Compress_Y12_To_HY12(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + } + else + return ICERR_BADFORMAT; + + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_Y12) + { + if (icinfo->lpbiInput->biCompression != mmioFOURCC('Y', '1', '2', ' ') || icinfo->lpbiInput->biBitCount != 16) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_Y12_To_Y12(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_HUYVY) + { + if (icinfo->lpbiInput->biCompression != mmioFOURCC('U', 'Y', 'V', 'Y') || icinfo->lpbiInput->biBitCount != 16) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_UYVY_To_HUYVY(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_HRGB24) + { + if (icinfo->lpbiInput->biCompression != BI_RGB || icinfo->lpbiInput->biBitCount != 24) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_RGB24_To_HRGB24(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + else if (header->buffer_type == BTYPE_HRGB32) + { + if (icinfo->lpbiInput->biCompression != BI_RGB || icinfo->lpbiInput->biBitCount != 32) + return ICERR_BADFORMAT; + + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + + DWORD size = Compress_RGB32_To_HRGB32(icinfo->lpbiInput->biWidth, abs(icinfo->lpbiInput->biHeight), in_frame, out_frame); + icinfo->lpbiOutput->biSizeImage = size; + + return ICERR_OK; + } + } + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Compress Failed ICERR_ERROR"); +#endif + + return ICERR_ERROR; +} + +DWORD CompressEnd() +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("CompressEnd"); +#endif + + // Cleanup + + return ICERR_OK; +} + +DWORD DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ + if (!lpbiIn) + return ICERR_BADFORMAT; + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressQuery in FOURCC:%s bitCount:%d w:%d h:%d", fourCCStr(lpbiIn->biCompression), lpbiIn->biBitCount, lpbiIn->biWidth, lpbiIn->biHeight); + + if (lpbiOut) + logMessage("DecompressQuery out FOURCC:%s bitCount:%d w:%d h:%d", fourCCStr(lpbiOut->biCompression), lpbiOut->biBitCount, lpbiOut->biWidth, lpbiOut->biHeight); +#endif + + if (lpbiIn->biCompression!=FOURCC_AZCL) + { +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Can only decompress AZCL"); +#endif + return ICERR_BADFORMAT; + } + + if (lpbiIn->biSize < sizeof(BITMAPINFOHEADER) + sizeof(ZoeCodecHeader)) + { +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Bad header"); +#endif + return ICERR_BADFORMAT; + } + + const ZoeCodecHeader* header = (const ZoeCodecHeader*)(&lpbiIn[1]); + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressQuery version:%d buffer_type:%d", header->version, header->buffer_type); +#endif + + if (header->version != 1 || !IsValidType(header->buffer_type)) + { +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Bad header"); +#endif + return ICERR_BADFORMAT; + } + + if (lpbiOut) + { + // Decompressing to a different size is not supported + if (lpbiIn->biWidth!=lpbiOut->biWidth || lpbiIn->biHeight!=lpbiOut->biHeight) + return ICERR_BADFORMAT; + + // Identify all possible output formats for each BTYPE + switch (header->buffer_type) + { + case BTYPE_HRGB24: + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==32) + return ICERR_OK; + // intentional fall-thru to next case + case BTYPE_RGB24: + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==24) + return ICERR_OK; + break; + case BTYPE_RGB32: + case BTYPE_HRGB32: + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==32) + return ICERR_OK; + break; + case BTYPE_HY8: + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==32) + return ICERR_OK; + // intentional fall-thru to next case + case BTYPE_Y8: + if (lpbiOut->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && lpbiOut->biBitCount==8) + return ICERR_OK; + if (lpbiOut->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && lpbiOut->biBitCount==16) + return ICERR_OK; + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==24) + return ICERR_OK; + break; + case BTYPE_HY10: + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==32) + return ICERR_OK; + // intentional fall-thru to next case + case BTYPE_Y10: + if (lpbiOut->biCompression == mmioFOURCC('Y', '1', '0', ' ') && lpbiOut->biBitCount==16) + return ICERR_OK; + if (lpbiOut->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && lpbiOut->biBitCount==16) // lossy (10->8) + return ICERR_OK; + if (lpbiOut->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && lpbiOut->biBitCount==8) // lossy (10->8) + return ICERR_OK; + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==24) + return ICERR_OK; + break; + case BTYPE_HY12: + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==32) + return ICERR_OK; + // intentional fall-thru to next case + case BTYPE_Y12: + if (lpbiOut->biCompression == mmioFOURCC('Y', '1', '2', ' ') && lpbiOut->biBitCount==16) + return ICERR_OK; + if (lpbiOut->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && lpbiOut->biBitCount==16) // lossy (12->8) + return ICERR_OK; + if (lpbiOut->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && lpbiOut->biBitCount==8) // lossy (12->8) + return ICERR_OK; + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==24) + return ICERR_OK; + break; + case BTYPE_HUYVY: + if (lpbiOut->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && lpbiOut->biBitCount==16) + return ICERR_OK; + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==24) // convert UYVY to RGB24 + return ICERR_OK; + if (lpbiOut->biCompression == BI_RGB && lpbiOut->biBitCount==32) // convert UYVY to RGB32 + return ICERR_OK; + break; + } + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Output not supported"); +#endif + return ICERR_BADFORMAT; + } + + return ICERR_OK; +} + +DWORD DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetFormat"); +#endif + + if (lpbiIn->biCompression != FOURCC_AZCL) + { +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetFormat: only AZCL is supported"); +#endif + return ICERR_BADFORMAT; + } + + if (!lpbiOut) + { +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetFormat: lpbiOut is null"); +#endif + return sizeof(BITMAPINFOHEADER); // size of returned structure + } + + const ZoeCodecHeader* header = (const ZoeCodecHeader*)(&lpbiIn[1]); + + // Fill output structure + lpbiOut->biSize = sizeof(BITMAPINFOHEADER); + lpbiOut->biWidth = lpbiIn->biWidth; + lpbiOut->biHeight = lpbiIn->biHeight; + lpbiOut->biPlanes = 1; + lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter; + lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter; + lpbiOut->biClrUsed = 0; + lpbiOut->biClrImportant = 0; + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetFormat: Header version:%d type:%d", header->version, header->buffer_type); +#endif + + if (header->version == 1) + { + // Identify default output format for each BTYPE + + const bool forceRGBOutput = exeRequiresForceRGB(); + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetFormat: Force RGB format: %s", forceRGBOutput?"YES":"NO"); +#endif + + if (header->buffer_type == BTYPE_RGB24 || header->buffer_type == BTYPE_HRGB24) + { + lpbiOut->biBitCount = 24; + lpbiOut->biCompression = BI_RGB; + } + else if (header->buffer_type == BTYPE_RGB32 || header->buffer_type == BTYPE_HRGB32) + { + lpbiOut->biBitCount = 32; + lpbiOut->biCompression = BI_RGB; + } + else if (header->buffer_type == BTYPE_Y8 || header->buffer_type == BTYPE_HY8) + { + if (forceRGBOutput) + { + lpbiOut->biBitCount = 24; + lpbiOut->biCompression = BI_RGB; + } + else + { + lpbiOut->biBitCount = 8; + lpbiOut->biCompression = mmioFOURCC('Y', '8', ' ', ' '); + } + } + else if (header->buffer_type == BTYPE_Y10 || header->buffer_type == BTYPE_HY10) + { + if (forceRGBOutput) + { + lpbiOut->biBitCount = 24; + lpbiOut->biCompression = BI_RGB; + } + else + { + lpbiOut->biBitCount = 16; + lpbiOut->biCompression = mmioFOURCC('Y', '1', '0', ' '); + } + } + else if (header->buffer_type == BTYPE_Y12 || header->buffer_type == BTYPE_HY12) + { + if (forceRGBOutput) + { + lpbiOut->biBitCount = 24; + lpbiOut->biCompression = BI_RGB; + } + else + { + lpbiOut->biBitCount = 16; + lpbiOut->biCompression = mmioFOURCC('Y', '1', '2', ' '); + } + } + else if (header->buffer_type == BTYPE_HUYVY) + { + if (forceRGBOutput) + { + lpbiOut->biBitCount = 24; + lpbiOut->biCompression = BI_RGB; + } + else + { + lpbiOut->biBitCount = 16; + lpbiOut->biCompression = mmioFOURCC('U', 'Y', 'V', 'Y'); + } + } + else + return ICERR_BADFORMAT; + + lpbiOut->biSizeImage = (lpbiOut->biWidth * abs(lpbiOut->biHeight) * lpbiOut->biBitCount) / 8; + + return ICERR_OK; + } + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetFormat Failed ICERR_BADFORMAT"); +#endif + + return ICERR_BADFORMAT; +} + +DWORD DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressBegin"); + + if (lpbiIn) + logMessage("DecompressBegin in FOURCC:%s bitCount:%d", fourCCStr(lpbiIn->biCompression), lpbiIn->biBitCount); + if (lpbiOut) + logMessage("DecompressBegin out FOURCC:%s bitCount:%d", fourCCStr(lpbiOut->biCompression), lpbiOut->biBitCount); +#endif + + // Initialization + + return ICERR_OK; +} + +DWORD Decompress(ICDECOMPRESS* icinfo, DWORD dwSize) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Decompress outW:%d outH:%d outFOURCC:%s outBpp:%d outputsize:%d", icinfo->lpbiOutput->biWidth, icinfo->lpbiOutput->biHeight, fourCCStr(icinfo->lpbiOutput->biCompression), icinfo->lpbiOutput->biBitCount, icinfo->lpbiOutput->biSizeImage); +#endif + + if (icinfo->lpbiInput->biCompression != FOURCC_AZCL) + return ICERR_BADFORMAT; + + // TODO: Verify when image has to be flipped vertically + // If output is UYVY: Positive biHeight implies top-down image (top line first) [http://www.fourcc.org/yuv.php#UYVY] + // If output is BI_RGB: For uncompressed RGB bitmaps, if biHeight is positive, the bitmap is a bottom-up DIB with the origin at the lower left corner. If biHeight is negative, the bitmap is a top-down DIB with the origin at the upper left corner. + // If output is a YUV variant: For YUV bitmaps, the bitmap is always top-down, regardless of the sign of biHeight. Decoders should offer YUV formats with positive biHeight, but for backward compatibility they should accept YUV formats with either positive or negative biHeight. + // For compressed formats, biHeight must be positive, regardless of image orientation. [http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229%28v=vs.85%29.aspx] + + const ZoeCodecHeader* header = (const ZoeCodecHeader*)(&icinfo->lpbiInput[1]); + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("version:%d type:%d", header->version, header->buffer_type); +#endif + + if (header->version == 1) + { + icinfo->lpbiOutput->biSizeImage = (icinfo->lpbiOutput->biWidth * abs(icinfo->lpbiOutput->biHeight) * icinfo->lpbiOutput->biBitCount) >> 3; + + const unsigned char* in_frame = (unsigned char*)icinfo->lpInput; + unsigned char* out_frame = (unsigned char*)icinfo->lpOutput; + + if (header->buffer_type == BTYPE_RGB24) + { + if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 24) + { + if (Decompress_RGB24_To_RGB24(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_RGB32) + { + if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_RGB32_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + if (header->buffer_type == BTYPE_HRGB24) + { + if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 24) + { + if (Decompress_HRGB24_To_RGB24(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_HRGB24_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame, icinfo->lpbiOutput->biHeight<0)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_HRGB32) + { + if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_HRGB32_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_Y8) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && icinfo->lpbiOutput->biBitCount == 8) + { + if (Decompress_Y8_To_Y8(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_Y8_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_HY8) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && icinfo->lpbiOutput->biBitCount == 8) + { + if (Decompress_HY8_To_Y8(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_HY8_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 24) + { + if (Decompress_HY8_To_RGB24(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_HY8_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_HY10) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && icinfo->lpbiOutput->biBitCount == 8) + { + if (Decompress_HY10_To_Y8(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '1', '0', ' ') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_HY10_To_Y10(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_HY10_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 24) + { + if (Decompress_HY10_To_RGB24(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_HY10_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_HY12) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && icinfo->lpbiOutput->biBitCount == 8) + { + if (Decompress_HY12_To_Y8(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '1', '2', ' ') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_HY12_To_Y12(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_HY12_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 24) + { + if (Decompress_HY12_To_RGB24(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_HY12_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_HUYVY) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_HUYVY_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 24) + { + if (Decompress_HUYVY_To_RGB24(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == BI_RGB && icinfo->lpbiOutput->biBitCount == 32) + { + if (Decompress_HUYVY_To_RGB32(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_Y10) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && icinfo->lpbiOutput->biBitCount == 8) + { + if (Decompress_Y10_To_Y8(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '1', '0', ' ') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_Y10_To_Y10(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_Y10_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + else if (header->buffer_type == BTYPE_Y12) + { + if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '8', ' ', ' ') && icinfo->lpbiOutput->biBitCount == 8) + { + if (Decompress_Y12_To_Y8(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('Y', '1', '2', ' ') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_Y12_To_Y12(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + else if (icinfo->lpbiOutput->biCompression == mmioFOURCC('U', 'Y', 'V', 'Y') && icinfo->lpbiOutput->biBitCount == 16) + { + if (Decompress_Y12_To_UYVY(icinfo->lpbiInput->biSizeImage, icinfo->lpbiOutput->biWidth, abs(icinfo->lpbiOutput->biHeight), in_frame, out_frame)) + return ICERR_OK; + } + } + } + +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("Decompress Failed ICERR_BADFORMAT"); +#endif + + return ICERR_BADFORMAT; +} + +DWORD DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressGetPalette"); +#endif + + return ICERR_BADFORMAT; +} + +DWORD DecompressEnd() +{ +#if defined(LOG_TO_FILE) || defined(LOG_TO_STDOUT) + logMessage("DecompressEnd"); +#endif + + // Cleanup + + return ICERR_OK; +} + diff --git a/ZoeCodec.h b/ZoeCodec.h new file mode 100644 index 0000000..f38910f --- /dev/null +++ b/ZoeCodec.h @@ -0,0 +1,54 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +static const DWORD FOURCC_AZCL = mmioFOURCC('A','Z','C','L'); // Zoe Lossless codec + +BOOL QueryAbout(); +DWORD About(HWND hwnd); + +BOOL QueryConfigure(); +DWORD Configure(HWND hwnd); + +DWORD GetState(LPVOID pv, DWORD dwSize); +DWORD SetState(LPVOID pv, DWORD dwSize); + +DWORD GetInfo(ICINFO* icinfo, DWORD dwSize); + +DWORD CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD Compress(ICCOMPRESS* icinfo, DWORD dwSize); +DWORD CompressEnd(); + +DWORD DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD Decompress(ICDECOMPRESS* icinfo, DWORD dwSize); +DWORD DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); +DWORD DecompressEnd(); + diff --git a/ZoeCodec.sln b/ZoeCodec.sln new file mode 100644 index 0000000..2f9061e --- /dev/null +++ b/ZoeCodec.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoeCodec", "ZoeCodec.vcxproj", "{593C6401-0389-4AB5-9432-47BDA9E1A938}" + ProjectSection(ProjectDependencies) = postProject + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0} = {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codec_test", "codec_test\codec_test.vcxproj", "{AA9B1B20-0207-41E4-B8F5-0B0529B60D41}" + ProjectSection(ProjectDependencies) = postProject + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0} = {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zoe_codec_lib", "zoe_codec_lib.vcxproj", "{1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Debug|Win32.ActiveCfg = Debug|Win32 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Debug|Win32.Build.0 = Debug|Win32 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Debug|x64.ActiveCfg = Debug|x64 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Debug|x64.Build.0 = Debug|x64 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Release|Win32.ActiveCfg = Release|Win32 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Release|Win32.Build.0 = Release|Win32 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Release|x64.ActiveCfg = Release|x64 + {593C6401-0389-4AB5-9432-47BDA9E1A938}.Release|x64.Build.0 = Release|x64 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Debug|Win32.Build.0 = Debug|Win32 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Debug|x64.ActiveCfg = Debug|x64 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Debug|x64.Build.0 = Debug|x64 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Release|Win32.ActiveCfg = Release|Win32 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Release|Win32.Build.0 = Release|Win32 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Release|x64.ActiveCfg = Release|x64 + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41}.Release|x64.Build.0 = Release|x64 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Debug|Win32.ActiveCfg = Debug|Win32 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Debug|Win32.Build.0 = Debug|Win32 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Debug|x64.ActiveCfg = Debug|x64 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Debug|x64.Build.0 = Debug|x64 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Release|Win32.ActiveCfg = Release|Win32 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Release|Win32.Build.0 = Release|Win32 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Release|x64.ActiveCfg = Release|x64 + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ZoeCodec.vcxproj b/ZoeCodec.vcxproj new file mode 100644 index 0000000..b1dc53d --- /dev/null +++ b/ZoeCodec.vcxproj @@ -0,0 +1,256 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {593C6401-0389-4AB5-9432-47BDA9E1A938} + Win32Proj + ZoeCodec + + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + + + + + + + + + + + + + + + + + true + zoecod32 + + + true + zoecod64 + + + false + zoecod32 + + + false + zoecod64 + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ZOECODEC_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + zoecod32.def + install_$(Configuration)/$(TargetName)$(TargetExt) + + + + + + + + + + copy zoecod32.inf install_$(Configuration) + copy readme.txt install_$(Configuration) + copy install_zoe_codec.bat install_$(Configuration) + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ZOECODEC_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + zoecod64.def + install_$(Configuration)/$(TargetName)$(TargetExt) + + + + + + + + + + copy zoecod64.inf install_$(Configuration) + copy readme.txt install_$(Configuration) + copy install_zoe_codec.bat install_$(Configuration) + + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ZOECODEC_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + NotSet + zoecod32.def + install_$(Configuration)/$(TargetName)$(TargetExt) + + + + + + + + + + copy zoecod32.inf install_$(Configuration) + copy readme.txt install_$(Configuration) + copy install_zoe_codec.bat install_$(Configuration) + + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ZOECODEC_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + zoecod64.def + install_$(Configuration)/$(TargetName)$(TargetExt) + + + + + + + + + + copy zoecod64.inf install_$(Configuration) + copy readme.txt install_$(Configuration) + copy install_zoe_codec.bat install_$(Configuration) + + + + + + + + Document + + + + Document + + + + + + + + + + + + false + false + + + + + false + false + + + + + + + Create + Create + Create + Create + + + + + + {1657f79c-ff78-4cac-adaa-3ff571d0a4a0} + false + true + false + true + false + + + + + + \ No newline at end of file diff --git a/codec_test/codec_test.cpp b/codec_test/codec_test.cpp new file mode 100644 index 0000000..27b12b3 --- /dev/null +++ b/codec_test/codec_test.cpp @@ -0,0 +1,460 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include + +#include "../codecs.h" +#include "../huffman.h" + + +class TestBitPacker +{ +public: + TestBitPacker(char* bufferStart) : cur_ptr(bufferStart), cur(0), used_bits(0) + { + } + void pack(int bitcount, unsigned int value) + { + while (bitcount>0) + { + int to_use = std::min(bitcount, 8-used_bits); + cur <<= to_use; + unsigned int mask = ((1<> (bitcount-to_use); + bitcount -= to_use; + used_bits += to_use; + if (used_bits==8) + { + *cur_ptr = cur; + cur = 0; + used_bits = 0; + cur_ptr++; + } + } + } + void flush() + { + if (used_bits>0) + *cur_ptr = cur; + } +private: + unsigned char cur; + int used_bits; + char * cur_ptr; +}; + +void pack10Bits(const std::vector& in, unsigned char * packed) +{ + TestBitPacker bitPacker((char*)packed); + + for (int i=0;i& in, unsigned char * packed) +{ + TestBitPacker bitPacker((char*)packed); + + for (int i=0;i +void print_binary(T b) +{ + for (int i=(sizeof(T)*8)-1;i>=0;i--) + printf("%c", (b&(1< input_data(test_width * test_height*3); + srand(2501); + fillSemiRandom(&input_data[0], test_width * test_height*3); + + std::vector compressed(test_width * test_height*3 * 2); + unsigned int compressed_size = Compress_Y8_To_HY8(test_width*3, test_height, &input_data[0], &compressed[0]); + + printf(" Compressed size %d/%d\n", compressed_size, test_width*3 * test_height); + + compressed.resize(compressed_size); + + std::vector output_data(test_width*3 * test_height); + Decompress_HY8_To_Y8(compressed_size, test_width*3, test_height, &compressed[0], &output_data[0]); + + for (int i=0;i input_data(test_width * test_height * nb_channels); + srand(2501); + for (int c=0;c compressed(test_width * test_height * nb_channels * 1000, 0); + unsigned int compressed_size = Compress_Y8_To_HY8(test_width * nb_channels, test_height, &input_data[0], &compressed[0]); + + printf(" Compressed size %d/%d\n", compressed_size, test_width * test_height * nb_channels); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height * nb_channels, 0); + Decompress_HY8_To_Y8(compressed_size, test_width * nb_channels, test_height, &compressed[0], &output_data[0]); + + for (int i=0;i compressed(test_width * test_height * nb_channels * 1000, 0); + unsigned int compressed_size = Compress_RGB24_To_HRGB24(test_width, test_height, &input_data[0], &compressed[0]); + + printf(" Compressed size %d/%d\n", compressed_size, test_width * test_height * nb_channels); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height * nb_channels, 0); + Decompress_HRGB24_To_RGB24(compressed_size, test_width, test_height, &compressed[0], &output_data[0]); + + for (int i=0;i input_data(test_width * test_height * nb_channels); + srand(2501); + for (int c=0;c compressed(test_width * test_height * nb_channels * 1000, 0); + unsigned int compressed_size = Compress_Y8_To_HY8(test_width * nb_channels, test_height, &input_data[0], &compressed[0]); + + printf(" Compressed size %d/%d\n", compressed_size, test_width * test_height * nb_channels); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height * nb_channels, 0); + Decompress_HY8_To_Y8(compressed_size, test_width * nb_channels, test_height, &compressed[0], &output_data[0]); + + for (int i=0;i compressed(test_width * test_height * nb_channels * 1000, 0); + unsigned int compressed_size = Compress_UYVY_To_HUYVY(test_width, test_height, &input_data[0], &compressed[0]); + + printf(" Compressed size %d/%d\n", compressed_size, test_width * test_height * nb_channels); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height * nb_channels, 0); + Decompress_HUYVY_To_UYVY(compressed_size, test_width, test_height, &compressed[0], &output_data[0]); + + for (int i=0;i input_data(test_width * test_height); // 10 bits in LSB of 16 + srand(2501); + fillSemiRandom10(&input_data[0], test_width * test_height); + + std::vector compressed(test_width * test_height * 2 * 2); + unsigned int compressed_size = Compress_Y10_To_HY10(test_width, test_height, (const unsigned char *)&input_data[0], &compressed[0]); + + printf(" Compressed size %d/%d\n", compressed_size, test_width * test_height * 2); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height); + Decompress_HY10_To_Y10(compressed_size, test_width, test_height, &compressed[0], (unsigned char *)&output_data[0]); + + for (int i=0;i input_data(16); + input_data[0] = 0x03FF; + input_data[1] = 0; + input_data[2] = 0x03FF; + input_data[3] = 0; + input_data[4] = 0x03FF; + input_data[5] = 0; + input_data[6] = 0x03FF; + input_data[7] = 0; + input_data[8] = 0x03FF; + input_data[9] = 0; + input_data[10] = 0x03FF; + input_data[11] = 0; + input_data[12] = 0x03FF; + input_data[13] = 0; + input_data[14] = 0x03FF; + input_data[15] = 0; + + std::vector packed_buffer(20); + + pack10Bits(input_data, &packed_buffer[0]); + + for (int i=0;i<20;i++) + { + printf("byte %d : ", i); + print_binary(packed_buffer[i]); + printf(" (%08X)\n", packed_buffer[i]); + } + + UnpackBitReader<10, unsigned short> reader((const unsigned short *)&packed_buffer[0]); + for (int i=0;i<16;i++) + { + unsigned short data = reader.next(); + printf("result: %08X\n", data); + } + } + + printf("Test grayscale 10 bit (packed 10 bit data)\n"); + { + std::vector input_data(test_width * test_height); // 10 bits in LSB of 16 + srand(2501); + fillSemiRandom10(&input_data[0], test_width * test_height); + + // Swap endianness + for (unsigned int i=0;i packed_buffer(test_width * test_height * 20 / 16); + pack10Bits(input_data, &packed_buffer[0]); + + UnpackBitReader<10, unsigned short> reader((const unsigned short *)&packed_buffer[0]); + + std::vector compressed(test_width * test_height * 2 * 4); + unsigned int compressed_size = Compress_PY10_To_HY10(test_width, test_height, (const unsigned char *)&packed_buffer[0], &compressed[0]); + + printf(" Compressed size %d/%d (unpacked:%d)\n", compressed_size, packed_buffer.size(), test_width * test_height * 2); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height); + Decompress_HY10_To_Y10(compressed_size, test_width, test_height, &compressed[0], (unsigned char *)&output_data[0]); + + for (int i=0;i input_data(test_width * test_height); // 12 bits in LSB of 16 + srand(2501); + fillSemiRandom12(&input_data[0], test_width * test_height); + + // Swap endianness + for (unsigned int i=0;i packed_buffer(test_width * test_height * 2); + pack12Bits(input_data, &packed_buffer[0]); + + UnpackBitReader<12, unsigned short> reader((const unsigned short *)&packed_buffer[0]); + + std::vector compressed(test_width * test_height * 2 * 4); + unsigned int compressed_size = Compress_PY12_To_HY12(test_width, test_height, (const unsigned char *)&packed_buffer[0], &compressed[0]); + + printf(" Compressed size %d/%d (unpacked:%d)\n", compressed_size, packed_buffer.size(), test_width * test_height * 2); + + compressed.resize(compressed_size); + + std::vector output_data(test_width * test_height); + Decompress_HY12_To_Y12(compressed_size, test_width, test_height, &compressed[0], (unsigned char *)&output_data[0]); + + for (int i=0;i + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AA9B1B20-0207-41E4-B8F5-0B0529B60D41} + Win32Proj + codec_test + + + + Application + true + NotSet + + + Application + true + NotSet + + + Application + false + true + NotSet + + + Application + false + true + NotSet + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + {1657f79c-ff78-4cac-adaa-3ff571d0a4a0} + false + true + false + true + false + + + + + + \ No newline at end of file diff --git a/codecs.cpp b/codecs.cpp new file mode 100644 index 0000000..063305f --- /dev/null +++ b/codecs.cpp @@ -0,0 +1,374 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Revision History: +// 2014-03-28 E. Danvoye Initial Release +// + +#include "stdafx.h" +#include "codecs.h" +#include "huffman.h" + +unsigned Compress_RGB24_To_RGB24(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 3; + memcpy(out_frame, in_frame, len); // uncompressed + return len; +} + +unsigned Compress_RGB32_To_RGB32(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 4; + memcpy(out_frame, in_frame, len); // uncompressed + return len; +} + +bool Decompress_RGB24_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 3; + + if (inSize != len) + return false; + + memcpy(out_frame, in_frame, len); + return true; +} + +bool Decompress_RGB32_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 4; + + if (inSize != len) + return false; + + memcpy(out_frame, in_frame, len); + return true; +} + +unsigned Compress_Y8_To_Y8(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 1; + memcpy(out_frame, in_frame, len); // uncompressed + return len; +} + +unsigned Compress_Y8_To_HY8(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const char *)in_frame, (char*)out_frame); + return len; +} + +unsigned Compress_Y10_To_HY10(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const short *)in_frame, (char*)out_frame); + return len; +} + +unsigned Compress_PY10_To_HY10(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const short *)in_frame, (char*)out_frame); + return len; +} + +unsigned Compress_PY12_To_HY12(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const short *)in_frame, (char*)out_frame); + return len; +} + +unsigned Compress_Y10_To_Y10(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 2; + memcpy(out_frame, in_frame, len); // uncompressed + return len; +} + +bool Decompress_Y8_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 1; + + if (inSize != len) + return false; + + memcpy(out_frame, in_frame, len); + return true; +} + +bool Decompress_HY8_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HY8_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HY10_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HY10_To_Y10(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (short*)out_frame); +} + +bool Decompress_HY8_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HY10_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (short*)out_frame); +} + +bool Decompress_HY10_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_Y10_To_Y10(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 2; + + if (inSize != len) + return false; + + memcpy(out_frame, in_frame, len); + return true; +} + +bool Decompress_Y10_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 2; + + if (inSize != len) + return false; + + const unsigned short* in_values = (const unsigned short*)(in_frame); + + for (unsigned i=0;i>2)&0x00FF; + + return true; +} + +bool Decompress_Y8_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + int* destination = (int *)(out_frame); + + // Convert MONO to YUV422 (U and V will be zero) + for (unsigned i=0;i>2; + unsigned char pixel2 = img_16bit[i*2+1]>>2; + unsigned int yuv = (pixel1<<8) | (pixel2<<24) | 0x00800080; + destination[i] = yuv; + } + + return true; +} + +unsigned Compress_RGB24_To_HRGB24(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const char *)in_frame, (char*)out_frame); + return len; +} + +bool Decompress_HRGB24_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +unsigned Compress_RGB32_To_HRGB32(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const char *)in_frame, (char*)out_frame); + return len; +} + +bool Decompress_HRGB32_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +unsigned Compress_UYVY_To_HUYVY(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const char *)in_frame, (char*)out_frame); + return len; +} + +bool Decompress_HUYVY_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HUYVY_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HRGB24_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame, bool reverse_y) +{ + ZoeHuffmanCodec huff(width, height); + if (reverse_y) + return huff.decode((const char *)in_frame, (char*)out_frame); + else + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HY8_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HY10_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +bool Decompress_HUYVY_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + +unsigned Compress_Y12_To_Y12(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 2; + memcpy(out_frame, in_frame, len); // uncompressed + return len; +} +bool Decompress_Y12_To_Y12(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 2; + + if (inSize != len) + return false; + + memcpy(out_frame, in_frame, len); + return true; +} +bool Decompress_Y12_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + // LOSSY, we drop the four LSB of the Y12 data + + const unsigned short * img_16bit = (const unsigned short *)(in_frame); + int* destination = (int *)(out_frame); + + for (unsigned i=0;i>4; + unsigned char pixel2 = img_16bit[i*2+1]>>4; + unsigned int yuv = (pixel1<<8) | (pixel2<<24) | 0x00800080; + destination[i] = yuv; + } + + return true; +} +unsigned Compress_Y12_To_HY12(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + unsigned len = huff.encode >((const short *)in_frame, (char*)out_frame); + return len; +} +bool Decompress_HY12_To_Y12(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (short*)out_frame); +} +bool Decompress_HY12_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (short*)out_frame); +} +bool Decompress_HY12_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} +bool Decompress_Y12_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + unsigned len = width * height * 2; + + if (inSize != len) + return false; + + const unsigned short* in_values = (const unsigned short*)(in_frame); + + for (unsigned i=0;i>4)&0x00FF; + + return true; +} +bool Decompress_HY12_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} +bool Decompress_HY12_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame) +{ + ZoeHuffmanCodec huff(width, height); + return huff.decode((const char *)in_frame, (char*)out_frame); +} + diff --git a/codecs.h b/codecs.h new file mode 100644 index 0000000..f7eb3c5 --- /dev/null +++ b/codecs.h @@ -0,0 +1,82 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +unsigned Compress_RGB24_To_RGB24(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_RGB24_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_RGB32_To_RGB32(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_RGB32_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_Y8_To_Y8(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y8_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y8_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_Y10_To_Y10(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y10_To_Y10(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y10_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +// Huffman +unsigned Compress_Y8_To_HY8(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY8_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY8_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY8_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_Y10_To_HY10(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +unsigned Compress_PY10_To_HY10(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY10_To_Y10(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY10_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY10_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +bool Decompress_Y10_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY10_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_RGB24_To_HRGB24(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HRGB24_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_RGB32_To_HRGB32(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HRGB32_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_UYVY_To_HUYVY(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HUYVY_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HUYVY_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +bool Decompress_HRGB24_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame, bool reverse_y); +bool Decompress_HY8_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY10_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HUYVY_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); + +unsigned Compress_Y12_To_Y12(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y12_To_Y12(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y12_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +unsigned Compress_Y12_To_HY12(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +unsigned Compress_PY12_To_HY12(unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY12_To_Y12(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY12_To_UYVY(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY12_To_RGB24(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_Y12_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY12_To_Y8(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); +bool Decompress_HY12_To_RGB32(unsigned inSize, unsigned width, unsigned height, const unsigned char* in_frame, unsigned char* out_frame); diff --git a/dllmain.cpp b/dllmain.cpp new file mode 100644 index 0000000..7b79d18 --- /dev/null +++ b/dllmain.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Revision History: +// 2014-03-28 E. Danvoye Initial Release +// + +#include "stdafx.h" + +#include "dllmain.h" +#include "ZoeCodec.h" + +BOOL WINAPI DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +ZOECODEC_API LRESULT WINAPI DriverProc(DWORD dwDriverID, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2) +{ + + switch (uiMessage) { + case DRV_LOAD: + return (LRESULT)1L; + + case DRV_FREE: + return (LRESULT)1L; + + case DRV_OPEN: + return (LRESULT)1L; + + case DRV_CLOSE: + return (LRESULT)1L; + + case DRV_QUERYCONFIGURE: + return (LRESULT)1L; + + case DRV_CONFIGURE: + Configure((HWND)lParam1); + return DRV_OK; + + case ICM_CONFIGURE: + // return ICERR_OK if you will do a configure box, error otherwise + if (lParam1 == -1) + return QueryConfigure() ? ICERR_OK : ICERR_UNSUPPORTED; + else + return Configure((HWND)lParam1); + + case ICM_ABOUT: + // return ICERR_OK if you will do a about box, error otherwise + if (lParam1 == -1) + return QueryAbout() ? ICERR_OK : ICERR_UNSUPPORTED; + else + return About((HWND)lParam1); + + case ICM_GETSTATE: + return GetState((LPVOID)lParam1, (DWORD)lParam2); + + case ICM_SETSTATE: + return SetState((LPVOID)lParam1, (DWORD)lParam2); + + case ICM_GETINFO: + return GetInfo((ICINFO*)lParam1, (DWORD)lParam2); + + case ICM_GETDEFAULTQUALITY: + if (lParam1) { + *((LPDWORD)lParam1) = 1000; + return ICERR_OK; + } + break; + + case ICM_COMPRESS: + return Compress((ICCOMPRESS*)lParam1, (DWORD)lParam2); + + case ICM_COMPRESS_QUERY: + return CompressQuery((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_BEGIN: + return CompressBegin((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_GET_FORMAT: + return CompressGetFormat((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_GET_SIZE: + return CompressGetSize((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_END: + return CompressEnd(); + + case ICM_DECOMPRESS_QUERY: + // The ICM_DECOMPRESS_QUERY message queries a video decompression driver to determine if it supports a specific input format or if it can decompress a specific input format to a specific output format. + return DecompressQuery((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS: + return Decompress((ICDECOMPRESS*)lParam1, (DWORD)lParam2); + + case ICM_DECOMPRESS_BEGIN: + return DecompressBegin((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS_GET_FORMAT: + // The ICM_DECOMPRESS_GET_FORMAT message requests the output format of the decompressed data from a video decompression driver. + return DecompressGetFormat((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS_GET_PALETTE: + return DecompressGetPalette((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS_END: + return DecompressEnd(); + + // Driver messages + + case DRV_DISABLE: + case DRV_ENABLE: + return (LRESULT)1L; + + case DRV_INSTALL: + case DRV_REMOVE: + return (LRESULT)DRV_OK; + } + + if (uiMessage < DRV_USER) + return DefDriverProc(dwDriverID, hDriver, uiMessage, lParam1, lParam2); + else + return ICERR_UNSUPPORTED; +} diff --git a/dllmain.h b/dllmain.h new file mode 100644 index 0000000..ee255f5 --- /dev/null +++ b/dllmain.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +#define ZOECODEC_API //extern "C" __declspec(dllexport) + +// Single point of entry for VFW codec +ZOECODEC_API LRESULT WINAPI DriverProc(DWORD dwDriverID, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2); diff --git a/huffman.cpp b/huffman.cpp new file mode 100644 index 0000000..7f87a1a --- /dev/null +++ b/huffman.cpp @@ -0,0 +1,438 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Revision History: +// 2014-03-28 E. Danvoye Initial Release +// + +#include "stdafx.h" + +#include "huffman.h" + +#include +#include + +// Manual instantiation of template +template class ZoeHuffmanCodec; +template class ZoeHuffmanCodec; +template class ZoeHuffmanCodec; +template class ZoeHuffmanCodec; +template class ZoeHuffmanCodec; +template class ZoeHuffmanCodec; + +struct HuffNode { + unsigned freq; + unsigned left; + unsigned right; +}; + +struct StoredTreeNode +{ + StoredTreeNode() : left(-1), right(-1) {} + + unsigned short left; + unsigned short right; +}; + +static void buildHuffFromNode(unsigned* huff_bits, unsigned* huff_length, const HuffNode& node, const HuffNode* nodes, unsigned depth, unsigned code) +{ + // Left + unsigned left_code = (code << 1); + if (node.left>=0x8000) + { + buildHuffFromNode(huff_bits, huff_length, nodes[node.left-0x8000], nodes, depth+1, left_code); + } + else + { + // logMessage("L Symbol:%d Depth:%d Len:%d Code:%s\n",node.left,depth,depth+1,binstr(left_code,depth+1)); + huff_bits[node.left] = left_code; + huff_length[node.left] = depth+1; + } + + // Right + unsigned right_code = (code << 1) | 1; + if (node.right>=0x8000) + { + buildHuffFromNode(huff_bits, huff_length, nodes[node.right-0x8000], nodes, depth+1, right_code); + } + else + { + // logMessage("R Symbol:%d Depth:%d Len:%d Code:%s\n",node.right,depth,depth+1,binstr(right_code,depth+1)); + huff_bits[node.right] = right_code; + huff_length[node.right] = depth+1; + } +} + +template +void buildHuffmanTables(std::pair* char_count, int& char_count_used, unsigned* huff_bits, unsigned* huff_length, int& storedTreeUsed, StoredTreeNode* storedTree) +{ + // Build Huffmann tree + HuffNode huffNodes[(1<1) + { + int rootCount = char_count_used; + unsigned newNodeIndex = usedHuffNodes++; + + // Create node from two smallest frequencies + HuffNode * newNode = &huffNodes[newNodeIndex]; + newNode->freq = char_count[rootCount-2].second + char_count[rootCount-1].second; + newNode->left = char_count[rootCount-2].first; + newNode->right =char_count[rootCount-1].first; + + // remove two items that have just been parented under the node + char_count_used-=2; + + // add this new node to the tree + char_count[char_count_used++] = std::make_pair(0x8000+newNodeIndex,newNode->freq); + + // Make sure the order is still preserved after this insertion + for (size_t i=char_count_used-1;i>0;i--) + { + if (char_count[i].second<=char_count[i-1].second) + break; + std::swap(char_count[i], char_count[i-1]); + } + } + + // Build tree to be included in stream + { + storedTreeUsed = usedHuffNodes; + for (int i=0;i +ZoeHuffmanCodec::ZoeHuffmanCodec(int width, int height) + : image_width(width), + image_height(height) +{ +} + +template +template +unsigned ZoeHuffmanCodec::encode(const T * image_src, char * image_dest) +{ + // Character usage count + for (int c=0;c::type du = ((std::make_unsigned::type)d)&BitMask; + + encoder_data[c].char_count[du].second++; + prev[c] = b; + } + } + + size_t compressed_size = 0; + + for (int c=0;c& a, std::pair& b){return a.second > b.second;}); + + // remove symbols with zero occurrences + while (encoder_data[c].char_count[encoder_data[c].char_count_used-1].second==0) + encoder_data[c].char_count_used--; + + // Store huffman tables in the compressed stream + StoredTreeNode storedTree[(1<(encoder_data[c].char_count, encoder_data[c].char_count_used, encoder_data[c].huff_bits, encoder_data[c].huff_length, storedTreeUsed, storedTree); + + // Store huffman tables in the compressed stream + *((unsigned int *)&image_dest[compressed_size]) = storedTreeUsed; + compressed_size+= 4; + *((unsigned int *)&image_dest[compressed_size]) = encoder_data[c].char_count[0].first - 0x8000; // root index + compressed_size+= 4; + memcpy(&image_dest[compressed_size], storedTree, sizeof(StoredTreeNode)*storedTreeUsed); + compressed_size += sizeof(StoredTreeNode)*storedTreeUsed; + } + + // For each line, build compressed stream by concatenating bits + BitPacker bitPacker(&image_dest[compressed_size]); + + reader.reset(); + + for (int y=0;y::type)d)&BitMask; + + bitPacker.pack(encoder_data[c].huff_length[du], encoder_data[c].huff_bits[du]); + prev[c] = b; + } + } + compressed_size += bitPacker.flush(); + + return (unsigned)compressed_size; +} + +template +class BitReader +{ +public: + BitReader(const char * src_ptr) : ptr((const T *)src_ptr), pos(0) + { + current = *ptr++; + } + bool next() + { + if (pos==sizeof(T)*8) + { + current = *ptr++; + pos = 0; + } + + bool r = (current & ((T)1<<(sizeof(T)*8-1)))!=0; + current <<= 1; + pos++; + + return r; + } +private: + const T * ptr; + int pos; + T current; +}; + +class HuffmanTree +{ +public: + HuffmanTree(int rootIndex, const StoredTreeNode * storedTree) : m_rootIndex(rootIndex), m_storedTree(storedTree), m_currentIndex(rootIndex) + { + } + HuffmanTree() : m_rootIndex(0), m_storedTree(0), m_currentIndex(0) + { + } + void init(int rootIndex, const StoredTreeNode * storedTree) + { + m_rootIndex = rootIndex; + m_storedTree = storedTree; + m_currentIndex = rootIndex; + } + unsigned int next(bool bit) + { + // return 0xFFFFFFFF if we have to continue searching + // return char value if we read a leaf + + int side = bit?m_storedTree[m_currentIndex].right:m_storedTree[m_currentIndex].left; + if (side<0x8000) + { + m_currentIndex = m_rootIndex; + return side; + } + else + { + m_currentIndex = side-0x8000; + return 0xFFFFFFFF; + } + } + +private: + int m_currentIndex; + int m_rootIndex; + const StoredTreeNode * m_storedTree; +}; + +unsigned char Clip(int clr) +{ + return (unsigned char)(clr < 0 ? 0 : ( clr > 255 ? 255 : clr )); +} + +template +template +bool ZoeHuffmanCodec::decode(const char * image_src, To * image_dest) +{ + HuffmanTree tree[Channels]; + + for (int c=0;c reader(src_ptr); + + for (int y=0;y::type du = ((std::make_unsigned::type)prev[chan])&BitMask; + + if (op==OutputProcessing::interleave_yuyv && sizeof(To)==1) + *dest_ptr++ = (To)0x80; + if (op==OutputProcessing::interleave_yuyv && sizeof(To)==2) + du = ((du<(du); + + if (nb_read%4==3) // when we have decoded UYVY, convert two RGB24 pixels + { + // dest_ptr is currently pointing to the second G in RGBRGB + dest_ptr -= 4; // return to beginning of this pixel + + // Convert two pixels of UYVY to two RGB24 + const int y0 = ((unsigned char*)dest_ptr)[1] - 16; + const int y1 = ((unsigned char*)dest_ptr)[3] - 16; + const int cb = ((unsigned char*)dest_ptr)[0] - 128; + const int cr = ((unsigned char*)dest_ptr)[2] - 128; + *dest_ptr++ = Clip(( 298 * y0 + 516 * cb + 128) >> 8); // B0 + *dest_ptr++ = Clip(( 298 * y0 - 100 * cb - 208 * cr + 128) >> 8); // G0 + *dest_ptr++ = Clip(( 298 * y0 + 409 * cr + 128) >> 8); // R0 + if (op==OutputProcessing::uyvy_to_rgb32) + *dest_ptr++ = 0xFF; + *dest_ptr++ = Clip(( 298 * y1 + 516 * cb + 128) >> 8); // B1 + *dest_ptr++ = Clip(( 298 * y1 - 100 * cb - 208 * cr + 128) >> 8); // G1 + *dest_ptr++ = Clip(( 298 * y1 + 409 * cr + 128) >> 8); // R1 + if (op==OutputProcessing::uyvy_to_rgb32) + *dest_ptr++ = 0xFF; + } + } + else + { + for (int c=0;c<((op==OutputProcessing::gray_to_rgb32 || op==OutputProcessing::gray_to_rgb24)?3:1);c++) + { + if (sizeof(To)*8((du>>(UsedBits-sizeof(To)*8))&0xFF); + else + *dest_ptr++ = static_cast(du); + } + if (op==OutputProcessing::gray_to_rgb32) + *dest_ptr++ = 0xFF; + if ((op==OutputProcessing::rgb24_to_rgb32 || op==OutputProcessing::rgb24_to_rgb32_revY) && chan==2) + *dest_ptr++ = 0xFF; + } + + nb_read++; + } + } + + return true; +} + +// Manual instantiation of template function +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, short * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, short * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // Y8 decoded directly to RGB24 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // Y10 decoded directly to RGB24 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // UYVY decoded directly to RGB24 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // RGB24 converted to RGB32 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // RGB24 converted to RGB32, reverse Y +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // Y8 decoded directly to RGB32 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // Y10 decoded directly to RGB32 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // UYVY decoded directly to RGB32 + +template unsigned int ZoeHuffmanCodec::encode >(char const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(short const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(short const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(char const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(char const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(char const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(short const *,char *); +template unsigned int ZoeHuffmanCodec::encode >(short const *,char *); + +template bool ZoeHuffmanCodec::decode(const char * image_src, short * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, short * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // Y12 decoded directly to RGB24 +template bool ZoeHuffmanCodec::decode(const char * image_src, char * image_dest); // Y12 decoded directly to RGB32 + diff --git a/huffman.h b/huffman.h new file mode 100644 index 0000000..9f3a8bf --- /dev/null +++ b/huffman.h @@ -0,0 +1,170 @@ +// Copyright (c) 2014, Activision +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided +// that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +// promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include + +namespace OutputProcessing +{ + enum {Default, interleave_yuyv, gray_to_rgb24, uyvy_to_rgb24, rgb24_to_rgb32, gray_to_rgb32, uyvy_to_rgb32, rgb24_to_rgb32_revY}; +} + +template +class TrivialBitReader +{ +public: + TrivialBitReader(const T * ptr) : cur_ptr(ptr), org_ptr(ptr) + {} + T next() + { + T value = *cur_ptr; + cur_ptr++; + return value; + } + void reset() + { + cur_ptr = org_ptr; + } + typedef T typeT; +private: + const T* cur_ptr; + const T* org_ptr; +}; + +template +class UnpackBitReader +{ +public: + UnpackBitReader(const outputT * ptr) : cur_ptr((const char *)ptr), org_ptr((const char *)ptr), bits(8) + {} + outputT next() + { + // cur_ptr is the pointer to the current byte + // bits is the current offset in the current byte (how many bits are already read in this byte) + + // read remaining bits in the current byte + outputT mask = (1<<(bits)) - 1; + outputT value = (*cur_ptr)&mask; + + // goto next byte + cur_ptr++; + const int remaining_bits = bitCount-bits; + if (remaining_bits>0) + { + // read second part + outputT mask = ((1<> (8-remaining_bits)); + bits = 8-remaining_bits; + if (bits==0) + { + cur_ptr++; + bits = 8; + } + } + + return value; + } + void reset() + { + cur_ptr = org_ptr; + } + typedef outputT typeT; +private: + int bits; + const char* cur_ptr; + const char* org_ptr; +}; + +template +class ZoeHuffmanCodec +{ +public: + ZoeHuffmanCodec(int width, int height); + + template + unsigned encode(const T * src, char * dest); + + template + bool decode(const char * image_src, To * image_dest); + +private: + + static const int BitShift = sizeof(T)*8 - UsedBits; + static const int BitMask = (1< char_count[1<0x8000, it is huffNode index+0x8000 + int char_count_used; + unsigned huff_bits[1< +class BitPacker +{ +public: + BitPacker(char* bufferStart) : next((T*)bufferStart), start((T*)bufferStart), current(0), current_bitcount(0) { } + __inline void pack(int bitcount, unsigned bits) // relevant bits are in the LSB of bits + { + if (current_bitcount+bitcount > (sizeof(T)*8)) + { + unsigned first_bitcount = (sizeof(T)*8)-current_bitcount; + unsigned second_bitcount = bitcount-first_bitcount; + + *next = (current<>second_bitcount); + next++; + + current = bits; + current_bitcount = second_bitcount; + } + else + { + current = (current<0) + { + *next = current << ((sizeof(T)*8)-current_bitcount); + next++; + } + + return (unsigned)((char*)next-(char*)start); + } +private: + T * next; + T * start; + T current; + unsigned current_bitcount; +}; diff --git a/install_zoe_codec.bat b/install_zoe_codec.bat new file mode 100644 index 0000000..c80bf05 --- /dev/null +++ b/install_zoe_codec.bat @@ -0,0 +1,9 @@ +ECHO OFF + +ECHO Install 64 bit +rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 0 %~dp0zoecod64.inf + +ECHO Install 32 bit +c:\windows\syswow64\rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 0 %~dp0zoecod32.inf + +pause diff --git a/stdafx.cpp b/stdafx.cpp new file mode 100644 index 0000000..96298c2 --- /dev/null +++ b/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ZoeCaptureCodec.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 0000000..f05293c --- /dev/null +++ b/stdafx.h @@ -0,0 +1,21 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +#include // Video For Windows + +#include +#include + +#include +#include + diff --git a/targetver.h b/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/zoe_codec_lib.vcxproj b/zoe_codec_lib.vcxproj new file mode 100644 index 0000000..ca13930 --- /dev/null +++ b/zoe_codec_lib.vcxproj @@ -0,0 +1,137 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + {1657F79C-FF78-4CAC-ADAA-3FF571D0A4A0} + Win32Proj + zoe_codec_lib + + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/zoecod32.def b/zoecod32.def new file mode 100644 index 0000000..93c7ee7 --- /dev/null +++ b/zoecod32.def @@ -0,0 +1,4 @@ +LIBRARY ZOECOD32 + +EXPORTS + DriverProc diff --git a/zoecod32.inf b/zoecod32.inf new file mode 100644 index 0000000..f553f7e --- /dev/null +++ b/zoecod32.inf @@ -0,0 +1,52 @@ +; +; Zoe Lossless AVI video codec (32 bit) +; +; Copyright (c) 2013 Activision +; +[version] +signature="$CHICAGO$" + +[DefaultInstall] +CopyFiles=ZOECOD.Files.Inf,ZOECOD.Files.Dll +AddReg=ZOECOD.Reg +UpdateInis=ZOECOD.INIs + +[DefaultUnInstall] +DelFiles=ZOECOD.Files.Dll,ZOECOD.Files.Inf +DelReg=ZOECOD.Reg +UpdateInis=ZOECOD.INIs.Del + +[SourceDisksNames] +1="Zoe Lossless codec (32bit)","",1 + +[SourceDisksFiles] +ZOECOD32.INF=1 +ZOECOD32.DLL=1 + +[DestinationDirs] +ZOECOD.Files.Inf=17 +ZOECOD.Files.Dll=11 + +[ZOECOD.Files.Inf] +ZOECOD32.INF + +[ZOECOD.Files.Dll] +ZOECOD32.DLL + +[ZOECOD.Reg] +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.AZCL,Description,,"Zoe Lossless codec (32bit) [AZCL]" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.AZCL,Driver,,"ZOECOD32.dll" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.AZCL,FriendlyName,,"Zoe Lossless codec (32bit) [AZCL]" + +HKLM,"Software\Microsoft\Windows NT\CurrentVersion\drivers.desc",ZOECOD32.dll,,"Zoe Lossless codec (32bit) [AZCL]" +HKLM,"Software\Microsoft\Windows NT\CurrentVersion\Drivers32",VIDC.AZCL,,"ZOECOD32.dll" + +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZOECOD32 +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZOECOD32,DisplayName,,"Zoe Lossless codec (32bit) (Remove Only)" +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZOECOD32,UninstallString,,"%11%\rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 %17%\ZOECOD32.INF" + +[ZOECOD.INIs] +system.ini, drivers32,, "VIDC.AZCL=ZOECOD32.dll" + +[ZOECOD.INIs.Del] +system.ini, drivers32, "VIDC.AZCL=ZOECOD32.dll" diff --git a/zoecod64.def b/zoecod64.def new file mode 100644 index 0000000..23b2bf2 --- /dev/null +++ b/zoecod64.def @@ -0,0 +1,4 @@ +LIBRARY ZOECOD64 + +EXPORTS + DriverProc diff --git a/zoecod64.inf b/zoecod64.inf new file mode 100644 index 0000000..8d3655d --- /dev/null +++ b/zoecod64.inf @@ -0,0 +1,48 @@ +; +; Zoe Lossless AVI video codec (64 bit) +; +; Copyright (c) 2013 Activision +; +[version] +signature="$CHICAGO$" +Class = MEDIA + +[DefaultInstall] +CopyFiles=ZOECOD.Files.Inf,ZOECOD.Files.Dll +AddReg=ZOECOD.Reg +MediaType = SOFTWARE + +[Remove_AZCL] +DelFiles=ZOECOD.Files.Dll,ZOECOD.Files.Inf +DelReg=ZOECOD.Reg + +[SourceDisksNames] +1="Zoe Lossless codec (64bit)",,1 + +[SourceDisksFiles] +ZOECOD64.dll=1 +ZOECOD64.INF=1 + +[Installable.Drivers] +AZCL = 1:ZOECOD64.dll, "vidc.AZCL", "Zoe Lossless codec (64bit) [AZCL]",,, + +[DestinationDirs] +ZOECOD.Files.Inf=17 +ZOECOD.Files.Dll=11 + +[ZOECOD.Files.Inf] +ZOECOD64.INF + +[ZOECOD.Files.Dll] +ZOECOD64.DLL + +[ZOECOD.Reg] +HKLM,SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers32,vidc.AZCL,,ZOECOD64.dll +HKLM,SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers.desc, ZOECOD64.dll,, "Zoe Lossless codec (64bit)" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.AZCL,Description,,"Zoe Lossless codec (64bit) [AZCL]" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.AZCL,Driver,,"ZOECOD64.dll" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.AZCL,FriendlyName,,"Zoe Lossless codec (64bit) [AZCL]" + +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZOECOD64 +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZOECOD64,DisplayName,,"Zoe Lossless codec (64bit) (Remove Only)" +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZOECOD64,UninstallString,,"%11%\rundll32.exe setupapi,InstallHinfSection Remove_AZCL 132 %17%\ZOECOD64.INF"