📄 capstrm.cpp
字号:
*/
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -