|
|
//==========================================================================;
//
// 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 */
VOID CWDMCaptureStream::VideoSetState(PHW_STREAM_REQUEST_BLOCK pSrb, BOOL bVPConnected, BOOL bVPVBIConnected) { //
// For each stream, the following states are used:
//
// Stop: Absolute minimum resources are used. No outstanding IRPs.
// Pause: Getting ready to run. Allocate needed resources so that
// the eventual transition to Run is as fast as possible.
// SRBs will be queued at either the Stream class or in your
// driver.
// Run: Streaming.
//
// Moving to Stop or Run ALWAYS transitions through Pause, so that ONLY
// the following transitions are possible:
//
// Stop -> Pause
// Pause -> Run
// Run -> Pause
// Pause -> Stop
//
// Note that it is quite possible to transition repeatedly between states:
// Stop -> Pause -> Stop -> Pause -> Run -> Pause -> Run -> Pause -> Stop
//
BOOL bStreamCondition;
DBGINFO(("CWDMCaptureStream::VideoSetState for stream %d\n", pSrb->StreamObject->StreamNumber));
pSrb->Status = STATUS_SUCCESS;
switch (pSrb->CommandData.StreamState) { case KSSTATE_STOP: DBGINFO((" state KSSTATE_STOP"));
ASSERT(m_stateChange == ChangeComplete); m_stateChange = Stopping; FlushBuffers(); KeResetEvent(&m_specialEvent); KeSetEvent(&m_stateTransitionEvent, 0, TRUE); KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL); ASSERT(m_stateChange == ChangeComplete); break;
case KSSTATE_ACQUIRE: DBGINFO((" state KSSTATE_ACQUIRE")); ASSERT(m_KSState == KSSTATE_STOP); break;
case KSSTATE_PAUSE: DBGINFO((" state KSSTATE_PAUSE")); switch( pSrb->StreamObject->StreamNumber) { case STREAM_VideoCapture: bStreamCondition = bVPConnected; break;
case STREAM_VBICapture: bStreamCondition = bVPVBIConnected; break;
default: bStreamCondition = FALSE; break; } if( !bStreamCondition) { pSrb->Status = STATUS_UNSUCCESSFUL; } else
if (m_pVideoDecoder->PreEventOccurred() && (m_KSState == KSSTATE_STOP || m_KSState == KSSTATE_ACQUIRE)) { pSrb->Status = STATUS_UNSUCCESSFUL; } else if (m_KSState == KSSTATE_STOP || m_KSState == KSSTATE_ACQUIRE) { ResetFrameCounters(); ResetFieldNumber(); if (!GetCaptureHandle()) pSrb->Status = STATUS_UNSUCCESSFUL; } else if (m_KSState == KSSTATE_RUN) { // Transitioning from run to pause
ASSERT(m_stateChange == ChangeComplete); m_stateChange = Pausing; FlushBuffers(); KeResetEvent(&m_specialEvent); KeSetEvent(&m_stateTransitionEvent, 0, TRUE); KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL); ASSERT(m_stateChange == ChangeComplete); } break;
case KSSTATE_RUN: DBGINFO((" state KSSTATE_RUN"));
ASSERT(m_KSState == KSSTATE_ACQUIRE || m_KSState == KSSTATE_PAUSE);
if (m_pVideoDecoder->PreEventOccurred()) { pSrb->Status = STATUS_UNSUCCESSFUL; } else { ResetFieldNumber();
// Transitioning from pause to run
ASSERT(m_stateChange == ChangeComplete); m_stateChange = Running; KeResetEvent(&m_specialEvent); KeSetEvent(&m_stateTransitionEvent, 0, TRUE); KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL); ASSERT(m_stateChange == ChangeComplete); } break; }
if (pSrb->Status == STATUS_SUCCESS) { m_KSState = pSrb->CommandData.StreamState; DBGINFO((" entered\n")); } else DBGINFO((" NOT entered ***\n")); }
VOID CWDMCaptureStream::VideoStreamGetConnectionProperty (PHW_STREAM_REQUEST_BLOCK pSrb) { PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; PKSALLOCATOR_FRAMING Framing = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo;
ASSERT(pSPD->Property->Id == KSPROPERTY_CONNECTION_ALLOCATORFRAMING); if (pSPD->Property->Id == KSPROPERTY_CONNECTION_ALLOCATORFRAMING) {
RtlZeroMemory(Framing, sizeof(KSALLOCATOR_FRAMING));
Framing->RequirementsFlags = KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY | KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER | KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY; Framing->PoolType = NonPagedPool; Framing->Frames = NumBuffers; Framing->FrameSize = GetFrameSize(); Framing->FileAlignment = 0;//FILE_QUAD_ALIGNMENT;// PAGE_SIZE - 1;
pSrb->ActualBytesTransferred = sizeof(KSALLOCATOR_FRAMING); } else {
pSrb->Status = STATUS_NOT_IMPLEMENTED; } }
/*
** VideoStreamGetDroppedFramesProperty ** ** Gets dropped frame information ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */
VOID CWDMCaptureStream::VideoStreamGetDroppedFramesProperty(PHW_STREAM_REQUEST_BLOCK pSrb) { PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames = (PKSPROPERTY_DROPPEDFRAMES_CURRENT_S) pSPD->PropertyInfo;
ASSERT(pSPD->Property->Id == KSPROPERTY_DROPPEDFRAMES_CURRENT); if (pSPD->Property->Id == KSPROPERTY_DROPPEDFRAMES_CURRENT) {
RtlCopyMemory(pDroppedFrames, pSPD->Property, sizeof(KSPROPERTY)); // initialize the unused portion
GetDroppedFrames(pDroppedFrames);
DBGINFO(("PictNumber: 0x%x; DropCount: 0x%x; BufSize: 0x%x\n", (ULONG) pDroppedFrames->PictureNumber, (ULONG) pDroppedFrames->DropCount, (ULONG) pDroppedFrames->AverageFrameSize));
pSrb->ActualBytesTransferred = sizeof (KSPROPERTY_DROPPEDFRAMES_CURRENT_S); } else {
pSrb->Status = STATUS_NOT_IMPLEMENTED; } }
VOID CWDMCaptureStream::CloseCapture() { DBGTRACE(("DDNOTIFY_CLOSECAPTURE; stream = %d\n", m_pStreamObject->StreamNumber));
m_hCapture = 0; }
VOID CWDMCaptureStream::EmptyIncomingDataSrbQueue() { KIRQL Irql; PKSSTREAM_HEADER pDataPacket; if ( m_stateChange == Initializing ) { return; // queue not setup yet, so we can return knowing that nothing is in the queue
} // Think about replacing with ExInterlockedRemoveHeadList.
KeAcquireSpinLock(&m_streamDataLock, &Irql); while (!IsListEmpty(&m_incomingDataSrbQueue)) { PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)RemoveHeadList(&m_incomingDataSrbQueue); PHW_STREAM_REQUEST_BLOCK pSrb = pSrbExt->pSrb; pSrb->Status = STATUS_SUCCESS; pDataPacket = pSrb->CommandData.DataBufferArray; pDataPacket->DataUsed = 0; KeReleaseSpinLock(&m_streamDataLock, Irql); DBGINFO(("Completing Srb 0x%x in STATE_STOP\n", pSrb)); StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb); KeAcquireSpinLock(&m_streamDataLock, &Irql); } KeReleaseSpinLock(&m_streamDataLock, Irql); }
BOOL CWDMCaptureStream::ReleaseCaptureHandle() { int streamNumber = m_pStreamObject->StreamNumber; DWORD ddOut = DD_OK; DDCLOSEHANDLE ddClose;
if (m_hCapture != 0) { DBGTRACE(("Stream %d releasing capture handle\n", streamNumber)); ddClose.hHandle = m_hCapture;
DxApi(DD_DXAPI_CLOSEHANDLE, &ddClose, sizeof(ddClose), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) { DBGERROR(("DD_DXAPI_CLOSEHANDLE failed.\n")); TRAP(); return FALSE; } m_hCapture = 0; } return TRUE; }
VOID CWDMCaptureStream::HandleBusmasterCompletion(PHW_STREAM_REQUEST_BLOCK pCurrentSrb) { int streamNumber = m_pStreamObject->StreamNumber; PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pCurrentSrb->SRBExtension; KIRQL Irql; // This function is called as a result of DD completing a BM. That means
// m_stateChange will not be in the Initializing state for sure
// First handle case where we get a Busmaster completion
// indication while we are trying to pause or stop
if (m_stateChange == Pausing || m_stateChange == Stopping) { PUCHAR ptr; KeAcquireSpinLock(&m_streamDataLock, &Irql);
// Put it at the head of the temporary 'reversal' queue.
InsertHeadList(&m_reversalQueue, &pSrbExt->srbListEntry); if (IsListEmpty(&m_waitQueue)) { // if there is nothing left in the wait queue we can now
// proceed to move everything back to the incoming queue.
// This whole ugly ordeal is to
// make sure that they end up in the original order
while (!IsListEmpty(&m_reversalQueue)) { ptr = (PUCHAR)RemoveHeadList(&m_reversalQueue); InsertHeadList(&m_incomingDataSrbQueue, (PLIST_ENTRY) ptr); } KeReleaseSpinLock(&m_streamDataLock, Irql); if (m_stateChange == Stopping) { EmptyIncomingDataSrbQueue(); } // Indicate that we have successfully completed this part
// of the transition to the pause state.
m_stateChange = ChangeComplete; KeSetEvent(&m_specialEvent, 0, FALSE); return; }
KeReleaseSpinLock(&m_streamDataLock, Irql); return; }
// else it is a regular busmaster completion while in the run state
else { ASSERT (pCurrentSrb); PKSSTREAM_HEADER pDataPacket = pCurrentSrb->CommandData.DataBufferArray; pDataPacket->OptionsFlags = 0;
pSrbExt = (PSRB_DATA_EXTENSION)pCurrentSrb->SRBExtension;
DBGINFO(("FieldNum: %d; ddRVal: 0x%x; polarity: 0x%x\n", pSrbExt->ddCapBuffInfo.dwFieldNumber, pSrbExt->ddCapBuffInfo.ddRVal, pSrbExt->ddCapBuffInfo.bPolarity));
// It's possible that the srb got cancelled while we were waiting.
// Currently, this status is reset below
if (pCurrentSrb->Status == STATUS_CANCELLED) { DBGINFO(("pCurrentSrb 0x%x was cancelled while we were waiting\n", pCurrentSrb)); pDataPacket->DataUsed = 0; }
// It's also possible that there was a problem in DD-land
else if (pSrbExt->ddCapBuffInfo.ddRVal != DD_OK) { // Two cases of which I am aware.
// 1) flushed buffers
if (pSrbExt->ddCapBuffInfo.ddRVal == E_FAIL) { DBGINFO(("ddRVal = 0x%x. Assuming we flushed\n", pSrbExt->ddCapBuffInfo.ddRVal)); pDataPacket->DataUsed = 0; } // 2) something else
else { DBGERROR(("= 0x%x. Problem in Busmastering?\n", pSrbExt->ddCapBuffInfo.ddRVal)); pDataPacket->DataUsed = 0; } }
// There is also the remote possibility that everything is OK
else { SetFrameInfo(pCurrentSrb); TimeStampSrb(pCurrentSrb); pDataPacket->DataUsed = pDataPacket->FrameExtent; } DBGINFO(("StreamRequestComplete for SRB 0x%x\n", pCurrentSrb));
// Always return success. Failure
// is indicated by setting DataUsed to 0.
pCurrentSrb->Status = STATUS_SUCCESS;
ASSERT(pCurrentSrb->Irp->MdlAddress);
StreamClassStreamNotification( StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb); } }
void CWDMCaptureStream::AddBuffersToDirectDraw() { KIRQL Irql; BOOL fAdded; KeAcquireSpinLock(&m_streamDataLock, &Irql); while (!IsListEmpty(&m_incomingDataSrbQueue)) { // So if we've reached this point, we are in the run state, and
// we have an SRB on our incoming queue, and we are holding the
// the stream lock
PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)RemoveHeadList(&m_incomingDataSrbQueue); PHW_STREAM_REQUEST_BLOCK pSrb = pSrbExt->pSrb;
// Calls to DXAPI must be at Passive level, so release the spinlock temporarily
KeReleaseSpinLock(&m_streamDataLock, Irql);
DBGINFO(("Removed 0x%x from data queue\n", pSrb));
fAdded = AddBuffer(pSrb);
KeAcquireSpinLock(&m_streamDataLock, &Irql);
if (fAdded) { DBGINFO(("Adding 0x%x to wait queue\n", pSrb)); InsertTailList(&m_waitQueue, &pSrbExt->srbListEntry); } else { DBGINFO(("Adding 0x%x back to dataqueue\n", pSrb));
// put it back where it was
InsertHeadList(&m_incomingDataSrbQueue, &pSrbExt->srbListEntry); break; } } KeReleaseSpinLock(&m_streamDataLock, Irql); }
BOOL CWDMCaptureStream::AddBuffer(PHW_STREAM_REQUEST_BLOCK pSrb) { DDADDVPCAPTUREBUFF ddAddVPCaptureBuffIn; DWORD ddOut = DD_OK;
PIRP irp = pSrb->Irp; PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension; DBGINFO(("In AddBuffer. pSrb: 0x%x.\n", pSrb));
// For handling full-screen DOS, res changes, etc.
if (m_hCapture == 0) { if (!GetCaptureHandle()) { return FALSE; } }
ddAddVPCaptureBuffIn.hCapture = m_hCapture; ddAddVPCaptureBuffIn.dwFlags = DDADDBUFF_SYSTEMMEMORY; ddAddVPCaptureBuffIn.pMDL = irp->MdlAddress;
ddAddVPCaptureBuffIn.lpBuffInfo = &pSrbExt->ddCapBuffInfo; ddAddVPCaptureBuffIn.pKEvent = &pSrbExt->bufferDoneEvent;
DxApi(DD_DXAPI_ADDVPCAPTUREBUFFER, &ddAddVPCaptureBuffIn, sizeof(ddAddVPCaptureBuffIn), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) { // Not necessarily an error.
DBGINFO(("DD_DXAPI_ADDVPCAPTUREBUFFER failed.\n")); // TRAP();
return FALSE; }
return TRUE; }
VOID CWDMCaptureStream::HandleStateTransition() { KIRQL Irql; switch (m_stateChange) { case Running: AddBuffersToDirectDraw(); m_stateChange = ChangeComplete; KeSetEvent(&m_specialEvent, 0, FALSE); break;
case Pausing: KeAcquireSpinLock(&m_streamDataLock, &Irql); if (IsListEmpty(&m_waitQueue)) { KeReleaseSpinLock(&m_streamDataLock, Irql); m_stateChange = ChangeComplete; KeSetEvent(&m_specialEvent, 0, FALSE); } else { KeReleaseSpinLock(&m_streamDataLock, Irql); } break;
case Stopping: KeAcquireSpinLock(&m_streamDataLock, &Irql); if (IsListEmpty(&m_waitQueue)) { KeReleaseSpinLock(&m_streamDataLock, Irql); EmptyIncomingDataSrbQueue(); m_stateChange = ChangeComplete; KeSetEvent(&m_specialEvent, 0, FALSE); } else { KeReleaseSpinLock(&m_streamDataLock, Irql); } break;
case Closing: m_stateChange = ChangeComplete; KeSetEvent(&m_specialEvent, 0, FALSE); DBGTRACE(("StreamThread exiting\n")); PsTerminateSystemThread(STATUS_SUCCESS);
DBGERROR(("Shouldn't get here\n")); TRAP(); break;
case ChangeComplete: DBGTRACE(("Must have completed transition in HandleBusMasterCompletion\n")); break;
default: TRAP(); break; } }
BOOL CWDMCaptureStream::ResetFieldNumber() { int streamNumber = m_pStreamObject->StreamNumber; DDSETFIELDNUM ddSetFieldNum; DWORD ddOut;
ASSERT(streamNumber == STREAM_VideoCapture || streamNumber == STREAM_VBICapture);
if (m_pVideoPort->GetDirectDrawHandle() == 0) { DBGERROR(("Didn't expect ring0DirectDrawHandle to be zero.\n")); TRAP(); return FALSE; } if (m_pVideoPort->GetVideoPortHandle() == 0) { DBGERROR(("Didn't expect ring0VideoPortHandle to be zero.\n")); TRAP(); return FALSE; } RtlZeroMemory(&ddSetFieldNum, sizeof(ddSetFieldNum)); RtlZeroMemory(&ddOut, sizeof(ddOut));
KSPROPERTY_DROPPEDFRAMES_CURRENT_S DroppedFrames; GetDroppedFrames(&DroppedFrames);
ddSetFieldNum.hDirectDraw = m_pVideoPort->GetDirectDrawHandle(); ddSetFieldNum.hVideoPort = m_pVideoPort->GetVideoPortHandle(); ddSetFieldNum.dwFieldNum = ((ULONG)DroppedFrames.PictureNumber + 1) * GetFieldInterval(); DxApi(DD_DXAPI_SET_VP_FIELD_NUMBER, &ddSetFieldNum, sizeof(ddSetFieldNum), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) { DBGERROR(("DD_DXAPI_SET_VP_FIELD_NUMBER failed.\n")); TRAP(); return FALSE; } else { #ifdef DEBUG
DBGINFO(("PictureNumber: %d; ", DroppedFrames.PictureNumber)); DBGINFO(("DropCount: %d\n", DroppedFrames.DropCount)); DBGINFO(("AverageFrameSize: %d\n", DroppedFrames.AverageFrameSize)); #endif
return TRUE; } }
BOOL CWDMCaptureStream::FlushBuffers() { DWORD ddOut = DD_OK;
// commented out the trap because it is possible that capture handle is closed in DD before flushbuffer is called during mode switch
if (m_hCapture == NULL) { //DBGERROR(("m_hCapture === NULL in FlushBuffers.\n"));
//TRAP();
return FALSE; }
DxApi(DD_DXAPI_FLUSHVPCAPTUREBUFFERS, &m_hCapture, sizeof(HANDLE), &ddOut, sizeof(ddOut));
if (ddOut != DD_OK) { DBGERROR(("DD_DXAPI_FLUSHVPCAPTUREBUFFERS failed.\n")); TRAP(); return FALSE; } else { return TRUE; } }
VOID CWDMCaptureStream::TimeStampSrb(PHW_STREAM_REQUEST_BLOCK pSrb) { PKSSTREAM_HEADER pDataPacket = pSrb->CommandData.DataBufferArray; PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
pDataPacket->Duration = GetFieldInterval() * NTSCFieldDuration;
pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DURATIONVALID | KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
// Find out what time it is, if we're using a clock
if (m_hMasterClock) { LARGE_INTEGER Delta;
HW_TIME_CONTEXT TimeContext;
// TimeContext.HwDeviceExtension = pHwDevExt;
TimeContext.HwDeviceExtension = (struct _HW_DEVICE_EXTENSION *)m_pVideoDecoder; TimeContext.HwStreamObject = m_pStreamObject; TimeContext.Function = TIME_GET_STREAM_TIME;
StreamClassQueryMasterClockSync ( m_hMasterClock, &TimeContext);
// This calculation should result in the stream time WHEN the buffer
// was filled.
Delta.QuadPart = TimeContext.SystemTime - pSrbExt->ddCapBuffInfo.liTimeStamp.QuadPart;
// Be safe, just use the current stream time, without the correction for when
// DDraw actually returned the buffer to us.
pDataPacket->PresentationTime.Time = TimeContext.Time;
#ifdef THIS_SHOULD_WORK_BUT_IT_DOESNT
if (TimeContext.Time > (ULONGLONG) Delta.QuadPart) { pDataPacket->PresentationTime.Time = TimeContext.Time - Delta.QuadPart; } else { // There's a bug in Ks or Stream after running for 2 hours
// that makes this hack necessary. Will be fixed soon...
pDataPacket->PresentationTime.Time = TimeContext.Time; } #endif
#ifdef DEBUG
ULONG *tmp1, *tmp2;
tmp1 = (ULONG *)&pDataPacket->PresentationTime.Time; tmp2 = (ULONG *)&TimeContext.Time; DBGINFO(("PT: 0x%x%x; ST: 0x%x%x\n", tmp1[1], tmp1[0], tmp2[1], tmp2[0])); #endif
pDataPacket->PresentationTime.Numerator = 1; pDataPacket->PresentationTime.Denominator = 1;
pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID; } else { pDataPacket->OptionsFlags &= ~KSSTREAM_HEADER_OPTIONSF_TIMEVALID; } }
void CWDMCaptureStream::CancelPacket( PHW_STREAM_REQUEST_BLOCK pSrbToCancel) { PHW_STREAM_REQUEST_BLOCK pCurrentSrb; KIRQL Irql; PLIST_ENTRY Entry; BOOL bFound = FALSE;
if ( m_stateChange == Initializing ) // Stream not completely setup, so nothing in the queue
{ DBGINFO(( "Bt829: Didn't find Srb 0x%x\n", pSrbToCancel)); return; }
KeAcquireSpinLock( &m_streamDataLock, &Irql);
Entry = m_incomingDataSrbQueue.Flink;
//
// Loop through the linked list from the beginning to end,
// trying to find the SRB to cancel
//
while( Entry != &m_incomingDataSrbQueue) { PSRB_DATA_EXTENSION pSrbExt; pSrbExt = ( PSRB_DATA_EXTENSION)Entry; pCurrentSrb = pSrbExt->pSrb; if( pCurrentSrb == pSrbToCancel) { RemoveEntryList( Entry); bFound = TRUE; break; } Entry = Entry->Flink; }
KeReleaseSpinLock( &m_streamDataLock, Irql);
if( bFound) { pCurrentSrb->Status = STATUS_CANCELLED; pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0; DBGINFO(( "Bt829: Cancelled Srb 0x%x\n", pCurrentSrb)); StreamClassStreamNotification( StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb); } else { // If this is a DATA_TRANSFER and a STREAM_REQUEST SRB,
// then it must be in the waitQueue, being filled by DDraw.
// If so, mark it cancelled, and it will
// be returned when DDraw is finished with it.
if(( pSrbToCancel->Flags & (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST)) == (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST)) { pSrbToCancel->Status = STATUS_CANCELLED; DBGINFO(( "Bt829: Cancelled Srb on waitQueue 0x%x\n", pSrbToCancel)); } else { DBGINFO(( "Bt829: Didn't find Srb 0x%x\n", pSrbToCancel)); } } }
|