528 lines
14 KiB
C
528 lines
14 KiB
C
|
/****************************************************************************
|
||
|
*
|
||
|
* DRAWPROC.C
|
||
|
*
|
||
|
* Standard AVI drawing handler.
|
||
|
*
|
||
|
* InstallAVIDrawHandler()
|
||
|
*
|
||
|
* Copyright (c) 1992 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* You have a royalty-free right to use, modify, reproduce and
|
||
|
* distribute the Sample Files (and/or any modified version) in
|
||
|
* any way you find useful, provided that you agree that
|
||
|
* Microsoft has no warranty obligations or liability for any
|
||
|
* Sample Application Files which are modified.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include <win32.h>
|
||
|
#define NOAVIFILE
|
||
|
#include <vfw.h>
|
||
|
#include "common.h"
|
||
|
#include "mciavi.h"
|
||
|
|
||
|
#define FOURCC_VIDS mmioFOURCC('v','i','d','s')
|
||
|
#define FOURCC_AVIDraw mmioFOURCC('D','R','A','W')
|
||
|
#define VERSION_AVIDraw 0x00010000 // 1.00
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
HDRAWDIB ghdd;
|
||
|
#endif
|
||
|
|
||
|
#ifndef HUGE
|
||
|
#define HUGE _huge
|
||
|
#endif
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
|
||
|
typedef struct {
|
||
|
HDRAWDIB hdd;
|
||
|
|
||
|
HDC hdc; // HDC to draw to
|
||
|
|
||
|
int xDst; // destination rectangle
|
||
|
int yDst;
|
||
|
int dxDst;
|
||
|
int dyDst;
|
||
|
int xSrc; // source rectangle
|
||
|
int ySrc;
|
||
|
int dxSrc;
|
||
|
int dySrc;
|
||
|
BOOL fBackground;
|
||
|
|
||
|
BOOL fRle;
|
||
|
DWORD biSizeImage;
|
||
|
BOOL fNeedUpdate;
|
||
|
|
||
|
LONG rate; // playback rate (uSec / frame)
|
||
|
} INSTINFO, *PINSTINFO;
|
||
|
|
||
|
// static stuff in this file.
|
||
|
LONG_PTR FAR PASCAL _loadds ICAVIDrawProc(DWORD_PTR id, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2);
|
||
|
|
||
|
static LONG_PTR AVIDrawOpen(ICOPEN FAR * icopen);
|
||
|
static LONG AVIDrawClose(PINSTINFO pi);
|
||
|
static LONG AVIDrawGetInfo(ICINFO FAR *icinfo, LONG lSize);
|
||
|
static LONG AVIDrawQuery(PINSTINFO pi, LPBITMAPINFOHEADER lpbiIn);
|
||
|
static LONG AVIDrawSuggestFormat(PINSTINFO pi, ICDRAWSUGGEST FAR *lpicd, LONG cbicd);
|
||
|
STATICFN LONG AVIDrawBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd);
|
||
|
STATICFN LONG AVIDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd);
|
||
|
static LONG AVIDrawEnd(PINSTINFO pi);
|
||
|
static LONG AVIDrawChangePalette(PINSTINFO pi, LPBITMAPINFOHEADER lpbi);
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
|
||
|
LONG_PTR FAR PASCAL _loadds ICAVIDrawProc(DWORD_PTR id, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2)
|
||
|
{
|
||
|
INSTINFO *pi = (INSTINFO *)id;
|
||
|
|
||
|
switch (uiMessage)
|
||
|
{
|
||
|
case DRV_LOAD:
|
||
|
case DRV_FREE:
|
||
|
return 1;
|
||
|
|
||
|
/*********************************************************************
|
||
|
open
|
||
|
*********************************************************************/
|
||
|
|
||
|
case DRV_OPEN:
|
||
|
if (lParam2 == 0L)
|
||
|
return 1;
|
||
|
|
||
|
return AVIDrawOpen((ICOPEN FAR *)lParam2);
|
||
|
|
||
|
case DRV_CLOSE:
|
||
|
return AVIDrawClose(pi);
|
||
|
|
||
|
/*********************************************************************
|
||
|
Configure/Info messages
|
||
|
*********************************************************************/
|
||
|
|
||
|
case DRV_QUERYCONFIGURE: // configuration from drivers applet
|
||
|
return 0;
|
||
|
|
||
|
case DRV_CONFIGURE:
|
||
|
return 1;
|
||
|
|
||
|
case ICM_CONFIGURE:
|
||
|
case ICM_ABOUT:
|
||
|
return ICERR_UNSUPPORTED;
|
||
|
|
||
|
/*********************************************************************
|
||
|
state messages
|
||
|
*********************************************************************/
|
||
|
|
||
|
case ICM_GETSTATE:
|
||
|
case ICM_SETSTATE:
|
||
|
return 0L;
|
||
|
|
||
|
// case ICM_GETINFO:
|
||
|
// return AVIDrawGetInfo((ICINFO FAR *)lParam1, lParam2);
|
||
|
|
||
|
/*********************************************************************
|
||
|
decompress messages
|
||
|
*********************************************************************/
|
||
|
|
||
|
case ICM_DRAW_QUERY:
|
||
|
return AVIDrawQuery(pi, (LPBITMAPINFOHEADER)lParam1);
|
||
|
|
||
|
case ICM_DRAW_SUGGESTFORMAT:
|
||
|
return AVIDrawSuggestFormat(pi, (ICDRAWSUGGEST FAR *) lParam1, (LONG) lParam2);
|
||
|
|
||
|
case ICM_DRAW_BEGIN:
|
||
|
return AVIDrawBegin(pi, (ICDRAWBEGIN FAR *) lParam1, (LONG) lParam2);
|
||
|
|
||
|
case ICM_DRAW_REALIZE:
|
||
|
pi->hdc = (HDC) lParam1;
|
||
|
|
||
|
if (!pi->hdc || !pi->hdd)
|
||
|
break;
|
||
|
|
||
|
pi->fBackground = (BOOL) lParam2;
|
||
|
|
||
|
return DrawDibRealize(pi->hdd, pi->hdc, pi->fBackground);
|
||
|
|
||
|
case ICM_DRAW_GET_PALETTE:
|
||
|
if (!pi->hdd)
|
||
|
break;
|
||
|
|
||
|
return (LONG_PTR) DrawDibGetPalette(pi->hdd);
|
||
|
|
||
|
case ICM_DRAW:
|
||
|
return AVIDraw(pi, (ICDRAW FAR *)lParam1, (LONG) lParam2);
|
||
|
|
||
|
case ICM_DRAW_CHANGEPALETTE:
|
||
|
return AVIDrawChangePalette(pi, (LPBITMAPINFOHEADER) lParam1);
|
||
|
|
||
|
case ICM_DRAW_END:
|
||
|
return AVIDrawEnd(pi);
|
||
|
|
||
|
case ICM_DRAW_START:
|
||
|
return DrawDibStart(pi->hdd, pi->rate);
|
||
|
|
||
|
case ICM_DRAW_STOP:
|
||
|
return DrawDibStop(pi->hdd);
|
||
|
|
||
|
/*********************************************************************
|
||
|
standard driver messages
|
||
|
*********************************************************************/
|
||
|
|
||
|
case DRV_DISABLE:
|
||
|
case DRV_ENABLE:
|
||
|
return 1;
|
||
|
|
||
|
case DRV_INSTALL:
|
||
|
case DRV_REMOVE:
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return ICERR_UNSUPPORTED;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AVIDrawOpen() is called from the DRV_OPEN message
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
static LONG_PTR AVIDrawOpen(ICOPEN FAR * icopen)
|
||
|
{
|
||
|
INSTINFO * pinst;
|
||
|
|
||
|
if (icopen->dwFlags & ICMODE_COMPRESS)
|
||
|
return 0;
|
||
|
|
||
|
if (icopen->dwFlags & ICMODE_DECOMPRESS)
|
||
|
return 0;
|
||
|
|
||
|
pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
|
||
|
|
||
|
if (!pinst)
|
||
|
{
|
||
|
icopen->dwError = ICERR_MEMORY;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
DPF2(("*** AVIDrawOpen()\n"));
|
||
|
|
||
|
//
|
||
|
// init structure
|
||
|
//
|
||
|
pinst->hdd = DrawDibOpen();
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
// hack: put the hdd where FindDrawDevice can find it
|
||
|
ghdd = pinst->hdd;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// return success.
|
||
|
//
|
||
|
icopen->dwError = ICERR_OK;
|
||
|
|
||
|
return (LONG_PTR) (UINT_PTR) pinst;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Close() is called on the DRV_CLOSE message.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
static LONG AVIDrawClose(PINSTINFO pi)
|
||
|
{
|
||
|
DPF2(("*** AVIDrawClose()\n"));
|
||
|
|
||
|
if (pi->hdd) {
|
||
|
DrawDibClose(pi->hdd);
|
||
|
}
|
||
|
LocalFree((HLOCAL) pi);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AVIDrawGetInfo() implements the ICM_GETINFO message
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
static LONG AVIDrawGetInfo(ICINFO FAR *icinfo, LONG lSize)
|
||
|
{
|
||
|
if (icinfo == NULL)
|
||
|
return sizeof(ICINFO);
|
||
|
|
||
|
if (lSize < sizeof(ICINFO))
|
||
|
return 0;
|
||
|
|
||
|
icinfo->dwSize = sizeof(ICINFO);
|
||
|
icinfo->fccType = FOURCC_VIDS;
|
||
|
icinfo->fccHandler = FOURCC_AVIDraw;
|
||
|
icinfo->dwFlags = VIDCF_DRAW; // supports inter-frame
|
||
|
icinfo->dwVersion = VERSION_AVIDraw;
|
||
|
icinfo->dwVersionICM = ICVERSION;
|
||
|
icinfo->szName[0] = 0;
|
||
|
icinfo->szDescription[0]= 0;
|
||
|
|
||
|
return sizeof(ICINFO);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AVIDrawQuery() implements ICM_DRAW_QUERY
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
static LONG AVIDrawQuery(PINSTINFO pi,
|
||
|
LPBITMAPINFOHEADER lpbiIn)
|
||
|
{
|
||
|
//
|
||
|
// determine if the input DIB data is in a format we like.
|
||
|
//
|
||
|
if (lpbiIn == NULL)
|
||
|
return ICERR_BADFORMAT;
|
||
|
|
||
|
//
|
||
|
// determine if the input DIB data is in a format we like.
|
||
|
//
|
||
|
|
||
|
// !!! Do we need a DrawDibQuery or something here to let this handle
|
||
|
// any compressed format?
|
||
|
|
||
|
#ifdef DRAWDIBNODECOMPRESS
|
||
|
if (lpbiIn->biCompression != BI_RGB &&
|
||
|
#if 0
|
||
|
!(lpbiIn->biBitCount == 8 && lpbiIn->biCompression == BI_RLE8))
|
||
|
#else
|
||
|
1)
|
||
|
#endif
|
||
|
return ICERR_BADFORMAT;
|
||
|
#endif
|
||
|
|
||
|
return ICERR_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
static LONG AVIDrawSuggestFormat(PINSTINFO pi, ICDRAWSUGGEST FAR *lpicd, LONG cbicd)
|
||
|
{
|
||
|
HIC hic;
|
||
|
|
||
|
if (lpicd->lpbiSuggest == NULL)
|
||
|
return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
|
||
|
|
||
|
hic = ICGetDisplayFormat(NULL, lpicd->lpbiIn, lpicd->lpbiSuggest,
|
||
|
0, lpicd->dxDst, lpicd->dyDst);
|
||
|
|
||
|
if (hic)
|
||
|
ICClose(hic);
|
||
|
|
||
|
|
||
|
return sizeof(BITMAPINFOHEADER) + lpicd->lpbiSuggest->biClrUsed * sizeof(RGBQUAD);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AVIDrawBegin() implements ICM_DRAW_BEGIN
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
STATICFN LONG AVIDrawBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd)
|
||
|
{
|
||
|
LONG l;
|
||
|
UINT wFlags;
|
||
|
|
||
|
if (lpicd->dwFlags & ICDRAW_FULLSCREEN)
|
||
|
return ICERR_UNSUPPORTED;
|
||
|
|
||
|
l = AVIDrawQuery(pi, lpicd->lpbi);
|
||
|
|
||
|
if ((l != ICERR_OK) || (lpicd->dwFlags & ICDRAW_QUERY))
|
||
|
return l;
|
||
|
|
||
|
// Copy over whatever we want to remember
|
||
|
pi->xDst = lpicd->xDst;
|
||
|
pi->yDst = lpicd->yDst;
|
||
|
pi->dxDst = lpicd->dxDst;
|
||
|
pi->dyDst = lpicd->dyDst;
|
||
|
pi->xSrc = lpicd->xSrc;
|
||
|
pi->ySrc = lpicd->ySrc;
|
||
|
pi->dxSrc = lpicd->dxSrc;
|
||
|
pi->dySrc = lpicd->dySrc;
|
||
|
pi->rate = muldiv32(lpicd->dwScale,1000000,lpicd->dwRate);
|
||
|
pi->hdc = lpicd->hdc;
|
||
|
|
||
|
// !!! Should this be done somewhere else? drawdib mabey!
|
||
|
|
||
|
if (pi->hdc)
|
||
|
SetStretchBltMode(pi->hdc, COLORONCOLOR);
|
||
|
|
||
|
wFlags = 0;
|
||
|
|
||
|
// !!! We need some way to have a "stupid" mode here....
|
||
|
if (lpicd->dwFlags & ICDRAW_BUFFER)
|
||
|
wFlags |= DDF_BUFFER;
|
||
|
|
||
|
// Don't animate if we're realizing in the background
|
||
|
if (lpicd->dwFlags & ICDRAW_ANIMATE && !(pi->fBackground))
|
||
|
wFlags |= DDF_ANIMATE;
|
||
|
|
||
|
//
|
||
|
// remember if this is RLE because we may need to hack it later.
|
||
|
//
|
||
|
pi->fRle = lpicd->lpbi->biCompression == BI_RLE8;
|
||
|
pi->biSizeImage = (DWORD)(((UINT)lpicd->lpbi->biWidth+3)&~3)*(DWORD)(UINT)lpicd->lpbi->biHeight;
|
||
|
|
||
|
DPF2(("*** AVIDrawBegin()\n"));
|
||
|
|
||
|
if (lpicd->hpal == (HPALETTE)MCI_AVI_SETVIDEO_PALETTE_HALFTONE) {
|
||
|
DrawDibSetPalette(pi->hdd, NULL);
|
||
|
wFlags |= DDF_HALFTONE;
|
||
|
}
|
||
|
else
|
||
|
DrawDibSetPalette(pi->hdd, lpicd->hpal);
|
||
|
|
||
|
if (!DrawDibBegin(pi->hdd, pi->hdc,
|
||
|
pi->dxDst, pi->dyDst,
|
||
|
lpicd->lpbi,
|
||
|
pi->dxSrc, pi->dySrc,
|
||
|
wFlags))
|
||
|
return ICERR_UNSUPPORTED;
|
||
|
|
||
|
if (pi->hdc)
|
||
|
DrawDibRealize(pi->hdd, pi->hdc, pi->fBackground);
|
||
|
|
||
|
return ICERR_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AVIDraw() implements ICM_DRAW
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
STATICFN LONG AVIDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd)
|
||
|
{
|
||
|
UINT wFlags;
|
||
|
BOOL f;
|
||
|
|
||
|
wFlags = DDF_SAME_DRAW|DDF_SAME_HDC; // !!! Right flags?
|
||
|
|
||
|
if ((lpicd->lpData == NULL) || (lpicd->cbData == 0)) {
|
||
|
|
||
|
if ((lpicd->dwFlags & ICDRAW_UPDATE) || pi->fNeedUpdate) {
|
||
|
DrawDibRealize(pi->hdd, pi->hdc, pi->fBackground);
|
||
|
wFlags |= DDF_UPDATE;
|
||
|
pi->fNeedUpdate = FALSE;
|
||
|
lpicd->lpData = NULL;
|
||
|
lpicd->cbData = 0;
|
||
|
}
|
||
|
else
|
||
|
return ICERR_OK; // no data to draw.
|
||
|
}
|
||
|
else {
|
||
|
if (lpicd->dwFlags & ICDRAW_PREROLL) {
|
||
|
wFlags |= DDF_DONTDRAW;
|
||
|
pi->fNeedUpdate = TRUE;
|
||
|
} else if (lpicd->dwFlags & ICDRAW_HURRYUP) {
|
||
|
wFlags |= DDF_HURRYUP;
|
||
|
pi->fNeedUpdate = TRUE;
|
||
|
} else
|
||
|
pi->fNeedUpdate = FALSE;
|
||
|
|
||
|
if (lpicd->dwFlags & ICDRAW_NOTKEYFRAME)
|
||
|
wFlags |= DDF_NOTKEYFRAME;
|
||
|
|
||
|
//
|
||
|
// if we get a update while playing and we are drawing RLE delta's
|
||
|
// make sure we update.
|
||
|
//
|
||
|
if (pi->fRle && (lpicd->dwFlags & ICDRAW_UPDATE)) {
|
||
|
DrawDibDraw(pi->hdd, pi->hdc, pi->xDst, pi->yDst,
|
||
|
0,0,NULL,NULL,0,0,0,0,DDF_UPDATE|DDF_SAME_HDC|DDF_SAME_DRAW);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We need a hack here for the RLE case, to make sure that
|
||
|
// DIBs are marked correctly as BI_RLE8 or BI_RGB....
|
||
|
//
|
||
|
if (pi->fRle) {
|
||
|
DPF2(("pi->fRle is true, cbData==%d, biSizeImage=%d\n",
|
||
|
lpicd->cbData, pi->biSizeImage));
|
||
|
|
||
|
if (lpicd->cbData == pi->biSizeImage)
|
||
|
((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression = BI_RGB;
|
||
|
else {
|
||
|
((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression = BI_RLE8;
|
||
|
// We MUST set the correct size
|
||
|
((LPBITMAPINFOHEADER)lpicd->lpFormat)->biSizeImage = lpicd->cbData;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
f = DrawDibDraw(pi->hdd, pi->hdc,
|
||
|
pi->xDst, pi->yDst,
|
||
|
pi->dxDst, pi->dyDst,
|
||
|
lpicd->lpFormat,
|
||
|
lpicd->lpData,
|
||
|
pi->xSrc, pi->ySrc,
|
||
|
pi->dxSrc, pi->dySrc,
|
||
|
wFlags);
|
||
|
|
||
|
if (pi->fRle)
|
||
|
((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression = BI_RLE8;
|
||
|
|
||
|
if (!f) {
|
||
|
|
||
|
if (wFlags & DDF_UPDATE)
|
||
|
DPF(("DrawDibUpdate failed\n"));
|
||
|
else
|
||
|
DPF(("DrawDibDraw failed\n"));
|
||
|
|
||
|
if (wFlags & DDF_UPDATE) {
|
||
|
if (lpicd->dwFlags & ICDRAW_UPDATE)
|
||
|
return ICERR_CANTUPDATE;
|
||
|
else
|
||
|
return ICERR_OK;
|
||
|
} else
|
||
|
return ICERR_ERROR;
|
||
|
}
|
||
|
|
||
|
return ICERR_OK;
|
||
|
}
|
||
|
|
||
|
static LONG AVIDrawChangePalette(PINSTINFO pi, LPBITMAPINFOHEADER lpbi)
|
||
|
{
|
||
|
PALETTEENTRY ape[256];
|
||
|
LPRGBQUAD lprgb;
|
||
|
int i;
|
||
|
|
||
|
lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize);
|
||
|
|
||
|
for (i = 0; i < (int) lpbi->biClrUsed; i++) {
|
||
|
ape[i].peRed = lprgb[i].rgbRed;
|
||
|
ape[i].peGreen = lprgb[i].rgbGreen;
|
||
|
ape[i].peBlue = lprgb[i].rgbBlue;
|
||
|
ape[i].peFlags = 0;
|
||
|
}
|
||
|
|
||
|
DrawDibChangePalette(pi->hdd, 0, (int) lpbi->biClrUsed,
|
||
|
(LPPALETTEENTRY)ape);
|
||
|
|
||
|
return ICERR_OK;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AVIDrawEnd() implements ICM_DRAW_END
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
static LONG AVIDrawEnd(PINSTINFO pi)
|
||
|
{
|
||
|
return ICERR_OK;
|
||
|
}
|