363 lines
9.7 KiB
C
363 lines
9.7 KiB
C
|
/******************************************************************************
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
|
|||
|
|
|||
|
Title: avitask.c - Background task that actually manipulates AVI files.
|
|||
|
|
|||
|
*****************************************************************************/
|
|||
|
#include "graphic.h"
|
|||
|
|
|||
|
void FAR PASCAL DebugBreak(void);
|
|||
|
|
|||
|
BOOL FAR PASCAL mciaviCloseFile(NPMCIGRAPHIC npMCI);
|
|||
|
BOOL FAR PASCAL mciaviOpenFile(NPMCIGRAPHIC npMCI);
|
|||
|
|
|||
|
#if defined(WIN32) || !defined(DEBUG)
|
|||
|
#define StackTop() (void *)0
|
|||
|
#define StackMin() (void *)0
|
|||
|
#define StackBot() (void *)0
|
|||
|
#define StackMark()
|
|||
|
#define StackTest() TRUE
|
|||
|
#else
|
|||
|
#define STACK _based(_segname("_STACK"))
|
|||
|
#define StackTop() *((UINT STACK *)10)
|
|||
|
#define StackMin() *((UINT STACK *)12)
|
|||
|
#define StackBot() *((UINT STACK *)14)
|
|||
|
#define StackMark() *((UINT STACK*)StackBot()) = 42
|
|||
|
#define StackTest() *((UINT STACK*)StackBot()) == 42
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
/***************************************************************************
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
#ifndef WIN32
|
|||
|
#pragma optimize("", off)
|
|||
|
void FAR SetPSP(UINT psp)
|
|||
|
{
|
|||
|
_asm {
|
|||
|
mov bx,psp
|
|||
|
mov ah,50h
|
|||
|
int 21h
|
|||
|
}
|
|||
|
}
|
|||
|
#pragma optimize("", on)
|
|||
|
#endif
|
|||
|
|
|||
|
/***************************************************************************
|
|||
|
*
|
|||
|
* @doc INTERNAL MCIAVI
|
|||
|
*
|
|||
|
* @api void | mciaviTask | This function is the background task which plays
|
|||
|
* AVI files. It is called as a result of the call to mmTaskCreate()
|
|||
|
* in DeviceOpen(). When this function returns, the task is destroyed.
|
|||
|
*
|
|||
|
* @parm DWORD | dwInst | instance data passed to mmCreateTask - contains
|
|||
|
* a pointer to an instance data block.
|
|||
|
*
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
void FAR PASCAL _LOADDS mciaviTask(DWORD dwInst)
|
|||
|
{
|
|||
|
NPMCIGRAPHIC npMCI;
|
|||
|
|
|||
|
npMCI = (NPMCIGRAPHIC) dwInst;
|
|||
|
|
|||
|
// Set this task's error mode to the same as the parent's.
|
|||
|
SetErrorMode(npMCI->uErrorMode);
|
|||
|
|
|||
|
DPF2(("MCIAVI: Bkgd Task hTask=%04X\n", GetCurrentTask()));
|
|||
|
DPF2(("MCIAVI: Stack: %04X %04X %04X\n", StackTop(), StackMin(), StackBot()));
|
|||
|
|
|||
|
/* Task state is TASKBEINGCREATED at fn. entry, then goes to TASKINIT. */
|
|||
|
|
|||
|
Assert(npMCI && npMCI->wTaskState == TASKBEINGCREATED);
|
|||
|
|
|||
|
npMCI->wTaskState = TASKINIT;
|
|||
|
|
|||
|
#ifndef WIN32
|
|||
|
//
|
|||
|
// in order to make this task, more like a "thread" we want to use the
|
|||
|
// same PSP as our parent, so we can share file handles and things.
|
|||
|
//
|
|||
|
// when we get created hTask is a PSP
|
|||
|
//
|
|||
|
npMCI->pspTask = GetCurrentPDB(); // save our PSP
|
|||
|
#endif
|
|||
|
|
|||
|
npMCI->hTask = GetCurrentTask();
|
|||
|
npMCI->dwTaskError = 0;
|
|||
|
|
|||
|
/* Open the file */
|
|||
|
|
|||
|
if (!mciaviOpenFile(npMCI)) {
|
|||
|
// NOTE: IsTask() returns FALSE when hTask==0
|
|||
|
// Set hTask to 0 BEFORE setting wTaskState. Our creator is polling
|
|||
|
// the state of wTaskState...
|
|||
|
// npMCI->wTaskState = TASKABORT;
|
|||
|
// npMCI->hTask = 0; // This stops others using this task thread.
|
|||
|
DPF1(("Failed to open AVI file\n"));
|
|||
|
goto exit;
|
|||
|
}
|
|||
|
|
|||
|
while (IsTask(npMCI->hTask)) {
|
|||
|
|
|||
|
npMCI->wTaskState = TASKIDLE;
|
|||
|
DPF2(("MCIAVI: Idle\n"));
|
|||
|
DPF2(("MCIAVI: Stack: %04X %04X %04X\n", StackTop(), StackMin(), StackBot()));
|
|||
|
|
|||
|
StackMark();
|
|||
|
|
|||
|
/* Block until task is needed. The task count could */
|
|||
|
/* be anything at the exit of playfile or recordfile */
|
|||
|
/* so continue to block until the state really changes. */
|
|||
|
|
|||
|
while (npMCI->wTaskState == TASKIDLE)
|
|||
|
{
|
|||
|
mmTaskBlock(npMCI->hTask);
|
|||
|
}
|
|||
|
|
|||
|
mciaviMessage(npMCI, npMCI->wTaskState);
|
|||
|
|
|||
|
AssertSz(StackTest(), "Stack overflow");
|
|||
|
|
|||
|
if (npMCI->wTaskState == TASKCLOSE) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
exit:
|
|||
|
mciaviTaskCleanup(npMCI);
|
|||
|
}
|
|||
|
|
|||
|
/***************************************************************************
|
|||
|
*
|
|||
|
* @doc INTERNAL MCIAVI
|
|||
|
*
|
|||
|
* @api WORD | mciaviTaskCleanup | called when the background task
|
|||
|
* is being destroyed. This is where critical cleanup goes.
|
|||
|
*
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
void FAR PASCAL mciaviTaskCleanup(NPMCIGRAPHIC npMCI)
|
|||
|
{
|
|||
|
|
|||
|
#ifndef WIN32
|
|||
|
//
|
|||
|
// restore our PSP back to normal before exit.
|
|||
|
//
|
|||
|
if (npMCI->pspTask)
|
|||
|
{
|
|||
|
SetPSP(npMCI->pspTask);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef USEAVIFILE
|
|||
|
//
|
|||
|
// we must do this so COMPOBJ will shut down right.
|
|||
|
//
|
|||
|
FreeAVIFile(npMCI);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// call a MSVideo shutdown routine.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Signal the foreground task that we're all done.
|
|||
|
// This must be absolutely the last thing we do.
|
|||
|
//
|
|||
|
npMCI->hTask = 0;
|
|||
|
npMCI->wTaskState = TASKCLOSED;
|
|||
|
}
|
|||
|
|
|||
|
/***************************************************************************
|
|||
|
*
|
|||
|
* @doc INTERNAL MCIAVI
|
|||
|
*
|
|||
|
* @api void | mciaviMessage | this function handles a message from the
|
|||
|
* background task.
|
|||
|
*
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
void NEAR PASCAL mciaviMessage(NPMCIGRAPHIC npMCI, UINT msg)
|
|||
|
{
|
|||
|
UINT wNotification;
|
|||
|
|
|||
|
switch (msg) {
|
|||
|
|
|||
|
case TASKREADINDEX:
|
|||
|
Assert(0);
|
|||
|
break;
|
|||
|
|
|||
|
/* Check to see if we just got closed */
|
|||
|
|
|||
|
case TASKCLOSE:
|
|||
|
DPF1(("MCIAVI: Closing\n"));
|
|||
|
|
|||
|
// hold critsec during close in case someone comes in to
|
|||
|
// eg DeviceRealize during the close when things are half-deleted.
|
|||
|
EnterCrit(npMCI);
|
|||
|
mciaviCloseFile(npMCI);
|
|||
|
LeaveCrit(npMCI);
|
|||
|
|
|||
|
/* The htask must be set to NULL, otherwise CloseDevice() will */
|
|||
|
/* get stuck. */
|
|||
|
|
|||
|
// NOTE: IsTask() returns FALSE when hTask==0
|
|||
|
// npMCI->hTask = 0;
|
|||
|
// npMCI->wTaskState = TASKABORT;
|
|||
|
return;
|
|||
|
|
|||
|
case TASKRELOAD:
|
|||
|
DPF(("MCIAVI: Loading new file....\n"));
|
|||
|
mciaviCloseFile(npMCI);
|
|||
|
npMCI->dwTaskError = 0;
|
|||
|
npMCI->wTaskState = TASKINIT;
|
|||
|
|
|||
|
if (!mciaviOpenFile(npMCI)) {
|
|||
|
// !!! mciaviOpenNew() !!!!!!!!!!!!!!!!!!!!!
|
|||
|
npMCI->wTaskState = TASKCLOSE;
|
|||
|
// npMCI->hTask = 0;
|
|||
|
return;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
// We've been woken up to play....
|
|||
|
case TASKSTARTING:
|
|||
|
DPF2(("MCIAVI: Now busy\n"));
|
|||
|
|
|||
|
/* Reset to no error */
|
|||
|
npMCI->dwTaskError = 0;
|
|||
|
|
|||
|
wNotification = mciaviPlayFile(npMCI);
|
|||
|
|
|||
|
if ((wNotification != MCI_NOTIFY_FAILURE) ||
|
|||
|
((npMCI->dwFlags & MCIAVI_WAITING) == 0))
|
|||
|
GraphicDelayedNotify(npMCI, wNotification);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DPF(("MCIAVI: Unknown task state!!!! (%d)\n", msg));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#ifdef WIN32
|
|||
|
|
|||
|
/***************************************************************************
|
|||
|
*
|
|||
|
* @doc INTERNAL MCIAVI
|
|||
|
*
|
|||
|
* @api int | GetPrioritySeparation | Find the foreground process priority
|
|||
|
* boost
|
|||
|
*
|
|||
|
* @rdesc Returns 0, 1 or 2
|
|||
|
*
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
DWORD GetPrioritySeparation(void)
|
|||
|
{
|
|||
|
static DWORD Win32PrioritySeparation = 0xFFFFFFFF;
|
|||
|
|
|||
|
/* If we're not initialized get the current separation */
|
|||
|
|
|||
|
if (Win32PrioritySeparation == 0xFFFFFFFF) {
|
|||
|
HKEY hKey;
|
|||
|
Win32PrioritySeparation = 2; // This is the default
|
|||
|
|
|||
|
/* Code copied from shell\control\main\prictl.c */
|
|||
|
|
|||
|
if (RegOpenKeyEx(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
TEXT("SYSTEM\\CurrentControlSet\\Control\\PriorityControl"),
|
|||
|
0,
|
|||
|
KEY_QUERY_VALUE,
|
|||
|
&hKey) == ERROR_SUCCESS) {
|
|||
|
|
|||
|
DWORD Type;
|
|||
|
DWORD Length;
|
|||
|
|
|||
|
Length = sizeof(Win32PrioritySeparation);
|
|||
|
|
|||
|
/* Read the value which is the priority boost given to
|
|||
|
forground processes */
|
|||
|
|
|||
|
if (RegQueryValueEx(
|
|||
|
hKey,
|
|||
|
TEXT("Win32PrioritySeparation"),
|
|||
|
NULL,
|
|||
|
&Type,
|
|||
|
(LPBYTE)&Win32PrioritySeparation,
|
|||
|
&Length
|
|||
|
) != ERROR_SUCCESS) {
|
|||
|
|
|||
|
Win32PrioritySeparation = 2;
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hKey);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Win32PrioritySeparation;
|
|||
|
}
|
|||
|
#endif // WIN32
|
|||
|
|
|||
|
/***************************************************************************
|
|||
|
*
|
|||
|
* @doc INTERNAL MCIAVI
|
|||
|
*
|
|||
|
* @api void| aviTaskYield | This function yields in the picky way windows
|
|||
|
* wants us to.
|
|||
|
*
|
|||
|
* basicly we Dispatch any messages in our que that belong to a window.
|
|||
|
*
|
|||
|
* NOTE we should not remove
|
|||
|
*
|
|||
|
***************************************************************************/
|
|||
|
|
|||
|
void NEAR PASCAL aviTaskYield(void)
|
|||
|
{
|
|||
|
MSG msg;
|
|||
|
|
|||
|
#ifdef WIN32
|
|||
|
DWORD PrioritySeparation;
|
|||
|
|
|||
|
//
|
|||
|
// Do our own kind of 'yield'. The reason for doing the
|
|||
|
// Peekmessage on Windows 3.1 was that if you didn't call
|
|||
|
// it Windows would think you were spinning out of control.
|
|||
|
// For Windows NT if you call PeekMessage 100 times without
|
|||
|
// getting anything your priority is lowered which would mess
|
|||
|
// up our tinkering with the priority here.
|
|||
|
//
|
|||
|
|
|||
|
PrioritySeparation = GetPrioritySeparation();
|
|||
|
|
|||
|
if (PrioritySeparation != 0) {
|
|||
|
SetThreadPriority(GetCurrentThread(),
|
|||
|
PrioritySeparation == 1 ?
|
|||
|
THREAD_PRIORITY_BELOW_NORMAL : // minus 1
|
|||
|
THREAD_PRIORITY_LOWEST); // minus 2
|
|||
|
Sleep(0); // Causes reschedule decision
|
|||
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
|
|||
|
} else {
|
|||
|
Sleep(0); // Let other threads in
|
|||
|
}
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
//
|
|||
|
// if we were MCIWAVE we would do this....
|
|||
|
//
|
|||
|
//if (PeekMessage(&msg, NULL, 0, WM_MM_RESERVED_FIRST-1, PM_REMOVE))
|
|||
|
|
|||
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|||
|
DPF(("aviTaskYield: got message %04X to window %04X\n", msg.message, msg.hwnd));
|
|||
|
DispatchMessage(&msg);
|
|||
|
}
|
|||
|
#endif // WIN32
|
|||
|
}
|
|||
|
|