?? capvideo.c
字號:
** Context - pointer to the stream extension
**
** Returns: nothing
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoTimerRoutine(
PVOID Context
)
{
PSTREAMEX pStrmEx = ((PSTREAMEX)Context);
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
// If we're stopped and the timer is still running, just return.
// This will stop the timer.
if (pStrmEx->KSState == KSSTATE_STOP) {
return;
}
// Capture a frame if it's time and we have a buffer
VideoCaptureRoutine(pStrmEx);
// Schedule the next timer event
// Make it run at 2x the requested capture rate (which is in 100nS units)
StreamClassScheduleTimer (
pStrmEx->pStreamObject, // StreamObject
pHwDevExt, // HwDeviceExtension
(ULONG) (pStrmEx->AvgTimePerFrame / 20), // Microseconds
VideoTimerRoutine, // TimerRoutine
pStrmEx); // Context
}
/*
** VideoCaptureRoutine()
**
** Routine to capture video frames based on a timer.
**
** Note: Devices capable of using interrupts should always
** trigger capture on a VSYNC interrupt, and not use a timer.
**
** Arguments:
**
** Returns: nothing
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoCaptureRoutine(
IN PSTREAMEX pStrmEx
)
{
PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
PKSSTREAM_HEADER pDataPacket;
PKS_FRAME_INFO pFrameInfo;
// If we're stopped and the timer is still running, just return.
// This will stop the timer.
if (pStrmEx->KSState == KSSTATE_STOP) {
return;
}
// Find out what time it is, if we're using a clock
if (pStrmEx->hMasterClock ) {
HW_TIME_CONTEXT TimeContext;
TimeContext.HwDeviceExtension = pHwDevExt;
TimeContext.HwStreamObject = pStrmEx->pStreamObject;
TimeContext.Function = TIME_GET_STREAM_TIME;
StreamClassQueryMasterClockSync (
pStrmEx->hMasterClock,
&TimeContext);
pStrmEx->QST_StreamTime = TimeContext.Time;
pStrmEx->QST_Now = TimeContext.SystemTime;
if (pStrmEx->QST_NextFrame == 0) {
pStrmEx->QST_NextFrame = pStrmEx->QST_StreamTime + pStrmEx->AvgTimePerFrame;
}
#ifdef CREATE_A_FLURRY_OF_TIMING_SPEW
DbgLogTrace(("TestCap: Time=%6d mS at SystemTime=%I64d\n",
(LONG) ((LONGLONG) TimeContext.Time / 10000),
TimeContext.SystemTime));
#endif
}
// Only capture in the RUN state
if (pStrmEx->KSState == KSSTATE_RUN) {
//
// Determine if it is time to capture a frame based on
// how much time has elapsed since capture started.
// If there isn't a clock available, then capture immediately.
//
if ((!pStrmEx->hMasterClock) ||
(pStrmEx->QST_StreamTime >= pStrmEx->QST_NextFrame)) {
PHW_STREAM_REQUEST_BLOCK pSrb;
// Increment the picture count (usually this is VSYNC count)
pStrmEx->FrameInfo.PictureNumber++;
//
// Get the next queue SRB (if any)
//
pSrb = VideoQueueRemoveSRB (
pHwDevExt,
StreamNumber);
if (pSrb) {
pDataPacket = pSrb->CommandData.DataBufferArray;
pFrameInfo = (PKS_FRAME_INFO) (pDataPacket + 1);
//
// Call the routine which synthesizes images
//
ImageSynth (pSrb,
IMAGE_XFER_GRAY_INCREASING,
pStrmEx->VideoControlMode & KS_VideoControlFlag_FlipHorizontal);
// Set additional info fields about the data captured such as:
// Frames Captured
// Frames Dropped
// Field Polarity
pStrmEx->FrameInfo.ExtendedHeaderSize = pFrameInfo->ExtendedHeaderSize;
*pFrameInfo = pStrmEx->FrameInfo;
// Init the flags to zero
pDataPacket->OptionsFlags = 0;
// Set the discontinuity flag if frames have been previously
// dropped, and then reset our internal flag
if (pStrmEx->fDiscontinuity) {
pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
pStrmEx->fDiscontinuity = FALSE;
}
//
// Return the timestamp for the frame
//
pDataPacket->PresentationTime.Numerator = 1;
pDataPacket->PresentationTime.Denominator = 1;
pDataPacket->Duration = pStrmEx->AvgTimePerFrame;
//
// if we have a master clock AND this is the capture stream
//
if (pStrmEx->hMasterClock && (StreamNumber == 0)) {
pDataPacket->PresentationTime.Time = pStrmEx->QST_StreamTime;
pDataPacket->OptionsFlags |=
KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
}
else {
//
// no clock or the preview stream, so just mark the time as unknown
//
pDataPacket->PresentationTime.Time = 0;
// clear the timestamp valid flags
pDataPacket->OptionsFlags &=
~(KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
}
// Every frame we generate is a key frame (aka SplicePoint)
// Delta frames (B or P) should not set this flag
pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
// Output a frame count every 100th frame in Debug mode
if (pStrmEx->FrameInfo.PictureNumber % 100 == 0) {
DbgLogInfo(("TestCap: Picture %u, Stream=%d\n",
(unsigned int)pStrmEx->FrameInfo.PictureNumber,
StreamNumber));
}
CompleteStreamSRB (pSrb);
} // if we have an SRB
else {
//
// No buffer was available when we should have captured one
// Increment the counter which keeps track of
// dropped frames
pStrmEx->FrameInfo.DropCount++;
// Set the (local) discontinuity flag
// This will cause the next packet processed to have the
// KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY flag set.
pStrmEx->fDiscontinuity = TRUE;
}
// Figure out when to capture the next frame
pStrmEx->QST_NextFrame += pStrmEx->AvgTimePerFrame;
} // endif time to capture a frame
} // endif we're running
}
/*
** VideoSetState()
**
** Sets the current state for a given stream
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoSetState(
PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
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 = pStrmEx->KSState;
//
// Set the new state
//
pStrmEx->KSState = pSrb->CommandData.StreamState;
switch (pSrb->CommandData.StreamState)
{
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
VideoQueueCancelAllSRBs (pStrmEx);
DbgLogInfo(("TestCap: STATE Stopped, Stream=%d\n", StreamNumber));
break;
case KSSTATE_ACQUIRE:
//
// This is a KS only state, that has no correspondence in DirectShow
//
DbgLogInfo(("TestCap: STATE Acquire, Stream=%d\n", StreamNumber));
break;
case KSSTATE_PAUSE:
//
// On a transition to pause from acquire or stop, start our timer running.
//
if (PreviousState == KSSTATE_ACQUIRE || PreviousState == KSSTATE_STOP) {
// Zero the frame counters
pStrmEx->FrameInfo.PictureNumber = 0;
pStrmEx->FrameInfo.DropCount = 0;
pStrmEx->FrameInfo.dwFrameFlags = 0;
// Setup the next timer callback(s)
VideoTimerRoutine(pStrmEx);
}
DbgLogInfo(("TestCap: STATE Pause, Stream=%d\n", StreamNumber));
break;
case KSSTATE_RUN:
//
// Begin Streaming.
//
// Reset the discontinuity flag
pStrmEx->fDiscontinuity = FALSE;
// Setting the NextFrame time to zero will cause the value to be
// reset from the stream time
pStrmEx->QST_NextFrame = 0;
DbgLogInfo(("TestCap: STATE Run, Stream=%d\n", StreamNumber));
break;
} // end switch (pSrb->CommandData.StreamState)
}
/*
** VideoGetState()
**
** Gets the current state of the requested stream
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoGetState(
PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
pSrb->CommandData.StreamState = pStrmEx->KSState;
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 (pStrmEx->KSState == KSSTATE_PAUSE) {
pSrb->Status = STATUS_NO_DATA_DETECTED;
}
}
/*
** VideoStreamGetConnectionProperty()
**
** Gets the properties for a stream
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoStreamGetConnectionProperty(
PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
ULONG Id = pSPD->Property->Id; // index of the property
int streamNumber = (int)pSrb->StreamObject->StreamNumber;
KdPrint(("VideoStreamGetConnectionProperty\n"));
switch (Id) {
// This property describes the allocator requirements for the stream
case KSPROPERTY_CONNECTION_ALLOCATORFRAMING:
{
PKSALLOCATOR_FRAMING Framing =
(PKSALLOCATOR_FRAMING) pSPD->PropertyInfo;
Framing->RequirementsFlags =
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER |
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
Framing->PoolType = PagedPool;
Framing->FileAlignment = 0; // FILE_LONG_ALIGNMENT???;
Framing->Reserved = 0;
pSrb->ActualBytesTransferred = sizeof (KSALLOCATOR_FRAMING);
switch (streamNumber) {
case STREAM_Capture:
case STREAM_Preview:
Framing->Frames = 2;
Framing->FrameSize =
pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage;
break;
default:
pSrb->Status = STATUS_INVALID_PARAMETER;
break;
}
break;
}
default:
TRAP;
break;
}
}
/*
** VideoStreamGetDroppedFramesProperty()
**
** Gets dynamic information about the progress of the capture process.
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoStreamGetDroppedFramesProperty(
PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
ULONG Id = pSPD->Property->Id; // index of the property
KdPrint(("VideoStreamGetDroppedFramesProperty\n"));
switch (Id) {
case KSPROPERTY_DROPPEDFRAMES_CURRENT:
{
PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames =
(PKSPROPERTY_DROPPEDFRAMES_CURRENT_S) pSPD->PropertyInfo;
pDroppedFrames->PictureNumber = pStrmEx->FrameInfo.PictureNumber;
pDroppedFrames->DropCount = pStrmEx->FrameInfo.DropCount;
pDroppedFrames->AverageFrameSize = pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage;
pSrb->ActualBytesTransferred = sizeof (KSPROPERTY_DROPPEDFRAMES_CURRENT_S);
}
break;
default:
TRAP;
break;
}
}
//==========================================================================;
// Clock Handling Routines
//==========================================================================;
/*
** VideoIndicateMasterClock ()
**
** If this stream is not being used as the master clock, this function
** is used to provide us with a handle to the clock to use when
** requesting the current stream time.
**
** Arguments:
**
** pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects: none
*/
VOID
STREAMAPI
VideoIndicateMasterClock(
PHW_STREAM_REQUEST_BLOCK pSrb
)
{
PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
pStrmEx->hMasterClock = pSrb->CommandData.MasterClockHandle;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -