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