📄 capstrm.cpp
字号:
//==========================================================================;
//
// CWDMCaptureStream - Capture Stream base class implementation
//
// $Date: 22 Feb 1999 15:13:58 $
// $Revision: 1.1 $
// $Author: KLEBANOV $
//
// $Copyright: (c) 1997 - 1998 ATI Technologies Inc. All Rights Reserved. $
//
//==========================================================================;
extern "C"
{
#include "strmini.h"
#include "ksmedia.h"
#include "ddkmapi.h"
}
#include "wdmvdec.h"
#include "wdmdrv.h"
#include "aticonfg.h"
#include "capdebug.h"
#include "defaults.h"
#include "winerror.h"
void CWDMCaptureStream::TimeoutPacket(IN OUT PHW_STREAM_REQUEST_BLOCK pSrb)
{
if (m_KSState == KSSTATE_STOP || !m_pVideoDecoder->PreEventOccurred())
{
DBGTRACE(("Attempting to complete Srbs.\n"));
EmptyIncomingDataSrbQueue();
}
}
void CWDMCaptureStream::Startup(PUINT puiErrorCode)
{
KIRQL Irql;
DBGTRACE(("CWDMCaptureStream::Startup()\n"));
KeInitializeEvent(&m_specialEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&m_stateTransitionEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&m_SrbAvailableEvent, SynchronizationEvent, FALSE);
KeInitializeSpinLock(&m_streamDataLock);
KeAcquireSpinLock(&m_streamDataLock, &Irql);
InitializeListHead(&m_incomingDataSrbQueue);
InitializeListHead(&m_waitQueue);
InitializeListHead(&m_reversalQueue);
KeReleaseSpinLock(&m_streamDataLock, Irql);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
ASSERT(m_stateChange == Initializing);
m_stateChange = Starting;
HANDLE threadHandle;
NTSTATUS status = PsCreateSystemThread(&threadHandle,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
(PKSTART_ROUTINE) ThreadStart,
(PVOID) this);
if (status != STATUS_SUCCESS)
{
DBGERROR(("CreateStreamThread failed\n"));
*puiErrorCode = WDMMINI_ERROR_MEMORYALLOCATION;
return;
}
// Don't need this for anything, so might as well close it now.
// The thread will call PsTerminateThread on itself when it
// is done.
ZwClose(threadHandle);
KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
ASSERT(m_stateChange == ChangeComplete);
DBGTRACE(("SrbOpenStream got notification that thread started\n"));
*puiErrorCode = WDMMINI_NOERROR;
}
void CWDMCaptureStream::Shutdown()
{
KIRQL Irql;
DBGTRACE(("CWDMCaptureStream::Shutdown()\n"));
if ( m_stateChange != Initializing )
{
ASSERT(m_stateChange == ChangeComplete);
m_stateChange = Closing;
KeResetEvent(&m_specialEvent);
KeSetEvent(&m_stateTransitionEvent, 0, TRUE);
KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
ASSERT(m_stateChange == ChangeComplete);
KeAcquireSpinLock(&m_streamDataLock, &Irql);
if (!IsListEmpty(&m_incomingDataSrbQueue))
{
TRAP();
}
if (!IsListEmpty(&m_waitQueue))
{
TRAP();
}
KeReleaseSpinLock(&m_streamDataLock, Irql);
}
ReleaseCaptureHandle();
}
void CWDMCaptureStream::ThreadProc()
{
PHW_STREAM_REQUEST_BLOCK pCurrentSrb = NULL;
PSRB_DATA_EXTENSION pSrbExt = NULL;
KEVENT DummyEvent;
const int numEvents = 3;
NTSTATUS status;
// Wo unto you if you overrun this array
PVOID eventArray[numEvents];
KeInitializeEvent(&DummyEvent, SynchronizationEvent, FALSE);
ASSERT(m_stateChange == Starting);
// Indicates to SrbOpenStream() to continue
m_stateChange = ChangeComplete;
KeSetEvent(&m_specialEvent, 0, FALSE);
// These should remain constant the whole time
eventArray[0] = &m_stateTransitionEvent;
eventArray[1] = &m_SrbAvailableEvent;
// eventArray[2] changes, so it is set below
// This runs until the thread terminates itself
// inside of HandleStateTransition
while (1)
{
// May not be necessary
#define ENABLE_TIMEOUT
#ifdef ENABLE_TIMEOUT
LARGE_INTEGER i;
#endif
if (pCurrentSrb == NULL)
{
pSrbExt = (PSRB_DATA_EXTENSION)ExInterlockedRemoveHeadList(&m_waitQueue, &m_streamDataLock);
if (pSrbExt)
{
pCurrentSrb = pSrbExt->pSrb;
eventArray[2] = &pSrbExt->bufferDoneEvent;
}
else
{
#ifdef DEBUG
if (m_KSState == KSSTATE_RUN &&
m_stateChange == ChangeComplete &&
m_pVideoDecoder->PreEventOccurred() == FALSE)
{
static int j;
// Indicates that we are starved for buffers. Probably
// a higher level is not handing them to us in a timely
// fashion for some reason
DBGPRINTF((" S "));
if ((++j % 10) == 0)
{
DBGPRINTF(("\n"));
}
}
#endif
pCurrentSrb = NULL;
eventArray[2] = &DummyEvent;
}
}
#ifdef ENABLE_TIMEOUT
// This is meant mainly as a failsafe measure.
i.QuadPart = -2000000; // 200 ms
#endif
status = KeWaitForMultipleObjects( numEvents, // count
eventArray, // DispatcherObjectArray
WaitAny, // WaitType
Executive, // WaitReason
KernelMode, // WaitMode
FALSE, // Alertable
#ifdef ENABLE_TIMEOUT
&i, // Timeout (Optional)
#else
NULL,
#endif
NULL); // WaitBlockArray (Optional)
switch (status)
{
// State transition. May including killing this very thread
case 0:
if ( pCurrentSrb )
{
ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
pCurrentSrb = NULL;
}
HandleStateTransition();
break;
// New Srb available
case 1:
if ( pCurrentSrb )
{
ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
pCurrentSrb = NULL;
}
if (m_KSState == KSSTATE_RUN && m_stateChange == ChangeComplete)
{
AddBuffersToDirectDraw();
}
break;
// Busmaster complete
case 2:
if ( pCurrentSrb )
{
HandleBusmasterCompletion(pCurrentSrb);
pCurrentSrb = NULL;
}
break;
#ifdef ENABLE_TIMEOUT
// If we timeout in the RUN state, this is our chance to try again
// to add buffers. May not be necessary, since currently, we go
// through a state transition for DOS boxes, etc.
case STATUS_TIMEOUT:
if ( pCurrentSrb )
{
ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
pCurrentSrb = NULL;
}
if (m_KSState == KSSTATE_RUN &&
m_stateChange == ChangeComplete &&
m_pVideoDecoder->PreEventOccurred() == FALSE)
{
AddBuffersToDirectDraw();
}
break;
#endif
default:
TRAP();
break;
}
}
}
VOID STREAMAPI CWDMCaptureStream::VideoReceiveDataPacket(IN PHW_STREAM_REQUEST_BLOCK pSrb)
{
KIRQL Irql;
PSRB_DATA_EXTENSION pSrbExt;
ASSERT(pSrb->Irp->MdlAddress);
DBGINFO(("Receiving SD---- SRB=%x\n", pSrb));
pSrb->Status = STATUS_SUCCESS;
switch (pSrb->Command) {
case SRB_READ_DATA:
// Rule:
// Only accept read requests when in either the Pause or Run
// States. If Stopped, immediately return the SRB.
if ( (m_KSState == KSSTATE_STOP) || ( m_stateChange == Initializing ) ) {
StreamClassStreamNotification( StreamRequestComplete,
pSrb->StreamObject,
pSrb);
break;
}
pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
RtlZeroMemory (pSrbExt, sizeof (SRB_DATA_EXTENSION));
pSrbExt->pSrb = pSrb;
KeInitializeEvent(&pSrbExt->bufferDoneEvent, SynchronizationEvent, FALSE);
DBGINFO(("Adding 0x%x to data queue\n", pSrb));
KeAcquireSpinLock(&m_streamDataLock, &Irql);
InsertTailList(&m_incomingDataSrbQueue, &pSrbExt->srbListEntry);
KeReleaseSpinLock(&m_streamDataLock, Irql);
KeSetEvent(&m_SrbAvailableEvent, 0, FALSE);
break;
default:
//
// invalid / unsupported command. Fail it as such
//
TRAP();
pSrb->Status = STATUS_NOT_IMPLEMENTED;
StreamClassStreamNotification( StreamRequestComplete,
pSrb->StreamObject,
pSrb);
break;
}
}
/*
** VideoGetProperty()
**
** Routine to process video property requests
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects: none
*/
VOID CWDMCaptureStream::VideoGetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
{
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
if (IsEqualGUID (KSPROPSETID_Connection, pSPD->Property->Set)) {
VideoStreamGetConnectionProperty (pSrb);
}
else if (IsEqualGUID (PROPSETID_VIDCAP_DROPPEDFRAMES, pSPD->Property->Set)) {
VideoStreamGetDroppedFramesProperty (pSrb);
}
else {
pSrb->Status = STATUS_NOT_IMPLEMENTED;
}
}
/*
** VideoSetState()
**
** Sets the current state of the requested stream
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
** BOOL bVPVBIConnected
** BOOL bVPConnected
**
** Returns:
**
** Side Effects: none
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -