1235 lines
37 KiB
C
1235 lines
37 KiB
C
/*----------------------------------------------------------------------+
|
|
| 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
|