windows-nt/Source/XPSP1/NT/multimedia/media/avi/mciavi.16/avitask.c

363 lines
9.7 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/******************************************************************************
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
}