2051 lines
81 KiB
C
2051 lines
81 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (C) Microsoft Corporation, 1999 - 2000
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
MSDVLowr.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Interface code with 61883 or 1394 class driver.
|
||
|
|
||
|
Last changed by:
|
||
|
|
||
|
Author: Yee J. Wu
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode only
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
$Revision:: $
|
||
|
$Date:: $
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "strmini.h"
|
||
|
#include "ksmedia.h"
|
||
|
#include "1394.h"
|
||
|
#include "61883.h"
|
||
|
#include "dbg.h"
|
||
|
#include "msdvfmt.h"
|
||
|
#include "msdvdef.h"
|
||
|
#include "MSDVUtil.h"
|
||
|
#include "MSDVGuts.h"
|
||
|
#include "XPrtDefs.h"
|
||
|
#include "EDevCtrl.h"
|
||
|
|
||
|
|
||
|
extern DV_FORMAT_INFO DVFormatInfoTable[];
|
||
|
extern const GUID KSEVENTSETID_Connection_Local;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Simple function prototype
|
||
|
//
|
||
|
VOID
|
||
|
DVSRBRead(
|
||
|
IN PKSSTREAM_HEADER pStrmHeader,
|
||
|
IN ULONG ulFrameSize,
|
||
|
IN PDVCR_EXTENSION pDevExt,
|
||
|
IN PSTREAMEX pStrmExt,
|
||
|
IN PHW_STREAM_REQUEST_BLOCK pSrb // needs Srb->Status
|
||
|
);
|
||
|
NTSTATUS
|
||
|
DVAttachWriteFrame(
|
||
|
IN PSTREAMEX pStrmExt
|
||
|
);
|
||
|
VOID
|
||
|
DVFormatAttachFrame(
|
||
|
IN KSPIN_DATAFLOW DataFlow,
|
||
|
IN PSTREAMEX pStrmExt,
|
||
|
IN PAV_61883_REQUEST pAVReq,
|
||
|
IN PHW_STREAM_REQUEST_BLOCK pSrb,
|
||
|
IN PSRB_DATA_PACKET pSrbDataPacket,
|
||
|
IN ULONG ulSourceLength, // Packet length in bytes
|
||
|
IN ULONG ulFrameSize,
|
||
|
IN PVOID pFrameBuffer
|
||
|
);
|
||
|
VOID
|
||
|
DVAttachFrameThread(
|
||
|
IN PSTREAMEX pStrmExt
|
||
|
);
|
||
|
VOID
|
||
|
DVTerminateAttachFrameThread(
|
||
|
IN PSTREAMEX pStrmExt
|
||
|
);
|
||
|
|
||
|
#if DBG
|
||
|
ULONG cntInvSrcPkt = 0;
|
||
|
#endif
|
||
|
#if 0 // Enable later
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGE, DVSRBRead)
|
||
|
#pragma alloc_text(PAGE, DVFormatAttachFrame)
|
||
|
#pragma alloc_text(PAGE, DVAttachFrameThread)
|
||
|
#pragma alloc_text(PAGE, DVTerminateAttachFrameThread)
|
||
|
#pragma alloc_text(PAGE, DVAttachWriteFrame)
|
||
|
#pragma alloc_text(PAGE, DVFormatAttachFrame)
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
ULONG
|
||
|
DVReadFrameValidate(
|
||
|
IN PCIP_VALIDATE_INFO pInfo
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Used to detect the start of a DV frame. A DV frame is started with a header section.
|
||
|
|
||
|
Return
|
||
|
|
||
|
0 verified
|
||
|
1: invallid
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if(pInfo->Packet) {
|
||
|
|
||
|
//
|
||
|
// Detect header 0 signature.
|
||
|
//
|
||
|
if(
|
||
|
(pInfo->Packet[0] & DIF_BLK_ID0_SCT_MASK) == 0
|
||
|
&& (pInfo->Packet[1] & DIF_BLK_ID1_DSEQ_MASK) == 0
|
||
|
&& (pInfo->Packet[2] & DIF_BLK_ID2_DBN_MASK) == 0
|
||
|
) {
|
||
|
|
||
|
//
|
||
|
// This can be used to detect dynamic format change if this function is called
|
||
|
// to check for data packets always. This may require setting this flag:
|
||
|
// CIP_VALIDATE_ALL_SOURCE instead of CIP_VALIDATE_FIRST_SOURCE
|
||
|
//
|
||
|
#if 0 // DBG
|
||
|
|
||
|
|
||
|
PSRB_DATA_PACKET pSrbDataPacket = pInfo->Context;
|
||
|
PSTREAMEX pStrmExt = pSrbDataPacket->pStrmExt;
|
||
|
PDVCR_EXTENSION pDevExt = pStrmExt->pDevExt;
|
||
|
|
||
|
if((pInfo->Packet[0] & DIF_HEADER_DSF) == 0) {
|
||
|
// Indicate a 10 DIF sequences include in a video frame (525-60)/NTSC.
|
||
|
if(
|
||
|
pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_PAL
|
||
|
|| pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_PAL
|
||
|
) {
|
||
|
// Dynamic format changes!!
|
||
|
TRACE(TL_STRM_ERROR|TL_CIP_WARNING,("Detect dynamic format change PAL -> NTSC!\n"));
|
||
|
}
|
||
|
} else {
|
||
|
// Indicate a 12 DIF sequences include in a video frame (625-50)/PAL.
|
||
|
if(
|
||
|
pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC
|
||
|
|| pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC
|
||
|
) {
|
||
|
// Dynamic format changes!!
|
||
|
TRACE(TL_STRM_ERROR|TL_CIP_WARNING,("Detect dynamic format change NTSC -> PAL!\n"));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Check TF1, TF2, and TF3: 1: not transmitted; 0:transmitted
|
||
|
// TF1:Audio; TF2:Video; TF3:Subcode; they all need to be 0 to be valid.
|
||
|
if(
|
||
|
(pInfo->Packet[5] & DIF_HEADER_TFn)
|
||
|
|| (pInfo->Packet[6] & DIF_HEADER_TFn)
|
||
|
|| (pInfo->Packet[7] & DIF_HEADER_TFn)
|
||
|
) {
|
||
|
TRACE(TL_STRM_ERROR|TL_CIP_WARNING,("\'%d inv src pkts; [%x %x %d %x], [%x %x %x %x]\n",
|
||
|
cntInvSrcPkt,
|
||
|
pInfo->Packet[0],
|
||
|
pInfo->Packet[1],
|
||
|
pInfo->Packet[2],
|
||
|
pInfo->Packet[3],
|
||
|
pInfo->Packet[4],
|
||
|
pInfo->Packet[5],
|
||
|
pInfo->Packet[6],
|
||
|
pInfo->Packet[7]
|
||
|
));
|
||
|
// Valid header but DIF block for this area is not transmitted.
|
||
|
// Some DV (such as DVCPro) may wait untill its "mecha and servo" to be stable to make these valid.
|
||
|
// This should happen if a graph is in run state before a tape is played (and stablized).
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#if DBG
|
||
|
if(cntInvSrcPkt > 0) {
|
||
|
TRACE(TL_CIP_TRACE,("\'%d inv src pkts; [%x %x %d %x] [%x %x %x %x]\n",
|
||
|
cntInvSrcPkt,
|
||
|
pInfo->Packet[0],
|
||
|
pInfo->Packet[1],
|
||
|
pInfo->Packet[2],
|
||
|
pInfo->Packet[3],
|
||
|
pInfo->Packet[4],
|
||
|
pInfo->Packet[5],
|
||
|
pInfo->Packet[6],
|
||
|
pInfo->Packet[7]
|
||
|
));
|
||
|
cntInvSrcPkt = 0; // Reset
|
||
|
}
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
else {
|
||
|
#if DBG
|
||
|
|
||
|
//
|
||
|
// To detect invalid src pkt sequence;
|
||
|
// If it exceeded the number of source packet per frame, we need to know about it.
|
||
|
//
|
||
|
|
||
|
PSRB_DATA_PACKET pSrbDataPacket = pInfo->Context;
|
||
|
PSTREAMEX pStrmExt = pSrbDataPacket->pStrmExt;
|
||
|
PDVCR_EXTENSION pDevExt = pStrmExt->pDevExt;
|
||
|
|
||
|
if(++cntInvSrcPkt >= DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets) {
|
||
|
TRACE(TL_CIP_TRACE,("(%d) Invalid SrcPkt >= max inv src pkt %d; ID0,1,2 = [%x %x %x]\n",
|
||
|
cntInvSrcPkt,
|
||
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets,
|
||
|
pInfo->Packet[0], pInfo->Packet[1], pInfo->Packet[2]
|
||
|
));
|
||
|
|
||
|
if(DVTraceMask & TL_CIP_TRACE) {
|
||
|
ASSERT(cntInvSrcPkt < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets);
|
||
|
}
|
||
|
cntInvSrcPkt = 0; // Reset
|
||
|
}
|
||
|
else {
|
||
|
TRACE(TL_CIP_INFO,("(%d) Invalid SrcPktSeq; ID0,1,2 = [%x,%x,%x]\n",
|
||
|
cntInvSrcPkt, pInfo->Packet[0], pInfo->Packet[1], pInfo->Packet[2] ));
|
||
|
}
|
||
|
#endif
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
TRACE(TL_CIP_WARNING, ("\'Validate: invalid SrcPktSeq; Packet %x\n", pInfo->Packet));
|
||
|
return 1;
|
||
|
}
|
||
|
} // DVReadFrameValidate
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
LONGLONG PreviousPictureNumber;
|
||
|
LONGLONG PreviousTime;
|
||
|
CYCLE_TIME PreviousTimestamp;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
DVCompleteSrbRead(
|
||
|
PCIP_NOTIFY_INFO pInfo
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
61883 has completed receiving data and callback to us to complete.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PSRB_DATA_PACKET pSrbDataPacket;
|
||
|
PHW_STREAM_REQUEST_BLOCK pSrb;
|
||
|
PKSSTREAM_HEADER pStrmHeader;
|
||
|
PDVCR_EXTENSION pDevExt;
|
||
|
PSTREAMEX pStrmExt;
|
||
|
LONGLONG LastPictureNumber;
|
||
|
PUCHAR pFrameBuffer;
|
||
|
KIRQL oldIrql;
|
||
|
PKS_FRAME_INFO pFrameInfo; // For VidOnly pin only
|
||
|
#if DBG
|
||
|
PXMT_FRAME_STAT pXmtStat;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Callback and might be at the DISPATCH_LEVEL
|
||
|
// The caller might have acquired spinlock as well!
|
||
|
|
||
|
pSrbDataPacket = pInfo->Context;
|
||
|
|
||
|
if(!pSrbDataPacket) {
|
||
|
ASSERT(pSrbDataPacket && "Context is NULL!");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
pStrmExt = pSrbDataPacket->pStrmExt;
|
||
|
|
||
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
||
|
|
||
|
#if DBG
|
||
|
// Once it is completed by 61883, it becomes non-cancellable.
|
||
|
if(!pStrmExt->bIsochIsActive) {
|
||
|
TRACE(TL_CIP_WARNING,("CompleteSrbRead: bIsochActive:%d; pSrbDataPacket:%x\n", pStrmExt->bIsochIsActive, pSrbDataPacket));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
pSrb = pSrbDataPacket->pSrb; ASSERT(pSrbDataPacket->pSrb);
|
||
|
pDevExt = pStrmExt->pDevExt;
|
||
|
pFrameBuffer = (PUCHAR) pSrbDataPacket->FrameBuffer;
|
||
|
pStrmHeader = pSrb->CommandData.DataBufferArray; ASSERT(pStrmHeader->Size >= sizeof(KSSTREAM_HEADER));
|
||
|
|
||
|
//
|
||
|
// Check CIP_STATUS_* from 61883
|
||
|
//
|
||
|
// CIP_STATUS_CORRUPT_FRAME (0x00000001) // isoch header or cip header was incorrect
|
||
|
if(pSrbDataPacket->Frame->Status & CIP_STATUS_CORRUPT_FRAME) {
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_TRACE,("\'CIP_STATUS_CORRUPT_FRAME\n"));
|
||
|
pStrmHeader->OptionsFlags = 0;
|
||
|
pSrb->Status = STATUS_SUCCESS; // Success but no data !
|
||
|
pStrmHeader->DataUsed = 0;
|
||
|
pStrmExt->PictureNumber++; pStrmExt->FramesProcessed++;
|
||
|
}
|
||
|
else
|
||
|
// CIP_STATUS_SUCCESS (0x00000000) // 0 so cannot do bitwise operation!!
|
||
|
// CIP_STATUS_FIRST_FRAME (0x00000002) // First attached frame to 61883
|
||
|
if(pSrbDataPacket->Frame->Status == CIP_STATUS_SUCCESS ||
|
||
|
(pSrbDataPacket->Frame->Status & CIP_STATUS_FIRST_FRAME)) {
|
||
|
|
||
|
// Only increment FramesProcessed if it is a valid frame;
|
||
|
pStrmExt->FramesProcessed++;
|
||
|
|
||
|
pSrb->Status = STATUS_SUCCESS;
|
||
|
pStrmHeader->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
|
||
|
pStrmHeader->DataUsed = DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize;
|
||
|
|
||
|
|
||
|
// Put in Timestamp info depending on clock provider
|
||
|
pStrmHeader->PresentationTime.Numerator = 1;
|
||
|
pStrmHeader->PresentationTime.Denominator = 1;
|
||
|
|
||
|
if(pStrmExt->hMasterClock || pStrmExt->hClock) {
|
||
|
|
||
|
pStrmHeader->Duration =
|
||
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
|
||
|
|
||
|
pStrmHeader->OptionsFlags |=
|
||
|
(KSSTREAM_HEADER_OPTIONSF_TIMEVALID | // pStrmHeader->PresentationTime.Time is valid
|
||
|
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
|
||
|
}
|
||
|
//
|
||
|
// Only if there is a clock, presentation time and drop frames information are set.
|
||
|
// Acoording to DDK:
|
||
|
// The PictureNumber member count represents the idealized count of the current picture,
|
||
|
// which is calculated in one of two ways:
|
||
|
// ("Other" clock) Measure the time since the stream was started and divide by the frame duration.
|
||
|
// (MasterClock) Add together the count of frames captured and the count of frame dropped.
|
||
|
//
|
||
|
|
||
|
// Other device (audio?) is the clock provider
|
||
|
if(pStrmExt->hClock) {
|
||
|
|
||
|
pStrmExt->TimeContext.HwDeviceExtension = (struct _HW_DEVICE_EXTENSION *) pDevExt;
|
||
|
pStrmExt->TimeContext.HwStreamObject = pStrmExt->pStrmObject;
|
||
|
pStrmExt->TimeContext.Function = TIME_GET_STREAM_TIME;
|
||
|
pStrmExt->TimeContext.Time = 0;
|
||
|
pStrmExt->TimeContext.SystemTime = 0;
|
||
|
|
||
|
StreamClassQueryMasterClockSync(
|
||
|
pStrmExt->hClock,
|
||
|
&(pStrmExt->TimeContext)
|
||
|
);
|
||
|
|
||
|
pStrmHeader->PresentationTime.Time = pStrmExt->CurrentStreamTime = pStrmExt->TimeContext.Time;
|
||
|
|
||
|
// Calculate picture number and dropped frame;
|
||
|
// For NTSC, it could be 267 or 266 packet time per frame. Since integer calculation will round,
|
||
|
// we will add a packet time (TIME_PER_CYCLE = 125 us = 1250 100nsec) to that.This is only used for calculation.
|
||
|
LastPictureNumber = pStrmExt->PictureNumber;
|
||
|
pStrmExt->PictureNumber =
|
||
|
1 + // Picture number start with 1.
|
||
|
(pStrmHeader->PresentationTime.Time + TIME_PER_CYCLE)
|
||
|
* (LONGLONG) GET_AVG_TIME_PER_FRAME_DENOM(pStrmExt->pDevExt->VideoFormatIndex)
|
||
|
/ (LONGLONG) GET_AVG_TIME_PER_FRAME_NUM(pStrmExt->pDevExt->VideoFormatIndex);
|
||
|
|
||
|
// Detect discontinuity
|
||
|
if(pStrmExt->PictureNumber > LastPictureNumber+1) {
|
||
|
pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY; // If there is a skipped frame, set the discontinuity flag
|
||
|
TRACE(TL_CIP_WARNING,("\'Discontinuity: LastPic#:%d; Pic#%d; PresTime:%d;\n", (DWORD) LastPictureNumber, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmHeader->PresentationTime.Time));
|
||
|
}
|
||
|
|
||
|
// Detect if picture number did not progress.
|
||
|
// This could be due to two frame being completely very close to each other.
|
||
|
if(pStrmExt->PictureNumber <= LastPictureNumber) {
|
||
|
TRACE(TL_CIP_WARNING,("\'hClock:Same pic #:(%d->%d); tmPres:(%d->%d); (%d:%d:%d) -> (%d:%d:%d); AQD[%d:%d:%d]\n",
|
||
|
(DWORD) PreviousPictureNumber,
|
||
|
(DWORD) pStrmExt->PictureNumber,
|
||
|
(DWORD) PreviousTime,
|
||
|
(DWORD) pStrmHeader->PresentationTime.Time,
|
||
|
PreviousTimestamp.CL_SecondCount, PreviousTimestamp.CL_CycleCount, PreviousTimestamp.CL_CycleOffset,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleOffset,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
|
||
|
pStrmExt->PictureNumber = LastPictureNumber + 1; // Picture number must progress !!!!
|
||
|
}
|
||
|
#if DBG
|
||
|
PreviousPictureNumber = pStrmExt->PictureNumber;
|
||
|
PreviousTime = pStrmHeader->PresentationTime.Time;
|
||
|
PreviousTimestamp = pSrbDataPacket->Frame->Timestamp;
|
||
|
#endif
|
||
|
pStrmExt->FramesDropped = pStrmExt->PictureNumber - pStrmExt->FramesProcessed;
|
||
|
|
||
|
// This subunit driver is a Master clock
|
||
|
} else if (pStrmExt->hMasterClock) {
|
||
|
#ifdef NT51_61883
|
||
|
ULONG ulDeltaCycleCounts;
|
||
|
|
||
|
// No drop frame for PAUSE->RUN transition
|
||
|
if(pStrmExt->b1stNewFrameFromPauseState) {
|
||
|
|
||
|
pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
|
||
|
pStrmExt->b1stNewFrameFromPauseState = FALSE;
|
||
|
|
||
|
} else {
|
||
|
ULONG ulCycleCount16bits;
|
||
|
|
||
|
// Calculate skipped 1394 cycle from the returned CycleTime
|
||
|
VALIDATE_CYCLE_COUNTS(pSrbDataPacket->Frame->Timestamp);
|
||
|
ulCycleCount16bits = CALCULATE_CYCLE_COUNTS(pSrbDataPacket->Frame->Timestamp);
|
||
|
ulDeltaCycleCounts = CALCULATE_DELTA_CYCLE_COUNT(pStrmExt->CycleCount16bits, ulCycleCount16bits);
|
||
|
|
||
|
// Adjust to max allowable gap to the max elapsed time of the CycleTime returned by OHCI 1394.
|
||
|
if(ulDeltaCycleCounts > MAX_CYCLES)
|
||
|
ulDeltaCycleCounts = MAX_CYCLES; // Wrap around
|
||
|
|
||
|
//
|
||
|
// There are two cases for drop frames:
|
||
|
// (1) Starve of buffer; or,
|
||
|
// (2) no data (blank tape or tape is not playing)
|
||
|
//
|
||
|
|
||
|
// For case (1), 61883 returns CIP_STATUS_FIRST_FRAME.
|
||
|
if(pSrbDataPacket->Frame->Status & CIP_STATUS_FIRST_FRAME) {
|
||
|
// Use cycle count to calculate drop frame. We substract 1 from the MaxSrcPacket on purpose to avoid truncating.
|
||
|
// The max range is MAX_CYCLE (8 * 8000 = 64000 cycles)
|
||
|
// 64000 * 125 * 3 / 100100 = 239.76
|
||
|
// 64000 / 266 = 240
|
||
|
// 64000 / 267 = 239
|
||
|
if(ulDeltaCycleCounts >= (DVFormatInfoTable[pDevExt->VideoFormatIndex].ulMaxSrcPackets - 1)) {
|
||
|
ULONG ulFrameElapsed = ulDeltaCycleCounts / (DVFormatInfoTable[pDevExt->VideoFormatIndex].ulMaxSrcPackets - 1);
|
||
|
pStrmExt->FramesDropped += (ulFrameElapsed - 1); // There is a valid frame that is not dropped.
|
||
|
}
|
||
|
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("CIP_STATUS_FIRST_FRAME: Drop:%d; Processed:%d\n", (DWORD) pStrmExt->FramesDropped, pStrmExt->FramesProcessed ));
|
||
|
pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
|
||
|
|
||
|
} else {
|
||
|
// Ignore all "drop frames" in the "no data" case
|
||
|
// pStrmExt->FramesDropped += 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we are the clock provider, the stream time is based on sample number * AvgTimePerFrame
|
||
|
pStrmExt->PictureNumber = pStrmExt->FramesProcessed + pStrmExt->FramesDropped;
|
||
|
|
||
|
pStrmHeader->PresentationTime.Time = pStrmExt->CurrentStreamTime =
|
||
|
pStrmExt->PictureNumber
|
||
|
* (LONGLONG) GET_AVG_TIME_PER_FRAME_NUM(pStrmExt->pDevExt->VideoFormatIndex)
|
||
|
/ (LONGLONG) GET_AVG_TIME_PER_FRAME_DENOM(pStrmExt->pDevExt->VideoFormatIndex);
|
||
|
|
||
|
// Use to adjust the queried stream time
|
||
|
pStrmExt->LastSystemTime = GetSystemTime();
|
||
|
|
||
|
// Cache current CycleCount
|
||
|
pStrmExt->CycleCount16bits = CALCULATE_CYCLE_COUNTS(pSrbDataPacket->Frame->Timestamp);
|
||
|
|
||
|
#if DBG
|
||
|
// First frame or skipped frame
|
||
|
if(pStrmExt->PictureNumber <= 1 ||
|
||
|
pStrmExt->PictureNumber <= PreviousPictureNumber ||
|
||
|
ulDeltaCycleCounts > DVFormatInfoTable[pDevExt->VideoFormatIndex].ulMaxSrcPackets
|
||
|
)
|
||
|
TRACE(TL_CIP_WARNING,("\'hMasterClock: Same pic #:(%d->%d); tmPres:(%d->%d); (%d:%d:%d) -> (%d:%d:%d); AQD[%d:%d:%d]\n",
|
||
|
(DWORD) PreviousPictureNumber,
|
||
|
(DWORD) pStrmExt->PictureNumber,
|
||
|
(DWORD) PreviousTime,
|
||
|
(DWORD) pStrmHeader->PresentationTime.Time,
|
||
|
PreviousTimestamp.CL_SecondCount, PreviousTimestamp.CL_CycleCount, PreviousTimestamp.CL_CycleOffset,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleOffset,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
|
||
|
PreviousPictureNumber = pStrmExt->PictureNumber;
|
||
|
PreviousTime = pStrmHeader->PresentationTime.Time;
|
||
|
PreviousTimestamp = pSrbDataPacket->Frame->Timestamp;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#else // NT51_61883
|
||
|
// This is the old way when 61883 was not returning the correct CycleTime.
|
||
|
pStrmHeader->PresentationTime.Time = pStrmExt->CurrentStreamTime;
|
||
|
pStrmExt->LastSystemTime = GetSystemTime(); // Use to adjust the queried stream time
|
||
|
pStrmExt->CurrentStreamTime += DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
|
||
|
#endif // NT51_61883
|
||
|
|
||
|
// no Clock so "free flowing!"
|
||
|
} else {
|
||
|
pStrmHeader->PresentationTime.Time = 0;
|
||
|
pStrmHeader->Duration = 0; // No clock so not valid.
|
||
|
pStrmExt->PictureNumber++;
|
||
|
TRACE(TL_CIP_TRACE,("\'No clock: PicNum:%d\n", (DWORD) pStrmExt->PictureNumber));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// 61883 has not defined this new status at this time!
|
||
|
// Do not know what to do so we will complete it with 0 length for now.
|
||
|
pStrmHeader->OptionsFlags = 0;
|
||
|
pSrb->Status = STATUS_SUCCESS;
|
||
|
pStrmHeader->DataUsed = 0;
|
||
|
pStrmExt->PictureNumber++; pStrmExt->FramesProcessed++;
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_ERROR,("pSrbDataPacket:%x; unexpected Frame->Status %x\n", pSrbDataPacket, pSrbDataPacket->Frame->Status));
|
||
|
ASSERT(FALSE && "Unknown pSrbDataPacket->Frame->Status");
|
||
|
}
|
||
|
|
||
|
// For VidOnly which uses VideoInfoHeader and has
|
||
|
// an extended frame information (KS_FRAME_INFO) appended to KSSTREAM_HEADER
|
||
|
if( pDevExt->idxStreamNumber == 0 &&
|
||
|
(pStrmHeader->Size >= (sizeof(KSSTREAM_HEADER) + sizeof(PKS_FRAME_INFO)))
|
||
|
) {
|
||
|
pFrameInfo = (PKS_FRAME_INFO) (pStrmHeader + 1);
|
||
|
pFrameInfo->ExtendedHeaderSize = sizeof(KS_FRAME_INFO);
|
||
|
pFrameInfo->PictureNumber = pStrmExt->PictureNumber;
|
||
|
pFrameInfo->DropCount = pStrmExt->FramesDropped;
|
||
|
pFrameInfo->dwFrameFlags =
|
||
|
KS_VIDEO_FLAG_FRAME | // Complete frame
|
||
|
KS_VIDEO_FLAG_I_FRAME; // Every DV frame is an I frame
|
||
|
}
|
||
|
|
||
|
#if DBG
|
||
|
// Validate that the data is return in the right sequence
|
||
|
if(pSrbDataPacket->FrameNumber != pStrmExt->FramesProcessed) {
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_ERROR,("\'pSrbDataPacket:%x; Status:%x; Out of Sequence %d != %d; (Dropped:%x)\n",
|
||
|
pSrbDataPacket, pSrbDataPacket->Frame->Status,
|
||
|
(DWORD) pSrbDataPacket->FrameNumber, (DWORD) pStrmExt->FramesProcessed,
|
||
|
(DWORD) pStrmExt->FramesDropped
|
||
|
));
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
// Collect transmit buffer statistics
|
||
|
if(pStrmExt->ulStatEntries < MAX_XMT_FRAMES_TRACED) {
|
||
|
pXmtStat = pStrmExt->paXmtStat + pStrmExt->ulStatEntries;
|
||
|
|
||
|
pXmtStat->StreamState = pStrmExt->StreamState;
|
||
|
|
||
|
pXmtStat->cntSRBReceived = (LONG) pStrmExt->cntSRBReceived;
|
||
|
pXmtStat->cntSRBPending = (LONG) pStrmExt->cntSRBPending;
|
||
|
pXmtStat->cntSRBQueued = (LONG) pStrmExt->cntSRBQueued;
|
||
|
pXmtStat->cntDataAttached= pStrmExt->cntDataAttached;
|
||
|
|
||
|
pXmtStat->FrameSlot = (DWORD) pStrmExt->PictureNumber;
|
||
|
pXmtStat->tmStreamTime = pStrmExt->CurrentStreamTime;
|
||
|
|
||
|
pXmtStat->DropCount = (DWORD) pStrmExt->FramesDropped;
|
||
|
|
||
|
pXmtStat->FrameNumber = (DWORD) pSrbDataPacket->FrameNumber;
|
||
|
pXmtStat->OptionsFlags = pSrb->CommandData.DataBufferArray->OptionsFlags;
|
||
|
pXmtStat->tmPresentation = pSrb->CommandData.DataBufferArray->PresentationTime.Time;
|
||
|
|
||
|
pXmtStat->tsTransmitted= pSrbDataPacket->Frame->Timestamp;
|
||
|
|
||
|
pStrmExt->ulStatEntries++;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// Mark completion is called.
|
||
|
//
|
||
|
pSrbDataPacket->State |= DE_IRP_CALLBACK_COMPLETED;
|
||
|
|
||
|
//
|
||
|
// Attached->Completed or Completed->Attached.
|
||
|
//
|
||
|
if(IsStateSet(pSrbDataPacket->State, DE_IRP_ATTACHED_COMPLETED)) {
|
||
|
|
||
|
//
|
||
|
// Recycle it back to the detach list
|
||
|
//
|
||
|
RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
|
||
|
InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
|
||
|
|
||
|
#if DBG
|
||
|
// Detect if 61883 is starve. This cause discontinuity.
|
||
|
// This can happen for many valid reasons (slow system).
|
||
|
// An assert is added to detect other unknown reason.
|
||
|
if(pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starved in RUN state (read); AQD[%d:%d:%d]\n\n",
|
||
|
pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
|
||
|
));
|
||
|
// ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Complete this Srb
|
||
|
//
|
||
|
|
||
|
StreamClassStreamNotification(StreamRequestComplete, pStrmExt->pStrmObject, pSrbDataPacket->pSrb );
|
||
|
pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
|
||
|
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
|
||
|
} else {
|
||
|
|
||
|
TRACE(TL_STRM_WARNING,("CompleteSrbRead: pSrbDataPacket:%x; Completed before attach.\n", pSrbDataPacket));
|
||
|
|
||
|
}
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
return 0;
|
||
|
} // DVCompleteSrbRead
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
DVAttachFrameCR(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP pIrp,
|
||
|
IN PSRB_DATA_PACKET pSrbDataPacket
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Completion routine for attaching a frame for transmitting.
|
||
|
Apply to attaching listen and talk frame.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PHW_STREAM_REQUEST_BLOCK pSrb;
|
||
|
PSTREAMEX pStrmExt;
|
||
|
PLONG plSrbUseCount; // When this count is 0, it can be completed.
|
||
|
KIRQL oldIrql;
|
||
|
|
||
|
|
||
|
pStrmExt = pSrbDataPacket->pStrmExt;
|
||
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
||
|
|
||
|
pSrb = pSrbDataPacket->pSrb;
|
||
|
|
||
|
// This entry is be already attached before IoCallDriver.
|
||
|
// This is done this way because this buffer could be filled and
|
||
|
// completed before the attach completion routine (here) is called.
|
||
|
// If it is completed and callback is called,
|
||
|
// pSrbDataPacket->pSrb has been set to NULL.
|
||
|
// In the error case, pSrbDataPacket->pSrb should not be NULL.
|
||
|
if(!NT_SUCCESS(pIrp->IoStatus.Status)) {
|
||
|
if(pSrbDataPacket->pSrb == NULL) {
|
||
|
// PBinder told me that this cannot happen.
|
||
|
// A buffer is completed (pSRb set to NULL), and still return with an error!
|
||
|
ASSERT(pSrbDataPacket->pSrb);
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
pSrbDataPacket->State |= DE_IRP_ERROR;
|
||
|
|
||
|
plSrbUseCount = (PLONG) (pSrb->SRBExtension);
|
||
|
(*plSrbUseCount) --; // -- for being remove from queue
|
||
|
ASSERT(*plSrbUseCount >= 0);
|
||
|
|
||
|
TRACE(TL_CIP_ERROR,("DVAttachFrameCR: pSrb:%x; pSrb->Status:%x; failed pIrp->Status %x; UseCnt:%d\n", pSrb, pSrb->Status, pIrp->IoStatus.Status, *plSrbUseCount));
|
||
|
ASSERT(NT_SUCCESS(pIrp->IoStatus.Status) && "DVAttachFrameCR");
|
||
|
// Complete this SRB only if the count is 0.
|
||
|
if(*plSrbUseCount == 0 && pSrb->Status != STATUS_CANCELLED) {
|
||
|
pSrb->Status = pIrp->IoStatus.Status;
|
||
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
||
|
|
||
|
// Complete SRB
|
||
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrbDataPacket->pSrb);
|
||
|
pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Recycle list
|
||
|
RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
|
||
|
InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
|
||
|
|
||
|
#if DBG
|
||
|
// Detect if 61883 is starve. This cause discontinuity.
|
||
|
// This can happen for many valid reasons (slow system).
|
||
|
// An assert is added to detect other unknown reason.
|
||
|
if(!pStrmExt->bEOStream && pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (AttachCR); AQD[%d:%d:%d]\n\n",
|
||
|
pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
|
||
|
));
|
||
|
if (pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
|
||
|
// ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Mark attached buffer completed.
|
||
|
//
|
||
|
pSrbDataPacket->State |= DE_IRP_ATTACHED_COMPLETED;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Special case: Completed and then Attached.
|
||
|
//
|
||
|
if(IsStateSet(pSrbDataPacket->State, DE_IRP_CALLBACK_COMPLETED)) {
|
||
|
|
||
|
//
|
||
|
// Recycle it back to the detach list
|
||
|
//
|
||
|
RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
|
||
|
InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
|
||
|
|
||
|
#if DBG
|
||
|
// Detect if 61883 is starve. This cause discontinuity.
|
||
|
// This can happen for many valid reasons (slow system).
|
||
|
// An assert is added to detect other unknown reason.
|
||
|
if(!pStrmExt->bEOStream && pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (AttachCR); AQD[%d:%d:%d]\n\n",
|
||
|
pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
|
||
|
));
|
||
|
if (pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
|
||
|
// ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Complete this Srb
|
||
|
//
|
||
|
StreamClassStreamNotification(StreamRequestComplete, pStrmExt->pStrmObject, pSrbDataPacket->pSrb);
|
||
|
pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
|
||
|
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
|
||
|
TRACE(TL_STRM_WARNING,("AttachFrameCR: pSrbDataPacket:%x; completed before DttachFrameCR.\n", pSrbDataPacket));
|
||
|
}
|
||
|
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
TRACE(TL_CIP_INFO,("\'DVAttachFrameCR: pSrb:%x; AttachCnt:%d\n", pSrb, pStrmExt->cntDataAttached));
|
||
|
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DVSRBRead(
|
||
|
IN PKSSTREAM_HEADER pStrmHeader,
|
||
|
IN ULONG ulFrameSize,
|
||
|
IN PDVCR_EXTENSION pDevExt,
|
||
|
IN PSTREAMEX pStrmExt,
|
||
|
IN PHW_STREAM_REQUEST_BLOCK pSrb // needs Srb->Status
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Called when an Read Data Srb request is received
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
KIRQL oldIrql;
|
||
|
NTSTATUS Status;
|
||
|
PSRB_DATA_PACKET pSrbDataPacket;
|
||
|
PAV_61883_REQUEST pAVReq;
|
||
|
PLONG plSrbUseCount;
|
||
|
PIO_STACK_LOCATION NextIrpStack;
|
||
|
ULONG ulSrcPktLen; // Packet length in bytes
|
||
|
PVOID pFrameBuffer;
|
||
|
|
||
|
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
|
||
|
//
|
||
|
// Some validation
|
||
|
//
|
||
|
if(pStrmHeader->FrameExtent < ulFrameSize) {
|
||
|
TRACE(TL_CIP_WARNING,("\'SRBRead: FrmExt %d < FrmSz %d\n", pStrmHeader->FrameExtent, ulFrameSize));
|
||
|
#ifdef SUPPORT_NEW_AVC
|
||
|
if(pStrmExt->bDV2DVConnect) {
|
||
|
pSrb->Status = STATUS_SUCCESS; // Testing...
|
||
|
} else {
|
||
|
#endif
|
||
|
ASSERT(pStrmHeader->FrameExtent >= ulFrameSize);
|
||
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
||
|
#ifdef SUPPORT_NEW_AVC
|
||
|
}
|
||
|
#endif
|
||
|
goto ExitReadStreamError;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Make sure that there is enough entry
|
||
|
//
|
||
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
||
|
if(IsListEmpty(&pStrmExt->DataDetachedListHead)) {
|
||
|
//
|
||
|
// This can happen only if the upper layer send down more than what we preallocated.
|
||
|
// In this case, we will expand the list.
|
||
|
//
|
||
|
if(!(pSrbDataPacket = ExAllocatePool(NonPagedPool, sizeof(SRB_DATA_PACKET)))) {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
goto ExitReadStreamError;
|
||
|
}
|
||
|
RtlZeroMemory(pSrbDataPacket, sizeof(SRB_DATA_PACKET));
|
||
|
if(!(pSrbDataPacket->Frame = ExAllocatePool(NonPagedPool, sizeof(CIP_FRAME)))) {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
ExFreePool(pSrbDataPacket);
|
||
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
goto ExitReadStreamError;
|
||
|
}
|
||
|
if(!(pSrbDataPacket->pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE))) {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
ExFreePool(pSrbDataPacket->Frame); pSrbDataPacket->Frame = 0;
|
||
|
ExFreePool(pSrbDataPacket); pSrbDataPacket = 0;
|
||
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
goto ExitReadStreamError;
|
||
|
}
|
||
|
InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
|
||
|
TRACE(TL_CIP_WARNING,("\'Add one node to DetachList\n"));
|
||
|
}
|
||
|
|
||
|
// Get a a nonpaged system-space virtual address for the buffer
|
||
|
// This could fail it there is not enough system resource (MDL).
|
||
|
#ifdef USE_WDM110 // Win2000
|
||
|
//
|
||
|
// Driver verifier flag to use this but if this is used, this driver will not load for Millen!!!
|
||
|
//
|
||
|
pFrameBuffer = MmGetSystemAddressForMdlSafe(pSrb->Irp->MdlAddress, NormalPagePriority);
|
||
|
#else // Win9x
|
||
|
pFrameBuffer = MmGetSystemAddressForMdl (pSrb->Irp->MdlAddress);
|
||
|
#endif
|
||
|
if(pFrameBuffer == NULL) {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
ASSERT(FALSE && "DVFormatAttachFrame() insufficient resource!");
|
||
|
goto ExitReadStreamError;
|
||
|
}
|
||
|
|
||
|
pSrbDataPacket = (PSRB_DATA_PACKET) RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
|
||
|
plSrbUseCount = (PLONG) (pSrb->SRBExtension); (*plSrbUseCount) = 0; // Not in a queue so 0.
|
||
|
pAVReq = &pSrbDataPacket->AVReq;
|
||
|
|
||
|
|
||
|
ulSrcPktLen = \
|
||
|
(DVFormatInfoTable[pDevExt->VideoFormatIndex].DataBlockSize << 2) * \
|
||
|
(1 << DVFormatInfoTable[pDevExt->VideoFormatIndex].FractionNumber);
|
||
|
|
||
|
//
|
||
|
// Format an attach frame request
|
||
|
//
|
||
|
DVFormatAttachFrame(
|
||
|
pStrmExt->pStrmInfo->DataFlow,
|
||
|
pStrmExt,
|
||
|
pAVReq,
|
||
|
pSrb,
|
||
|
pSrbDataPacket,
|
||
|
ulSrcPktLen,
|
||
|
ulFrameSize,
|
||
|
pFrameBuffer
|
||
|
);
|
||
|
|
||
|
// Completion callback can be called before the attach frame completion routine;
|
||
|
// Add this to the attached list now; if it ever failed, it will be removed in the completion routine.
|
||
|
InsertTailList(&pStrmExt->DataAttachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached++;
|
||
|
(*plSrbUseCount) ++; // ++ for being in queue
|
||
|
ASSERT(*plSrbUseCount > 0);
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
|
||
|
NextIrpStack = IoGetNextIrpStackLocation(pSrbDataPacket->pIrp);
|
||
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
|
||
|
NextIrpStack->Parameters.Others.Argument1 = &pSrbDataPacket->AVReq;
|
||
|
|
||
|
IoSetCompletionRoutine(
|
||
|
pSrbDataPacket->pIrp,
|
||
|
DVAttachFrameCR,
|
||
|
pSrbDataPacket,
|
||
|
TRUE,
|
||
|
TRUE,
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
// Must set to _PENDING or MediaSample will return empty KSSTREAM_HEADER
|
||
|
pSrb->Status = STATUS_PENDING;
|
||
|
pSrbDataPacket->pIrp->IoStatus.Status = STATUS_SUCCESS; // Initialize it
|
||
|
|
||
|
Status = IoCallDriver( pStrmExt->pDevExt->pBusDeviceObject, pSrbDataPacket->pIrp);
|
||
|
|
||
|
ASSERT(Status == STATUS_PENDING || Status == STATUS_SUCCESS);
|
||
|
|
||
|
return;
|
||
|
|
||
|
ExitReadStreamError:
|
||
|
|
||
|
StreamClassStreamNotification(
|
||
|
StreamRequestComplete,
|
||
|
pSrb->StreamObject,
|
||
|
pSrb
|
||
|
);
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
DVCompleteSrbWrite(
|
||
|
PCIP_NOTIFY_INFO pInfo
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This fucntion is called when 61883 has completed transmitting a frame.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PSRB_DATA_PACKET pSrbDataPacket ;
|
||
|
PHW_STREAM_REQUEST_BLOCK pSrb;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PDVCR_EXTENSION pDevExt;
|
||
|
PSTREAMEX pStrmExt;
|
||
|
PLONG plSrbUseCount; // When this count is 0, it can be completed.
|
||
|
KIRQL oldIrql;
|
||
|
#if DBG
|
||
|
LONG lCycleCountElapsed;
|
||
|
PXMT_FRAME_STAT pXmtStat;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
// Callback and in DISPATCH_LEVEL
|
||
|
// Caller might have acquired SpinLock as well!
|
||
|
pSrbDataPacket = pInfo->Context;
|
||
|
|
||
|
if(!pSrbDataPacket) {
|
||
|
ASSERT(pSrbDataPacket);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
pStrmExt = pSrbDataPacket->pStrmExt;
|
||
|
ASSERT(pStrmExt);
|
||
|
|
||
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
||
|
|
||
|
ASSERT(pSrbDataPacket->pSrb);
|
||
|
|
||
|
pSrb = pSrbDataPacket->pSrb;
|
||
|
|
||
|
pDevExt = pStrmExt->pDevExt;
|
||
|
plSrbUseCount = (PLONG) pSrb->SRBExtension;
|
||
|
|
||
|
// Check return Status
|
||
|
if(!NT_SUCCESS(pSrbDataPacket->Frame->Status)) {
|
||
|
TRACE(TL_CIP_ERROR,("\'DVCompleteSrbWrite: %d: Frame->Status %x\n", (DWORD) pSrbDataPacket->FrameNumber, pSrbDataPacket->Frame->Status));
|
||
|
ASSERT(NT_SUCCESS(pSrbDataPacket->Frame->Status));
|
||
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
else {
|
||
|
pSrb->Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
(*plSrbUseCount) --; // This count need to be 0 before the SRB is completed.
|
||
|
ASSERT(*plSrbUseCount >= 0);
|
||
|
|
||
|
#if DBG
|
||
|
if(pSrbDataPacket->StreamState == KSSTATE_PAUSE) {
|
||
|
pStrmExt->lPrevCycleCount = pSrbDataPacket->Frame->Timestamp.CL_CycleCount;
|
||
|
pStrmExt->lTotalCycleCount = 0;
|
||
|
pStrmExt->lFramesAccumulatedRun = 0;
|
||
|
pStrmExt->lFramesAccumulatedPaused++;
|
||
|
|
||
|
} else if(pSrbDataPacket->StreamState == KSSTATE_RUN) {
|
||
|
|
||
|
if((LONG) pSrbDataPacket->Frame->Timestamp.CL_CycleCount > pStrmExt->lPrevCycleCount)
|
||
|
lCycleCountElapsed = pSrbDataPacket->Frame->Timestamp.CL_CycleCount - pStrmExt->lPrevCycleCount;
|
||
|
else
|
||
|
lCycleCountElapsed = pSrbDataPacket->Frame->Timestamp.CL_CycleCount + 8000 - pStrmExt->lPrevCycleCount;
|
||
|
|
||
|
if(lCycleCountElapsed <= (LONG) DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets) {
|
||
|
TRACE(TL_CIP_WARNING, ("\'#### CycleCounts between frames %d <= expected %d + empty pkt?\n",
|
||
|
lCycleCountElapsed,
|
||
|
DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets
|
||
|
));
|
||
|
}
|
||
|
|
||
|
pStrmExt->lTotalCycleCount += lCycleCountElapsed;
|
||
|
pStrmExt->lFramesAccumulatedRun++;
|
||
|
|
||
|
TRACE(TL_CIP_TRACE,("\'%d) Attached:%d; pSrb:%x; FmSt:%x; CyTm:[SC:%d:CC:%d]; CyclElaps:%d; fps:%d/%d\n",
|
||
|
(DWORD) pSrbDataPacket->FrameNumber,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pSrb,
|
||
|
pSrbDataPacket->Frame->Status,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
|
||
|
lCycleCountElapsed,
|
||
|
pStrmExt->lTotalCycleCount,
|
||
|
(DWORD) pStrmExt->lFramesAccumulatedRun
|
||
|
));
|
||
|
|
||
|
pStrmExt->lPrevCycleCount = pSrbDataPacket->Frame->Timestamp.CL_CycleCount;
|
||
|
} else {
|
||
|
TRACE(TL_CIP_ERROR,("\'This data was attached at %d state ?????\n", pSrbDataPacket->StreamState));
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
TRACE(TL_CIP_INFO,("\'%d) FmSt %x; Cnt %d; CyTm:[%d:%d:%d]; PrevCyclCnt:%d\n",
|
||
|
(DWORD) pSrbDataPacket->FrameNumber,
|
||
|
pSrbDataPacket->Frame->Status,
|
||
|
*plSrbUseCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_CycleOffset,
|
||
|
pStrmExt->lPrevCycleCount
|
||
|
));
|
||
|
|
||
|
TRACE(TL_CIP_INFO,("\'DVCompleteSrbWrite: Frm:%d; Attached:%d; cntUse:%d, Srb:%x; FrmSt:%x; CyclElaps:%d\n",
|
||
|
(DWORD) pSrbDataPacket->FrameNumber,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
*plSrbUseCount,
|
||
|
pSrb,
|
||
|
pSrbDataPacket->Frame->Status,
|
||
|
lCycleCountElapsed
|
||
|
));
|
||
|
|
||
|
|
||
|
//
|
||
|
// Mark completion is called.
|
||
|
//
|
||
|
pSrbDataPacket->State |= DE_IRP_CALLBACK_COMPLETED;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Attached->Completed or Completed->Attached.
|
||
|
//
|
||
|
if(IsStateSet(pSrbDataPacket->State, DE_IRP_ATTACHED_COMPLETED)) {
|
||
|
|
||
|
//
|
||
|
// Recycle it back to the detach list
|
||
|
//
|
||
|
RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
|
||
|
InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
|
||
|
|
||
|
#if DBG
|
||
|
// Detect if 61883 is starve. This cause discontinuity.
|
||
|
// This can happen for many valid reasons (slow system).
|
||
|
// An assert is added to detect other unknown reason.
|
||
|
if(!pStrmExt->bEOStream && pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
|
||
|
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (write);AQD[%d:%d:%d]\n\n",
|
||
|
pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
|
||
|
));
|
||
|
if (pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
|
||
|
// ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Complete this SRB only if the count is 0.
|
||
|
if(*plSrbUseCount == 0) {
|
||
|
|
||
|
TRACE(TL_CIP_TRACE,("\'------------ Srb:%x completing..----------------\n", pSrb));
|
||
|
// Frame that possibly made it to the device
|
||
|
pStrmExt->FramesProcessed++;
|
||
|
pSrb->CommandData.DataBufferArray->DataUsed = DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize;
|
||
|
|
||
|
StreamClassStreamNotification(StreamRequestComplete, pStrmExt->pStrmObject, pSrbDataPacket->pSrb );
|
||
|
pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
TRACE(TL_STRM_WARNING,("CompleteSrbWrite: pSrbDataPacket:%x; Completed before attach.\n", pSrbDataPacket));
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
// Collect transmit buffer statistics
|
||
|
if((pStrmExt->lFramesAccumulatedPaused + pStrmExt->lFramesAccumulatedRun) <= MAX_XMT_FRAMES_TRACED) {
|
||
|
pXmtStat = pStrmExt->paXmtStat + (pStrmExt->lFramesAccumulatedPaused + pStrmExt->lFramesAccumulatedRun - 1);
|
||
|
pXmtStat->tsTransmitted = pSrbDataPacket->Frame->Timestamp;
|
||
|
if(pSrbDataPacket->Frame->Timestamp.CL_CycleCount == 0) {
|
||
|
TRACE(TL_CIP_WARNING,("\'PAUSE:%d; RUN:%d; %d:%d\n", pStrmExt->lFramesAccumulatedPaused, pStrmExt->lFramesAccumulatedRun,
|
||
|
pSrbDataPacket->Frame->Timestamp.CL_SecondCount, pSrbDataPacket->Frame->Timestamp.CL_CycleCount));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Signal that all SRBs have been attached and transmitted.
|
||
|
if(pStrmExt->bEOStream) {
|
||
|
if(pStrmExt->cntDataAttached == 0 && pStrmExt->cntSRBQueued == 0) {
|
||
|
|
||
|
//
|
||
|
// Signal any pending clock events
|
||
|
//
|
||
|
DVSignalClockEvent(0, pStrmExt, 0, 0);
|
||
|
|
||
|
//
|
||
|
// No data request queued or pending; it is time to signal EOStream to
|
||
|
// trigger EC_COMPLETE.
|
||
|
//
|
||
|
StreamClassStreamNotification(
|
||
|
SignalMultipleStreamEvents,
|
||
|
pStrmExt->pStrmObject,
|
||
|
(GUID *)&KSEVENTSETID_Connection_Local,
|
||
|
KSEVENT_CONNECTION_ENDOFSTREAM
|
||
|
);
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'*-*-* EOStream Signalled: pSrb:%x completed; AQD [%d:%d:%d]; Took %d msec;\n",
|
||
|
pSrb, pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached,
|
||
|
(DWORD) ((GetSystemTime() - pStrmExt->tmStreamStart)/(ULONGLONG) 10000)));
|
||
|
}
|
||
|
else {
|
||
|
TRACE(TL_CIP_TRACE,("\' *EOStream: pSrb:%x completed; cntAttached:%d; cntSRBQ:%d\n", pSrb, (DWORD) pStrmExt->cntDataAttached, (DWORD) pStrmExt->cntSRBQueued));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// If we are not in the ending situtation (EOS pr Stop state) and number of
|
||
|
// attach data request is below a threashold, we singal an event to the
|
||
|
// code that does "throttle" to quickly attach another frame.
|
||
|
//
|
||
|
|
||
|
if(!pStrmExt->bEOStream ||
|
||
|
(pStrmExt->bEOStream && pStrmExt->cntSRBQueued > 0)) {
|
||
|
|
||
|
if(pStrmExt->StreamState != KSSTATE_STOP &&
|
||
|
pStrmExt->cntDataAttached < NUM_BUF_ATTACHED_THEN_ISOCH) {
|
||
|
KeSetEvent(&pStrmExt->hSrbArriveEvent, 0, FALSE);
|
||
|
TRACE(TL_CIP_WARNING,("Threadshold:.AQD:[%d %d %d] < %d\n",
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached,
|
||
|
NUM_BUF_ATTACHED_THEN_ISOCH
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
return 0;
|
||
|
} // DVCompleteSrbWrite
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
DVAttachWriteFrame(
|
||
|
IN PSTREAMEX pStrmExt
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Prepare and submit a frame to 61883 for transmit.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
KIRQL oldIrql;
|
||
|
PSRB_DATA_PACKET pSrbDataPacket;
|
||
|
PSRB_ENTRY pSrbEntry;
|
||
|
#if DBG
|
||
|
ULONG SrbNumCache; // Cache the SRB number of tracking purpose
|
||
|
PXMT_FRAME_STAT pXmtStat;
|
||
|
#endif
|
||
|
PHW_STREAM_REQUEST_BLOCK pSrb;
|
||
|
PHW_STREAM_REQUEST_BLOCK pSrbNext;
|
||
|
PVOID pFrameBuffer;
|
||
|
PIO_STACK_LOCATION NextIrpStack;
|
||
|
NTSTATUS Status;
|
||
|
PLONG plSrbUseCount; // When this count is 0, it can be completed.
|
||
|
ULONG ulSrcPktLen;
|
||
|
LARGE_INTEGER Timeout;
|
||
|
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
|
||
|
// Serialize setting state to STOP
|
||
|
if(pStrmExt->StreamState != KSSTATE_PAUSE &&
|
||
|
pStrmExt->StreamState != KSSTATE_RUN) {
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'DVAttachWriteFrame: StreamState:%d; no attach! Wait!\n", pStrmExt->StreamState));
|
||
|
Timeout.HighPart = -1;
|
||
|
Timeout.LowPart = (ULONG)(-1 * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame);
|
||
|
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
||
|
|
||
|
if(IsListEmpty(&pStrmExt->SRBQueuedListHead) ||
|
||
|
IsListEmpty(&pStrmExt->DataDetachedListHead) ) {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
#if DBG
|
||
|
if(!pStrmExt->bEOStream) {
|
||
|
TRACE(TL_CIP_WARNING,("\'StrmSt:%d; DetachList or SrbQ empty: EOStream:%d; AQD [%d:%d:%d]; Wait one frame time.\n",
|
||
|
pStrmExt->StreamState,
|
||
|
pStrmExt->bEOStream,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
}
|
||
|
#endif
|
||
|
Timeout.HighPart = -1;
|
||
|
Timeout.LowPart = (ULONG)(-1 * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame);
|
||
|
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
|
||
|
// SRB is queued so it is OK. We will process that later.
|
||
|
// This is usually cause by receiving more than what we pre-allocate.
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
// KSSTATE_PAUSE: "reuse" head of the SrbQ.
|
||
|
// KSSTATE_RUN: "remove" a Srb from the queue.
|
||
|
|
||
|
|
||
|
// Get NEXT(SrbQ) and determine if it needs to be removed.
|
||
|
pSrbEntry = (PSRB_ENTRY) pStrmExt->SRBQueuedListHead.Flink; pSrb = pSrbEntry->pSrb; plSrbUseCount = (PLONG) pSrb->SRBExtension;
|
||
|
ASSERT(*plSrbUseCount >= 0);
|
||
|
#if DBG
|
||
|
SrbNumCache = pSrbEntry->SrbNum;
|
||
|
#endif
|
||
|
|
||
|
// Get a a nonpaged system-space virtual address for the buffer
|
||
|
// This could fail it there is not enough system resource (MDL).
|
||
|
#ifdef USE_WDM110 // Win2000
|
||
|
//
|
||
|
// Driver verifier flag to use this but if this is used, this driver will not load for Millen!!!
|
||
|
//
|
||
|
pFrameBuffer = MmGetSystemAddressForMdlSafe(pSrb->Irp->MdlAddress, NormalPagePriority);
|
||
|
#else
|
||
|
pFrameBuffer = MmGetSystemAddressForMdl (pSrb->Irp->MdlAddress);
|
||
|
#endif
|
||
|
if(pFrameBuffer == NULL) {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
ASSERT(FALSE && "Insufficient MDL\n");
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// Only in RUN state, the stream time in the Srb is considered and Srbs in the SrbQ will be dequeued.
|
||
|
if(pStrmExt->StreamState == KSSTATE_RUN) {
|
||
|
|
||
|
#define ALLOWABLE_TIMING_LATENCY TIME_PER_CYCLE
|
||
|
|
||
|
// Presentation time is honor only if we are the master clock.
|
||
|
if(pStrmExt->hMasterClock) {
|
||
|
|
||
|
LONGLONG tmExpectedFrame;
|
||
|
|
||
|
|
||
|
if( pStrmExt->pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_PAL
|
||
|
|| pStrmExt->pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_PAL
|
||
|
)
|
||
|
tmExpectedFrame = pStrmExt->PictureNumber * (LONGLONG) FRAME_TIME_PAL;
|
||
|
else {
|
||
|
tmExpectedFrame = (pStrmExt->PictureNumber * (LONGLONG) 1000 * (LONGLONG) 1001 ) / (LONGLONG) 3; // trouble NTSC!
|
||
|
// Adjustment for rounding
|
||
|
if((pStrmExt->PictureNumber % 3) == 1)
|
||
|
tmExpectedFrame++;
|
||
|
}
|
||
|
|
||
|
// Use to adjust the querued stream time.
|
||
|
pStrmExt->LastSystemTime = GetSystemTime();
|
||
|
|
||
|
// There are three situations about the NEXT(SrbQ) comparing with tmExpectedFrame:
|
||
|
// 1. Early; 2. OnTime; 3.Late
|
||
|
//
|
||
|
// tmExpectedFrame
|
||
|
// |
|
||
|
// 3>------------2>-----------------1>---------------
|
||
|
// 3.Late | 2.On Time | 1.Early
|
||
|
// | x | x |
|
||
|
// where "x" is the allowable latency (for calculation rounding)
|
||
|
//
|
||
|
// Note: allow TIME_PER_CYCLE latency
|
||
|
/*Early*/
|
||
|
/*N+1/++*/ if((tmExpectedFrame + ALLOWABLE_TIMING_LATENCY) <= pSrb->CommandData.DataBufferArray->PresentationTime.Time) {
|
||
|
// FUTURE: if a frame arrive sooner than expected, do not remove SrbQ;
|
||
|
// instead, repeat until passing its "scheduled departure".
|
||
|
|
||
|
// Remove NEXT(SrbQ) only if bEOStream
|
||
|
if(pStrmExt->bEOStream) {
|
||
|
TRACE(TL_CIP_TRACE,("\'EOStream=== Srb:%x; (SrbNum:%d ?= PicNum:%d) cntSrbQ:%d; Attach:%d ===\n",
|
||
|
pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntSRBQueued, (DWORD) pStrmExt->cntDataAttached));
|
||
|
RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
|
||
|
ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
|
||
|
}
|
||
|
TRACE(TL_CIP_TRACE,("\'** Repeat: pSrb:%x; RefCnt:%d; cntSrbQ:%d; PicNum:%d; Drp:%d; PresTime:%d >= CurTime:%d\n",
|
||
|
pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
|
||
|
(DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) tmExpectedFrame/10000));
|
||
|
|
||
|
/*OnTime*/ } else
|
||
|
/* N */ if((tmExpectedFrame - ALLOWABLE_TIMING_LATENCY) <= pSrb->CommandData.DataBufferArray->PresentationTime.Time) {
|
||
|
// ON-TIME: may exactly matching or due to integer calculation, within one frame time.
|
||
|
// Dequeue if there are more than one Srb in the queue.
|
||
|
#if DBG
|
||
|
// Detect if a pSrb is used more than once
|
||
|
if((*plSrbUseCount) > 1) {
|
||
|
TRACE(TL_CIP_TRACE,("\'* Go: pSrb:%x; RefCnt:%d; cntSrbQ:%d; PicNum:%d; Drp:%d; PresTime:%d >= CurTime:%d\n",
|
||
|
pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
|
||
|
(DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) tmExpectedFrame/10000));
|
||
|
}
|
||
|
#endif
|
||
|
if(pStrmExt->bEOStream) {
|
||
|
// Remove NEXT(SrbQ) only if there are more than one SRB or bEOStream
|
||
|
TRACE(TL_CIP_TRACE,("\'EOStream=== Srb:%x; (SrbNum:%d ?= PicNum:%d) cntSrbQ:%d; Attach:%d ===\n",
|
||
|
pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntSRBQueued, (DWORD) pStrmExt->cntDataAttached));
|
||
|
RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
|
||
|
ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
|
||
|
// Remove SRB if more than one SRBs in Q and there is not a discontinuity, or end of stream.
|
||
|
} else if(pStrmExt->cntSRBQueued > 1) {
|
||
|
LONGLONG tmExpectedNextFrame = tmExpectedFrame + DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
|
||
|
|
||
|
pSrbNext = ((SRB_ENTRY *) (pSrbEntry->ListEntry.Flink))->pSrb;
|
||
|
|
||
|
// Next SRB has the next presentation time
|
||
|
// May add this check as well: (but check Presentation time is more reliable)
|
||
|
// pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY
|
||
|
/* N,N+1 */ if((tmExpectedNextFrame + ALLOWABLE_TIMING_LATENCY) > pSrbNext->CommandData.DataBufferArray->PresentationTime.Time) {
|
||
|
|
||
|
TRACE(TL_CIP_TRACE,("\'=== Srb:%x; (SrbNum:%d ?= PicNum:%d) cntSrbQ:%d; Attach:%d ===\n",
|
||
|
pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntSRBQueued, (DWORD) pStrmExt->cntDataAttached));
|
||
|
RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
|
||
|
ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
|
||
|
|
||
|
/* N, N+2/++ */ } else {
|
||
|
TRACE(TL_CIP_TRACE,("\'=== GO(Stale=TRUE) Srb:%x; (SrbNum:%d ?= PicNum:%d) Attach:%d ==\n",
|
||
|
pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntDataAttached));
|
||
|
// Mark this stale and be remove as soon as another is attached.
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
TRACE(TL_CIP_TRACE,("\'=== GO(Stale=TRUE) Srb:%x; (SrbNum:%d ?= PicNum:%d) Attach:%d ==\n",
|
||
|
pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntDataAttached));
|
||
|
// Mark this stale and be remove as soon as another is attached.
|
||
|
pSrbEntry->bStale = TRUE;
|
||
|
}
|
||
|
|
||
|
// CLOCK: tick when a frame is transmitted.
|
||
|
|
||
|
// LATE: this is dropped until there is only one Srb in the SrbQ.
|
||
|
// WORKITEM: we may need to implement IQualityManagement to inform application to read ahead.
|
||
|
/*Late*/ }
|
||
|
/*N-1*/ else {
|
||
|
|
||
|
if(pStrmExt->cntSRBQueued > 1) {
|
||
|
|
||
|
pSrbNext = ((SRB_ENTRY *) (pSrbEntry->ListEntry.Flink))->pSrb;
|
||
|
|
||
|
// Next SRB has the next presentation time; it can be:
|
||
|
// Current time is N
|
||
|
// Current frame is late (N-1 or N-2..) and we have more than one Srb in the queue;
|
||
|
// check next frame:
|
||
|
// (N?)
|
||
|
// N-2, N-1, N late more than one frame; (Next frame is also late; dequeu and not transmit; "catch up" case.)
|
||
|
// N-1, N late one frame; (Next frame is on time; dequeu this frame) <-- Normal case
|
||
|
// N-1, N+1 late one frame, but next frame is not N+1; (Next frame is early; *current frame will be repeated*)
|
||
|
//
|
||
|
// May add this check this as well: (but check Presentation time is more reliable)
|
||
|
// pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY
|
||
|
//
|
||
|
// ******************************************************************************************************
|
||
|
// If next frame is earlier than current stream time, "repeat" current stale frame; else we need to "catch up"!
|
||
|
// ******************************************************************************************************
|
||
|
/* N-1++, N */ if((tmExpectedFrame + ALLOWABLE_TIMING_LATENCY) > pSrbNext->CommandData.DataBufferArray->PresentationTime.Time) {
|
||
|
|
||
|
TRACE(TL_CIP_TRACE,("\'*** Stale(not Sent): pSrb:%x; RefCnt:%d; cntSrbQ:%d; cntAtt:%d; PicNum:%d; Drp:%d; PTm:%d < ExpTm:%d\n",
|
||
|
pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
|
||
|
(DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) (tmExpectedFrame/10000) ));
|
||
|
|
||
|
// Never been attached; remove late entry
|
||
|
RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
|
||
|
ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
|
||
|
|
||
|
if(*plSrbUseCount == 0) {
|
||
|
// If no reference to is, complete this.
|
||
|
pSrb->Status = STATUS_SUCCESS; // It is not a failure but late; maybe other status to indicate "non-fatal" late status..
|
||
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
||
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
// Since SrbQ is not empty and this is a stale frame, call recursively to get to next frame.
|
||
|
// Only possible error is if there is not sufficient resource (esp MDL)
|
||
|
// then, we bail out by self terminating this thread.
|
||
|
if(STATUS_INSUFFICIENT_RESOURCES ==
|
||
|
DVAttachWriteFrame(pStrmExt)) {
|
||
|
TRACE(TL_CIP_ERROR,("DVAttachWriteFrame: STATUS_INSUFFICIENT_RESOURCES\n"));
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
} else {
|
||
|
return STATUS_SUCCESS; // SUCESS unless there is another status to indicate "non-fatal" late.
|
||
|
}
|
||
|
/*N-2++, N-1++*/ } else {
|
||
|
pSrbEntry->bStale = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// EOStream and is a stale stream, it is the last element in SrbQ.
|
||
|
// Remove it.
|
||
|
if(pStrmExt->bEOStream) {
|
||
|
TRACE(TL_CIP_TRACE,("\'*** Stale(bEOStream): pSrb:%x; RefCnt:%d; cntSrbQ:%d; cntAtt:%d; PicNum:%d; Drp:%d; PTm:%d < ExpTm:%d\n",
|
||
|
pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
|
||
|
(DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) (tmExpectedFrame/10000) ));
|
||
|
|
||
|
RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
|
||
|
ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
|
||
|
if(*plSrbUseCount == 0) {
|
||
|
// If no reference to is, complete this.
|
||
|
pSrb->Status = STATUS_SUCCESS; // It is not a failure but late; maybe other status to indicate "non-fatal" late status..
|
||
|
pSrb->CommandData.DataBufferArray->DataUsed = 0;
|
||
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
|
||
|
#if DBG
|
||
|
pStrmExt->cntSRBPending--;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
// Update current stream time
|
||
|
pStrmExt->CurrentStreamTime = tmExpectedFrame;
|
||
|
|
||
|
return STATUS_SUCCESS; // SUCESS unless there is another status to indicate "non-fatal" late.
|
||
|
}
|
||
|
|
||
|
TRACE(TL_CIP_TRACE,("\'*** Stale(Sent): pSrb:%x; RefCnt:%d; cntSrbQ:%d; cntAtt:%d; PicNum:%d; Drp:%d; PTm:%d < ExpTm:%d\n",
|
||
|
pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
|
||
|
(DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) (tmExpectedFrame/10000) ));
|
||
|
|
||
|
// If this is stale and this is the only frame in SrbQ, Xmt it
|
||
|
}
|
||
|
|
||
|
// If late, this frame is always drop.
|
||
|
pStrmExt->FramesDropped++;
|
||
|
}
|
||
|
|
||
|
// Update current stream time
|
||
|
pStrmExt->CurrentStreamTime = tmExpectedFrame;
|
||
|
|
||
|
} // if(pStrmExt->hMasterClock)
|
||
|
else {
|
||
|
// Not the master clock, no "pacing" so always dequeu (SrbQ) and transmit
|
||
|
// as long as there is one Srb in the queue.
|
||
|
if(pStrmExt->cntSRBQueued > 1 || pStrmExt->bEOStream) {
|
||
|
RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
|
||
|
ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
|
||
|
}
|
||
|
TRACE(TL_CIP_TRACE,("\'* GO: (NoClock) pSrb:%x; RefCnt:%d; cntSrbQ:%d; PicNum:%d;\n", pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, (DWORD) pStrmExt->PictureNumber));
|
||
|
} // if(pStrmExt->hMasterClock)
|
||
|
|
||
|
|
||
|
// pStrmExt->FramesProcessed is updated when a frame has been transmitted in the notify routine.
|
||
|
// **** THIS IS THE CLOCK TICK ****
|
||
|
pStrmExt->PictureNumber++; // After tmExpectedFrame is calculated; Another frame to be attached
|
||
|
if(pStrmExt->hMasterClock) {
|
||
|
#ifdef SUPPORT_QUALITY_CONTROL
|
||
|
// +: late; -: early
|
||
|
pStrmExt->KSQuality.DeltaTime = pStrmExt->CurrentStreamTime - pSrb->CommandData.DataBufferArray->PresentationTime.Time;
|
||
|
// Percentage * 10 of frame transmitted
|
||
|
pStrmExt->KSQuality.Proportion = (ULONG)
|
||
|
((pStrmExt->PictureNumber - pStrmExt->FramesDropped) * 1000 / pStrmExt->PictureNumber);
|
||
|
pStrmExt->KSQuality.Context = /* NOT USED */ 0;
|
||
|
#define MIN_ATTACH_BUFFER 3
|
||
|
// This is where we may want to signal that we are near Famine!!
|
||
|
if (pStrmExt->KSQuality.DeltaTime >
|
||
|
(DV_NUM_OF_XMT_BUFFERS - MIN_ATTACH_BUFFER) * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame) {
|
||
|
TRACE(TL_CIP_TRACE,("\'QualityControl: pic#%d; drop:%d; Prop:%d; DeltaTime:%d (Srb.tmPres:%d, tmStream:%d)\n",
|
||
|
(DWORD) pStrmExt->PictureNumber,
|
||
|
(DWORD) pStrmExt->FramesDropped,
|
||
|
pStrmExt->KSQuality.Proportion,
|
||
|
(DWORD) pStrmExt->KSQuality.DeltaTime/10000,
|
||
|
(DWORD) pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000,
|
||
|
(DWORD) pStrmExt->CurrentStreamTime/10000
|
||
|
));
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
} // KSSTATE_RUN
|
||
|
|
||
|
#if DBG
|
||
|
// Collect transmit buffer statistics
|
||
|
if(pStrmExt->ulStatEntries < MAX_XMT_FRAMES_TRACED) {
|
||
|
pXmtStat = pStrmExt->paXmtStat + pStrmExt->ulStatEntries;
|
||
|
|
||
|
pXmtStat->StreamState = pStrmExt->StreamState;
|
||
|
|
||
|
pXmtStat->cntSRBReceived = (LONG) pStrmExt->cntSRBReceived;
|
||
|
pXmtStat->cntSRBPending = (LONG) pStrmExt->cntSRBPending;
|
||
|
pXmtStat->cntSRBQueued = (LONG) pStrmExt->cntSRBQueued;
|
||
|
pXmtStat->cntDataAttached= pStrmExt->cntDataAttached;
|
||
|
|
||
|
pXmtStat->FrameSlot = (DWORD) pStrmExt->PictureNumber;
|
||
|
pXmtStat->tmStreamTime = pStrmExt->CurrentStreamTime;
|
||
|
|
||
|
pXmtStat->DropCount = (DWORD) pStrmExt->FramesDropped;
|
||
|
|
||
|
pXmtStat->FrameNumber = SrbNumCache;
|
||
|
pXmtStat->OptionsFlags = pSrb->CommandData.DataBufferArray->OptionsFlags;
|
||
|
pXmtStat->tmPresentation = pSrb->CommandData.DataBufferArray->PresentationTime.Time;
|
||
|
|
||
|
// get the actual CyclTime when the frame is transmitted in the completion routine.
|
||
|
|
||
|
pStrmExt->ulStatEntries++;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef MSDV_SUPPORT_MUTE_AUDIO
|
||
|
// pSrbEntry could have been freed; if it has not and useCnt>1, then it could be a repeat frame.
|
||
|
if(pSrbEntry && (*plSrbUseCount) > 1) {
|
||
|
// Set it only once
|
||
|
if(!pSrbEntry->bAudioMute)
|
||
|
pSrbEntry->bAudioMute =
|
||
|
DVMuteDVFrame(pStrmExt->pDevExt, pFrameBuffer, TRUE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
// Get a data packet node as the context and list node
|
||
|
|
||
|
pSrbDataPacket = (PSRB_DATA_PACKET) RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
|
||
|
|
||
|
ulSrcPktLen = \
|
||
|
(DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].DataBlockSize << 2) * \
|
||
|
(1 << DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].FractionNumber);
|
||
|
|
||
|
// Format an attach frame request
|
||
|
DVFormatAttachFrame(
|
||
|
pStrmExt->pStrmInfo->DataFlow,
|
||
|
pStrmExt,
|
||
|
&pSrbDataPacket->AVReq,
|
||
|
pSrb,
|
||
|
pSrbDataPacket,
|
||
|
ulSrcPktLen,
|
||
|
DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulFrameSize,
|
||
|
pFrameBuffer
|
||
|
);
|
||
|
|
||
|
TRACE(TL_CIP_INFO,("\'------ New>> UseCnt:%d; pAVReq:%x; Srb:%x; DtaPkt:%x; AQD [%d:%d:%d]\n",
|
||
|
*plSrbUseCount,
|
||
|
&pSrbDataPacket->AVReq,
|
||
|
pSrb,
|
||
|
pSrbDataPacket,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
|
||
|
// Add this to the attached list
|
||
|
InsertTailList(&pStrmExt->DataAttachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached++;
|
||
|
(*plSrbUseCount) ++; // ++ for being in queue
|
||
|
ASSERT(*plSrbUseCount > 0);
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
|
||
|
NextIrpStack = IoGetNextIrpStackLocation(pSrbDataPacket->pIrp);
|
||
|
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
|
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
|
||
|
NextIrpStack->Parameters.Others.Argument1 = &pSrbDataPacket->AVReq;
|
||
|
|
||
|
IoSetCompletionRoutine(
|
||
|
pSrbDataPacket->pIrp,
|
||
|
DVAttachFrameCR,
|
||
|
pSrbDataPacket,
|
||
|
TRUE,
|
||
|
TRUE,
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
pSrbDataPacket->pIrp->IoStatus.Status = STATUS_SUCCESS; // Initialize it to something
|
||
|
|
||
|
Status = IoCallDriver( pStrmExt->pDevExt->pBusDeviceObject, pSrbDataPacket->pIrp);
|
||
|
|
||
|
ASSERT(Status == STATUS_PENDING || Status == STATUS_SUCCESS);
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
// put the resource back!
|
||
|
TRACE(TL_CIP_ERROR,("DVAttachWriteFrame: Failed to attach; St:%x\n", Status));
|
||
|
ASSERT(FALSE && "Failed to attach a Xmt frame.");
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// This is our throttle that regulate data attach to DV:
|
||
|
//
|
||
|
// This function is called by the attach thread which is running in an infinite loop.
|
||
|
// This function need to utilize the buffer that it receive and its repeat mechanism to
|
||
|
// regulate the incoming buffer from client and outgoing buffer attach to 1394 stadck for transmit.
|
||
|
// One way is to wait while there is certain number of frame already attach.
|
||
|
|
||
|
KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
|
||
|
if(!pStrmExt->bEOStream &&
|
||
|
// Need to keep NUM_BUF_ATTACHED_THEN_ISOCH buffer attached at all time to keep 61883 isoch xmt going.
|
||
|
(pStrmExt->StreamState == KSSTATE_RUN && pStrmExt->cntDataAttached > NUM_BUF_ATTACHED_THEN_ISOCH ||
|
||
|
pStrmExt->StreamState == KSSTATE_PAUSE && pStrmExt->cntDataAttached >= NUM_BUF_ATTACHED_THEN_ISOCH )
|
||
|
) {
|
||
|
NTSTATUS StatusDelay = STATUS_SUCCESS;
|
||
|
#if DBG
|
||
|
ULONGLONG tmStart = GetSystemTime();
|
||
|
TRACE(TL_CIP_TRACE,("\'[Pic# %d]; SrbNum:%d; Dropped:%d; pSrb:%x; StrmSt:%d; EOS:%d; AQD:[%d;%d;%d]; ",
|
||
|
(DWORD) pStrmExt->PictureNumber, SrbNumCache, (DWORD) pStrmExt->FramesDropped, pSrb, pStrmExt->StreamState, pStrmExt->bEOStream,
|
||
|
pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached));
|
||
|
#endif
|
||
|
Timeout.HighPart = -1;
|
||
|
Timeout.LowPart = (ULONG)(-1 * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame * \
|
||
|
(pStrmExt->StreamState == KSSTATE_PAUSE ? 1 : (pStrmExt->cntDataAttached - NUM_BUF_ATTACHED_THEN_ISOCH))) ;
|
||
|
|
||
|
// Wait the full time until we are very low in SrbQ or Attached buffers.
|
||
|
if(pStrmExt->cntSRBQueued <= 1 && pStrmExt->cntDataAttached <= NUM_BUF_ATTACHED_THEN_ISOCH) {
|
||
|
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql); // Guard against pStrmExt->cntSRBQueued
|
||
|
// Down to one frame so we will wait for an event and will be signalled
|
||
|
// when a new frame has arrived, or
|
||
|
// when number of attach buffer is below the minimum.
|
||
|
StatusDelay =
|
||
|
KeWaitForSingleObject(
|
||
|
&pStrmExt->hSrbArriveEvent,
|
||
|
Executive,
|
||
|
KernelMode,
|
||
|
FALSE,
|
||
|
&Timeout
|
||
|
);
|
||
|
|
||
|
// Important: If signalled, reset it else (timeout),
|
||
|
// we are still behind so next time we will not wait!
|
||
|
if(StatusDelay == STATUS_SUCCESS)
|
||
|
KeClearEvent(&pStrmExt->hSrbArriveEvent);
|
||
|
}
|
||
|
else {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
// Wait for frame(s) to be delivered; this is our throttle..
|
||
|
// The timeout period can be one or up to
|
||
|
// (pStrmExt->cntDataAttached - NUM_BUF_ATTACHED_THEN_ISOCH) frames
|
||
|
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
|
||
|
}
|
||
|
|
||
|
#if DBG
|
||
|
TRACE(TL_CIP_TRACE,("\'Wait(ST:%x) %d nsec!\n", StatusDelay, (DWORD) ((GetSystemTime() - tmStart)/10)));
|
||
|
#endif
|
||
|
} else {
|
||
|
KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DVFormatAttachFrame(
|
||
|
IN KSPIN_DATAFLOW DataFlow,
|
||
|
IN PSTREAMEX pStrmExt,
|
||
|
IN PAV_61883_REQUEST pAVReq,
|
||
|
IN PHW_STREAM_REQUEST_BLOCK pSrb,
|
||
|
IN PSRB_DATA_PACKET pSrbDataPacket,
|
||
|
IN ULONG ulSourceLength, // Packet length in bytes
|
||
|
IN ULONG ulFrameSize, // Buffer size; may contain one or multiple source packets
|
||
|
IN PVOID pFrameBuffer
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Format an attach frame request.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
ASSERT(pSrb);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Setup PSRB_DATA_PACKET, except its Frame structure (PCIP_APP_FRAME)
|
||
|
//
|
||
|
|
||
|
InitializeListHead(&pSrbDataPacket->ListEntry);
|
||
|
|
||
|
pSrbDataPacket->State = DE_PREPARED; // Initial state of a resued DataEntry (start over!)
|
||
|
|
||
|
pSrbDataPacket->pSrb = pSrb;
|
||
|
pSrbDataPacket->StreamState = pStrmExt->StreamState; // StreamState when this buffer is attached.
|
||
|
pSrbDataPacket->pStrmExt = pStrmExt;
|
||
|
pSrbDataPacket->FrameBuffer = pFrameBuffer;
|
||
|
|
||
|
ASSERT(pSrbDataPacket->FrameBuffer != NULL);
|
||
|
|
||
|
pSrbDataPacket->Frame->pNext = NULL;
|
||
|
pSrbDataPacket->Frame->Status = 0;
|
||
|
pSrbDataPacket->Frame->Packet = (PUCHAR) pFrameBuffer;
|
||
|
|
||
|
if(DataFlow == KSPIN_DATAFLOW_OUT) {
|
||
|
pSrbDataPacket->FrameNumber = pStrmExt->cntSRBReceived;
|
||
|
#ifdef NT51_61883
|
||
|
|
||
|
// This is needed since we have an old 61883.h in Lab06 (according to include path, anyway).
|
||
|
// Remove this when 61883.h is updated.
|
||
|
#ifndef CIP_RESET_FRAME_ON_DISCONTINUITY
|
||
|
#define CIP_RESET_FRAME_ON_DISCONTINUITY 0x00000040
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Set CIP_USE_SOURCE_HEADER_TIMESTAMP to get 25 bit CycleTime from source packet header (13CycleCount:12CycleOffset)
|
||
|
// Do not set this to get 16 bit CycleTime from isoch packet (3 SecondCount:13CycleCount)
|
||
|
//
|
||
|
pSrbDataPacket->Frame->Flags = CIP_VALIDATE_FIRST_SOURCE // Verify the start of a DV frame
|
||
|
| CIP_RESET_FRAME_ON_DISCONTINUITY; // No partial frame
|
||
|
#else
|
||
|
pSrbDataPacket->Frame->Flags = 0;
|
||
|
#endif
|
||
|
pSrbDataPacket->Frame->pfnValidate = DVReadFrameValidate; // use to validate the 1st source packet
|
||
|
pSrbDataPacket->Frame->ValidateContext = pSrbDataPacket;
|
||
|
pSrbDataPacket->Frame->pfnNotify = DVCompleteSrbRead;
|
||
|
}
|
||
|
else {
|
||
|
pSrbDataPacket->FrameNumber = pStrmExt->FramesProcessed;
|
||
|
pSrbDataPacket->Frame->Flags = CIP_DV_STYLE_SYT;
|
||
|
pSrbDataPacket->Frame->pfnValidate = NULL;
|
||
|
pSrbDataPacket->Frame->ValidateContext = NULL;
|
||
|
pSrbDataPacket->Frame->pfnNotify = DVCompleteSrbWrite;
|
||
|
}
|
||
|
pSrbDataPacket->Frame->NotifyContext = pSrbDataPacket;
|
||
|
|
||
|
//
|
||
|
// Av61883_AttachFrames
|
||
|
//
|
||
|
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
|
||
|
INIT_61883_HEADER(pAVReq, Av61883_AttachFrame);
|
||
|
pAVReq->AttachFrame.hConnect = pStrmExt->hConnect;
|
||
|
pAVReq->AttachFrame.FrameLength = ulFrameSize;
|
||
|
pAVReq->AttachFrame.SourceLength = ulSourceLength;
|
||
|
pAVReq->AttachFrame.Frame = pSrbDataPacket->Frame;
|
||
|
|
||
|
ASSERT(pStrmExt->hConnect);
|
||
|
ASSERT(pSrbDataPacket->Frame);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DVAttachFrameThread(
|
||
|
IN PSTREAMEX pStrmExt
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is a system thread to attach frame for transmit.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PDVCR_EXTENSION pDevExt;
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
pDevExt = pStrmExt->pDevExt;
|
||
|
|
||
|
//
|
||
|
// Pump up the priority since we are dealing with real time data
|
||
|
//
|
||
|
KeSetPriorityThread(KeGetCurrentThread(),
|
||
|
#if 1
|
||
|
LOW_REALTIME_PRIORITY
|
||
|
#else
|
||
|
HIGH_PRIORITY
|
||
|
#endif
|
||
|
);
|
||
|
|
||
|
while (!pStrmExt->bTerminateThread) {
|
||
|
|
||
|
//
|
||
|
// Halt this thread operation if other critical service
|
||
|
// is requested.
|
||
|
//
|
||
|
|
||
|
if(
|
||
|
!pStrmExt->bTerminateThread
|
||
|
&& (pStrmExt->lNeedService > 0)
|
||
|
) { // not fullly awake/powered.
|
||
|
NTSTATUS StatusWait;
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'Request stop thread for other service: lNeedService:%d; pStrmExt:%x; AQD[%d,%d,%d]\n",
|
||
|
pStrmExt->lNeedService, pStrmExt,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
|
||
|
InterlockedDecrement(&pStrmExt->lNeedService); // One reuqest serviced.
|
||
|
|
||
|
//
|
||
|
// Indicate that thread is about to stop. Signal it so other operation can begin.
|
||
|
//
|
||
|
KeSetEvent(&pStrmExt->hStopThreadEvent, 0 ,FALSE);
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'>>>> Enter WFSO(hRunThreadEvent)\n"));
|
||
|
StatusWait =
|
||
|
KeWaitForSingleObject(
|
||
|
&pStrmExt->hRunThreadEvent,
|
||
|
Executive,
|
||
|
KernelMode,
|
||
|
FALSE,
|
||
|
0
|
||
|
);
|
||
|
TRACE(TL_CIP_WARNING,("\'<<<< Exit WFSO(hRunThreadEvent); lNeedService:%d\n", pStrmExt->lNeedService));
|
||
|
ASSERT(pStrmExt->lNeedService == 0);
|
||
|
}
|
||
|
|
||
|
// Halt attach operation if
|
||
|
// not in either PAUSE or RUN state ( i.e. in STOP state)
|
||
|
// Device is removed
|
||
|
// in the process of being cancelled.
|
||
|
|
||
|
if(
|
||
|
!pStrmExt->bTerminateThread
|
||
|
&& pStrmExt->StreamState != KSSTATE_PAUSE
|
||
|
&& pStrmExt->StreamState != KSSTATE_RUN
|
||
|
|| pStrmExt->pDevExt->bDevRemoved
|
||
|
|| pStrmExt->lCancelStateWorkItem > 0
|
||
|
) {
|
||
|
NTSTATUS StatusWait;
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'Enter WFSO(hSrbArriveEvent): StrmState:%d; bDevRemoved:%d\n", pStrmExt->StreamState, pStrmExt->pDevExt->bDevRemoved));
|
||
|
|
||
|
StatusWait = // Can only return STATUS_SUCCESS (signal) or STATUS_TIMEOUT
|
||
|
KeWaitForSingleObject(
|
||
|
&pStrmExt->hSrbArriveEvent, // Signal with arrival of the first frame
|
||
|
Executive,
|
||
|
KernelMode, // Cannot return STATUS_USER_APC
|
||
|
FALSE, // Cannot be alerted STATUS_ALERTED
|
||
|
0 // INFINITE!!
|
||
|
);
|
||
|
|
||
|
// Reset notification event (or it will stay signalled).
|
||
|
KeClearEvent(&pStrmExt->hSrbArriveEvent);
|
||
|
TRACE(TL_CIP_WARNING,("\'Exit WFSO(hSrbArriveEvent): StrmState:%d; bDevRemoved:%d\n", pStrmExt->StreamState, pStrmExt->pDevExt->bDevRemoved));
|
||
|
|
||
|
|
||
|
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
|
||
|
|
||
|
// Simulate preroll at the RUN state
|
||
|
// We do this only when we are the clock provider to avoid dropping frame
|
||
|
// This timed WFSO is necessary if application send us only one frame while in RUN state.
|
||
|
#define PREROLL_WAITTIME 2000000
|
||
|
if(
|
||
|
!pStrmExt->bTerminateThread &&
|
||
|
pStrmExt->hMasterClock
|
||
|
) {
|
||
|
LARGE_INTEGER DueTime;
|
||
|
DueTime = RtlConvertLongToLargeInteger(-((LONG) PREROLL_WAITTIME));
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'Enter WFSO(hPreRollEvent)\n"));
|
||
|
StatusWait = // Can only return STATUS_SUCCESS (signal) or STATUS_TIMEOUT
|
||
|
KeWaitForSingleObject(
|
||
|
&pStrmExt->hPreRollEvent,
|
||
|
Executive,
|
||
|
KernelMode, // Cannot return STATUS_USER_APC
|
||
|
FALSE, // Cannot be alerted STATUS_ALERTED
|
||
|
&DueTime
|
||
|
);
|
||
|
// hPreRollEvent is a ont shot event; no need to reset it; let it stay signalled.
|
||
|
TRACE(TL_CIP_WARNING,("\'Exit WFSO(hPreRollEvent); waited %d msec; waitStatus:%x\n", (DWORD) ((GetSystemTime() - pStrmExt->tmStreamStart)/10000), StatusWait ));
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if DBG
|
||
|
if(
|
||
|
!pStrmExt->bTerminateThread
|
||
|
&& !pStrmExt->bEOStream
|
||
|
&& pStrmExt->FramesProcessed > 0
|
||
|
&& pStrmExt->cntDataAttached < NUM_BUF_ATTACHED_THEN_ISOCH
|
||
|
) {
|
||
|
|
||
|
TRACE(TL_CIP_TRACE,("\'AttachBuf is low!! SrbRcv:%d;Pic#:%d;Prc:%d;;Drop:%d;Cncl:%d; AQD [%d:%d:%d]\n",
|
||
|
(DWORD) pStrmExt->cntSRBReceived,
|
||
|
(DWORD) pStrmExt->PictureNumber,
|
||
|
(DWORD) pStrmExt->FramesProcessed,
|
||
|
(DWORD) pStrmExt->FramesDropped,
|
||
|
(DWORD) pStrmExt->cntSRBCancelled,
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
}
|
||
|
#endif
|
||
|
// Attach another frame for transmit
|
||
|
// Only possible error is if there is not sufficient resource (esp MDL)
|
||
|
// Then, we bail out by self terminating this thread.
|
||
|
if(
|
||
|
!pStrmExt->pDevExt->bDevRemoved
|
||
|
&& !pStrmExt->bTerminateThread
|
||
|
) {
|
||
|
if(STATUS_INSUFFICIENT_RESOURCES == \
|
||
|
DVAttachWriteFrame(pStrmExt)) {
|
||
|
TRACE(TL_CIP_ERROR,("STATUS_INSUFFICIENT_RESOURCES while attaching write frame.\n"));
|
||
|
pStrmExt->bTerminateThread = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Start Isoch_Talk once we have enough buffers attached.
|
||
|
// It is possible that streaming state is set to RUN before we have enough attach buffer
|
||
|
// start streaming. So we need to kick start here.
|
||
|
//
|
||
|
if(
|
||
|
!pStrmExt->bTerminateThread
|
||
|
&& !pStrmExt->pDevExt->bDevRemoved
|
||
|
&& pStrmExt->pDevExt->PowerState == PowerDeviceD0 // Need to be PoweredON
|
||
|
&& pStrmExt->lCancelStateWorkItem == 0 // No pending cancel work item
|
||
|
&& !pStrmExt->bIsochIsActive
|
||
|
&& (pStrmExt->StreamState == KSSTATE_PAUSE || pStrmExt->StreamState == KSSTATE_RUN)
|
||
|
&& pStrmExt->cntDataAttached >= NUM_BUF_ATTACHED_THEN_ISOCH
|
||
|
) {
|
||
|
|
||
|
Status =
|
||
|
DVStreamingStart(
|
||
|
pStrmExt->pStrmInfo->DataFlow,
|
||
|
pStrmExt,
|
||
|
pStrmExt->pDevExt
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TRACE(TL_STRM_WARNING,("\'*** ThreadTerminating... AQD [%d:%d:%d]\n",
|
||
|
pStrmExt->cntDataAttached,
|
||
|
pStrmExt->cntSRBQueued,
|
||
|
pStrmExt->cntDataDetached
|
||
|
));
|
||
|
|
||
|
KeAcquireSpinLock(&pStrmExt->pDevExt->AVCCmdLock, &OldIrql);
|
||
|
if(pStrmExt->lNeedService) {
|
||
|
TRACE(TL_STRM_WARNING,("Thread is exiting but lNeedService:%x != 0!\n", pStrmExt->lNeedService));
|
||
|
KeSetEvent(&pStrmExt->hStopThreadEvent, 0 ,FALSE);
|
||
|
InterlockedDecrement(&pStrmExt->lNeedService);
|
||
|
ASSERT(pStrmExt->lNeedService == 0);
|
||
|
}
|
||
|
KeReleaseSpinLock(&pStrmExt->pDevExt->AVCCmdLock, OldIrql);
|
||
|
|
||
|
KeSetEvent(&pStrmExt->hThreadEndEvent, 0, FALSE); // Signal it
|
||
|
Status = PsTerminateSystemThread(STATUS_SUCCESS); // Must be called at PASSIVE_LEVEL
|
||
|
// End of this thread!
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DVTerminateAttachFrameThread(
|
||
|
IN PSTREAMEX pStrmExt
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
To terminate the system thread. It waits for an event that is triggered
|
||
|
right before PsTerminateSystemThread() is called.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'DVTerminateAttachFrameThread enter\n"));
|
||
|
|
||
|
//
|
||
|
// Wake up the DataReady thread and terminate it if not already done so.
|
||
|
//
|
||
|
ASSERT(pStrmExt->bIsochIsActive == FALSE && "Terminate therad while IsochActive!");
|
||
|
|
||
|
|
||
|
//
|
||
|
// This function can be called from either CloseStrean or SurpriseRemoval;
|
||
|
// When a DV is surprise removal, this function may get called from both functions.
|
||
|
// Assuming StreamClass is serializing these two functions, no need to serialize it locally.
|
||
|
//
|
||
|
if(pStrmExt->bTerminateThread) {
|
||
|
TRACE(TL_CIP_ERROR,("DVTerminateAttachFrameThread: Thread already terminated. Was surprise removed?\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// ****** Terminate thread ******
|
||
|
pStrmExt->bTerminateThread = TRUE;
|
||
|
// ******
|
||
|
|
||
|
// With bTerminate thread set, let the thread run and terminate.
|
||
|
KeSetEvent(&pStrmExt->hRunThreadEvent, 0 ,FALSE);
|
||
|
|
||
|
|
||
|
// WFSO while in STOP state; signal so it can be terminated.
|
||
|
KeSetEvent(&pStrmExt->hSrbArriveEvent, 0, FALSE);
|
||
|
#ifdef SUPPORT_PREROLL_AT_RUN_STATE
|
||
|
// Signal it in case that it is still in WFSO.
|
||
|
KeSetEvent(&pStrmExt->hPreRollEvent, 0, FALSE);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
KeWaitForSingleObject(
|
||
|
&pStrmExt->hThreadEndEvent,
|
||
|
Executive,
|
||
|
KernelMode,
|
||
|
FALSE,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'Thread terminated!\n"));
|
||
|
|
||
|
ObDereferenceObject(
|
||
|
&pStrmExt->pAttachFrameThreadObject
|
||
|
);
|
||
|
|
||
|
TRACE(TL_CIP_WARNING,("\'ObDereferenceObject done!\n"));
|
||
|
}
|