windows-nt/Source/XPSP1/NT/multimedia/media/avi/msvidc/msvidc.c

1235 lines
37 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*----------------------------------------------------------------------+
| msvidc.c - Microsoft Video 1 Compressor |
| |
| Copyright (c) 1990-1995 Microsoft Corporation. |
| Portions Copyright Media Vision Inc. |
| All Rights Reserved. |
| |
| You have a non-exclusive, worldwide, royalty-free, and perpetual |
| license to use this source code in developing hardware, software |
| (limited to drivers and other software required for hardware |
| functionality), and firmware for video display and/or processing |
| boards. Microsoft makes no warranties, express or implied, with |
| respect to the Video 1 codec, including without limitation warranties |
| of merchantability or fitness for a particular purpose. Microsoft |
| shall not be liable for any damages whatsoever, including without |
| limitation consequential damages arising from your use of the Video 1 |
| codec. |
| |
| |
+----------------------------------------------------------------------*/
#include <win32.h>
#include <ole2.h>
#include <mmsystem.h>
#ifndef _INC_COMPDDK
#define _INC_COMPDDK 50 /* version number */
#endif
#include <vfw.h>
#ifdef _WIN32
#define abs(x) ((x) < 0 ? -(x) : (x))
#endif
#ifdef _WIN32
#include <memory.h> /* for memcpy */
#endif
#ifdef _WIN32
#define _FPInit() 0
#define _FPTerm(x)
#else
void _acrtused2(void) {}
extern LPVOID WINAPI _FPInit(void);
extern void WINAPI _FPTerm(LPVOID);
#endif
#include "msvidc.h"
#ifdef _WIN32
#include "profile.h"
#endif
#ifndef _WIN32
static BOOL gf286 = FALSE;
#endif
#define FOURCC_MSVC mmioFOURCC('M','S','V','C')
#define FOURCC_CRAM mmioFOURCC('C','R','A','M')
#define FOURCC_Cram mmioFOURCC('C','r','a','m')
#define TWOCC_XX aviTWOCC('d', 'c')
#define QUALITY_DEFAULT 2500
#define VERSION 0x00010000 // 1.0
ICSTATE DefaultState = {75};
INT_PTR FAR PASCAL _LOADDS ConfigureDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
#ifndef _WIN32
//
// put the compress stuff in the "rare" segment
//
#pragma alloc_text(_TEXT, ConfigureDlgProc)
#pragma alloc_text(_TEXT, CompressBegin)
#pragma alloc_text(_TEXT, CompressQuery)
#pragma alloc_text(_TEXT, CompressGetFormat)
#pragma alloc_text(_TEXT, Compress)
#pragma alloc_text(_TEXT, CompressGetSize)
#pragma alloc_text(_TEXT, CompressEnd)
#endif
/*****************************************************************************
* dither stuff..
****************************************************************************/
#include <dith775.h>
LPVOID lpDitherTable;
//////////////////////////////////////////////////////////////////////////////
//
// Dither16InitScale()
//
//////////////////////////////////////////////////////////////////////////////
#pragma optimize("", off)
STATICFN LPVOID Dither16InitScale()
{
LPVOID p;
LPBYTE pbLookup;
LPWORD pwScale;
UINT r,g,b;
p = GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE, 32768l*2+64000);
if (p == NULL)
return NULL;
pwScale = (LPWORD)p;
for (r=0; r<32; r++)
for (g=0; g<32; g++)
for (b=0; b<32; b++)
*pwScale++ = 1600 * r + 40 * g + b;
pbLookup = (LPBYTE)(((WORD _huge *)p) + 32768l);
for (r=0; r<40; r++)
for (g=0; g<40; g++)
for (b=0; b<40; b++)
*pbLookup++ = lookup775[35*rlevel[r] + 5*glevel[g] + blevel[b]];
return p;
}
#pragma optimize("", on)
/*****************************************************************************
****************************************************************************/
#ifndef _WIN32
BOOL NEAR PASCAL VideoLoad(void)
{
gf286 = (BOOL)(GetWinFlags() & WF_CPU286);
#ifdef DEBUG
gf286 = GetProfileIntA("Debug", "cpu", gf286 ? 286 : 386) == 286;
#endif
return TRUE;
}
#endif
/*****************************************************************************
****************************************************************************/
void NEAR PASCAL VideoFree()
{
// CompressFrameFree(); // let compression stuff clean up...
if (lpDitherTable != NULL) {
GlobalFreePtr(lpDitherTable);
lpDitherTable = NULL;
}
}
/*****************************************************************************
****************************************************************************/
INSTINFO * NEAR PASCAL VideoOpen(ICOPEN FAR * icinfo)
{
INSTINFO * pinst;
//
// refuse to open if we are not being opened as a Video compressor
//
if (icinfo->fccType != ICTYPE_VIDEO)
return NULL;
pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
if (!pinst) {
icinfo->dwError = (DWORD)ICERR_MEMORY;
return NULL;
}
//
// init structure
//
pinst->dwFlags = icinfo->dwFlags;
pinst->nCompress = 0;
pinst->nDecompress = 0;
pinst->nDraw = 0;
//
// set the default state.
//
SetState(pinst, NULL, 0);
//
// return success.
//
icinfo->dwError = ICERR_OK;
return pinst;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL VideoClose(INSTINFO * pinst)
{
while (pinst->nCompress > 0)
CompressEnd(pinst);
while (pinst->nDecompress > 0)
DecompressEnd(pinst);
while (pinst->nDraw > 0)
DrawEnd(pinst);
LocalFree((HLOCAL)pinst);
return 1;
}
/*****************************************************************************
****************************************************************************/
#ifndef QueryAbout
BOOL NEAR PASCAL QueryAbout(INSTINFO * pinst)
{
return TRUE;
}
#endif
LONG NEAR PASCAL About(INSTINFO * pinst, HWND hwnd)
{
char achDescription[128];
char achAbout[64];
LoadStringA(ghModule, IDS_DESCRIPTION, achDescription, sizeof(achDescription));
LoadStringA(ghModule, IDS_ABOUT, achAbout, sizeof(achAbout));
MessageBoxA(hwnd,achDescription,achAbout,
MB_OK|MB_ICONINFORMATION);
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
#ifndef QueryConfigure
BOOL NEAR PASCAL QueryConfigure(INSTINFO * pinst)
{
return TRUE;
}
#endif
LONG NEAR PASCAL Configure(INSTINFO * pinst, HWND hwnd)
{
return (LONG) DialogBoxParam(ghModule,TEXT("Configure"),hwnd,ConfigureDlgProc, (LONG_PTR)(UINT_PTR)pinst);
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL GetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
{
if (pv == NULL || dwSize == 0)
return sizeof(ICSTATE);
if (dwSize < sizeof(ICSTATE))
return 0;
*((ICSTATE FAR *)pv) = pinst->CurrentState;
// return number of bytes copied
return sizeof(ICSTATE);
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL SetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
{
if (pv == NULL)
pinst->CurrentState = DefaultState;
else if (dwSize == sizeof(ICSTATE))
pinst->CurrentState = *((ICSTATE FAR *)pv);
else
return 0;
// return number of bytes copied
return sizeof(ICSTATE);
}
#if !defined NUMELMS
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
#endif
#if defined _WIN32 && !defined UNICODE
int LoadUnicodeString(HINSTANCE hinst, UINT wID, LPWSTR lpBuffer, int cchBuffer)
{
char ach[128];
int i;
i = LoadString(hinst, wID, ach, sizeof(ach));
if (i > 0)
MultiByteToWideChar(CP_ACP, 0, ach, -1, lpBuffer, cchBuffer);
return i;
}
#else
#define LoadUnicodeString LoadString
#endif
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL GetInfo(INSTINFO * pinst, ICINFO FAR *icinfo, DWORD dwSize)
{
if (icinfo == NULL)
return sizeof(ICINFO);
if (dwSize < sizeof(ICINFO))
return 0;
icinfo->dwSize = sizeof(ICINFO);
icinfo->fccType = ICTYPE_VIDEO;
icinfo->fccHandler = FOURCC_MSVC;
icinfo->dwFlags = VIDCF_QUALITY | // supports quality
VIDCF_TEMPORAL; // supports inter-frame
icinfo->dwVersion = VERSION;
icinfo->dwVersionICM = ICVERSION;
LoadUnicodeString(ghModule, IDS_DESCRIPTION, icinfo->szDescription, NUMELMS(icinfo->szDescription));
LoadUnicodeString(ghModule, IDS_NAME, icinfo->szName, NUMELMS(icinfo->szName));
return sizeof(ICINFO);
}
/*****************************************************************************
****************************************************************************/
LONG FAR PASCAL CompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
if (lpbiOut)
DPF(("CompressQuery %dx%dx%d --> %dx%dx%d'%4.4hs'", (int)lpbiIn->biWidth, (int)lpbiIn->biHeight, (int)lpbiIn->biBitCount, (int)lpbiOut->biWidth, (int)lpbiOut->biHeight, (int)lpbiOut->biBitCount, (LPSTR)&lpbiOut->biCompression));
else
DPF(("CompressQuery %dx%dx%d", (int)lpbiIn->biWidth, (int)lpbiIn->biHeight, (int)lpbiIn->biBitCount));
//
// determine if the input DIB data is in a format we like.
//
if (lpbiIn == NULL ||
!(lpbiIn->biBitCount == 8 ||
lpbiIn->biBitCount == 16 ||
lpbiIn->biBitCount == 24 ||
lpbiIn->biBitCount == 32) ||
lpbiIn->biPlanes != 1 ||
lpbiIn->biWidth < 4 ||
lpbiIn->biHeight < 4 ||
lpbiIn->biCompression != BI_RGB)
return ICERR_BADFORMAT;
//
// are we being asked to query just the input format?
//
if (lpbiOut == NULL)
return ICERR_OK;
//
// make sure we can handle the format to compress to also.
//
if (!(lpbiOut->biCompression == FOURCC_MSVC || // must be 'MSVC' or 'CRAM'
lpbiOut->biCompression == FOURCC_CRAM) ||
!(lpbiOut->biBitCount == 16 || // must be 8 or 16
lpbiOut->biBitCount == 8) ||
(lpbiOut->biPlanes != 1) ||
(lpbiOut->biWidth & ~3) != (lpbiIn->biWidth & ~3) || // must be 1:1 (no stretch)
(lpbiOut->biHeight & ~3) != (lpbiIn->biHeight & ~3))
return ICERR_BADFORMAT;
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG FAR PASCAL CompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
LONG l;
if (l = CompressQuery(pinst, lpbiIn, NULL))
return l;
if (lpbiIn->biBitCount == 8)
{
//
// if lpbiOut == NULL then, return the size required to hold a output
// format
//
DWORD dwClrUsed = lpbiIn->biClrUsed;
if (dwClrUsed == 0) {
dwClrUsed = 256;
}
l = lpbiIn->biSize + (int)dwClrUsed * sizeof(RGBQUAD);
if (lpbiOut == NULL)
return l;
hmemcpy(lpbiOut, lpbiIn, (int)l);
lpbiOut->biBitCount = 8;
}
else
{
//
// if lpbiOut == NULL then, return the size required to hold a output
// format
//
if (lpbiOut == NULL)
return (int)lpbiIn->biSize;
*lpbiOut = *lpbiIn;
lpbiOut->biClrUsed = 0;
lpbiOut->biBitCount = 16;
}
lpbiOut->biWidth = lpbiIn->biWidth & ~3;
lpbiOut->biHeight = lpbiIn->biHeight & ~3;
lpbiOut->biCompression = FOURCC_CRAM;
lpbiOut->biSizeImage = CompressGetSize(pinst, lpbiIn, lpbiOut);
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG FAR PASCAL CompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
LONG l;
if (l = CompressQuery(pinst, lpbiIn, lpbiOut))
return l;
DPF(("CompressBegin %dx%dx%d --> %dx%dx%d'%4.4ls'", (int)lpbiIn->biWidth, (int)lpbiIn->biHeight, (int)lpbiIn->biBitCount, (int)lpbiOut->biWidth, (int)lpbiOut->biHeight, (int)lpbiOut->biBitCount,(LPSTR)&lpbiOut->biCompression));
//
// initialize for compression, for real....
//
pinst->nCompress = 1;
return CompressFrameBegin(lpbiIn, lpbiOut, &pinst->lpITable, pinst->rgbqOut);
}
/*****************************************************************************
****************************************************************************/
LONG FAR PASCAL CompressGetSize(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
int dx,dy;
dx = (int)lpbiIn->biWidth;
dy = (int)lpbiIn->biHeight;
/* maximum compressed size *** your code here *** */
if (lpbiOut->biBitCount == 8)
// worst case size of data 10 bytes per 16 pixels (8 colors + mask)
// remember the EOF code!
return ((DWORD)dx * (DWORD)dy * 10l) / 16l + 2l;
else
// worst case size of data 18 bytes per 16 pixels (8 colors + mask)
// remember the EOF code!
return ((DWORD)dx * (DWORD)dy * 10l) / 8l + 2l; // 10/8 ~= 18/16
////////return ((DWORD)dx * (DWORD)dy * 18l) / 16l + 2l;
}
/*****************************************************************************
****************************************************************************/
LONG FAR PASCAL Compress(INSTINFO * pinst, ICCOMPRESS FAR *icinfo, DWORD dwSize)
{
LONG l;
LPBITMAPINFOHEADER lpbiIn = icinfo->lpbiInput;
LPBITMAPINFOHEADER lpbiOut = icinfo->lpbiOutput;
DWORD threshold;
DWORD thresholdPrev;
DWORD dwQualityPrev;
DWORD dwQuality;
BOOL fBegin;
LPVOID smag;
PCELLS compressTemp;
if (l = CompressQuery(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
return l;
//
// check for being called without a BEGIN message, and do the begin for
// the caller
//
if (fBegin = (pinst->nCompress == 0))
{
if (l = CompressBegin(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
return l;
}
smag = _FPInit();
DPF(("Compress %dx%dx%d --> %dx%dx%d'%4.4ls'", (int)lpbiIn->biWidth, (int)lpbiIn->biHeight, (int)lpbiIn->biBitCount, (int)lpbiOut->biWidth, (int)lpbiOut->biHeight, (int)lpbiOut->biBitCount, (LPSTR)&lpbiOut->biCompression));
if (icinfo->dwQuality == ICQUALITY_DEFAULT)
dwQuality = QUALITY_DEFAULT;
else
dwQuality = ICQUALITY_HIGH - icinfo->dwQuality;
dwQualityPrev = MulDiv((UINT)dwQuality,100,pinst->CurrentState.wTemporalRatio);
threshold = QualityToThreshold(dwQuality);
thresholdPrev = QualityToThreshold(dwQualityPrev);
if (pinst->Status)
pinst->Status(pinst->lParam, ICSTATUS_START, 0);
// For Win16, this needs to be in the data segment so we
// can use a near pointer to it.
compressTemp = (PCELLS) LocalAlloc(LPTR, sizeof(CELLS));
if (!compressTemp)
return ICERR_MEMORY;
if (lpbiOut->biBitCount == 8)
l = CompressFrame8(
icinfo->lpbiInput, // DIB header to compress
icinfo->lpInput, // DIB bits to compress
icinfo->lpOutput, // put compressed data here
threshold, // edge threshold
thresholdPrev, // inter-frame threshold
icinfo->lpbiPrev, // previous frame
icinfo->lpPrev, // previous frame
pinst->Status, // status callback
pinst->lParam,
compressTemp,
pinst->lpITable,
pinst->rgbqOut);
else
l = CompressFrame16(
icinfo->lpbiInput, // DIB header to compress
icinfo->lpInput, // DIB bits to compress
icinfo->lpOutput, // put compressed data here
threshold, // edge threshold
thresholdPrev, // inter-frame threshold
icinfo->lpbiPrev, // previous frame
icinfo->lpPrev, // previous frame
pinst->Status, // status callback
pinst->lParam,
compressTemp);
LocalFree((HLOCAL) compressTemp);
if (pinst->Status)
pinst->Status(pinst->lParam, ICSTATUS_END, 0);
_FPTerm(smag);
if (l == -1)
return ICERR_ERROR;
lpbiOut->biWidth = lpbiIn->biWidth & ~3;
lpbiOut->biHeight = lpbiIn->biHeight & ~3;
lpbiOut->biCompression = FOURCC_CRAM;
lpbiOut->biSizeImage = l;
////lpbiOut->biBitCount = 16;
//
// return the chunk id
//
if (icinfo->lpckid)
*icinfo->lpckid = TWOCC_XX;
//
// set the AVI index flags,
//
// make it a keyframe?
//
if (icinfo->lpdwFlags) {
*icinfo->lpdwFlags = AVIIF_TWOCC;
if (icinfo->lpbiPrev == NULL || numberOfSkips == 0)
*icinfo->lpdwFlags |= AVIIF_KEYFRAME;
}
if (fBegin)
CompressEnd(pinst);
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG FAR PASCAL CompressEnd(INSTINFO * pinst)
{
if (pinst->nCompress == 0)
return ICERR_ERROR;
pinst->nCompress = 0;
return CompressFrameEnd(&pinst->lpITable);
}
/*****************************************************************************
*
* decompress tables
*
* indexed by:
* SRC: 0=8 bit Cram 1=16 bit Cram
* STRETCH: 0=1:1, 1=1:2
* DST: 0=8, 1=16, 2=24, 3=32
*
****************************************************************************/
#ifdef _WIN32
DECOMPPROC DecompressWin32[2][2][5] = {
DecompressFrame8, // Cram8 1:1 to 8
NULL, // Cram8 1:1 to 16 (555)
NULL, // Cram8 1:1 to 24
NULL, // Cram8 1:1 to 32
NULL, // Cram8 1:1 to 565
DecompressFrame8X2C, // Cram8 1:2 to 8
NULL, // Cram8 1:2 to 16 (555)
NULL, // Cram8 1:2 to 24
NULL, // Cram8 1:2 to 32
NULL, // Cram8 1:2 to 565
DecompressFrame16To8C, // Cram16 1:1 to 8
DecompressFrame16To555C, // Cram16 1:1 to 16 (555)
DecompressFrame24, // Cram16 1:1 to 24
NULL, // Cram16 1:1 to 32
DecompressFrame16To565C, // Cram16 1:1 to 565
DecompressFrame16To8X2C, // Cram16 1:2 to 8
NULL, // Cram16 1:2 to 16 (555)
NULL, // Cram16 1:2 to 24
NULL, // Cram16 1:2 to 32
NULL}; // Cram16 1:2 to 565
#else
DECOMPPROC Decompress386[2][2][5] = {
DecompressCram8, // Cram8 1:1 to 8
NULL, // Cram8 1:1 to 16 (555)
NULL, // Cram8 1:1 to 24
NULL, // Cram8 1:1 to 32
NULL, // Cram8 1:1 to 565
DecompressCram8x2, // Cram8 1:2 to 8
NULL, // Cram8 1:2 to 16 (555)
NULL, // Cram8 1:2 to 24
NULL, // Cram8 1:2 to 32
NULL, // Cram8 1:2 to 565
DecompressCram168, // Cram16 1:1 to 8
DecompressCram16, // Cram16 1:1 to 16 (555)
NULL, // Cram16 1:1 to 24
NULL /* DecompressCram32 */, // Cram16 1:1 to 32
NULL /* DecompressFrame16To565C */, // Cram16 1:1 to 565
NULL, // Cram16 1:2 to 8
DecompressCram16x2, // Cram16 1:2 to 16 (555)
NULL, // Cram16 1:2 to 24
NULL, // Cram16 1:2 to 32
NULL}; // Cram16 1:2 to 565
DECOMPPROC Decompress286[2][2][5] = {
DecompressCram8_286, // Cram8 1:1 to 8
NULL, // Cram8 1:1 to 16 (555)
NULL, // Cram8 1:1 to 24
NULL, // Cram8 1:1 to 32
NULL, // Cram8 1:1 to 565
NULL, // Cram8 1:2 to 8
NULL, // Cram8 1:2 to 16 (555)
NULL, // Cram8 1:2 to 24
NULL, // Cram8 1:2 to 32
NULL, // Cram8 1:2 to 565
NULL, // Cram16 1:1 to 8
DecompressCram16_286, // Cram16 1:1 to 16 (555)
NULL, // Cram16 1:1 to 24
NULL, // Cram16 1:1 to 32
NULL, // Cram16 1:1 to 565
NULL, // Cram16 1:2 to 8
NULL, // Cram16 1:2 to 16 (555)
NULL, // Cram16 1:2 to 24
NULL, // Cram16 1:2 to 32
NULL}; // Cram16 1:2 to 565
#endif
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DecompressQueryFmt(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiSrc)
{
//
// determine if the input DIB data is in a format we like.
//
if (lpbiSrc == NULL ||
!(lpbiSrc->biBitCount == 16 || lpbiSrc->biBitCount == 8) ||
(lpbiSrc->biPlanes != 1) ||
!(lpbiSrc->biCompression == FOURCC_MSVC ||
lpbiSrc->biCompression == FOURCC_CRAM))
return ICERR_BADFORMAT;
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DecompressQuery(
INSTINFO * pinst,
DWORD dwFlags,
LPBITMAPINFOHEADER lpbiSrc,
LPVOID pSrc,
int xSrc,
int ySrc,
int dxSrc,
int dySrc,
LPBITMAPINFOHEADER lpbiDst,
LPVOID pDst,
int xDst,
int yDst,
int dxDst,
int dyDst)
{
#ifndef _WIN32
DWORD biSizeImage;
#endif
DECOMPPROC fn;
int s,d,n;
//
// determine if the input DIB data is in a format we like.
//
if (DecompressQueryFmt(pinst, lpbiSrc))
return ICERR_BADFORMAT;
//
// allow (-1) as a default width/height
//
if (dxSrc == -1)
dxSrc = (int)lpbiSrc->biWidth;
if (dySrc == -1)
dySrc = (int)lpbiSrc->biHeight;
//
// we cant clip the source.
//
if (xSrc != 0 || ySrc != 0)
return ICERR_BADPARAM;
if ((dxSrc != (int)lpbiSrc->biWidth) || (dySrc != (int)lpbiSrc->biHeight))
return ICERR_BADPARAM;
//
// are we being asked to query just the input format?
//
if (lpbiDst == NULL)
return ICERR_OK;
//
// allow (-1) as a default width/height
//
if (dxDst == -1)
dxDst = (int)lpbiDst->biWidth;
if (dyDst == -1)
dyDst = abs((int)lpbiDst->biHeight);
#ifndef _WIN32
if (gf286)
biSizeImage = (DWORD)(UINT)abs((int)lpbiDst->biHeight)*(DWORD)(WORD)DIBWIDTHBYTES(*lpbiDst);
#endif
s = lpbiSrc->biBitCount/8-1; // s = 0,1
#ifdef _WIN32
// Can't support 16:32 access in our C version, of course....
if (lpbiDst->biCompression == BI_1632) {
return ICERR_BADFORMAT;
}
#endif
if (lpbiDst->biBitCount != 8 && lpbiDst->biBitCount != 16 && lpbiDst->biBitCount != 24 && lpbiDst->biBitCount != 32)
{
return ICERR_BADFORMAT;
}
// must be full dib or a '1632' DIB
if (lpbiDst->biCompression != BI_RGB &&
lpbiDst->biCompression != BI_1632) {
if (lpbiDst->biCompression != BI_BITFIELDS) {
DPF(("MSVIDC asked to decompress to '%.4hs'!", &lpbiDst->biCompression));
return ICERR_BADFORMAT;
}
// allow 565 dibs
if ((lpbiDst->biBitCount == 16) &&
(((LPDWORD)(lpbiDst+1))[0] == 0x00f800) &&
(((LPDWORD)(lpbiDst+1))[1] == 0x0007e0) &&
(((LPDWORD)(lpbiDst+1))[2] == 0x00001f) ) {
// ok - its 565 format
d = 4;
} else {
DPF(("Bad bitmask (%lX %lX %lX) in %d-bit BI_BITMAP case!",
lpbiDst->biBitCount,
((LPDWORD)(lpbiDst+1))[0],
((LPDWORD)(lpbiDst+1))[1],
((LPDWORD)(lpbiDst+1))[2]));
return ICERR_BADFORMAT;
}
} else {
d = lpbiDst->biBitCount/8-1; // d = 0,1,2,3
if (lpbiDst->biCompression == BI_1632 && lpbiDst->biBitCount == 16) {
if ((((LPDWORD)(lpbiDst+1))[0] == 0x007400) &&
(((LPDWORD)(lpbiDst+1))[1] == 0x0003f0) &&
(((LPDWORD)(lpbiDst+1))[2] == 0x00000f) ) {
// ok - it's 555 format
} else if ((((LPDWORD)(lpbiDst+1))[0] == 0x00f800) &&
(((LPDWORD)(lpbiDst+1))[1] == 0x0007e0) &&
(((LPDWORD)(lpbiDst+1))[2] == 0x00001f) ) {
// ok - it's 565 format
d = 4;
} else {
DPF(("Bad bitmask (%lX %lX %lX) in 16-bit BI_1632 case!",
((LPDWORD)(lpbiDst+1))[0],
((LPDWORD)(lpbiDst+1))[1],
((LPDWORD)(lpbiDst+1))[2]));
return ICERR_BADFORMAT;
}
}
// What about 24-bit BI_1632? Should we check the masks?
}
//
// n = 0 for 1:1, 1 for 1:2
//
if (dxDst == dxSrc && dyDst == dySrc)
n = 0;
else if (dxDst == dxSrc*2 && dyDst == dySrc*2)
n = 1;
else
return ICERR_BADSIZE;
#ifdef DEBUG
DPF(("DecompressQuery %dx%dx%d [%d,%d,%d,%d] --> %dx%dx%d (565) [%d,%d,%d,%d]",
(int)lpbiSrc->biWidth, (int)lpbiSrc->biHeight, (int)lpbiSrc->biBitCount,
xSrc, ySrc, dxSrc, dySrc,
(int)lpbiDst->biWidth, (int)lpbiDst->biHeight, (int)lpbiDst->biBitCount,
d == 4 ? "(565)" : "",
xDst, yDst, dxDst, dyDst));
#endif
#ifdef _WIN32
fn = DecompressWin32[s][n][d];
#else
if (gf286)
{
fn = Decompress286[s][n][d];
if (fn && biSizeImage > 64l*1024)
fn = fn==DecompressCram8_286 ? DecompressFrame8 : NULL;
}
else
{
fn = Decompress386[s][n][d];
}
#endif
if (fn == NULL)
return ICERR_BADFORMAT;
pinst->DecompressTest = fn; // return this to DecompressBegin.
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DecompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
LONG l;
int dx,dy;
if (l = DecompressQueryFmt(pinst, lpbiIn))
return l;
//
// if lpbiOut == NULL then, return the size required to hold a output
// format
//
if (lpbiOut == NULL)
return (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
hmemcpy(lpbiOut, lpbiIn,
(int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
dx = (int)lpbiIn->biWidth & ~3;
dy = (int)lpbiIn->biHeight & ~3;
lpbiOut->biWidth = dx;
lpbiOut->biHeight = dy;
lpbiOut->biBitCount = lpbiIn->biBitCount; // convert 8->8 16->16
lpbiOut->biPlanes = 1;
lpbiOut->biCompression = BI_RGB;
lpbiOut->biSizeImage = (DWORD)(WORD)abs(dy)*(DWORD)(WORD)DIBWIDTHBYTES(*lpbiOut);
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DecompressBegin(
INSTINFO * pinst,
DWORD dwFlags,
LPBITMAPINFOHEADER lpbiSrc,
LPVOID pSrc,
int xSrc,
int ySrc,
int dxSrc,
int dySrc,
LPBITMAPINFOHEADER lpbiDst,
LPVOID pDst,
int xDst,
int yDst,
int dxDst,
int dyDst)
{
LONG l;
if (l = DecompressQuery(pinst, dwFlags, lpbiSrc, pSrc, xSrc, ySrc, dxSrc, dySrc, lpbiDst, pDst, xDst, yDst, dxDst, dyDst))
return l;
pinst->DecompressProc = pinst->DecompressTest;
//
// make sure biSizeImage is set, the decompress code needs it to be
//
if (lpbiDst->biSizeImage == 0)
lpbiDst->biSizeImage = (DWORD)(WORD)abs((int)lpbiDst->biHeight)*(DWORD)(WORD)DIBWIDTHBYTES(*lpbiDst);
//
// init the dither tables !!! call MSVIDEO, dont have code here!!!
//
if (lpbiSrc->biBitCount == 16 &&
lpbiDst->biBitCount == 8)
{
if (lpDitherTable == NULL)
lpDitherTable = Dither16InitScale();
if (lpDitherTable == NULL)
return ICERR_MEMORY;
}
pinst->nDecompress = 1;
return ICERR_OK;
}
/*****************************************************************************
*
* Decompress
*
* we can assume certain things here because DecompressQuery() only lets
* valid stuff in.
*
* the source rect is always the entire source.
* the dest rect is either 1:1 or 1:2
*
****************************************************************************/
LONG NEAR PASCAL Decompress(
INSTINFO * pinst,
DWORD dwFlags,
LPBITMAPINFOHEADER lpbiSrc,
LPVOID pSrc,
int xSrc,
int ySrc,
int dxSrc,
int dySrc,
LPBITMAPINFOHEADER lpbiDst,
LPVOID pDst,
int xDst,
int yDst,
int dxDst,
int dyDst)
{
//
// if we are called without a begin do the begin now, but dont make
// the begin "stick"
//
if (pinst->nDecompress == 0)
{
LONG err;
if (err = DecompressBegin(pinst, dwFlags, lpbiSrc, pSrc, xSrc, ySrc, dxSrc, dySrc, lpbiDst, pDst, xDst, yDst, dxDst, dyDst))
return err;
pinst->nDecompress = 0;
}
#ifdef DEBUG
if (lpbiDst->biSizeImage == 0)
DebugBreak();
if (pinst->DecompressProc == NULL)
DebugBreak();
#endif
(*pinst->DecompressProc)(lpbiSrc,pSrc,lpbiDst,pDst,xDst,yDst);
return ICERR_OK;
}
/*****************************************************************************
*
* DecompressGetPalette() implements ICM_GET_PALETTE
*
* This function has no Compress...() equivalent
*
* It is used to pull the palette from a frame in order to possibly do
* a palette change.
*
****************************************************************************/
LONG NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
LONG l;
int i;
RGBQUAD FAR * prgb;
DPF(("DecompressGetPalette()"));
if (l = DecompressQueryFmt(pinst, lpbiIn))
return l;
if (lpbiOut->biBitCount != 8)
return ICERR_BADFORMAT;
//
// if you decompress full-color to 8 bit you need to put the "dither"
// palette in lpbiOut
//
if (lpbiIn->biBitCount != 8)
{
lpbiOut->biClrUsed = 256;
prgb = (LPVOID)(lpbiOut + 1);
for (i=0; i<256; i++)
{
prgb[i].rgbRed = dpal775[i][0];
prgb[i].rgbGreen = dpal775[i][1];
prgb[i].rgbBlue = dpal775[i][2];
prgb[i].rgbReserved = 0;
}
return ICERR_OK;
}
if (lpbiIn->biClrUsed == 0)
lpbiIn->biClrUsed = 256;
//
// return the 8bit palette used for decompression.
//
hmemcpy(
(LPBYTE)lpbiOut + (int)lpbiOut->biSize,
(LPBYTE)lpbiIn + (int)lpbiIn->biSize,
(int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
lpbiOut->biClrUsed = lpbiIn->biClrUsed;
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DecompressEnd(INSTINFO * pinst)
{
if (pinst->nDecompress == 0)
return ICERR_ERROR;
pinst->nDecompress = 0;
return ICERR_OK;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DrawBegin(INSTINFO * pinst,ICDRAWBEGIN FAR *icinfo, DWORD dwSize)
{
return ICERR_UNSUPPORTED;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL Draw(INSTINFO * pinst, ICDRAW FAR *icinfo, DWORD dwSize)
{
return ICERR_UNSUPPORTED;
}
/*****************************************************************************
****************************************************************************/
LONG NEAR PASCAL DrawEnd(INSTINFO * pinst)
{
return ICERR_UNSUPPORTED;
}
/*****************************************************************************
****************************************************************************/
INT_PTR FAR PASCAL _LOADDS ConfigureDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
int i;
HWND hsb;
TCHAR ach[10];
static TCHAR chDecimal = TEXT('.');
static INSTINFO *pinst;
#define SCROLL_MIN 1 // 0.00
#define SCROLL_MAX 100 // 1.00
switch (msg)
{
case WM_COMMAND:
switch (wParam)
{
case IDOK:
hsb = GetDlgItem(hdlg,ID_SCROLL);
pinst->CurrentState.wTemporalRatio = GetScrollPos(hsb,SB_CTL);
EndDialog(hdlg,TRUE);
break;
case IDCANCEL:
EndDialog(hdlg,FALSE);
break;
}
break;
case WM_HSCROLL:
hsb = GET_WM_HSCROLL_HWND(wParam, lParam);
i = GetScrollPos(hsb,SB_CTL);
switch (GET_WM_HSCROLL_CODE(wParam, lParam))
{
case SB_LINEDOWN: i += 1; break;
case SB_LINEUP: i -= 1; break;
case SB_PAGEDOWN: i += 10; break;
case SB_PAGEUP: i -= 10; break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
i = (int)GET_WM_HSCROLL_POS(wParam, lParam);
break;
default:
return TRUE;
}
i = max(SCROLL_MIN,min(SCROLL_MAX,i));
SetScrollPos(hsb,SB_CTL,i,TRUE);
wsprintf(ach, TEXT("%d%c%02d"), i/100, chDecimal, i%100);
SetDlgItemText(hdlg,ID_TEXT,ach);
return TRUE;
case WM_INITDIALOG:
pinst = (INSTINFO *)lParam;
ach[0] = chDecimal;
ach[1] = 0;
GetProfileString(TEXT("intl"), TEXT("sDecimal"), ach, ach,
sizeof(ach) / sizeof(ach[0]));
chDecimal = ach[0];
hsb = GetDlgItem(hdlg,ID_SCROLL);
i = pinst->CurrentState.wTemporalRatio;
SetScrollRange(hsb,SB_CTL,SCROLL_MIN, SCROLL_MAX, TRUE);
SetScrollPos(hsb,SB_CTL,i,TRUE);
wsprintf(ach, TEXT("%d%c%02d"), i/100, chDecimal, i%100);
SetDlgItemText(hdlg,ID_TEXT,ach);
return TRUE;
}
return FALSE;
}
/*****************************************************************************
****************************************************************************/
#ifdef DEBUG
#define _WINDLL
#include <stdarg.h>
#ifdef _WIN32
#define GetProfileIntA mmGetProfileIntA
#endif
void FAR CDECL dprintf(LPSTR szFormat, ...)
{
char ach[128];
static BOOL fDebug = -1;
va_list va;
va_start(va, szFormat);
if (fDebug == -1)
fDebug = GetProfileIntA("Debug", "MSVIDC", FALSE);
if (!fDebug)
return;
#ifdef _WIN32
wsprintfA(ach, "MSVIDC32: (tid %x) ", GetCurrentThreadId());
wvsprintfA(ach+strlen(ach),szFormat,va);
#else
lstrcpyA(ach, "MSVIDC: ");
wvsprintfA(ach+8,szFormat,va);
#endif
lstrcatA(ach, "\r\n");
OutputDebugStringA(ach);
va_end(va);
}
#endif