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

726 lines
19 KiB
C

/******************************Module*Header*******************************\
* Module Name: dispdib32.c
*
* Fakes the display of full screen videos.
*
*
* Created: 23-03-94
* Author: Stephen Estrop [StephenE]
*
* Copyright (c) 1994 Microsoft Corporation
\**************************************************************************/
#include <windows.h>
#include "dispdib.h"
#include "drawdib.h"
/* -------------------------------------------------------------------------
** Private constants
** -------------------------------------------------------------------------
*/
#define CX_MAX_MOVIE_DEFAULT 640
#define CY_MAX_MOVIE_DEFAULT 480
/* -------------------------------------------------------------------------
** Private functions prototypes
** -------------------------------------------------------------------------
*/
LRESULT CALLBACK
FullScreenWndProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
);
LRESULT CALLBACK
KeyboardHookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
);
UINT
DisplayDibEnter(
LPBITMAPINFOHEADER lpbi,
UINT wFlags
);
void
DisplayDibLeave(
UINT wFlags
);
int
DisplayCalcMovieMultiplier(
int cxOriginal,
int cyOriginal,
DWORD dwCompression
);
/* -------------------------------------------------------------------------
** Debugging stuff
** -------------------------------------------------------------------------
*/
#if DBG
void
dprintf(
LPSTR lpszFormat,
...
);
int DebugLevel = 1;
#define dpf( _x_ ) dprintf _x_
#define dpf1( _x_ ) if (DebugLevel >= 1) {dprintf _x_ ;} else
#define dpf2( _x_ ) if (DebugLevel >= 2) {dprintf _x_ ;} else
#define dpf3( _x_ ) if (DebugLevel >= 3) {dprintf _x_ ;} else
#define dpf4( _x_ ) if (DebugLevel >= 4) {dprintf _x_ ;} else
#define dpf5( _x_ ) if (DebugLevel >= 5) {dprintf _x_ ;} else
#else
#define dpf( _x_ )
#define dpf1( _x_ )
#define dpf2( _x_ )
#define dpf3( _x_ )
#define dpf4( _x_ )
#define dpf5( _x_ )
#endif
/* -------------------------------------------------------------------------
** Private Globals
** These are only valid in the process that started playing the movie.
** -------------------------------------------------------------------------
*/
HWND hwndFullScreen;
HDC hdcFullScreen;
HDRAWDIB hdd;
BOOL fClassRegistered;
int dxScreen;
int dyScreen;
int iMovieSizeMultiplier;
/* -------------------------------------------------------------------------
** Global data shared between all processes that attach to this library.
** This is required to make the keyboard hook work correctly.
** -------------------------------------------------------------------------
*/
#pragma data_seg( ".sdata" )
BOOL fStop;
HHOOK hHookK;
#pragma data_seg()
/******************************Public*Routine******************************\
* DisplayDib
*
* Just call DisplayDibEx
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
UINT FAR PASCAL
DisplayDib(
LPBITMAPINFOHEADER lpbi,
LPSTR lpBits,
UINT wFlags
)
{
dpf(( "Down level api, use DisplayDibEx" ));
return DisplayDibEx( lpbi, 0, 0, lpBits, wFlags );
}
/******************************Public*Routine******************************\
* @doc EXTERNAL DISPDIB
*
* @api UINT | DisplayDibEx | This function displays a 256-color bitmap on a
* standard VGA display. It reduces the display resolution to 320-by-200
* or 320-by-240 and uses the full screen to display the bitmap, clipping
* and centering it as necessary. The function normally does not return to
* the application until the user presses a key or clicks a mouse button.
*
* To call <f DisplayDibEx>, an application must be the active
* application. All inactive applications and GDI screen updates
* are suspended while <f DisplayDib> temporarily reconfigures
* the display.
*
* @parm LPBITMAPINFO | lpbi | Specifies a pointer to a <t BITMAPINFO>
* header describing the bitmap to be displayed.
*
* @parm int | x | x position to place DIB iff DISPLAYDIB_NOCENTER flags is set
* the lower left is (0,0)
*
* @parm int | y | y position to place DIB iff DISPLAYDIB_NOCENTER flags is set
* the lower left is (0,0)
*
* @parm LPSTR | lpBits | Specifies a pointer to the bitmap bits. If this
* parameter is NULL, the bits are assumed to follow the
* <t BITMAPINFO> structure pointed to by <p lpbi>.
*
* @parm UINT | wFlags | Specifies options for displaying the bitmap. Use
* the following flags:
*
* @flag DISPLAYDIB_MODE_DEFAULT | Use the default mode (320 by 240)
* to display the bitmap.
* @flag DISPLAYDIB_MODE_320x200x8 | Use 320-by-200 mode to display
* the bitmap.
* @flag DISPLAYDIB_MODE_320x240x8 | Use 320-by-240 mode to display
* the bitmap. This is the default.
* @flag DISPLAYDIB_NOWAIT | Return immediately after displaying the
* bitmap; don't wait for a key press or mouse click before returning.
* @flag DISPLAYDIB_NOPALETTE | Ignore the palette associated
* with the bitmap. You can use this flag when displaying a series
* of bitmaps that use a common palette.
* @flag DISPLAYDIB_NOCENTER | Don't center the image. The function
* displays the bitmap in the lower-left corner of the display.
* @flag DISPLAYDIB_NOIMAGE | Don't draw image
* @flag DISPLAYDIB_ZOOM2 | Stretch image by 2
* @flag DISPLAYDIB_DONTLOCKTASK | dont lock out other tasks
* @flag DISPLAYDIB_TEST | dont do any thing just test for support
* @flag DISPLAYDIB_BEGIN | Switch to the low-resolution
* display mode and set the palette. The bitmap is not displayed.
*
* If you are displaying a series of images that use the same palette,
* you can call <f DisplayDib> with this flag to prepare the display for
* the bitmaps, then make a series of <f DisplayDib> calls with the
* DISPLAYDIB_NOPALETTE flag. This technique
* eliminates the screen flicker that occurs when the display is
* switched between the low-resolution and standard VGA modes.
* To return the display to standard VGA mode, subsequently
* call <f DisplayDib> with the DISPLAYDIB_END flag.
*
* @flag DISPLAYDIB_END | Switch back to standard VGA mode
* and return without displaying a bitmap. Signifies the end of multiple
* calls to <f DisplayDib>. With this flag, you can specify
* NULL for the <p lpbi> and <p lpBits> parameters.
*
* @rdesc Returns zero if successful, otherwise returns an error code.
* Error codes are as follows:
*
* @flag DISPLAYDIB_NOTSUPPORTED | <f DisplayDib> is not supported
* in the current mode.
* @flag DISPLAYDIB_INVALIDDIB | The bitmap specified by
* <p lpbi> is not a valid bitmap.
* @flag DISPLAYDIB_INVALIDFORMAT | The bitmap specified by
* <p lpbi> specifes a type of bitmap that is not supported.
* @flag DISPLAYDIB_INVALIDTASK | The caller is an inactive application.
* <f DisplayDib> can only be called by an active application.
*
* @comm The <f DisplayDib> function displays bitmaps described with
* the Windows 3.0 <t BITMAPINFO> data structure in either BI_RGB
* or BI_RLE8 format; it does not support bitmaps described with
* the OS/2 <t BITMAPCOREHEADER> data structure.
*
* When <f DisplayDib> switches to a low-resolution display, it
* disables the current display driver. As a result, you cannot use GDI
* functions to update the display while <f DisplayDib> is displaying a
* bitmap.
*
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
UINT FAR PASCAL
DisplayDibEx(
LPBITMAPINFOHEADER lpbi,
int x,
int y,
LPSTR lpBits,
UINT wFlags
)
{
DWORD wNumColors;
LONG yExt;
LONG xExt;
int xScreen,yScreen;
/*
** If not already done so:
** Register our class and Create our window "fullscreen"
*/
if (wFlags & DISPLAYDIB_BEGIN) {
dpf4(( "DISPLAYDIB_BEGIN..." ));
return DisplayDibEnter( lpbi, wFlags );
}
/*
** Just testing return OK
*/
else if (wFlags & DISPLAYDIB_TEST) {
dpf1(( "lpbi->biCompression = 0x%X = %c%c%c%c",
lpbi->biCompression,
*((LPSTR)&lpbi->biCompression + 0),
*((LPSTR)&lpbi->biCompression + 1),
*((LPSTR)&lpbi->biCompression + 2),
*((LPSTR)&lpbi->biCompression + 3) ));
dpf4(( "DISPLAYDIB_TEST... returning OK" ));
return DISPLAYDIB_NOERROR;
}
/*
** Palette change message
*/
else if ( (wFlags & (DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE)) ==
(DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE) ) {
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(hdd, 0, (int)lpbi->biClrUsed, (LPPALETTEENTRY)ape);
return DISPLAYDIB_NOERROR;
}
/*
** Time to kill the window and the class
*/
else if (wFlags & DISPLAYDIB_END) {
dpf4(( "DISPLAYDIB_END..." ));
DisplayDibLeave( wFlags );
return DISPLAYDIB_NOERROR;
}
/*
** Do the drawing here !!
*/
else if ( !fStop ) {
/*
** If we were'nt asked to draw anything just return.
*/
if ( wFlags & DISPLAYDIB_NOIMAGE ) {
return DISPLAYDIB_NOERROR;
}
xExt = lpbi->biWidth;
yExt = lpbi->biHeight;
if ( wFlags & DISPLAYDIB_ZOOM2 ) {
xExt <<= 1;
yExt <<= 1;
}
else if ( iMovieSizeMultiplier ) {
xExt <<= iMovieSizeMultiplier;
yExt <<= iMovieSizeMultiplier;
}
wNumColors = lpbi->biClrUsed;
if (wNumColors == 0 && lpbi->biBitCount <= 8) {
wNumColors = 1 << (UINT)lpbi->biBitCount;
}
/*
** setup pointers
*/
if (lpBits == NULL) {
lpBits = (LPBYTE)lpbi + lpbi->biSize + wNumColors * sizeof(RGBQUAD);
}
/*
** center the image
*/
if (!(wFlags & DISPLAYDIB_NOCENTER)) {
xScreen = ((int)dxScreen - xExt) / 2;
yScreen = ((int)dyScreen - yExt) / 2;
}
else {
xScreen = 0;
yScreen = 0;
}
dpf5(( "Drawing to the screen..." ));
DrawDibDraw( hdd, hdcFullScreen,
xScreen, yScreen, xExt, yExt,
lpbi, lpBits,
0, 0, lpbi->biWidth, lpbi->biHeight,
DDF_SAME_HDC | DDF_SAME_DRAW );
return DISPLAYDIB_NOERROR;
}
/*
** The user pressed a key... time to stop
*/
else {
dpf4(( "The keyboard hook is telling us to stop..." ));
DisplayDibLeave( wFlags );
return DISPLAYDIB_NOTSUPPORTED;
}
}
/*****************************Private*Routine******************************\
* DisplayDibEnter
*
*
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
UINT
DisplayDibEnter(
LPBITMAPINFOHEADER lpbi,
UINT wFlags
)
{
WNDCLASS wc;
HINSTANCE hInst = GetModuleHandle( NULL );
/*
** If our class isn't already registered with windows register it
*/
fClassRegistered = GetClassInfo( hInst, TEXT("SJE_FULLSCREEN"), &wc );
if ( fClassRegistered == FALSE ) {
ZeroMemory( &wc, sizeof(wc) );
wc.style = CS_OWNDC;
wc.lpfnWndProc = FullScreenWndProc;
wc.hInstance = hInst;
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.lpszClassName = TEXT("SJE_FULLSCREEN");
fClassRegistered = RegisterClass( &wc );
dpf4(( "Class registered... %s", fClassRegistered ? "OK" : "FAILED" ));
}
if ( fClassRegistered ) {
/*
** Do we already have a window ??
*/
if ( hwndFullScreen == NULL ) {
hwndFullScreen = CreateWindowEx(WS_EX_TOPMOST,
TEXT("SJE_FULLSCREEN"),
NULL,
WS_POPUP,
0, 0, 0, 0,
NULL, NULL,
hInst, NULL );
dpf4(( "Window created... %s", hwndFullScreen ? "OK" : "FAILED" ));
}
if ( hwndFullScreen ) {
LONG yExt;
LONG xExt;
MSG msg;
/*
** purge the queue of keyboard messages before installing
** the hook.
*/
while ( PeekMessage( &msg, NULL, WM_KEYFIRST, WM_KEYLAST,
PM_REMOVE | PM_NOYIELD ) );
hHookK = SetWindowsHookEx( WH_KEYBOARD, KeyboardHookProc,
GetModuleHandle(TEXT("DISPDB32.DLL")),
0 );
dpf4(( "Hook created... %s", hHookK ? "OK" : "FAILED" ));
dxScreen = GetSystemMetrics( SM_CXSCREEN );
dyScreen = GetSystemMetrics( SM_CYSCREEN );
hdcFullScreen = GetDC( hwndFullScreen );
hdd = DrawDibOpen();
xExt = lpbi->biWidth;
yExt = lpbi->biHeight;
iMovieSizeMultiplier =
DisplayCalcMovieMultiplier( xExt, yExt, lpbi->biCompression );
if ( wFlags & DISPLAYDIB_ZOOM2 ) {
xExt <<= 1;
yExt <<= 1;
}
else if ( iMovieSizeMultiplier ) {
xExt <<= iMovieSizeMultiplier;
yExt <<= iMovieSizeMultiplier;
}
dpf1(( "Drawing at %d by %d... Flags = 0x%X", xExt, yExt, wFlags ));
DrawDibBegin( hdd, hdcFullScreen, xExt, yExt,
lpbi, lpbi->biWidth, lpbi->biHeight, 0 );
MoveWindow( hwndFullScreen, 0, 0, dxScreen, dyScreen, FALSE );
ShowWindow( hwndFullScreen, SW_SHOW );
UpdateWindow( hwndFullScreen );
ShowCursor( FALSE );
SetFocus( hwndFullScreen );
}
}
fStop = FALSE;
return hwndFullScreen != NULL ? DISPLAYDIB_NOERROR : DISPLAYDIB_NOTSUPPORTED;
}
/*****************************Private*Routine******************************\
* DisplayDibLeave
*
*
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
void
DisplayDibLeave(
UINT wFlags
)
{
if (hwndFullScreen) {
DestroyWindow( hwndFullScreen );
hwndFullScreen = NULL;
}
}
/*****************************Private*Routine******************************\
* DisplayCalcMovieMultiplier
*
* Determines the largest movie that the display is capable of displaying.
*
* History:
* dd-mm-94 - StephenE - Created
*
\**************************************************************************/
int
DisplayCalcMovieMultiplier(
int cxOriginal,
int cyOriginal,
DWORD dwCompression
)
{
SYSTEM_INFO SysInfo;
int iMult;
int iMultTemp;
int cxOriginalSave, cyOriginalSave;
/*
** For now, don't try to stretch 'cvid' compressed movies. This is
** because it looks bad!!
*/
if ( *((LPSTR)&dwCompression + 0) == 'c'
&& *((LPSTR)&dwCompression + 1) == 'v'
&& *((LPSTR)&dwCompression + 2) == 'i'
&& *((LPSTR)&dwCompression + 3) == 'd' ) {
return 0;
}
GetSystemInfo( &SysInfo );
iMultTemp = iMult = 0;
cxOriginalSave = cxOriginal;
cyOriginalSave = cyOriginal;
switch ( SysInfo.wProcessorArchitecture ) {
case PROCESSOR_ARCHITECTURE_INTEL:
if ( SysInfo.wProcessorLevel <= 3 ) {
break;
}
/*
** maybe later we will do something different for i486's
** for now they just fall through to the RISC / Pentium default
** case below.
*/
default:
while ( (cxOriginal <= CX_MAX_MOVIE_DEFAULT)
&& (cyOriginal <= CY_MAX_MOVIE_DEFAULT) ) {
iMult = iMultTemp;
iMultTemp++;
cxOriginal = cxOriginalSave << iMultTemp;
cyOriginal = cyOriginalSave << iMultTemp;
}
break;
}
return iMult;
}
/******************************Public*Routine******************************\
* FullScreenWndProc
*
*
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
LRESULT CALLBACK
FullScreenWndProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
switch ( message ) {
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
dpf4(( "Window needs painting" ));
BeginPaint( hwnd, &ps );
GetUpdateRect( hwnd, &rc, FALSE );
FillRect( hdcFullScreen, &rc, GetStockObject( BLACK_BRUSH ) );
EndPaint( hwnd, &ps );
}
break;
case WM_PALETTECHANGED:
if ( (HWND)wParam == hwnd ) {
break;
}
/* fall thru */
case WM_QUERYNEWPALETTE:
if ( DrawDibRealize( hdd, hdcFullScreen, FALSE ) > 0 ) {
InvalidateRect( hwnd, NULL, TRUE );
}
break;
case WM_DESTROY:
dpf4(( "Window destroyed releasing DC" ));
ReleaseDC( hwnd, hdcFullScreen );
DrawDibEnd( hdd );
DrawDibClose( hdd );
UnregisterClass( TEXT("SJE_FULLSCREEN"), GetModuleHandle( NULL ) );
fClassRegistered = FALSE;
fStop = FALSE;
ShowCursor( TRUE );
UnhookWindowsHookEx( hHookK );
break;
default:
return DefWindowProc( hwnd, message, wParam, lParam );
}
return (LRESULT)FALSE;
}
/******************************Public*Routine******************************\
* KeyboardHookProc
*
*
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
LRESULT CALLBACK
KeyboardHookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
if ( nCode == HC_ACTION) {
/*
** Only interested in keydowns
*/
if ( !(lParam & 0x80000000) ) {
dpf4(( "Stop requested from the keyboard hook" ));
fStop = TRUE;
}
}
return CallNextHookEx( hHookK, nCode, wParam, lParam );
}
#if DBG
/*****************************Private*Routine******************************\
* dprintf
*
* Standard debug out stuff
*
* History:
* 23-03-94 - StephenE - Created
*
\**************************************************************************/
void
dprintf(
LPSTR lpszFormat,
...
)
{
char buf[512];
UINT n;
va_list va;
n = wsprintfA(buf, "DISPDB32: (tid %x) ", GetCurrentThreadId());
va_start(va, lpszFormat);
n += wvsprintfA(buf+n, lpszFormat, va);
va_end(va);
buf[n++] = '\n';
buf[n] = 0;
OutputDebugStringA(buf);
}
#endif