|
|
/******************************************************************************
Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
Title: graphic.c - Multimedia Systems Media Control Interface driver for AVI.
*****************************************************************************/
// Define HEARTBEAT to create a permanent thread which can periodically
// dump mciavi device status
//#define HEARTBEAT
#include "graphic.h"
#include "dispdib.h"
//#include "cnfgdlg.h"
#include <string.h>
#ifdef EXPIRE
#include <dos.h>
#endif
#include "avitask.h"
#ifdef DEBUG
#define static
#endif
#ifdef _WIN32
extern BOOL FAR PASCAL WowUseMciavi16(VOID); #endif
//
// This is the version number of MSVIDEO.DLL we need in order to run
// build 81 is when we added the VideoForWindowsVersion() function to
// MSVIDEO.DLL
//
// in build 85
// we removed the ICDecompressOpen() function and it became a macro.
// we added a parameter to ICGetDisplayFormat()
// we make DrawDibProfileDisplay() take a parameter
//
// in build 108
// Added ICOpenFunction() to open a hic using a function directly,
// without calling ICInstall
// Added some more ICDRAW_ messages
//
// in build 109
// Addded ICMessage() to compman
// removed ICDrawSuggest() made it a macro.
// Added ICMODE_FASTDECOMPRESS to ICLocate()
//
// Under NT the first build is sufficient !!! Is this true now?
//
#ifdef _WIN32
#define MSVIDEO_VERSION (0x01000000) // 1.00.00.00
#else
#define MSVIDEO_VERSION (0x010a0000l+109) // 1.10.00.109
#endif
/* statics */ static INT swCommandTable = -1;
#if 0
#ifdef _WIN32
static SZCODE szDisplayDibLib[] = TEXT("DISPDB32.DLL"); #else
static SZCODE szDisplayDibLib[] = TEXT("DISPDIB.DLL"); #endif
#endif
/*
* files should be UNICODE. function names should not */
#ifdef _WIN32
STATICDT SZCODE szMSVideo[] = TEXT("MSVFW32"); // With GetModuleHandle
const TCHAR szReject[] = TEXT("RejectWOWOpenCalls"); #else
static SZCODE szMSVideo[] = TEXT("MSVIDEO"); #endif
BOOL gfEvil; // TRUE if we cant close cuz dialog box is up
BOOL gfEvilSysMenu; // TRUE if we cant close cuz system menu is up
NPMCIGRAPHIC npMCIList; // list of all open instances.
#ifdef _WIN32
CRITICAL_SECTION MCIListCritSec; // Must protect access to MCIList entries
#ifdef DEBUG
DWORD ListOwner; #endif // debug
#endif
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api void | GraphicInit | This function is called when the DriverProc * gets a DRV_LOAD message. * ***************************************************************************/ BOOL FAR PASCAL GraphicInit(void) { InitializeDebugOutput("MCIAVI");
if (!GraphicWindowInit()) return FALSE;
// The command table is name MCIAVI - same as the Ini/Registry/Module
swCommandTable = mciLoadCommandResource(ghModule, szIni, 0); #ifdef _WIN32
InitializeCriticalSection(&MCIListCritSec); #endif
return TRUE; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicDrvOpen | This function is called when the DriverProc * gets a DRV_OPEN message. This happens each time that a new movie * is opened thru MCI. * * @parm LPMCI_OPEN_DRIVER_PARMS | lpOpen | Far pointer to the standard * MCI open parameters * * @rdesc Returns the mci device id. The installable driver interface will * pass this ID to the DriverProc in the dwDriverID parameter on all * subsequent messages. To fail the open, return 0L. * ***************************************************************************/
DWORD PASCAL GraphicDrvOpen(LPMCI_OPEN_DRIVER_PARMS lpOpen) { /* Specify the custom command table and the device type */
lpOpen->wCustomCommandTable = swCommandTable; lpOpen->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
/* Set the device ID to the MCI Device ID */
return (DWORD) (UINT)lpOpen->wDeviceID; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api void | GraphicFree | This function is called when the DriverProc * gets a DRV_FREE message. This happens when the drivers open count * reaches 0. * ***************************************************************************/ #ifdef HEARTBEAT
BOOL fTerminate = FALSE; HANDLE hHeartBeatThread= 0; #endif
void PASCAL GraphicFree(void) { if (swCommandTable != -1) { mciFreeCommandResource(swCommandTable); swCommandTable = -1; }
#ifdef HEARTBEAT
if (hHeartBeatThread) { fTerminate=TRUE; WaitForSingleObject(hHeartBeatThread, 5000); CloseHandle(hHeartBeatThread); } #endif
#ifdef _WIN32
/*
* unregister class so we can re-register it next time we are loaded */ GraphicWindowFree(); #ifdef REMOTESTEAL
if (hkey) { RegCloseKey(hkey); hkey = 0; } #endif
DeleteCriticalSection(&MCIListCritSec); #endif
}
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicDelayedNotify | This is a utility function that * sends a notification saved with GraphicSaveCallback to mmsystem * which posts a message to the application. Called on either worker * or (occasionally if ever?) user thread. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data. * * @parm UINT | wStatus | The type of notification to use can be one of * MCI_NOTIFY_SUCCESSFUL, MCI_NOTIFY_SUPERSEDED, MCI_NOTIFY_ABORTED * or MCI_NOTIFY_FAILURE (see MCI ispec.) * ***************************************************************************/
void FAR PASCAL GraphicDelayedNotify(NPMCIGRAPHIC npMCI, UINT wStatus) { /* Send any saved notification */
if (npMCI->hCallback) {
DPF2(("GraphicDelayedNotify, npMCI=%8x, Status is %x\n", npMCI, wStatus)); // If the system menu is the only thing keeping us from closing, bring
// it down and then close.
if (gfEvilSysMenu) SendMessage(npMCI->hwndPlayback, WM_CANCELMODE, 0, 0);
// If a dialog box is up, and keeping us from closing, we can't send the
// notify or it will close us.
if (!gfEvil) mciDriverNotify(npMCI->hCallback, npMCI->wDevID, wStatus);
npMCI->hCallback = NULL; } }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicImmediateNotify | This is a utility function that * sends a successful notification message to mmsystem if the * notification flag is set and the error field is 0. * * @parm UINT | wDevID | device ID. * * @parm LPMCI_GENERIC_PARMS | lpParms | Far pointer to an MCI parameter * block. The first field of every MCI parameter block is the * callback handle. * * @parm DWORD | dwFlags | Parm. block flags - used to check whether the * callback handle is valid. * * @parm DWORD | dwErr | Notification only occurs if the command is not * returning an error. * ***************************************************************************/
void FAR PASCAL GraphicImmediateNotify(UINT wDevID, LPMCI_GENERIC_PARMS lpParms, DWORD dwFlags, DWORD dwErr) { if (!LOWORD(dwErr) && (dwFlags & MCI_NOTIFY)) { //Don't have an npMCI - see GraphicDelayedNotify
//if (gfEvil)
//SendMessage(npMCI->hwndPlayback, WM_CANCELMODE, 0, 0);
// If a dialog box is up, and keeping us from closing, we can't send the
// notify or it will close us.
if (!gfEvil) // !!! EVIL !!!
mciDriverNotify((HANDLE) (UINT)lpParms->dwCallback, wDevID, MCI_NOTIFY_SUCCESSFUL); } }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSaveCallback | This is a utility function that saves * a new callback in the instance data block. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data. * * @parm HANDLE | hCallback | callback handle * ***************************************************************************/
void NEAR PASCAL GraphicSaveCallback (NPMCIGRAPHIC npMCI, HANDLE hCallback) { /* If there's an old callback, kill it. */ GraphicDelayedNotify(npMCI, MCI_NOTIFY_SUPERSEDED);
/* Save new notification callback window handle */ npMCI->hCallback = hCallback; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicClose | This function closes the movie and * releases the instance data. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD PASCAL GraphicClose (NPMCIGRAPHIC npMCI) { DWORD dwRet = 0L; NPMCIGRAPHIC p;
if (npMCI) {
SetNTFlags(npMCI, NTF_CLOSING); #ifdef DEBUG
npMCI->mciid = MCIIDX; if (TestNTFlags(npMCI, NTF_AUDIO_OFF)) { DPF1(("Trying to close while audio command active\n")); DebugBreak(); } #endif
dwRet = DeviceClose (npMCI); Assert(dwRet == 0);
// If the system menu is the only thing keeping us from closing, bring
// it down and then close.
if (gfEvilSysMenu) SendMessage(npMCI->hwndPlayback, WM_CANCELMODE, 0, 0);
if (gfEvil) { DPF(("************************************************\n")); DPF(("** EVIL: Failing the close because we'd die **\n")); DPF(("************************************************\n")); ResetNTFlags(npMCI, NTF_CLOSING);
return MCIERR_DRIVER_INTERNAL; }
//
// find this instance on the list - and remove it
// Do this before destroying any element in this instance
//
EnterList(); if (npMCI == npMCIList) { npMCIList = npMCI->npMCINext; } else { for (p=npMCIList; p && p->npMCINext != npMCI; p=p->npMCINext) ;
Assert(p && p->npMCINext == npMCI);
p->npMCINext = npMCI->npMCINext; } LeaveList();
if (npMCI->szFilename) { LocalFree((HANDLE) (npMCI->szFilename)); }
#ifdef _WIN32
#ifdef DEBUG
if (npMCI->hmmio) { DPF1(("hmmio is still open, npMCI=%8x\n", npMCI)); } if (npMCI->hmmioAudio) { DPF1(("hmmioAudio is still open, npMCI=%8x\n", npMCI)); } #endif
#endif
#ifdef INTERVAL_TIMES
// Free the bucket space
if (npMCI->paIntervals) { LocalFree(npMCI->paIntervals); } #endif
/* Free the instance data block allocated in GraphicOpen */
LocalFree((HANDLE)npMCI); }
return dwRet; }
DWORD NEAR PASCAL FixFileName(NPMCIGRAPHIC npMCI, LPCTSTR lpName) { TCHAR ach[256];
ach[(NUMELMS(ach)) - 1] = TEXT('\0');
#ifndef _WIN32
_fstrncpy(ach, (LPTSTR) lpName, NUMELMS(ach) - 1); #else
wcsncpy(ach, (LPTSTR) lpName, NUMELMS(ach) - 1); #endif
//
// treat any string that starts with a '@' as valid and pass it to the
// device any way.
//
if (ach[0] != TEXT('@')) { if (!mmioOpen(ach, NULL, MMIO_PARSE)) return MCIERR_FILENAME_REQUIRED; }
Assert(0 == npMCI->szFilename); npMCI->szFilename = (NPTSTR) LocalAlloc(LPTR, sizeof(TCHAR) * (lstrlen(ach) + 1));
if (!npMCI->szFilename) { return MCIERR_OUT_OF_MEMORY; }
lstrcpy(npMCI->szFilename, ach);
return 0L; }
/**************************************************************************
***************************************************************************/
#define SLASH(c) ((c) == TEXT('/') || (c) == TEXT('\\'))
LPCTSTR FAR FileName(LPCTSTR szPath) { LPCTSTR sz;
sz = &szPath[lstrlen(szPath)]; for (; sz>szPath && !SLASH(*sz) && *sz!=TEXT(':');) { LPCTSTR pszOld = sz; if ((sz = CharPrev(szPath, sz)) == pszOld) break; } return (sz>szPath ? sz + 1 : sz); }
/****************************************************************************
****************************************************************************/
STATICFN DWORD NEAR PASCAL GetMSVideoVersion() { HANDLE h;
extern DWORD FAR PASCAL VideoForWindowsVersion(void);
//
// don't call VideoForWindowsVersion() if it does not exist or KERNEL
// will kill us with a undef dynalink error.
//
if ((h = GetModuleHandle(szMSVideo)) && GetProcAddress(h, (LPSTR) MAKEINTATOM(2))) return VideoForWindowsVersion(); else return 0; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicOpen | This function opens a movie file, * initializes an instance data block, and creates the default * stage window. * * @parm NPMCIGRAPHIC FAR * | lpnpMCI | Far pointer to a near pointer * to instance data block to be filled in by this function. * * @parm DWORD | dwFlags | Flags for the open message. * * @parm LPMCI_DGV_OPEN_PARMS | Parameters for the open message. * * @parm UINT | wDeviceID | The MCI Device ID for this instance. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD PASCAL GraphicOpen (NPMCIGRAPHIC FAR * lpnpMCI, DWORD dwFlags, LPMCI_DGV_OPEN_PARMS lpOpen, UINT wDeviceID) { NPMCIGRAPHIC npMCI; DWORD dwRet;
if (IsNTWOW()) { // Thunking nasties... by default we will open a 16 bit request
// on the 32 bit side. Most of the time this is what is wanted.
// However, there can be situations when the user must stay on the
// 16 bit side (e.g. use of 16 bit drawprocs). This is not known
// at this stage. Hence we provide a way through the configure
// dialog for the user to tell us to reject 16 bit open calls.
// The call will then return to 16 bit where it will work.
// However, we provide a way for applications to override this
// default.
// All that is said above is good. Except not many people will notice
// this little "Advanced" button ... In any event code below
// uses wow32's special function to extract this needed information
// (compatibility flag)
#ifdef _WIN32
if (WowUseMciavi16()) { DPF2(("Compat Flag -- mciavi16 should be used\n")); return(MCIERR_DEVICE_OPEN); } #endif
if ((mmGetProfileInt(szIni, szReject, 0) && !(dwFlags & MCI_DGV_OPEN_32BIT)) || (dwFlags & MCI_DGV_OPEN_16BIT) ) { DPF2(("Opening device on 16 bit side\n")); return MCIERR_DEVICE_OPEN; // return an error... any error
}
/*
** The only wow apps that I now off that specify the MCI_DGV_OPEN_PARENT ** flag are MS Dangerous Creatures and Tool Book. These apps go on to ** subclass the AVIWnd32 window. This is very bad on WOW as the ** subclassing stops all messages being processed for the AVIWnd32 ** window. Therefore, I will reject all open requests that specify ** this MCI_DGV_OPEN_PARENT flag. This is pretty drastic but I don't ** know of any other way of identifying these rogue apps. ** ** StephenE 16th Aug 1994. */ else if (dwFlags & MCI_DGV_OPEN_PARENT) { //if (dwFlags & MCI_DGV_OPEN_32BIT) {
// DPF0(("Now what are we meant to do???\n"));
//}
DPF2(("Failing open because APP specified MCI_DGV_OPEN_PARENT\n")); return MCIERR_DEVICE_OPEN; // return an error... any error
} else { DPF2(("might be able to open device on 32 bit side\n")); } }
if (dwFlags & MCI_OPEN_SHAREABLE) {
if (lpOpen->lpstrElementName == NULL || lpOpen->lpstrElementName[0] != '@') { return MCIERR_UNSUPPORTED_FUNCTION; } }
//
// check the verion of MSVIDEO.DLL before going any further
// if we run a "new" version of MCIAVI on a old MSVIDEO.DLL
// then bad things will happen. We assume all MSVIDEO.DLLs
// will be backward compatible so we check for any version
// greater than the expected version.
//
DPF(("GraphicOpen: Video For Windows Version %d.%02d.%02d.%02d\n", HIBYTE(HIWORD(GetMSVideoVersion())), LOBYTE(HIWORD(GetMSVideoVersion())), HIBYTE(LOWORD(GetMSVideoVersion())), LOBYTE(LOWORD(GetMSVideoVersion())) ));
if (GetMSVideoVersion() < MSVIDEO_VERSION) { TCHAR achError[128]; TCHAR ach[40];
LoadString(ghModule, MCIAVI_BADMSVIDEOVERSION, achError, NUMELMS(achError)); LoadString(ghModule, MCIAVI_PRODUCTNAME, ach, NUMELMS(ach)); MessageBox(NULL,achError,ach, #ifdef BIDI
MB_RTL_READING | #endif
MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
return MCIERR_DRIVER_INTERNAL; }
#ifndef _WIN32
#pragma message("Support passing in MMIOHANDLEs with OPEN_ELEMENT_ID?")
#endif
if (lpOpen->lpstrElementName == NULL) { // they're doing an "open new".
// !!! handle this, probably by not actually reading a file.
// ack.
}
/* Be sure we have a real, non-empty filename, not an id. */ if ((!(dwFlags & MCI_OPEN_ELEMENT)) || (lpOpen->lpstrElementName == NULL) || (*(lpOpen->lpstrElementName) == '\0')) return MCIERR_UNSUPPORTED_FUNCTION;
// Allocate an instance data block. Code ASSUMES Zero Init.
if (!(npMCI = (NPMCIGRAPHIC) LocalAlloc(LPTR, sizeof (MCIGRAPHIC)))) return MCIERR_OUT_OF_MEMORY;
#ifdef DEBUG
npMCI->mciid = MCIID; #ifdef HEARTBEAT
{ // Create a thread that regularly dumps the state of AVI devices.
DWORD HeartBeat(LPVOID lpvThreadData); if (!hHeartBeatThread) { DWORD dwThreadId; hHeartBeatThread = CreateThread(NULL, 0, HeartBeat, (LPVOID)0, 0, &dwThreadId); if (hHeartBeatThread) { // We hold the thread handle open until we are unloaded
DPF(("Created a heart beat thread, id=%x\n", dwThreadId)); } else { // Errors are ignored...
} } } #endif
#endif
//
// add this device to our list
//
EnterList(); npMCI->npMCINext = npMCIList; npMCIList = npMCI; LeaveList();
npMCI->wMessageCurrent = MCI_OPEN;
// Allocate some space for the filename
// Copy the filename into the data block
dwRet = FixFileName(npMCI, lpOpen->lpstrElementName); if (dwRet != 0L) { GraphicClose(npMCI); return dwRet; }
// For the default window, the caller may
// supply style and parent window. Note that the window
// is now created on the background thread in mcaviTask.
if (dwFlags & MCI_DGV_OPEN_PARENT) { if (!IsWindow(lpOpen->hWndParent)) { DPF(("Invalid parent window (%d) supplied\n", lpOpen->hWndParent)); GraphicClose(npMCI); return(MCIERR_CREATEWINDOW); } npMCI->hwndParent = lpOpen->hWndParent; } else npMCI->hwndParent = NULL;
if (dwFlags & MCI_DGV_OPEN_WS) { npMCI->dwStyle = lpOpen->dwStyle; } else { npMCI->dwStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; }
/* Fill in some more of the instance data.
** The rest of the fields are completed in DeviceOpen. */
// see comment in graphic.h
// If the default window won't be resizable, I don't think we should pay
// attention to zoom by 2 or fixed % window size defaults.
npMCI->fOKToUseDefaultSizing = (BOOL)((npMCI->dwStyle & WS_THICKFRAME) != 0);
npMCI->hCallingTask = GetCurrentTask(); npMCI->hCallback = NULL; npMCI->wDevID = wDeviceID; npMCI->hwndDefault = NULL; npMCI->hwndPlayback = NULL; npMCI->dwTimeFormat = MCI_FORMAT_FRAMES; npMCI->dwSpeedFactor = 1000; npMCI->dwVolume = MAKELONG(500, 500); npMCI->lTo = 0L; npMCI->dwFlags = MCIAVI_PLAYAUDIO | MCIAVI_SHOWVIDEO; npMCI->dwOptionFlags = ReadConfigInfo() | MCIAVIO_STRETCHTOWINDOW;
// perform device-specific initialization
dwRet = DeviceOpen(npMCI, dwFlags);
if (dwRet != 0) { // see above - we release and delete the critsec within GraphicClose
GraphicClose(npMCI); return dwRet; }
// Reset these globals every time we open a device. This is better
// than setting them every time we start playing...
gwHurryTolerance = mmGetProfileInt(szIni, TEXT("Hurry"), 2); gwSkipTolerance = mmGetProfileInt(szIni, TEXT("Skip"), gwHurryTolerance * 2); gwMaxSkipEver = mmGetProfileInt(szIni, TEXT("MaxSkip"), max(60, gwSkipTolerance * 10));
#ifdef INTERVAL_TIMES
// Allocate the bucket space
{ LONG n = npMCI->lFrames; // Allocate bucket space for the whole movie... might be
// expensive(!) so we reduce the count if no memory is
// available
DPF2(("Trying to allocate bucket space for %d frames\n", n)); while( !(npMCI->paIntervals = LocalAlloc(LPTR, n*sizeof(LONG))) && n>10) n /= 2;
if (npMCI->paIntervals) { npMCI->cIntervals = n; DPF2(("Allocated bucket space for %d frames\n", n)); } } #endif
*lpnpMCI = npMCI;
npMCI->wMessageCurrent = 0;
return 0L; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicLoad | This function supports the MCI_LOAD command. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the Load message. * * @parm LPMCI_DGV_LOAD_PARMS | lpLoad | Parameters for the LOAD message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicLoad(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_LOAD_PARMS lpLoad) { return MCIERR_UNSUPPORTED_FUNCTION; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSeek | This function sets the current frame. The * device state after a seek is MCI_MODE_PAUSE * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the seek message. * * @parm LPMCI_DGV_SEEK_PARMS | lpSeek | Parameters for the seek message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicSeek (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_SEEK_PARMS lpSeek) { LONG lTo; BOOL fTest = FALSE; LPARAM dwCallback = 0;
/* Do some range checking then pass onto the device-specific routine. */
if (dwFlags & MCI_TEST) { dwFlags &= ~(MCI_TEST); fTest = TRUE; }
/* Ignore the WAIT and NOTIFY flags when parsing the seek parameters */
switch (dwFlags & (~(MCI_WAIT | MCI_NOTIFY))) { case MCI_TO: lTo = ConvertToFrames(npMCI, lpSeek->dwTo); break;
case MCI_SEEK_TO_START: lTo = 0; break;
case MCI_SEEK_TO_END: lTo = npMCI->lFrames; break;
case 0: return MCIERR_MISSING_PARAMETER;
default: if (dwFlags & ~(MCI_TO | MCI_SEEK_TO_START | MCI_SEEK_TO_END | MCI_WAIT | MCI_NOTIFY)) return MCIERR_UNRECOGNIZED_KEYWORD; else return MCIERR_FLAGS_NOT_COMPATIBLE; break; }
if (!IsWindow(npMCI->hwndPlayback)) return MCIERR_NO_WINDOW;
if (lTo < 0 || lTo > npMCI->lFrames) return MCIERR_OUTOFRANGE;
if (fTest) return 0L;
if (dwFlags & (MCI_NOTIFY)) { dwCallback = lpSeek->dwCallback; }
return DeviceSeek(npMCI, lTo, dwFlags, dwCallback); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicCue | This function gets the movie ready to play, * but leaves it paused. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the cue message. * * @parm LPMCI_DGV_CUE_PARMS | lpCue | Parameters for the cue message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicCue(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpCue) { LONG lTo; DWORD dwRet = 0L;
if (dwFlags & MCI_DGV_CUE_INPUT) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_DGV_CUE_NOSHOW) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_TO) { lTo = ConvertToFrames(npMCI, lpCue->dwTo);
if (lTo < 0L || lTo > npMCI->lFrames) return MCIERR_OUTOFRANGE; }
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
dwRet = DeviceCue(npMCI, lTo, dwFlags, lpCue->dwCallback);
return dwRet; }
#ifndef _WIN32
#ifdef EXPIRE
//
// return the current date....
//
// dx = year
// ah = month
// al = day
//
#pragma optimize("", off)
DWORD DosGetDate(void) { if (0) return 0;
_asm { mov ah,2ah int 21h mov ax,dx mov dx,cx } } #pragma optimize("", on)
#endif
#endif
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicPlay | This function starts playback of the movie. If * the reverse flag is specified, the movie plays backwards. If the fast * or slow flags are specified the movie plays faster or slower. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the play message. * * @parm LPMCI_DGV_PLAY_PARMS | lpPlay | Parameters for the play message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicPlay (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_PLAY_PARMS lpPlay ) { HINSTANCE hInst; TCHAR achMod[MAX_PATH]; BOOL fMPlayer;
#ifdef EXPIRE
#pragma message("Remove the expiration code after Beta ships")
if (DosGetDate() >= EXPIRE) { return MCIERR_AVI_EXPIRED; } #endif
// If we haven't specifically asked for fullscreen or window, and we are
// the default window, listen to the configure options and maybe force
// fullscreen. We will also obey the fullscreen default for MPLAYER's
// window, to make mplayer just like using the default window.
hInst = GetWindowInstance(npMCI->hwndPlayback); if (hInst) GetModuleFileName(hInst, achMod, sizeof(achMod) / sizeof(achMod[0])); fMPlayer = lstrcmpi(FileName(achMod), TEXT ("MPLAY32.EXE")) == 0;
if (!(dwFlags & (MCI_MCIAVI_PLAY_FULLSCREEN | MCI_MCIAVI_PLAY_WINDOW)) && (npMCI->hwndPlayback == npMCI->hwndDefault || fMPlayer)) {
if ((npMCI->dwOptionFlags & MCIAVIO_USEVGABYDEFAULT) || (npMCI->rcDest.left == 0 && npMCI->rcDest.right == GetSystemMetrics(SM_CXSCREEN)) || (npMCI->rcDest.top == 0 && npMCI->rcDest.bottom == GetSystemMetrics(SM_CYSCREEN))) { dwFlags |= MCI_MCIAVI_PLAY_FULLSCREEN; } }
// see comment in graphic.h on npMCI->fOKToUseDefaultSizing
// We're playing, which will end up showing the window
// and we may want to pay attention to the registry default
// sizing (zoom by 2, fixed % of screen size, etc.)
// We also do this code when somebody calls "window state show".
// As an extra note I should say that it's important that we
// don't change it until now so that if somebody opens a file
// and does a "where destination" they get the original size,
// because if they're playing in their own window, it will
// not be altered anyway.
if (npMCI->fOKToUseDefaultSizing) { SetWindowToDefaultSize(npMCI, TRUE); ResetDestRect(npMCI, TRUE); }
// Never do this again
npMCI->fOKToUseDefaultSizing = FALSE;
// everything else needs to be on the worker thread to be reliable.
return DevicePlay(npMCI, dwFlags, lpPlay, lpPlay->dwCallback); }
/***************************************************************************
* * @doc INTERNAL MCIWAVE * * @api DWORD | GraphicStep | This function steps through several frames * of a movie. If the reverse flag is set, then the step is backwards. * If the step count is not specified then it defaults to 1. If the * step count plus the current position exceeds the movie length, the * step is out of range. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the step message. * * @parm LPMCI_DGV_STEP_PARMS | lpStep | Parameters for the step message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicStep (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpStep) { LONG lFrameCur; LONG lFrames; DWORD dwRet; BOOL fReverse; BOOL fSeekExactOff;
fReverse = (dwFlags & MCI_DGV_STEP_REVERSE) == MCI_DGV_STEP_REVERSE;
// Default to 1 frame step if frame count is not specified
if (dwFlags & MCI_DGV_STEP_FRAMES) { lFrames = (LONG) lpStep->dwFrames;
if (fReverse) { if (lFrames < 0) return MCIERR_FLAGS_NOT_COMPATIBLE; } } else lFrames = 1;
lFrames = fReverse ? -lFrames : lFrames;
/* stop before figuring out whether frame count is within range, */ /* unless the TEST flag is set. */
if (!(dwFlags & MCI_TEST)) { if (dwRet = DeviceStop(npMCI, MCI_WAIT)) return dwRet; }
if (dwRet = DevicePosition(npMCI, &lFrameCur)) return dwRet;
if ((lFrames + lFrameCur > npMCI->lFrames) || (lFrames + lFrameCur < 0)) return MCIERR_OUTOFRANGE;
if (!IsWindow(npMCI->hwndPlayback)) return MCIERR_NO_WINDOW;
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
fSeekExactOff = (npMCI->dwOptionFlags & MCIAVIO_SEEKEXACT) == 0;
npMCI->dwOptionFlags |= MCIAVIO_SEEKEXACT;
npMCI->dwFlags |= MCIAVI_NEEDTOSHOW;
if (fSeekExactOff) { /* If we were not in seek exact mode, make seek finish
** before we turn seek exact back off. */ dwRet = DeviceSeek(npMCI, lFrames + lFrameCur, dwFlags | MCI_WAIT, lpStep->dwCallback); npMCI->dwOptionFlags &= ~(MCIAVIO_SEEKEXACT); } else { dwRet = DeviceSeek(npMCI, lFrames + lFrameCur, dwFlags, lpStep->dwCallback); }
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicStop | This function stops playback of the movie. * After a stop the state will be MCI_MODE_STOP. The frame counter * is not reset. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the stop message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicStop (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { if (!IsWindow(npMCI->hwndPlayback)) return MCIERR_NO_WINDOW;
if (dwFlags & MCI_DGV_STOP_HOLD) return MCIERR_UNSUPPORTED_FUNCTION;
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
// this notify should be done on the worker thread if needed, but actually
// I don't think we need it, since the play code will issue it (either
// as an abort or as a success if it reached the right target).
//GraphicDelayedNotify (npMCI, MCI_NOTIFY_ABORTED);
/* Do we need to handle notify here? */ /* Do we have the swing at Luton? */ return DeviceStop(npMCI, dwFlags); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicPause | Pauses movie playback. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicPause(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { LPARAM dwCallback; if (!IsWindow(npMCI->hwndPlayback)) return MCIERR_NO_WINDOW;
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
if (lpParms) { dwCallback = lpParms->dwCallback; } else { dwCallback = 0; } return DevicePause(npMCI, dwFlags, dwCallback); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicResume | This function resumes playback of a paused * movie. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicResume (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { LPARAM dwCallback;
// Resume used to be only allowed if MCIAVI is paused or playing
// This is a little strange as some of the MCI commands automatically
// change PAUSED into STOPPED. There is no reason why we shouldn't
// treat resume as equivalent to play. (As does CDPLAYER.)
//
// if you decide to disagree, then don't forget that the DeviceMode()
// check can only safely be done *on the worker thread*
if (!IsWindow(npMCI->hwndPlayback)) return MCIERR_NO_WINDOW;
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
if (lpParms) { dwCallback = lpParms->dwCallback; } else { dwCallback = 0; } return DeviceResume(npMCI, dwFlags & MCI_WAIT, dwCallback); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicStatus | This function returns numeric status info. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the status message. * * @parm LPMCI_STATUS_PARMS | lpPlay | Parameters for the status message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicStatus (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_STATUS_PARMS lpStatus) { DWORD dwRet = 0L;
if (dwFlags & (MCI_DGV_STATUS_DISKSPACE)) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_STATUS_ITEM) {
lpStatus->dwReturn = 0L;
if ((dwFlags & MCI_TRACK) && !((lpStatus->dwItem == MCI_STATUS_POSITION) || (lpStatus->dwItem == MCI_STATUS_LENGTH))) return MCIERR_FLAGS_NOT_COMPATIBLE;
if ((dwFlags & MCI_STATUS_START) && (lpStatus->dwItem != MCI_STATUS_POSITION)) return MCIERR_FLAGS_NOT_COMPATIBLE;
if (dwFlags & MCI_DGV_STATUS_REFERENCE) return MCIERR_FLAGS_NOT_COMPATIBLE;
switch (lpStatus->dwItem) { case MCI_STATUS_POSITION:
if (dwFlags & MCI_TRACK) { /* POSITION with TRACK means return the start of the */ /* track. */
if (lpStatus->dwTrack != 1) dwRet = MCIERR_OUTOFRANGE; else /* return start frame of track (always 0) */ lpStatus->dwReturn = 0L; } else if (dwFlags & MCI_STATUS_START) // POSITION with START means return the starting playable
// position of the media.
lpStatus->dwReturn = 0L; else { /* Otherwise return current frame */ dwRet = DevicePosition(npMCI, (LPLONG) &lpStatus->dwReturn); lpStatus->dwReturn = ConvertFromFrames(npMCI, (LONG) lpStatus->dwReturn); } break;
case MCI_STATUS_LENGTH:
if (dwFlags & MCI_TRACK && lpStatus->dwTrack != 1) { /* LENGTH with TRACK means return the length of track */
lpStatus->dwReturn = 0L; dwRet = MCIERR_OUTOFRANGE; }
lpStatus->dwReturn = ConvertFromFrames(npMCI, npMCI->lFrames); break;
case MCI_STATUS_NUMBER_OF_TRACKS: case MCI_STATUS_CURRENT_TRACK:
lpStatus->dwReturn = 1L; break;
case MCI_STATUS_READY:
/* Return TRUE if device can receive commands */ if (DeviceMode(npMCI) != MCI_MODE_NOT_READY) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_STATUS_MODE: { WORD wMode; wMode = (WORD) DeviceMode(npMCI); lpStatus->dwReturn = (DWORD) MAKEMCIRESOURCE(wMode, wMode); dwRet = MCI_RESOURCE_RETURNED; } break;
case MCI_DGV_STATUS_PAUSE_MODE: if (DeviceMode(npMCI) != MCI_MODE_PAUSE) dwRet = MCIERR_NONAPPLICABLE_FUNCTION; else { lpStatus->dwReturn = MAKEMCIRESOURCE(MCI_MODE_PLAY, MCI_MODE_PLAY); dwRet = MCI_RESOURCE_RETURNED; } break;
case MCI_STATUS_MEDIA_PRESENT:
lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_FORWARD: if (npMCI->dwFlags & MCIAVI_REVERSE) lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); else lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_HWND:
lpStatus->dwReturn = (DWORD_PTR)(UINT_PTR)npMCI->hwndPlayback; if (!IsWindow(npMCI->hwndPlayback)) dwRet = MCIERR_NO_WINDOW; break;
case MCI_DGV_STATUS_HPAL:
// lpStatus->dwReturn = (DWORD) (UINT) DrawDibGetPalette(npMCI->hdd);
lpStatus->dwReturn = 0;
if (npMCI->nVideoStreams == 0) { dwRet = MCIERR_UNSUPPORTED_FUNCTION; } else { LRESULT l = ICSendMessage(npMCI->hicDraw, ICM_DRAW_GET_PALETTE, 0, 0);
if (l == ICERR_UNSUPPORTED) { dwRet = MCIERR_UNSUPPORTED_FUNCTION; } else { lpStatus->dwReturn = l; dwRet = 0; } } DPF2(("Status HPAL returns: %lu\n", lpStatus->dwReturn)); break;
case MCI_STATUS_TIME_FORMAT:
lpStatus->dwReturn = MAKEMCIRESOURCE(npMCI->dwTimeFormat, npMCI->dwTimeFormat + MCI_FORMAT_RETURN_BASE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_AUDIO: lpStatus->dwReturn = (npMCI->dwFlags & MCIAVI_PLAYAUDIO) ? (MAKEMCIRESOURCE(MCI_ON, MCI_ON_S)) : (MAKEMCIRESOURCE(MCI_OFF, MCI_OFF_S)); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break;
case MCI_DGV_STATUS_WINDOW_VISIBLE: if (npMCI->hwndPlayback && IsWindowVisible(npMCI->hwndPlayback)) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_WINDOW_MINIMIZED: if (npMCI->hwndPlayback && IsIconic(npMCI->hwndPlayback)) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_WINDOW_MAXIMIZED: if (npMCI->hwndPlayback && IsZoomed(npMCI->hwndPlayback)) lpStatus->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); else lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_SAMPLESPERSEC: case MCI_DGV_STATUS_AVGBYTESPERSEC: case MCI_DGV_STATUS_BLOCKALIGN: case MCI_DGV_STATUS_BITSPERSAMPLE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
case MCI_DGV_STATUS_BITSPERPEL: if (npMCI->psiVideo) lpStatus->dwReturn = ((LPBITMAPINFOHEADER)npMCI->psiVideo->lpFormat)->biBitCount; else dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
#ifndef _WIN32
#pragma message("Are we going to support brightness/color/contrast/tint?")
#endif
case MCI_DGV_STATUS_BRIGHTNESS: case MCI_DGV_STATUS_COLOR: case MCI_DGV_STATUS_CONTRAST: case MCI_DGV_STATUS_TINT: case MCI_DGV_STATUS_GAMMA: case MCI_DGV_STATUS_SHARPNESS: case MCI_DGV_STATUS_FILE_MODE: case MCI_DGV_STATUS_FILE_COMPLETION: case MCI_DGV_STATUS_KEY_INDEX: case MCI_DGV_STATUS_KEY_COLOR: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
case MCI_DGV_STATUS_FILEFORMAT: // Fall through to Unsupported case...
// lpStatus->dwReturn = MAKEMCIRESOURCE(MCI_DGV_FF_AVI,
// MCI_DGV_FF_AVI);
// dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER;
// break;
//
case MCI_DGV_STATUS_BASS: case MCI_DGV_STATUS_TREBLE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
case MCI_DGV_STATUS_VOLUME: { WORD wLeftVolume, wRightVolume; // Be sure volume is up to date....
DeviceGetVolume(npMCI);
wLeftVolume = LOWORD(npMCI->dwVolume); wRightVolume = LOWORD(npMCI->dwVolume);
switch (dwFlags & (MCI_DGV_STATUS_LEFT | MCI_DGV_STATUS_RIGHT)) { case MCI_DGV_STATUS_LEFT: lpStatus->dwReturn = (DWORD) wLeftVolume; break;
case 0: lpStatus->dwReturn = (DWORD) wRightVolume; break;
default: lpStatus->dwReturn = ((DWORD) wLeftVolume + (DWORD) wRightVolume) / 2; break; } } break;
case MCI_DGV_STATUS_MONITOR: lpStatus->dwReturn = (DWORD) MAKEMCIRESOURCE(MCI_DGV_MONITOR_FILE, MCI_DGV_FILE_S); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break;
case MCI_DGV_STATUS_SEEK_EXACTLY: lpStatus->dwReturn = (npMCI->dwOptionFlags & MCIAVIO_SEEKEXACT) ? (MAKEMCIRESOURCE(MCI_ON, MCI_ON_S)) : (MAKEMCIRESOURCE(MCI_OFF, MCI_OFF_S)); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break;
case MCI_DGV_STATUS_SIZE: /* We haven't reserved any space, so return zero. */ lpStatus->dwReturn = 0L; break;
case MCI_DGV_STATUS_SMPTE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
case MCI_DGV_STATUS_UNSAVED: lpStatus->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_STATUS_VIDEO: lpStatus->dwReturn = (npMCI->dwFlags & MCIAVI_SHOWVIDEO) ? (MAKEMCIRESOURCE(MCI_ON, MCI_ON_S)) : (MAKEMCIRESOURCE(MCI_OFF, MCI_OFF_S)); dwRet = MCI_RESOURCE_RETURNED | MCI_RESOURCE_DRIVER; break;
case MCI_DGV_STATUS_SPEED: lpStatus->dwReturn = npMCI->dwSpeedFactor; break;
case MCI_DGV_STATUS_FRAME_RATE: { DWORD dwTemp;
dwTemp = npMCI->dwMicroSecPerFrame;
/* If they haven't specifically asked for the "nominal"
** rate of play, adjust by the current speed. */ if (!(dwFlags & MCI_DGV_STATUS_NOMINAL)) dwTemp = muldiv32(dwTemp, 1000L, npMCI->dwSpeedFactor);
if (dwTemp == 0) lpStatus->dwReturn = 1000; else /* Our return value is in "thousandths of frames/sec",
** and dwTemp is the number of microseconds per frame. ** Thus, we divide a billion microseconds by dwTemp. */ lpStatus->dwReturn = muldiv32(1000000L, 1000L, dwTemp); break; }
case MCI_DGV_STATUS_AUDIO_STREAM: lpStatus->dwReturn = 0; if (npMCI->nAudioStreams) { int stream;
for (stream = 0; stream < npMCI->streams; stream++) { if (SH(stream).fccType == streamtypeAUDIO) ++lpStatus->dwReturn;
if (stream == npMCI->nAudioStream) break; } } break;
case MCI_DGV_STATUS_VIDEO_STREAM: case MCI_DGV_STATUS_AUDIO_INPUT: case MCI_DGV_STATUS_AUDIO_RECORD: case MCI_DGV_STATUS_AUDIO_SOURCE: case MCI_DGV_STATUS_VIDEO_RECORD: case MCI_DGV_STATUS_VIDEO_SOURCE: case MCI_DGV_STATUS_VIDEO_SRC_NUM: case MCI_DGV_STATUS_MONITOR_METHOD: case MCI_DGV_STATUS_STILL_FILEFORMAT: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
case MCI_AVI_STATUS_FRAMES_SKIPPED: lpStatus->dwReturn = npMCI->lSkippedFrames; break;
case MCI_AVI_STATUS_AUDIO_BREAKS: lpStatus->dwReturn = npMCI->lAudioBreaks; break;
case MCI_AVI_STATUS_LAST_PLAY_SPEED: lpStatus->dwReturn = npMCI->dwSpeedPercentage; break;
default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } /* end switch (item) */ } else if (dwFlags & MCI_DGV_STATUS_REFERENCE) {
if (lpStatus->dwReference > (DWORD) npMCI->lFrames) dwRet = MCIERR_OUTOFRANGE;
else if (npMCI->psiVideo) { DWORD dwReference; dwReference = MovieToStream(npMCI->psiVideo, lpStatus->dwReference);
lpStatus->dwReturn = FindPrevKeyFrame(npMCI, npMCI->psiVideo, dwReference);
lpStatus->dwReturn = StreamToMovie(npMCI->psiVideo, (DWORD) lpStatus->dwReturn); } else { lpStatus->dwReturn = 0; } } else /* item flag not set */ dwRet = MCIERR_MISSING_PARAMETER;
if ((dwFlags & MCI_TEST) && (LOWORD(dwRet) == 0)) { /* There is no error, but the test flag is on. Return as little
** as possible. */ dwRet = 0; lpStatus->dwReturn = 0; }
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicInfo | This function returns alphanumeric information. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the info. message. * * @parm LPMCI_INFO_PARMS | lpPlay | Parameters for the info message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicInfo(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_INFO_PARMS lpInfo) { DWORD dwRet = 0L; TCHAR ch = TEXT('\0'); BOOL fTest = FALSE;
if (!lpInfo->lpstrReturn) return MCIERR_PARAM_OVERFLOW;
if (dwFlags & MCI_TEST) fTest = TRUE;
dwFlags &= ~(MCI_WAIT | MCI_NOTIFY | MCI_TEST);
switch (dwFlags) { case 0L: return MCIERR_MISSING_PARAMETER;
case MCI_INFO_FILE: if (!npMCI) return MCIERR_UNSUPPORTED_FUNCTION;
if (lpInfo->dwRetSize < (DWORD)(lstrlen(npMCI->szFilename) + 1)) { ch = npMCI->szFilename[lpInfo->dwRetSize]; npMCI->szFilename[lpInfo->dwRetSize] = '\0'; dwRet = MCIERR_PARAM_OVERFLOW; } lstrcpy (lpInfo->lpstrReturn, npMCI->szFilename); if (ch) npMCI->szFilename[lpInfo->dwRetSize] = ch; break;
case MCI_INFO_PRODUCT:
#ifdef _WIN32
{ UINT n; #ifdef DEBUG
TCHAR versionstring[80]; #endif
n = LoadString(ghModule, MCIAVI_PRODUCTNAME, lpInfo->lpstrReturn, (UINT)lpInfo->dwRetSize); #ifdef DEBUG
#include "verinfo.h"
n += wsprintf(versionstring, TEXT(" (%d.%02d.%02d)"), MMVERSION, MMREVISION, MMRELEASE); if (n <= lpInfo->dwRetSize) { lstrcat(lpInfo->lpstrReturn, versionstring); } #endif
} #else // Win16 version follows
#ifdef DEBUG
#include "..\verinfo\usa\verinfo.h"
wsprintf(lpInfo->lpstrReturn, TEXT("VfW %d.%02d.%02d"), MMVERSION, MMREVISION, MMRELEASE); #else
/* !!! Not returning PARAM_OVERFLOW here but I am above - lazy eh */ LoadString(ghModule, MCIAVI_PRODUCTNAME, lpInfo->lpstrReturn, (UINT)lpInfo->dwRetSize); #endif
#endif
break;
case MCI_DGV_INFO_TEXT: if (!npMCI) return MCIERR_UNSUPPORTED_FUNCTION;
if (IsWindow(npMCI->hwndPlayback)) GetWindowText(npMCI->hwndPlayback, lpInfo->lpstrReturn, LOWORD(lpInfo->dwRetSize)); else dwRet = MCIERR_NO_WINDOW; break;
case MCI_INFO_VERSION: /* !!! Not returning PARAM_OVERFLOW here but I am above - lazy eh */ LoadString(ghModule, MCIAVI_VERSION, lpInfo->lpstrReturn, (UINT)lpInfo->dwRetSize); break;
case MCI_DGV_INFO_USAGE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
case MCI_DGV_INFO_ITEM: switch (lpInfo->dwItem) { case MCI_DGV_INFO_AUDIO_QUALITY: case MCI_DGV_INFO_VIDEO_QUALITY: case MCI_DGV_INFO_STILL_QUALITY: case MCI_DGV_INFO_AUDIO_ALG: case MCI_DGV_INFO_VIDEO_ALG: case MCI_DGV_INFO_STILL_ALG: default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } break;
default: dwRet = MCIERR_FLAGS_NOT_COMPATIBLE; break; }
if (fTest && (LOWORD(dwRet) == 0)) { /* There is no error, but the test flag is on. Return as little
** as possible. */ dwRet = 0; if (lpInfo->dwRetSize) lpInfo->lpstrReturn[0] = '\0'; }
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSet | This function sets various options. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set message. * * @parm LPMCI_SET_PARMS | lpSet | Parameters for the set message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicSet (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SET_PARMS lpSet) { DWORD dwRet = 0L; DWORD dwAction;
if (dwFlags & MCI_DGV_SET_FILEFORMAT) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_DGV_SET_STILL) return MCIERR_UNSUPPORTED_FUNCTION;
dwAction = dwFlags & (MCI_SET_TIME_FORMAT | MCI_SET_VIDEO | MCI_SET_AUDIO | MCI_DGV_SET_SEEK_EXACTLY | MCI_DGV_SET_SPEED );
/* Turn off all but the following three flags */ dwFlags &= (MCI_SET_ON | MCI_SET_OFF | MCI_TEST );
/* First, check if the parameters are all okay */
if (!dwAction) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwAction & MCI_SET_TIME_FORMAT) { if (lpSet->dwTimeFormat != MCI_FORMAT_FRAMES && lpSet->dwTimeFormat != MCI_FORMAT_MILLISECONDS) return MCIERR_UNSUPPORTED_FUNCTION; }
if ((dwAction & MCI_SET_AUDIO) && (lpSet->dwAudio != MCI_SET_AUDIO_ALL)) { return MCIERR_UNSUPPORTED_FUNCTION; }
if (dwAction & MCI_DGV_SET_SPEED) { if (lpSet->dwSpeed > 100000L) return MCIERR_OUTOFRANGE; }
switch (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { case 0: if (dwAction & (MCI_SET_AUDIO | MCI_SET_VIDEO | MCI_DGV_SET_SEEK_EXACTLY)) return MCIERR_MISSING_PARAMETER; break;
case MCI_SET_ON | MCI_SET_OFF: return MCIERR_FLAGS_NOT_COMPATIBLE;
default: if (dwAction & (MCI_DGV_SET_SPEED | MCI_SET_TIME_FORMAT)) return MCIERR_FLAGS_NOT_COMPATIBLE; break; }
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
/* Now, actually carry out the command */ if (dwAction & MCI_SET_TIME_FORMAT) npMCI->dwTimeFormat = lpSet->dwTimeFormat;
if (dwAction & MCI_SET_VIDEO) { npMCI->dwFlags &= ~(MCIAVI_SHOWVIDEO); if (dwFlags & MCI_SET_ON) { npMCI->dwFlags |= MCIAVI_SHOWVIDEO; InvalidateRect(npMCI->hwndPlayback, NULL, FALSE); } }
if (dwAction & MCI_DGV_SET_SEEK_EXACTLY) { npMCI->dwOptionFlags &= ~(MCIAVIO_SEEKEXACT); if (dwFlags & MCI_SET_ON) npMCI->dwOptionFlags |= MCIAVIO_SEEKEXACT; }
if (dwAction & MCI_DGV_SET_SPEED) { dwRet = DeviceSetSpeed(npMCI, lpSet->dwSpeed); }
if (dwRet == 0L && (dwAction & MCI_SET_AUDIO)) { dwRet = DeviceMute(npMCI, dwFlags & MCI_SET_OFF ? TRUE : FALSE); }
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSetAudio | This function sets various audio options. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set audio message. * * @parm LPMCI_SET_PARMS | lpSet | Parameters for the set audio message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSetAudio (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMS lpSet) { DWORD dwRet = 0L;
if (npMCI->nAudioStreams == 0) { return MCIERR_UNSUPPORTED_FUNCTION; }
if ((dwFlags & MCI_DGV_SETAUDIO_ITEM) && (lpSet->dwItem == MCI_DGV_SETAUDIO_VOLUME) && (dwFlags & MCI_DGV_SETAUDIO_VALUE)) { WORD wLeft, wRight;
if (dwFlags & (MCI_DGV_SETAUDIO_ALG | MCI_DGV_SETAUDIO_QUALITY | MCI_DGV_SETAUDIO_RECORD | MCI_DGV_SETAUDIO_CLOCKTIME)) return MCIERR_UNSUPPORTED_FUNCTION; if (lpSet->dwValue > 1000L) return MCIERR_OUTOFRANGE; if (dwFlags & MCI_TEST) return 0L;
// Be sure volume is up to date....
DeviceGetVolume(npMCI);
wLeft = LOWORD(npMCI->dwVolume); wRight = HIWORD(npMCI->dwVolume); if (!(dwFlags & MCI_DGV_SETAUDIO_RIGHT)) wLeft = (WORD) lpSet->dwValue;
if (!(dwFlags & MCI_DGV_SETAUDIO_LEFT)) wRight = (WORD) lpSet->dwValue;
dwRet = DeviceSetVolume(npMCI, MAKELONG(wLeft, wRight)); } else if ((dwFlags & MCI_DGV_SETAUDIO_ITEM) && (lpSet->dwItem == MCI_DGV_SETAUDIO_STREAM) && (dwFlags & MCI_DGV_SETAUDIO_VALUE)) { if (dwFlags & (MCI_DGV_SETAUDIO_ALG | MCI_DGV_SETAUDIO_QUALITY | MCI_DGV_SETAUDIO_RECORD | MCI_DGV_SETAUDIO_LEFT | MCI_DGV_SETAUDIO_CLOCKTIME | MCI_DGV_SETAUDIO_RIGHT)) return MCIERR_UNSUPPORTED_FUNCTION; if (lpSet->dwValue > (DWORD) npMCI->nAudioStreams || lpSet->dwValue == 0) return MCIERR_OUTOFRANGE; if (dwFlags & MCI_TEST) return 0L; dwRet = DeviceSetAudioStream(npMCI, (WORD) lpSet->dwValue); } else if (dwFlags & (MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_ALG | MCI_DGV_SETAUDIO_QUALITY | MCI_DGV_SETAUDIO_RECORD | MCI_DGV_SETAUDIO_LEFT | MCI_DGV_SETAUDIO_CLOCKTIME | MCI_DGV_SETAUDIO_RIGHT)) return MCIERR_UNSUPPORTED_FUNCTION;
dwRet = 0; switch (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) {
case MCI_SET_ON | MCI_SET_OFF: dwRet = MCIERR_FLAGS_NOT_COMPATIBLE; break;
case MCI_SET_OFF: dwRet = (DWORD)TRUE; // Drop through and call DeviceMute
case MCI_SET_ON: if (!(dwFlags & MCI_TEST)) dwRet = DeviceMute(npMCI, dwRet); else dwRet = 0; break;
default: if (!(dwFlags & MCI_DGV_SETAUDIO_ITEM)) dwRet = MCIERR_MISSING_PARAMETER; break; }
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSetVideo | This function sets various Video options. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set video message. * * @parm LPMCI_SET_PARMS | lpSet | Parameters for the set video message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSetVideo (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMS lpSet) { DWORD dwRet = 0L;
if (dwFlags & (MCI_DGV_SETVIDEO_RECORD | MCI_DGV_SETVIDEO_SRC_NUMBER | MCI_DGV_SETVIDEO_QUALITY | MCI_DGV_SETVIDEO_ALG | MCI_DGV_SETVIDEO_STILL | MCI_DGV_SETVIDEO_CLOCKTIME )) return MCIERR_UNSUPPORTED_FUNCTION;
if ((dwFlags & MCI_DGV_SETVIDEO_OVER) && (lpSet->dwItem != MCI_AVI_SETVIDEO_PALETTE_COLOR)) return MCIERR_UNSUPPORTED_FUNCTION;
if (dwFlags & MCI_DGV_SETVIDEO_ITEM) { switch (lpSet->dwItem) { case MCI_AVI_SETVIDEO_PALETTE_COLOR: if (!(dwFlags & MCI_DGV_SETVIDEO_OVER)) return MCIERR_MISSING_PARAMETER;
if (lpSet->dwOver >= npMCI->pbiFormat->biClrUsed) { return MCIERR_OUTOFRANGE; }
return DeviceSetPaletteColor(npMCI, lpSet->dwOver, lpSet->dwValue);
case MCI_DGV_SETVIDEO_PALHANDLE: if (dwFlags & MCI_DGV_SETVIDEO_VALUE) { if (lpSet->dwValue && lpSet->dwValue != MCI_AVI_SETVIDEO_PALETTE_HALFTONE && GetObjectType((HPALETTE) lpSet->dwValue) != OBJ_PAL) return MCIERR_AVI_BADPALETTE; }
if (!(dwFlags & MCI_TEST)) dwRet = DeviceSetPalette(npMCI, ((dwFlags & MCI_DGV_SETVIDEO_VALUE) ? (HPALETTE) lpSet->dwValue : NULL)); break;
case MCI_DGV_SETVIDEO_STREAM:
if (!(dwFlags & MCI_DGV_SETVIDEO_VALUE)) return MCIERR_UNSUPPORTED_FUNCTION;
if (lpSet->dwValue == 0 || lpSet->dwValue > (DWORD)npMCI->nVideoStreams + npMCI->nOtherStreams) return MCIERR_OUTOFRANGE;
if (dwFlags & MCI_SET_ON) DPF(("SetVideoStream to #%d on\n", (int)lpSet->dwValue)); else if (dwFlags & MCI_SET_OFF) DPF(("SetVideoStream to #%d off\n", (int)lpSet->dwValue)); else DPF(("SetVideoStream to #%d\n", (int)lpSet->dwValue));
if (!(dwFlags & MCI_TEST)) { dwRet = DeviceSetVideoStream(npMCI, (UINT)lpSet->dwValue, !(dwFlags & MCI_SET_OFF)); } break;
case MCI_AVI_SETVIDEO_DRAW_PROCEDURE:
if (DeviceMode(npMCI) != MCI_MODE_STOP) return MCIERR_UNSUPPORTED_FUNCTION;
if (npMCI->hicDrawDefault) { if (npMCI->hicDrawDefault != (HIC) -1) ICClose(npMCI->hicDrawDefault); npMCI->hicDrawDefault = 0; npMCI->dwFlags &= ~(MCIAVI_USERDRAWPROC); }
if (lpSet->dwValue) {
if (IsBadCodePtr((FARPROC) lpSet->dwValue)) { DPF(("Bad code pointer!!!!\n")); return MCIERR_OUTOFRANGE; //!!!MCIERR_BAD_PARAM;
}
npMCI->hicDrawDefault = ICOpenFunction(streamtypeVIDEO, FOURCC_AVIDraw,ICMODE_DRAW,(FARPROC) lpSet->dwValue);
if (!npMCI->hicDrawDefault) { return MCIERR_INTERNAL; } DPF(("Successfully set new draw procedure....\n"));
npMCI->dwFlags |= MCIAVI_USERDRAWPROC; }
npMCI->dwFlags |= MCIAVI_NEEDDRAWBEGIN; InvalidateRect(npMCI->hwndPlayback, NULL, FALSE); return 0;
default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } } else if (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { switch (dwFlags & (MCI_SET_ON | MCI_SET_OFF)) { case MCI_SET_ON: if (!(dwFlags & MCI_TEST)) { InvalidateRect(npMCI->hwndPlayback, NULL, FALSE); npMCI->dwFlags |= MCIAVI_SHOWVIDEO; } break; case MCI_SET_OFF: if (!(dwFlags & MCI_TEST)) npMCI->dwFlags &= ~(MCIAVI_SHOWVIDEO); break; case MCI_SET_ON | MCI_SET_OFF: dwRet = MCIERR_FLAGS_NOT_COMPATIBLE; break; } } else dwRet = MCIERR_MISSING_PARAMETER;
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicSignal | This function sets signals. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the set PositionAdvise message. * * @parm LPMCI_SIGNAL_PARMS | lpSignal | Parameters for the signal * message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicSignal(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpSignal) { DWORD dwRet = 0L; DWORD dwUser; DWORD dwPosition; DWORD dwPeriod;
dwUser = (dwFlags & MCI_DGV_SIGNAL_USERVAL) ? lpSignal->dwUserParm : 0L;
if (dwFlags & MCI_DGV_SIGNAL_CANCEL) { if (dwFlags & (MCI_DGV_SIGNAL_AT | MCI_DGV_SIGNAL_EVERY | MCI_DGV_SIGNAL_POSITION)) return MCIERR_FLAGS_NOT_COMPATIBLE;
if (!npMCI->dwSignals) return MCIERR_NONAPPLICABLE_FUNCTION;
if (dwUser && (npMCI->signal.dwUserParm != dwUser)) return MCIERR_NONAPPLICABLE_FUNCTION;
if (!(dwFlags & MCI_TEST)) --npMCI->dwSignals; } else { if ((npMCI->dwSignals != 0) && (dwUser != npMCI->signal.dwUserParm)) { /* !!! Should we allow more than one signal? */ return MCIERR_DGV_DEVICE_LIMIT; }
if (dwFlags & MCI_DGV_SIGNAL_AT) { /* Use position passed in */ dwPosition = ConvertToFrames(npMCI, lpSignal->dwPosition); if (dwPosition > (DWORD) npMCI->lFrames) return MCIERR_OUTOFRANGE; } else { /* Get current position */ DevicePosition(npMCI, (LPLONG) &dwPosition); }
if (dwFlags & MCI_DGV_SIGNAL_EVERY) { dwPeriod = (DWORD) ConvertToFrames(npMCI, lpSignal->dwPeriod);
if (dwPeriod == 0 || (dwPeriod > (DWORD) npMCI->lFrames)) return MCIERR_OUTOFRANGE; } else { /* It's a one-time signal */ dwPeriod = 0L; }
if (dwFlags & MCI_TEST) return 0;
npMCI->signal.dwPosition = dwPosition; npMCI->signal.dwPeriod = dwPeriod; npMCI->signal.dwUserParm = dwUser; npMCI->signal.dwCallback = lpSignal->dwCallback; npMCI->dwSignalFlags = dwFlags;
/* The signal isn't really activated until we do this. */ if (!npMCI->dwSignals) ++npMCI->dwSignals; }
return 0L; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicList | This function supports the MCI_LIST command. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the List message. * * @parm LPMCI_DGV_LIST_PARMS | lpList | Parameters for the list message. * * @rdesc Returns an MCI error code. * ***************************************************************************/ DWORD NEAR PASCAL GraphicList(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_LIST_PARMS lpList) { return MCIERR_UNSUPPORTED_FUNCTION; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicGetDevCaps | This function returns device * capabilities * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the GetDevCaps message. * * @parm LPMCI_GETDEVCAPS_PARMS | lpCaps | Parameters for the GetDevCaps * message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicGetDevCaps (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpCaps ) {
DWORD dwRet = 0L;
if (dwFlags & MCI_GETDEVCAPS_ITEM) {
switch (lpCaps->dwItem) { case MCI_GETDEVCAPS_CAN_RECORD: case MCI_GETDEVCAPS_CAN_EJECT: case MCI_GETDEVCAPS_CAN_SAVE: case MCI_DGV_GETDEVCAPS_CAN_LOCK: case MCI_DGV_GETDEVCAPS_CAN_STR_IN: case MCI_DGV_GETDEVCAPS_CAN_FREEZE: case MCI_DGV_GETDEVCAPS_HAS_STILL:
lpCaps->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_GETDEVCAPS_CAN_REVERSE: case MCI_GETDEVCAPS_CAN_PLAY: case MCI_GETDEVCAPS_HAS_AUDIO: case MCI_GETDEVCAPS_HAS_VIDEO: case MCI_GETDEVCAPS_USES_FILES: case MCI_GETDEVCAPS_COMPOUND_DEVICE: case MCI_DGV_GETDEVCAPS_PALETTES: case MCI_DGV_GETDEVCAPS_CAN_STRETCH: case MCI_DGV_GETDEVCAPS_CAN_TEST: lpCaps->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_GETDEVCAPS_DEVICE_TYPE:
lpCaps->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_DIGITAL_VIDEO, MCI_DEVTYPE_DIGITAL_VIDEO); dwRet = MCI_RESOURCE_RETURNED; break;
case MCI_DGV_GETDEVCAPS_MAX_WINDOWS: case MCI_DGV_GETDEVCAPS_MAXIMUM_RATE: case MCI_DGV_GETDEVCAPS_MINIMUM_RATE: default:
dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; } } else dwRet = MCIERR_MISSING_PARAMETER;
if ((dwFlags & MCI_TEST) && (LOWORD(dwRet) == 0)) { /* There is no error, but the test flag is on. Return as little
** as possible. */ dwRet = 0; lpCaps->dwReturn = 0; }
return (dwRet); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicWindow | This function controls the stage window * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the window message. * * @parm LPMCI_DGV_WINDOW_PARMS | lpPlay | Parameters for the window message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicWindow (NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_WINDOW_PARMS lpWindow) { DWORD dwRet = 0L; int i = 0; HWND hWndNew;
if (dwFlags & MCI_DGV_WINDOW_HWND) { // Set a new stage window. If the parameter is NULL, then
// use the default window. Otherwise, hide the default
// window and use the given window handle.
if (!lpWindow->hWnd) hWndNew = npMCI->hwndDefault; else hWndNew = lpWindow->hWnd;
if (!IsWindow(hWndNew)) return MCIERR_NO_WINDOW;
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
// only change if the new window handle is different from the current
// stage window handle
if (hWndNew != npMCI->hwndPlayback) { dwRet = DeviceSetWindow(npMCI, hWndNew);
if (npMCI->hwndPlayback != npMCI->hwndDefault) {
// see comment in graphic.h
// They've specified their own window for playback. Don't use
// the default registry sizing
npMCI->fOKToUseDefaultSizing = FALSE;
if (IsWindow(npMCI->hwndDefault)) ShowWindow(npMCI->hwndDefault, SW_HIDE); } } }
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return dwRet;
if (!dwRet) { if (IsWindow(npMCI->hwndPlayback)) { if (dwFlags & MCI_DGV_WINDOW_STATE) { // see comment in graphic.h on npMCI->fOKToUseDefaultSizing
// This is the moment of truth. We're showing the window
// and we may want to pay attention to the registry default
// sizing (zoom by 2, fixed % of screen size, etc.)
// As an extra note I should say that it's important that we
// don't change it until now so that if somebody opens a file
// and does a "where destination" they get the original size,
// because if they're playing in their own window, it will
// not be altered anyway.
if (lpWindow->nCmdShow != SW_HIDE) { if (npMCI->fOKToUseDefaultSizing) { SetWindowToDefaultSize(npMCI, TRUE); ResetDestRect(npMCI, TRUE); }
// Never do this again
npMCI->fOKToUseDefaultSizing = FALSE; }
ShowWindow (npMCI->hwndPlayback, lpWindow->nCmdShow); }
if (dwFlags & MCI_DGV_WINDOW_TEXT) SetWindowText(npMCI->hwndPlayback, lpWindow->lpstrText); } else dwRet = MCIERR_NO_WINDOW; }
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicPut | This function sets the offset and extent * of the animation within the client area of the stage window. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the put message. * * @parm LPMCI_DGV_RECT_PARMS | lpDestination | Parameters for the * destination message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicPut ( NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms) { BOOL frc; RECT rc;
if (dwFlags & (MCI_DGV_PUT_FRAME | MCI_DGV_PUT_VIDEO)) return MCIERR_UNSUPPORTED_FUNCTION;
frc = (dwFlags & MCI_DGV_RECT) == MCI_DGV_RECT;
if (!IsWindow(npMCI->hwndPlayback)) return MCIERR_NO_WINDOW;
switch (dwFlags & (MCI_DGV_PUT_SOURCE | MCI_DGV_PUT_DESTINATION | MCI_DGV_PUT_WINDOW)) { case 0L: return MCIERR_MISSING_PARAMETER;
case MCI_DGV_PUT_SOURCE: // If a rectangle is supplied, use it.
if (frc) { rc.left = lpParms->ptOffset.x; rc.top = lpParms->ptOffset.y; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; DPF2(("GraphicPut_Source: rc [%d %d %d %d]\n", rc));
if (lpParms->ptExtent.x <= 0) { rc.right = rc.left + (npMCI->rcDest.right - npMCI->rcDest.left); } if (lpParms->ptExtent.y <= 0) { rc.bottom = rc.top + (npMCI->rcDest.bottom - npMCI->rcDest.top); } } else { /* Reset to default */ rc = npMCI->rcMovie; DPF2(("GraphicPut_Source (default): rc [%d %d %d %d]\n", rc)); } break;
case MCI_DGV_PUT_DESTINATION: // If a rectangle is supplied, use it.
if (frc) { rc.left = lpParms->ptOffset.x; rc.top = lpParms->ptOffset.y; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; DPF2(("GraphicPut_Destination: rc [%d %d %d %d]\n", rc));
if (lpParms->ptExtent.x <= 0) { rc.right = rc.left + (npMCI->rcDest.right - npMCI->rcDest.left); } if (lpParms->ptExtent.y <= 0) { rc.bottom = rc.top + (npMCI->rcDest.bottom - npMCI->rcDest.top); }
} else { /* Reset to size of stage window */ GetClientRect(npMCI->hwndPlayback, &rc); DPF2(("GraphicPut_Destination (default): rc [%d %d %d %d]\n", rc)); } break;
case MCI_DGV_PUT_WINDOW: if (dwFlags & MCI_TEST) return 0L;
// De-minimize their window, so we don't end up with
// a giant icon....
if (IsIconic(npMCI->hwndPlayback)) ShowWindow(npMCI->hwndPlayback, SW_RESTORE);
// If a rectangle is supplied, use it.
if (frc) { RECT rcOld;
rc.left = lpParms->ptOffset.x; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.top = lpParms->ptOffset.y; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y; if (dwFlags & MCI_DGV_PUT_CLIENT) { AdjustWindowRect(&rc, GetWindowLong(npMCI->hwndPlayback, GWL_STYLE), FALSE); }
// Default to just moving if width, height == 0....
GetWindowRect(npMCI->hwndPlayback, &rcOld); if (lpParms->ptExtent.x <= 0) { rc.right = rc.left + (rcOld.right - rcOld.left); } if (lpParms->ptExtent.y <= 0) { rc.bottom = rc.top + (rcOld.bottom - rcOld.top); }
MoveWindow(npMCI->hwndPlayback, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); } else { // !!! What should we do if there's no rectangle?
/* Reset to "natural" size? */ rc = npMCI->rcMovie;
if (npMCI->dwOptionFlags & MCIAVIO_ZOOMBY2) SetRect(&rc, 0, 0, rc.right*2, rc.bottom*2);
AdjustWindowRect(&rc, GetWindowLong(npMCI->hwndPlayback, GWL_STYLE), FALSE);
SetWindowPos(npMCI->hwndPlayback, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); }
// Premiere 1.0 depends on the window always being visible
// after a PUT_WINDOW command. Make it so.
ShowWindow(npMCI->hwndPlayback, SW_RESTORE); return 0L;
default: return MCIERR_FLAGS_NOT_COMPATIBLE; }
if (dwFlags & MCI_DGV_PUT_CLIENT) return MCIERR_FLAGS_NOT_COMPATIBLE;
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
// see comment in graphic.h
// Any "put" command is dicking with the playback window and I think that's
// grounds to not use the default window sizing.
npMCI->fOKToUseDefaultSizing = FALSE;
return DevicePut(npMCI, &rc, dwFlags); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicWhere | This function returns the current * source and destination rectangles, in offset/extent form. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the query source message. * * @parm LPMCI_DGV_RECT_PARMS | lpParms | Parameters for the message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicWhere(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms) { RECT rc;
if (dwFlags & (MCI_DGV_WHERE_FRAME | MCI_DGV_WHERE_VIDEO)) return MCIERR_UNSUPPORTED_FUNCTION;
// !!! WHERE_WINDOW?
switch (dwFlags & (MCI_DGV_WHERE_SOURCE | MCI_DGV_WHERE_DESTINATION | MCI_DGV_WHERE_WINDOW)) { case 0L: return MCIERR_MISSING_PARAMETER;
case MCI_DGV_WHERE_SOURCE: if (dwFlags & MCI_DGV_WHERE_MAX) { lpParms->ptOffset.x = npMCI->rcMovie.left; lpParms->ptOffset.y = npMCI->rcMovie.top; lpParms->ptExtent.x = npMCI->rcMovie.right - npMCI->rcMovie.left; lpParms->ptExtent.y = npMCI->rcMovie.bottom - npMCI->rcMovie.top; DPF2(("Where source (max): [%d, %d, %d, %d]\n", npMCI->rcMovie)); } else { lpParms->ptOffset.x = npMCI->rcSource.left; lpParms->ptOffset.y = npMCI->rcSource.top; lpParms->ptExtent.x = npMCI->rcSource.right - npMCI->rcSource.left; lpParms->ptExtent.y = npMCI->rcSource.bottom - npMCI->rcSource.top; DPF2(("Where source: [%d, %d, %d, %d]\n", npMCI->rcSource)); } break;
case MCI_DGV_WHERE_DESTINATION: if (dwFlags & MCI_DGV_WHERE_MAX) { /* Return size of window */ GetClientRect(npMCI->hwndPlayback, &rc); lpParms->ptOffset.x = 0; lpParms->ptOffset.y = 0; lpParms->ptExtent.x = rc.right; lpParms->ptExtent.y = rc.bottom; DPF2(("Where destination (max): [%d, %d, %d, %d]\n", rc)); } else { /* Return current destination size */ lpParms->ptOffset.x = npMCI->rcDest.left; lpParms->ptOffset.y = npMCI->rcDest.top; lpParms->ptExtent.x = npMCI->rcDest.right - npMCI->rcDest.left; lpParms->ptExtent.y = npMCI->rcDest.bottom - npMCI->rcDest.top; DPF2(("Where destination: [%d, %d, %d, %d]\n", npMCI->rcDest)); } break;
case MCI_DGV_WHERE_WINDOW: if (dwFlags & MCI_DGV_WHERE_MAX) { /* Return maximum size of window */ GetClientRect(npMCI->hwndPlayback, &rc); lpParms->ptOffset.x = 0; lpParms->ptOffset.y = 0; lpParms->ptExtent.x = GetSystemMetrics(SM_CXSCREEN); lpParms->ptExtent.y = GetSystemMetrics(SM_CYSCREEN); } else { /* Return size of window */ GetWindowRect(npMCI->hwndPlayback, &rc); lpParms->ptOffset.x = rc.left; lpParms->ptOffset.y = rc.top; lpParms->ptExtent.x = rc.right - rc.left; lpParms->ptExtent.y = rc.bottom - rc.top; } break;
default: return MCIERR_FLAGS_NOT_COMPATIBLE; }
return 0L; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicRealize | This function realizes the current palette * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicRealize(NPMCIGRAPHIC npMCI, DWORD dwFlags) { /* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
npMCI->fForceBackground = (dwFlags & MCI_DGV_REALIZE_BKGD) != 0;
return DeviceRealize(npMCI); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicUpdate | This function refreshes the current frame. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the message. * * @parm LPMCI_DGV_UPDATE_PARMS | lpParms | Parameters for the message. * * @rdesc Returns an MCI error code. * ***************************************************************************/
DWORD NEAR PASCAL GraphicUpdate(NPMCIGRAPHIC npMCI, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms) { RECT rc;
rc.left = lpParms->ptOffset.x; rc.top = lpParms->ptOffset.y; rc.right = lpParms->ptOffset.x + lpParms->ptExtent.x; rc.bottom = lpParms->ptOffset.y + lpParms->ptExtent.y;
if (!(dwFlags & MCI_DGV_UPDATE_HDC)) { InvalidateRect(npMCI->hwndPlayback, (dwFlags & MCI_DGV_RECT) ? &rc : NULL, TRUE);
// this will cause the winproc thread to do the repaint now
UpdateWindow(npMCI->hwndPlayback); return 0; }
/* If the test flag is set, return without doing anything. */ /* Question: do we have to check for more possible errors? */ if (dwFlags & MCI_TEST) return 0L;
return DeviceUpdate (npMCI, dwFlags, lpParms); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | GraphicConfig | This function brings up the configure dialog. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwFlags | Flags for the message. * The only flag bit checked is MCI_TEST * * @rdesc Returns 0. * ***************************************************************************/
DWORD FAR PASCAL GraphicConfig(NPMCIGRAPHIC npMCI, DWORD dwFlags) { DWORD dwOptions = npMCI->dwOptionFlags;
if (!(dwFlags & MCI_TEST)) { BOOL f; gfEvil++;
f = ConfigDialog(NULL, npMCI); if (f) {
#ifdef DEBUG
//
// in DEBUG always reset the dest rect because the user may
// have played with the DEBUG DrawDib options and we will
// need to call DrawDibBegin() again.
//
if (TRUE) { #else
if ((npMCI->dwOptionFlags & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2 |MCIAVIO_WINDOWSIZEMASK)) != (dwOptions & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2 |MCIAVIO_WINDOWSIZEMASK)) ) { #endif
npMCI->lFrameDrawn = (- (LONG) npMCI->wEarlyRecords) - 1; SetWindowToDefaultSize(npMCI, TRUE);
// don't do this on the user thread
//SetRectEmpty(&npMCI->rcDest); //This will force a change!
ResetDestRect(npMCI, TRUE); } } else { npMCI->dwOptionFlags = dwOptions; } gfEvil--; }
return 0L; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | mciSpecial | This function handles all the MCI * commands that don't require instance data such as open. * * @parm UINT | wDeviceID | The MCI device ID * * @parm UINT | wMessage | The requested action to be performed. * * @parm DWORD | dwFlags | Flags for the message. * * @parm DWORD | lpParms | Parameters for this message. * * @rdesc Error Constant. 0L on success * ***************************************************************************/
DWORD NEAR PASCAL mciSpecial (UINT wDeviceID, UINT wMessage, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { NPMCIGRAPHIC npMCI = 0L; DWORD dwRet;
/* since there in no instance block, there is no saved notification */ /* to abort. */
switch (wMessage) { case MCI_OPEN_DRIVER: if (dwFlags & (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID)) dwRet = GraphicOpen (&npMCI, dwFlags, (LPMCI_DGV_OPEN_PARMS) lpParms, wDeviceID); else dwRet = 0L;
mciSetDriverData (wDeviceID, (UINT_PTR)npMCI); break;
case MCI_GETDEVCAPS: dwRet = GraphicGetDevCaps(NULL, dwFlags, (LPMCI_GETDEVCAPS_PARMS)lpParms); break;
case MCI_CONFIGURE:
if (!(dwFlags & MCI_TEST)) ConfigDialog(NULL, NULL);
dwRet = 0L; break;
case MCI_INFO: dwRet = GraphicInfo(NULL, dwFlags, (LPMCI_DGV_INFO_PARMS)lpParms); break;
case MCI_CLOSE_DRIVER: dwRet = 0L; break;
default: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break; }
GraphicImmediateNotify (wDeviceID, lpParms, dwFlags, dwRet); return (dwRet); }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | mciDriverEntry | This function is the MCI handler * * @parm UINT | wDeviceID | The MCI device ID * * @parm UINT | wMessage | The requested action to be performed. * * @parm DWORD | dwFlags | Flags for the message. * * @parm DWORD | lpParms | Parameters for this message. * * @rdesc Error Constant. 0L on success * ***************************************************************************/
DWORD PASCAL mciDriverEntry (UINT wDeviceID, UINT wMessage, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) { NPMCIGRAPHIC npMCI = 0L; DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND; BOOL fDelayed = FALSE; BOOL fNested = FALSE;
/* All current commands require a parameter block. */
if (!lpParms && (dwFlags & MCI_NOTIFY)) return (MCIERR_MISSING_PARAMETER);
npMCI = (NPMCIGRAPHIC) mciGetDriverData(wDeviceID);
if (!npMCI) return mciSpecial(wDeviceID, wMessage, dwFlags, lpParms); #ifdef DEBUG
else Assert(npMCI->mciid == MCIID); #endif
/*
** If a WOW app has subclassed the AVIWnd32 window, ** this is very bad as it stops all "Sent" message processing on ** that window, "Posted" messages seem to be OK. This means ** that it is not possible to close the movie window. */ if ( IsNTWOW() ) {
DPF2(( "WOW mcidriverentry\n")); if ( IsWindow(npMCI->hwndDefault) ) {
WNDPROC wndProc = (WNDPROC)GetWindowLongPtr( npMCI->hwndDefault, GWLP_WNDPROC ); if ( wndProc != GraphicWndProc ) {
DPF2(( "WOW app has subclassed AVIWnd32 window - correcting\n" )); SetWindowLongPtr( npMCI->hwndDefault, GWLP_WNDPROC, (LONG_PTR)GraphicWndProc ); } wndProc = (WNDPROC)GetClassLongPtr(npMCI->hwndDefault, GCLP_WNDPROC); if (wndProc != GraphicWndProc) { DPF2(( "WOW app has subclassed AVIWnd32 class! - correcting\n" )); SetClassLongPtr( npMCI->hwndDefault, GCLP_WNDPROC, (LONG_PTR)GraphicWndProc ); } } }
if (npMCI->wMessageCurrent) { fNested = TRUE;
if (wMessage != MCI_STATUS && wMessage != MCI_GETDEVCAPS && wMessage != MCI_INFO) { DPF(("Warning!!!!!\n")); DPF(("Warning!!!!! MCIAVI reentered: received %x while processing %x\n", wMessage, npMCI->wMessageCurrent)); DPF(("Warning!!!!!\n")); // Assert(0);
// return MCIERR_DEVICE_NOT_READY;
} } else npMCI->wMessageCurrent = wMessage;
switch (wMessage) {
case MCI_CLOSE_DRIVER:
// Question: Should we set the driver data to NULL
// before closing the device? It would seem the right order.
// So... we have moved this line before the call to GraphicClose
mciSetDriverData(wDeviceID, 0L);
// note that GraphicClose will release and delete the critsec
dwRet = GraphicClose(npMCI);
npMCI = NULL; break;
case MCI_PLAY:
dwRet = GraphicPlay(npMCI, dwFlags, (LPMCI_PLAY_PARMS)lpParms); fDelayed = TRUE; break;
case MCI_CUE:
dwRet = GraphicCue(npMCI, dwFlags, (LPMCI_DGV_CUE_PARMS)lpParms); fDelayed = TRUE; break;
case MCI_STEP:
dwRet = GraphicStep(npMCI, dwFlags, (LPMCI_DGV_STEP_PARMS)lpParms); fDelayed = TRUE; break;
case MCI_STOP:
dwRet = GraphicStop(npMCI, dwFlags, lpParms); break;
case MCI_SEEK:
dwRet = GraphicSeek (npMCI, dwFlags, (LPMCI_SEEK_PARMS)lpParms); fDelayed = TRUE; break;
case MCI_PAUSE:
dwRet = GraphicPause(npMCI, dwFlags, lpParms); fDelayed = TRUE; break;
case MCI_RESUME:
dwRet = GraphicResume(npMCI, dwFlags, lpParms); fDelayed = TRUE; break;
case MCI_SET:
dwRet = GraphicSet(npMCI, dwFlags, (LPMCI_DGV_SET_PARMS)lpParms); break;
case MCI_STATUS:
dwRet = GraphicStatus(npMCI, dwFlags, (LPMCI_DGV_STATUS_PARMS)lpParms); break;
case MCI_INFO:
dwRet = GraphicInfo (npMCI, dwFlags, (LPMCI_DGV_INFO_PARMS)lpParms); break;
case MCI_GETDEVCAPS:
dwRet = GraphicGetDevCaps(npMCI, dwFlags, (LPMCI_GETDEVCAPS_PARMS)lpParms); break;
case MCI_REALIZE:
dwRet = GraphicRealize(npMCI, dwFlags); break;
case MCI_UPDATE:
dwRet = GraphicUpdate(npMCI, dwFlags, (LPMCI_DGV_UPDATE_PARMS)lpParms); break;
case MCI_WINDOW:
dwRet = GraphicWindow(npMCI, dwFlags, (LPMCI_DGV_WINDOW_PARMS)lpParms); break;
case MCI_PUT:
dwRet = GraphicPut(npMCI, dwFlags, (LPMCI_DGV_RECT_PARMS)lpParms); break;
case MCI_WHERE:
dwRet = GraphicWhere(npMCI, dwFlags, (LPMCI_DGV_RECT_PARMS)lpParms); break;
case MCI_CONFIGURE: dwRet = GraphicConfig(npMCI, dwFlags); break;
case MCI_SETAUDIO: dwRet = GraphicSetAudio(npMCI, dwFlags, (LPMCI_DGV_SETAUDIO_PARMS) lpParms); break;
case MCI_SETVIDEO: dwRet = GraphicSetVideo(npMCI, dwFlags, (LPMCI_DGV_SETVIDEO_PARMS) lpParms); break;
case MCI_SIGNAL: dwRet = GraphicSignal(npMCI, dwFlags, (LPMCI_DGV_SIGNAL_PARMS) lpParms); break;
case MCI_LIST: dwRet = GraphicList(npMCI, dwFlags, (LPMCI_DGV_LIST_PARMS) lpParms); break;
case MCI_LOAD: dwRet = GraphicLoad(npMCI, dwFlags, (LPMCI_DGV_LOAD_PARMS) lpParms); break;
case MCI_RECORD: case MCI_SAVE:
case MCI_CUT: case MCI_COPY: case MCI_PASTE: case MCI_UNDO:
case MCI_DELETE: case MCI_CAPTURE: case MCI_QUALITY: case MCI_MONITOR: case MCI_RESERVE: case MCI_FREEZE: case MCI_UNFREEZE: dwRet = MCIERR_UNSUPPORTED_FUNCTION; break;
/* Do we need this case? */ default: dwRet = MCIERR_UNRECOGNIZED_COMMAND; break; }
if (!fDelayed || (dwFlags & MCI_TEST)) { /* We haven't processed the notify yet. */ if (npMCI && (dwFlags & MCI_NOTIFY) && (!LOWORD(dwRet))) /* Throw away the old notify */ GraphicDelayedNotify(npMCI, MCI_NOTIFY_SUPERSEDED);
/* And send the new one out immediately. */ GraphicImmediateNotify(wDeviceID, lpParms, dwFlags, dwRet); }
if (npMCI) { /* Everything from here on relies on npMCI still being around */
/* If there's an error, don't save the callback.... */ if (fDelayed && dwRet != 0 && (dwFlags & MCI_NOTIFY)) {
// this might be too late, of course, but shouldn't do
// any harm
npMCI->hCallback = 0; }
//
// see if we need to tell the DRAW device about moving.
// MPlayer is sending the status and position command alot
// so this is a "timer"
//
// !!!do we need to do it this often?
//
if (npMCI->dwFlags & MCIAVI_WANTMOVE) CheckWindowMove(npMCI, FALSE);
if (!fNested) npMCI->wMessageCurrent = 0;
}
return dwRet; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | ConvertToFrames | Convert from the current time format into * frames. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm DWORD | dwTime | Input time. * ***************************************************************************/ LONG NEAR PASCAL ConvertToFrames(NPMCIGRAPHIC npMCI, DWORD dwTime) { if (npMCI->dwTimeFormat == MCI_FORMAT_FRAMES) { return (LONG) dwTime; } else { if (npMCI->dwMicroSecPerFrame > 1000) { /* This needs to round down--muldiv32 likes to round off. */ return (LONG) muldivrd32(dwTime, 1000L, npMCI->dwMicroSecPerFrame); } else { return (LONG) muldivru32(dwTime, 1000L, npMCI->dwMicroSecPerFrame); } } }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api DWORD | ConvertFromFrames | Convert from frames into the current * time format. * * @parm NPMCIGRAPHIC | npMCI | Near pointer to instance data block * * @parm LONG | lFrame | Frame number to convert. * ***************************************************************************/ DWORD NEAR PASCAL ConvertFromFrames(NPMCIGRAPHIC npMCI, LONG lFrame) { if (npMCI->dwTimeFormat == MCI_FORMAT_FRAMES) { return (DWORD)lFrame; } else { if (npMCI->dwMicroSecPerFrame > 1000) return muldivru32(lFrame, npMCI->dwMicroSecPerFrame, 1000L); else return muldivrd32(lFrame, npMCI->dwMicroSecPerFrame, 1000L); } }
#ifdef HEARTBEAT
DWORD Interval = 60000; // 1 minute
DWORD HeartBeatBreak = FALSE; DWORD HeartBeatDump = FALSE;
DWORD HeartBeat(LPVOID lpvThreadData) {
NPMCIGRAPHIC npMCI; int n; while (TRUE) {
for (n=Interval/1000; n--; ) { Sleep(1000); if (fTerminate) { ExitThread(0); } }
if (HeartBeatDump) {
LPTSTR pszFilename;
EnterList(); npMCI = npMCIList; while (npMCI) {
pszFilename = npMCI->szFilename; if (!pszFilename) { pszFilename = L"<NULL>"; } DPF0(("\nDevice dump : %8x : Name > %ls <\n" "\t: CmdCritSec owner=%x, count=%x " "\t: WinCritSec owner=%x, count=%x " ": HDCCritSec owner=%x, count=%x\n" "\t State=%x hWave=%x", npMCI, pszFilename, (npMCI->CmdCritSec).OwningThread, (npMCI->CmdCritSec).RecursionCount, (npMCI->WinCritSec).OwningThread, (npMCI->WinCritSec).RecursionCount, (npMCI->HDCCritSec).OwningThread, (npMCI->HDCCritSec).RecursionCount, npMCI->wTaskState, npMCI->hWave));
npMCI = npMCI->npMCINext; } LeaveList(); }
if (HeartBeatBreak) { DebugBreak(); } } return (0); } #endif
|