windows-nt/Source/XPSP1/NT/multimedia/media/avi/mciavi32/drawproc.c
2020-09-26 16:20:57 +08:00

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;
}