📄 basestrm.cpp
字号:
// basestrm.cpp - base class for streams of Video Capture sample
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060 USA
//
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================
#include <vdw.h>
#include <kstream.h>
#include "basestrm.h"
#ifdef __VIDCAP_TRACEON__
KTrace TVS("VidCap Classes");
#endif
DEFINE_KSPROPERTY_TABLE(VidcapBaseStream::m_VideoStreamConnectionProperties)
{
DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
TRUE, // GetSupported or Handler
sizeof(KSPROPERTY), // MinProperty
sizeof(KSALLOCATOR_FRAMING), // MinData
FALSE, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
sizeof(ULONG) // SerializedSize
),
};
DEFINE_KSPROPERTY_TABLE(VidcapBaseStream::m_VideoStreamDroppedFramesProperties)
{
DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_DROPPEDFRAMES_CURRENT,
TRUE, // GetSupported or Handler
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S), // MinProperty
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S), // MinData
FALSE, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
0 // SerializedSize
),
};
// ------------------------------------------------------------------------
// Array of all of the property sets supported by video streams
// ------------------------------------------------------------------------
DEFINE_KSPROPERTY_SET_TABLE(VidcapBaseStream::m_VideoStreamProperties)
{
DEFINE_KSPROPERTY_SET
(
&KSPROPSETID_Connection, // Set
SIZEOF_ARRAY(m_VideoStreamConnectionProperties), // PropertiesCount
m_VideoStreamConnectionProperties, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
),
DEFINE_KSPROPERTY_SET
(
&PROPSETID_VIDCAP_DROPPEDFRAMES, // Set
SIZEOF_ARRAY(m_VideoStreamDroppedFramesProperties), // PropertiesCount
m_VideoStreamDroppedFramesProperties, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
),
};
const ULONG VidcapBaseStream::m_VideoStreamPropertiesCount = SIZEOF_ARRAY(m_VideoStreamProperties);
VidcapBaseStream::VidcapBaseStream()
: KStream(),
m_RequestQueueCount(0),
m_pVideoInfoHeader(NULL),
m_fDiscontinuity(0),
m_QST_Now(0),
m_QST_NextFrame(0),
m_QST_StreamTime(0)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::VidcapBaseStream -- constructing\n";
#endif
RtlZeroMemory(&m_FrameInfo, sizeof(KS_FRAME_INFO)); // PictureNumber, etc.
for (int i = 0; i < (720*3); i++)
m_LineBuffer[i] = 0; // working buffer (RGB24)
}
// -- our version of InitializeBaseClass called from derived stream classes --
void VidcapBaseStream::InitializeBaseClass(const HW_STREAM_INFORMATION& info, ULONG uStreamHeaderMediaSpecific)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::InitializeBaseClass -- calling KStream::InitializeBaseClass\n";
#endif
KStream::InitializeBaseClass(
info,
0, // uClockSupportFlags
FALSE, // Not a master clock
FALSE, // bDma
TRUE, // bPio,
uStreamHeaderMediaSpecific, // StreamHeaderMediaSpecific
0 ); // StreamHeaderWorkspace
}
void VidcapBaseStream::QueueSrb(PHW_STREAM_REQUEST_BLOCK pSrb)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::QueueSrb -- Start\n";
#endif
PIRP pIrp(pSrb->Irp);
// -- make the SRB part of the Irp's Driver Context and
// then QUEUE the IRP on our IRP Queue --
Lock();
pIrp->Tail.Overlay.DriverContext[0] = pSrb;
m_RequestQueue.InsertTail(pIrp);
m_RequestQueueCount++;
Unlock();
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::QueueSrb -- End\n";
#endif
}
PHW_STREAM_REQUEST_BLOCK VidcapBaseStream::DequeueSrb(void)
{
// -- excessive tracing use for DEBUG only! --
// #ifdef __VIDCAP_TRACEON__
// TVS << TraceInfo << "VidcapBaseStream::DequeueSrb -- Start\n";
// #endif
PHW_STREAM_REQUEST_BLOCK pSrb = NULL;
// -- since the SRB actually contains the IRP, and our
// driver context of the IRP now points to the SRB,
// we can dequeue the IRP, pull of the SRB and return
// only that object... the IRP is already pointed to
// BY the SRB itself! --
Lock();
if (!m_RequestQueue.IsEmpty())
{
PIRP pIrp = m_RequestQueue.RemoveHead();
pSrb = (PHW_STREAM_REQUEST_BLOCK)pIrp->Tail.Overlay.DriverContext[0];
m_RequestQueueCount--;
}
else
pSrb = NULL;
Unlock();
// -- excessive tracing use for DEBUG only! --
// #ifdef __VIDCAP_TRACEON__
// TVS << TraceInfo << "VidcapBaseStream::DequeueSrb -- End\n";
// #endif
return pSrb;
}
void VidcapBaseStream::CancelAllRequests(void)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- Start\n";
#endif
PHW_STREAM_REQUEST_BLOCK pSrb;
Lock();
while ( !m_RequestQueue.IsEmpty() )
{
PIRP pIrp = m_RequestQueue.RemoveHead();
pSrb = (PHW_STREAM_REQUEST_BLOCK)pIrp->Tail.Overlay.DriverContext[0];
m_RequestQueueCount--;
pSrb->CommandData.DataBufferArray->DataUsed = 0;
RequestComplete(pSrb);
// pSrb->Status = ??
}
Unlock();
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- End\n";
#endif
}
void VidcapBaseStream::CancelRequest(PHW_STREAM_REQUEST_BLOCK pSrb)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- Start\n";
#endif
PIRP pIrp;
BOOLEAN Removed=FALSE;
Lock();
for (pIrp=m_RequestQueue.Head(); pIrp!=NULL; pIrp=m_RequestQueue.Next(pIrp))
{
if (pIrp->Tail.Overlay.DriverContext[0] == pSrb)
{
m_RequestQueue.Remove(pIrp);
m_RequestQueueCount--;
Removed = TRUE;
break;
}
}
Unlock();
if (Removed)
{
pSrb->CommandData.DataBufferArray->DataUsed = 0;
RequestComplete(pSrb);
}
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- End\n";
#endif
}
void VidcapBaseStream::DispatchControl(PHW_STREAM_REQUEST_BLOCK pSrb)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::DispatchControl -- Start\n";
#endif
if ( !m_ControlSrbList.AddIfBusy(pSrb) )
do
{
pSrb->Status = STATUS_SUCCESS; // default is success
KStream::DispatchControl(pSrb);
} while ( m_ControlSrbList.RemoveIfAvailable(pSrb) );
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::DispatchControl -- End\n";
#endif
}
void VidcapBaseStream::OnGetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnGetProperty -- Start\n";
#endif
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
if (IsEqualGUID (KSPROPSETID_Connection, pSPD->Property->Set))
GetConnectionProperty(pSrb);
else if (IsEqualGUID (PROPSETID_VIDCAP_DROPPEDFRAMES, pSPD->Property->Set))
GetDroppedFramesProperty(pSrb);
else
pSrb->Status = STATUS_NOT_IMPLEMENTED;
NextSrb(pSrb, pSrb->Status);
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnGetProperty -- End\n";
#endif
}
void VidcapBaseStream::OnGetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnGetState -- Start\n";
#endif
pSrb->CommandData.StreamState = m_eState;
pSrb->ActualBytesTransferred = sizeof (KSSTATE);
// A very odd rule:
// When transitioning from stop to pause, DShow tries to preroll
// the graph. Capture sources can't preroll, and indicate this
// by returning VFW_S_CANT_CUE in user mode. To indicate this
// condition from drivers, they must return STATUS_NO_DATA_DETECTED
if (m_eState == KSSTATE_PAUSE)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnGetState -- Paused, returning STATUS_NO_DATA_DETECTED\n";
#endif
NextSrb(pSrb,STATUS_NO_DATA_DETECTED);
}
else
NextSrb(pSrb,STATUS_SUCCESS);
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnGetState -- End\n";
#endif
}
void VidcapBaseStream::OnSetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnSetState -- Start\n";
#endif
KSSTATE PreviousState;
//
// For each stream, the following states are used:
//
// Stop: Absolute minimum resources are used. No outstanding IRPs.
// Acquire: KS only state that has no DirectShow correpondence
// Acquire needed resources.
// Pause: Getting ready to run. Allocate needed resources so that
// the eventual transition to Run is as fast as possible.
// Read SRBs will be queued at either the Stream class
// or in your driver (depending on when you send "ReadyForNext")
// and whether you're using the Stream class for synchronization
// Run: Streaming.
//
// Moving to Stop to Run always transitions through Pause.
//
// But since a client app could crash unexpectedly, drivers should handle
// the situation of having outstanding IRPs cancelled and open streams
// being closed WHILE THEY ARE STREAMING!
//
// Note that it is quite possible to transition repeatedly between states:
// Stop -> Pause -> Stop -> Pause -> Run -> Pause -> Run -> Pause -> Stop
//
//
// Remember the state we're transitioning away from
//
PreviousState = m_eState;
//
// Set the new state
//
m_eState = pSrb->CommandData.StreamState;
switch (m_eState)
{
case KSSTATE_STOP:
//
// The stream class will cancel all outstanding IRPs for us
// (but only if it is maintaining the queue ie. using Stream Class synchronization)
// Since Testcap is not using Stream Class synchronization, we must clear the queue here
#ifdef __VIDCAP_TRACEON__
TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_STOP\n";
#endif
CancelAllRequests();
break;
case KSSTATE_ACQUIRE:
//
// This is a KS only state, that has no correspondence in DirectShow
//
#ifdef __VIDCAP_TRACEON__
TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_ACQUIRE\n";
#endif
break;
case KSSTATE_PAUSE:
//
// On a transition to pause from acquire or stop, start our timer running.
//
#ifdef __VIDCAP_TRACEON__
TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_PAUSE\n";
#endif
if (PreviousState == KSSTATE_ACQUIRE || PreviousState == KSSTATE_STOP)
{
// Zero the frame counters
m_FrameInfo.PictureNumber = 0;
m_FrameInfo.DropCount = 0;
m_FrameInfo.dwFrameFlags = 0;
// Setup the next timer callback
// Make it run at 2x the requested capture rate (which is in 100nS units)
StreamClassScheduleTimer (
pSrb->StreamObject, // StreamObject
Adapter(), // HwDeviceExtension
(ULONG) (m_pVideoInfoHeader->AvgTimePerFrame / 20), // Microseconds
VideoTimerRoutine, // TimerRoutine
this); // Context (also this stream)
}
break;
case KSSTATE_RUN:
//
// Begin Streaming.
//
#ifdef __VIDCAP_TRACEON__
TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_RUN\n";
#endif
// Reset the discontinuity flag
m_fDiscontinuity = FALSE;
// Setting the NextFrame time to zero will cause the value to be
// reset from the stream time
m_QST_NextFrame = 0;
break;
} // end switch (pSrb->CommandData.StreamState)
NextSrb(pSrb);
#ifdef __VIDCAP_TRACEON__
TVS << TraceInfo << "VidcapBaseStream::OnSetState -- End\n";
#endif
}
// -- used in this sample for generating video frames --
void STREAMAPI VidcapBaseStream::VideoTimerRoutine(PVOID pContext)
{
// -- this trace tends to really make the monitor go crazy! --
// #ifdef __VIDCAP_TRACEON__
// TVS << TraceInfo << "VidcapBaseStream::VideoTimerRoutine\n";
// #endif
((VidcapBaseStream*)pContext)->OnVideoTimer();
}
// -- can be overridden in derived classes to generate video for that class --
void VidcapBaseStream::OnVideoTimer()
{
// If we're stopped and the timer is still running, just return.
// This will stop the timer.
// -- excessive tracing... use during DEBUG only! --
// #ifdef __VIDCAP_TRACEON__
// TVS << TraceInfo << "VidcapBaseStream::OnVideoTimer -- Start\n";
// #endif
if (KSSTATE_STOP == m_eState)
{
#ifdef __VIDCAP_TRACEON__
TVS << TraceAlways << "VidcapBaseStream::OnVideoTimer -- State = KSSTATE_STOP... returning\n";
#endif
return;
}
// Capture a frame if it's time and we have a buffer
CaptureFrame();
// Schedule the next timer event
// Make it run at 2x the requested capture rate (which is in 100nS units)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -