Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2051 lines
70 KiB

/*++
Copyright (C) 1999 Microsoft Corporation
Module Name:
avcutil.c
Abstract
MS AVC streaming utility functions
Author:
Yee Wu 03/17/2000
Revision History:
Date Who What
----------- --------- ------------------------------------------------------------
03/17/2000 YJW created
--*/
#include "filter.h"
#include "ksmedia.h" // KSPROERTY_DROPPEDFRAMES_CURRENT
/************************************
* Synchronous IOCall to lower driver
************************************/
NTSTATUS
IrpSynchCR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PKEVENT Event
)
{
ENTER("IrpSynchCR");
KeSetEvent(Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
} // IrpSynchCR
NTSTATUS
SubmitIrpSynch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PAV_61883_REQUEST pAVReq
)
{
NTSTATUS Status;
KEVENT Event;
PIO_STACK_LOCATION NextIrpStack;
ENTER("SubmitIrpSynch");
Status = STATUS_SUCCESS;;
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
NextIrpStack->Parameters.Others.Argument1 = pAVReq;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(
pIrp,
IrpSynchCR,
&Event,
TRUE,
TRUE,
TRUE
);
Status =
IoCallDriver(
DeviceObject,
pIrp
);
if (Status == STATUS_PENDING) {
TRACE(TL_PNP_INFO,("Irp is pending...\n"));
if(KeGetCurrentIrql() < DISPATCH_LEVEL) {
KeWaitForSingleObject(
&Event,
Executive,
KernelMode,
FALSE,
NULL
);
TRACE(TL_PNP_TRACE,("Irp returned; IoStatus.Status %x\n", pIrp->IoStatus.Status));
Status = pIrp->IoStatus.Status; // Final status
}
else {
ASSERT(FALSE && "Pending but in DISPATCH_LEVEL!");
return Status;
}
}
EXIT("SubmitIrpSynch", Status);
return Status;
} // SubmitIrpSynchAV
/****************************
* Control utility functions
****************************/
NTSTATUS
AVCStrmGetPlugHandle(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
{
NTSTATUS Status;
PAV_61883_REQUEST pAVReq;
PAGED_CODE();
ENTER("AVCStrmGetPlugHandle");
Status = STATUS_SUCCESS;
// Claim ownership of hMutexAVReqIsoch
KeWaitForMutexObject(&pAVCStrmExt->hMutexAVReq, Executive, KernelMode, FALSE, NULL);
pAVReq = &pAVCStrmExt->AVReq;
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_GetPlugHandle);
pAVReq->GetPlugHandle.PlugNum = 0;
pAVReq->GetPlugHandle.hPlug = 0;
pAVReq->GetPlugHandle.Type = pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT ? CMP_PlugOut : CMP_PlugIn;
Status = SubmitIrpSynch(DeviceObject, pAVCStrmExt->pIrpAVReq, pAVReq);
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("GetPlugHandle: Failed:%x\n", Status));
ASSERT(NT_SUCCESS(Status));
pAVCStrmExt->hPlugRemote = NULL;
}
else {
TRACE(TL_61883_TRACE,("GetPlugHandle:hPlug:%x\n", pAVReq->GetPlugHandle.hPlug));
pAVCStrmExt->hPlugRemote = pAVReq->GetPlugHandle.hPlug;
}
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
EXIT("AVCStrmGetPlugHandle", Status);
return Status;
}
NTSTATUS
AVCStrmGetPlugState(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
Ask 61883.sys for the plug state.
Arguments:
Return Value:
Nothing
--*/
{
NTSTATUS Status;
PAV_61883_REQUEST pAVReq;
PAGED_CODE();
ENTER("AVCStrmGetPlugState");
Status = STATUS_SUCCESS;
//
// Check only requirement: hConnect
//
if(pAVCStrmExt->hPlugRemote == NULL) {
TRACE(TL_STRM_ERROR,("GetPlugState: hPlugRemote is NULL.\n"));
ASSERT(pAVCStrmExt->hPlugRemote != NULL);
return STATUS_UNSUCCESSFUL;
}
// Claim ownership of hMutexAVReqIsoch
KeWaitForMutexObject(&pAVCStrmExt->hMutexAVReq, Executive, KernelMode, FALSE, NULL);
pAVReq = &pAVCStrmExt->AVReq;
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_GetPlugState);
pAVReq->GetPlugState.hPlug = pAVCStrmExt->hPlugRemote;
Status =
SubmitIrpSynch(
DeviceObject,
pAVCStrmExt->pIrpAVReq,
pAVReq
);
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("GetPlugState Failed %x\n", Status));
}
else {
// Cache plug state (note: these are dynamic values)
pAVCStrmExt->RemotePlugState = pAVReq->GetPlugState;
TRACE(TL_61883_TRACE,("GetPlugState: ST %x; State %x; DRate %d; Payld %d; BCCnt %d; PPCnt %d\n",
pAVReq->Flags ,
pAVReq->GetPlugState.State,
pAVReq->GetPlugState.DataRate,
pAVReq->GetPlugState.Payload,
pAVReq->GetPlugState.BC_Connections,
pAVReq->GetPlugState.PP_Connections
));
}
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
EXIT("AVCStrmGetPlugState", Status);
return Status;
}
NTSTATUS
AVCStrmMakeConnection(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
Make an isoch connection.
--*/
{
NTSTATUS Status;
PAV_61883_REQUEST pAVReq;
PAVCSTRM_FORMAT_INFO pAVCStrmFormatInfo;
PAGED_CODE();
ENTER("AVCStrmMakeConnection");
// Claim ownership of hMutexAVReqIsoch
KeWaitForMutexObject(&pAVCStrmExt->hMutexAVReq, Executive, KernelMode, FALSE, NULL);
TRACE(TL_61883_TRACE,("MakeConnect: State:%d; hConnect:%x\n", pAVCStrmExt->StreamState, pAVCStrmExt->hConnect));
if(pAVCStrmExt->hConnect) {
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
return STATUS_SUCCESS;
}
Status = STATUS_SUCCESS;
pAVCStrmFormatInfo = pAVCStrmExt->pAVCStrmFormatInfo;
pAVReq = &pAVCStrmExt->AVReq;
INIT_61883_HEADER(pAVReq, Av61883_Connect);
pAVReq->Connect.Type = CMP_PointToPoint; // !!
// see which way we the data will flow...
if(pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT) {
// Remote(oPCR)->Local(iPCR)
pAVReq->Connect.hOutputPlug = pAVCStrmExt->hPlugRemote;
pAVReq->Connect.hInputPlug = pAVCStrmExt->hPlugLocal;
// Other parameters !!
} else {
// Remote(iPCR)<-Local(oPCR)
pAVReq->Connect.hOutputPlug = pAVCStrmExt->hPlugLocal;
pAVReq->Connect.hInputPlug = pAVCStrmExt->hPlugRemote;
pAVReq->Connect.Format.FMT = (UCHAR) pAVCStrmFormatInfo->cipHdr2.FMT; // From AV/C in/outpug plug signal format status cmd
// 00 for NTSC, 80 for PAL; set the 50/60 bit
// From AV/C in/outpug plug signal format status cmd
pAVReq->Connect.Format.FDF_hi =
((UCHAR) pAVCStrmFormatInfo->cipHdr2.F5060_OR_TSF << 7) |
((UCHAR) pAVCStrmFormatInfo->cipHdr2.STYPE << 2) |
((UCHAR) pAVCStrmFormatInfo->cipHdr2.RSV);
//
// 16bit SYT field = 4BitCycleCount:12BitCycleOffset;
// Will be set by 61883
//
pAVReq->Connect.Format.FDF_mid = 0;
pAVReq->Connect.Format.FDF_lo = 0;
//
// Constants depend on the A/V data format (in or out plug format)
//
pAVReq->Connect.Format.bHeader = (BOOL) pAVCStrmFormatInfo->cipHdr1.SPH;
pAVReq->Connect.Format.Padding = (UCHAR) pAVCStrmFormatInfo->cipHdr1.QPC;
pAVReq->Connect.Format.BlockSize = (UCHAR) pAVCStrmFormatInfo->cipHdr1.DBS;
pAVReq->Connect.Format.Fraction = (UCHAR) pAVCStrmFormatInfo->cipHdr1.FN;
}
pAVReq->Connect.Format.BlockPeriod = pAVCStrmFormatInfo->BlockPeriod;
TRACE(TL_61883_TRACE,("Connect:hOutPlg:%x<->hInPlug:%x; cipQuad2[%.2x:%.2x:%.2x:%.2x]; BlkSz %d; SrcPkt %d; AvgTm %d, BlkPrd %d\n",
pAVReq->Connect.hOutputPlug,
pAVReq->Connect.hInputPlug,
pAVReq->Connect.Format.FMT,
pAVReq->Connect.Format.FDF_hi,
pAVReq->Connect.Format.FDF_mid,
pAVReq->Connect.Format.FDF_lo,
pAVReq->Connect.Format.BlockSize,
pAVCStrmFormatInfo->SrcPacketsPerFrame,
pAVCStrmFormatInfo->AvgTimePerFrame,
pAVReq->Connect.Format.BlockPeriod
));
Status =
SubmitIrpSynch(
DeviceObject,
pAVCStrmExt->pIrpAVReq,
pAVReq
);
if(!NT_SUCCESS(Status)) {
TRACE(TL_61883_ERROR,("Connect Failed = 0x%x\n", Status));
pAVCStrmExt->hConnect = NULL;
}
else {
TRACE(TL_61883_TRACE,("hConnect = 0x%x\n", pAVReq->Connect.hConnect));
pAVCStrmExt->hConnect = pAVReq->Connect.hConnect;
}
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
EXIT("AVCStrmMakeConnection", Status);
return Status;
}
NTSTATUS
AVCStrmBreakConnection(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
Break the isoch connection.
--*/
{
NTSTATUS Status;
PAV_61883_REQUEST pAVReq;
#if DBG
PAVC_STREAM_DATA_STRUCT pDataStruc;
#endif
PAGED_CODE();
ENTER("AVCStrmBreakConnection");
// Claim ownership of hMutexAVReqIsoch
KeWaitForMutexObject(&pAVCStrmExt->hMutexAVReq, Executive, KernelMode, FALSE, NULL);
TRACE(TL_STRM_TRACE,("BreakConnect: State:%d; hConnect:%x\n", pAVCStrmExt->StreamState, pAVCStrmExt->hConnect));
if(!pAVCStrmExt->hConnect) {
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
return STATUS_SUCCESS;
}
Status = STATUS_SUCCESS;
#if DBG
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
#endif
pAVReq = &pAVCStrmExt->AVReq;
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_Disconnect);
pAVReq->Disconnect.hConnect = pAVCStrmExt->hConnect;
Status =
SubmitIrpSynch(
DeviceObject,
pAVCStrmExt->pIrpAVReq,
pAVReq
);
// This could be caused that the connection was not P2P, and
// it tried to disconnect.
if(!NT_SUCCESS(Status) || Status == STATUS_NO_SUCH_DEVICE) {
TRACE(TL_61883_ERROR,("Disconnect Failed:%x; AvReq->ST %x\n", Status, pAVReq->Flags ));
} else {
TRACE(TL_61883_TRACE,("Disconnect suceeded; ST %x; AvReq->ST %x\n", Status, pAVReq->Flags ));
}
TRACE(TL_STRM_WARNING,("*** DisConn St:%x; Stat: DataRcved:%d; [Pic# =? Prcs:Drp:Cncl] [%d ?=%d+%d+%d]\n",
Status,
(DWORD) pDataStruc->cntDataReceived,
(DWORD) pDataStruc->PictureNumber,
(DWORD) pDataStruc->FramesProcessed,
(DWORD) pDataStruc->FramesDropped,
(DWORD) pDataStruc->cntFrameCancelled
));
// We will not have another chance to reconnect it so we assume it is disconnected.
pAVCStrmExt->hConnect = NULL;
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
EXIT("AVCStrmBreakConnection", Status);
return Status;
}
NTSTATUS
AVCStrmStartIsoch(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
Start streaming.
--*/
{
NTSTATUS Status;
PAVC_STREAM_DATA_STRUCT pDataStruc;
PAGED_CODE();
ENTER("AVCStrmStartIsoch");
// Claim ownership of hMutexAVReqIsoch
KeWaitForMutexObject(&pAVCStrmExt->hMutexAVReq, Executive, KernelMode, FALSE, NULL);
if(pAVCStrmExt->IsochIsActive) {
TRACE(TL_STRM_WARNING,("Isoch already active!"));
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
return STATUS_SUCCESS;
}
if(!pAVCStrmExt->hConnect) {
ASSERT(pAVCStrmExt->hConnect && "Cannot start isoch while graph is not connected!\n");
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
return STATUS_INVALID_PARAMETER;
}
Status = STATUS_SUCCESS;
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
TRACE(TL_61883_TRACE,("StartIsoch: flow %d; AQD [%d:%d:%d]\n", pAVCStrmExt->DataFlow, pDataStruc->cntDataAttached, pDataStruc->cntDataQueued, pDataStruc->cntDataDetached));
RtlZeroMemory(&pAVCStrmExt->AVReq, sizeof(AV_61883_REQUEST));
if(pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT) {
INIT_61883_HEADER(&pAVCStrmExt->AVReq, Av61883_Listen);
pAVCStrmExt->AVReq.Listen.hConnect = pAVCStrmExt->hConnect;
} else {
INIT_61883_HEADER(&pAVCStrmExt->AVReq, Av61883_Talk);
pAVCStrmExt->AVReq.Talk.hConnect = pAVCStrmExt->hConnect;
if(pAVCStrmExt->pAVCStrmFormatInfo->AVCStrmFormat == AVCSTRM_FORMAT_MPEG2TS)
pAVCStrmExt->AVReq.Flags = CIP_TALK_DOUBLE_BUFFER | CIP_TALK_USE_SPH_TIMESTAMP;
}
Status =
SubmitIrpSynch(
DeviceObject,
pAVCStrmExt->pIrpAVReq,
&pAVCStrmExt->AVReq
);
if (NT_SUCCESS(Status)) {
pAVCStrmExt->IsochIsActive = TRUE;
TRACE(TL_61883_TRACE,("Av61883_%s; Status %x; Streaming...\n", (pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT ? "Listen" : "Talk"), Status));
}
else {
TRACE(TL_61883_ERROR,("Av61883_%s; failed %x\n", (pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT ? "Listen" : "Talk"), Status));
ASSERT(NT_SUCCESS(Status) && "Start isoch failed!");
}
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
EXIT("AVCStrmStartIsoch", Status);
return Status;
}
//
// This wait is based on testing transmitting MPEG2TS data with up to 32 date request.
// Each data request has 256 MPEG2TS data packets. There is a slow motion mode,
// and it may take longer for video to be transmitted in the slow motion mode.
//
#define MAX_ATTACH_WAIT 50000000 // max wait time in seconds
VOID
AVCStrmWaitUntilAttachedAreCompleted(
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
{
KIRQL oldIrql;
PAVC_STREAM_DATA_STRUCT pDataStruc;
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
//
// Wait until attached data to complete transmission before aborting (cancel) them
//
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
if( pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_IN
&& pDataStruc->cntDataAttached > 0
) {
LARGE_INTEGER tmMaxWait;
NTSTATUS StatusWait;
#if DBG
ULONGLONG tmStart;
#endif
TRACE(TL_STRM_TRACE,("StopIsoch: MaxWait %d (msec) for %d data buffer to finished transmitting!\n",
MAX_ATTACH_WAIT/10000, pDataStruc->cntDataAttached));
//
// This event will be signalled when all attach buffers are returned.
// It is protected by Spinlock for common data pDataStruc->cntDataAttached.
//
KeClearEvent(&pDataStruc->hNoAttachEvent);
#if DBG
tmStart = GetSystemTime();
#endif
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
tmMaxWait = RtlConvertLongToLargeInteger(-(MAX_ATTACH_WAIT));
StatusWait =
KeWaitForSingleObject(
&pDataStruc->hNoAttachEvent,
Executive,
KernelMode,
FALSE,
&tmMaxWait
);
if(StatusWait == STATUS_TIMEOUT) {
TRACE(TL_STRM_ERROR,("TIMEOUT (%d msec) on hNoAttachEvent! DataRcv:%d; AQD [%d:%d:%d]\n",
(DWORD) (GetSystemTime()-tmStart)/10000,
(DWORD) pDataStruc->cntDataReceived,
pAVCStrmExt->pAVCStrmDataStruc->cntDataAttached,
pAVCStrmExt->pAVCStrmDataStruc->cntDataQueued,
pAVCStrmExt->pAVCStrmDataStruc->cntDataDetached
));
} else {
TRACE(TL_STRM_WARNING,("Status:%x; (%d msec) on hNoAttachEvent. DataRcv:%d; AQD [%d:%d:%d]\n",
StatusWait,
(DWORD) (GetSystemTime()-tmStart)/10000,
(DWORD) pDataStruc->cntDataReceived,
pAVCStrmExt->pAVCStrmDataStruc->cntDataAttached,
pAVCStrmExt->pAVCStrmDataStruc->cntDataQueued,
pAVCStrmExt->pAVCStrmDataStruc->cntDataDetached
));
}
} else {
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
}
}
NTSTATUS
AVCStrmStopIsoch(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
Stop streaming.
--*/
{
NTSTATUS Status;
PAVC_STREAM_DATA_STRUCT pDataStruc;
PAGED_CODE();
ENTER("AVCStrmStopIsoch");
// Claim ownership of hMutexAVReqIsoch
KeWaitForMutexObject(&pAVCStrmExt->hMutexAVReq, Executive, KernelMode, FALSE, NULL);
if(!pAVCStrmExt->IsochIsActive) {
TRACE(TL_STRM_WARNING|TL_61883_WARNING,("Isoch already not active!"));
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
return STATUS_SUCCESS;
}
if(!pAVCStrmExt->hConnect) {
ASSERT(pAVCStrmExt->hConnect && "Cannot stop isoch while graph is not connected!\n");
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
return STATUS_INVALID_PARAMETER;
}
Status = STATUS_SUCCESS;
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
TRACE(TL_STRM_TRACE,("IsochSTOP; flow %d; AQD [%d:%d:%d]\n", pAVCStrmExt->DataFlow, pDataStruc->cntDataAttached, pDataStruc->cntDataQueued, pDataStruc->cntDataDetached));
RtlZeroMemory(&pAVCStrmExt->AVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(&pAVCStrmExt->AVReq, Av61883_Stop);
pAVCStrmExt->AVReq.Listen.hConnect = pAVCStrmExt->hConnect;
Status =
SubmitIrpSynch(
DeviceObject,
pAVCStrmExt->pIrpAVReq,
&pAVCStrmExt->AVReq
);
if (NT_SUCCESS(Status) || Status == STATUS_NO_SUCH_DEVICE) {
TRACE(TL_61883_TRACE,("Av61883_%s; Status %x; Stopped...\n", (pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT ? "Listen" : "Talk"), Status));
} else {
TRACE(TL_61883_ERROR,("Av61883_%s; failed %x\n", (pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT ? "Listen" : "Talk"), Status));
ASSERT(NT_SUCCESS(Status) && "Stop isoch failed!");
}
// Assume isoch is stopped regardless of the return status.
pAVCStrmExt->IsochIsActive = FALSE;
KeReleaseMutex(&pAVCStrmExt->hMutexAVReq, FALSE);
EXIT("AVCStrmStopIsoch", Status);
return Status;
}
/******************************
* Streaming utility funcrtions
*******************************/
//
// GetSystemTime in 100 nS units
//
ULONGLONG GetSystemTime()
{
LARGE_INTEGER rate, ticks;
ticks = KeQueryPerformanceCounter(&rate);
return (KSCONVERT_PERFORMANCE_TIME(rate.QuadPart, ticks));
}
///
// The "signature" of the header section of Seq0 of incoming source packets:
//
// "Blue" book, Part2, 11.4 (page 50); Figure 66, table 36 (page 111)
//
// ID0 = {SCT2,SCT1,SCT0,RSV,Seq3,Seq2,Seq1,Seq0}
//
// SCT2-0 = {0,0,0} = Header Section Type
// RSV = {1}
// Seq3-0 = {1,1,1,1} for NoInfo or {0,0,0,} for Sequence 0
//
// ID1 = {DSeq3-0, 0, RSV, RSV, RSV}
// DSeq3-0 = {0, 0, 0, 0} = Beginning of a DV frame
//
// ID2 = {DBN7,DBN6,DBN5,DBN4,DBN3,DBN2,DBN1,DBN0}
// DBB7-0 = {0,0,0,0,0,0,0,0,0} = Beginning of a DV frame
//
#define DIF_BLK_ID0_SCT_MASK 0xe0 // 11100000b; Section Type (SCT)2-0 are all 0's for the Header section
#define DIF_BLK_ID1_DSEQ_MASK 0xf0 // 11110000b; DIF Sequence Number(DSEQ)3-0 are all 0's
#define DIF_BLK_ID2_DBN_MASK 0xff // 11111111b; Data Block Number (DBN)7-0 are all 0's
#define DIF_HEADER_DSF 0x80 // 10000000b; DSF=0; 10 DIF Sequences (525-60)
// DSF=1; 12 DIF Sequences (625-50)
#define DIF_HEADER_TFn 0x80 // 10000000b; TFn=0; DIF bloick of area N are transmitted in the current DIF sequence.
// TFn=1; DIF bloick of area N are NOT transmitted in the current DIF sequence.
ULONG
AVCStrmDVReadFrameValidate(
IN PCIP_VALIDATE_INFO pInfo
)
/*++
Routine Description:
Used to validate the header section of a frame. so 61883 will start filling data for a DVFrame.
Note: This routine apply only to DV ONLY.
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
) {
// 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] & 0x80) ||
(pInfo->Packet[6] & 0x80) ||
(pInfo->Packet[7] & 0x80)
) {
TRACE(TL_CIP_TRACE,("inv src pkts; [%x %x %d %x], [%x %x %x %x]\n",
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;
}
return 0;
}
else {
return 1;
}
}
else {
TRACE(TL_CIP_ERROR,("Validate: invalid SrcPktSeq; Packet %x\n", pInfo->Packet));
return 1;
}
} // DVReadFrameValidate
NTSTATUS
AVCStrmProcessReadComplete(
PAVCSTRM_DATA_ENTRY pDataEntry,
PAVC_STREAM_EXTENSION pAVCStrmExt,
PAVC_STREAM_DATA_STRUCT pDataStruc
)
/*++
Routine Description:
Process the data read completion.
--*/
{
PKSSTREAM_HEADER pStrmHeader;
LONGLONG LastPictureNumber;
NTSTATUS Status = STATUS_SUCCESS;
pStrmHeader = pDataEntry->StreamHeader;
ASSERT(pStrmHeader->Size >= sizeof(KSSTREAM_HEADER));
// Check CIP_STATUS from 61883
// CIP_STATUS_CORRUPT_FRAME (0x00000001)
if(pDataEntry->Frame->Status & CIP_STATUS_CORRUPT_FRAME) {
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("CIP_STATUS_CORRUPT_FRAME\n"));
pStrmHeader->OptionsFlags = 0;
Status = STATUS_SUCCESS; // Success but no data !
pStrmHeader->DataUsed = 0;
pDataStruc->PictureNumber++; pDataStruc->FramesProcessed++;
}
else
// CIP_STATUS_SUCCESS (0x00000000)
// CIP_STATUS_FIRST_FRAME (0x00000002)
if(pDataEntry->Frame->Status == CIP_STATUS_SUCCESS ||
pDataEntry->Frame->Status & CIP_STATUS_FIRST_FRAME) {
// Only increment FramesProcessed if it is a valid frame;
pDataStruc->FramesProcessed++;
Status = STATUS_SUCCESS;
pStrmHeader->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
#ifdef NT51_61883
pStrmHeader->DataUsed = pDataEntry->Frame->CompletedBytes;
#else
pStrmHeader->DataUsed = pAVCStrmExt->pAVCStrmDataStruc->FrameSize;
#endif
// This subunit driver is a Master clock
if (pDataEntry->ClockProvider) {
#ifdef NT51_61883
ULONG ulDeltaCycleCounts;
// If not the first frame. we will calculate the drop frame information.
if(pAVCStrmExt->b1stNewFrameFromPauseState) {
// Default number of packets for a DV frame
if(pDataStruc->FramesProcessed > 1) // PAUSE->RUN->PAUSE->RUN case; no increase for the 1st frame.
pDataStruc->CurrentStreamTime += pAVCStrmExt->pAVCStrmFormatInfo->AvgTimePerFrame;
pAVCStrmExt->b1stNewFrameFromPauseState = FALSE;
} else {
ULONG ulCycleCount16bits;
// Calculate skipped 1394 cycle from the returned CycleTime
VALIDATE_CYCLE_COUNTS(pDataEntry->Frame->Timestamp);
ulCycleCount16bits = CALCULATE_CYCLE_COUNTS(pDataEntry->Frame->Timestamp);
ulDeltaCycleCounts = CALCULATE_DELTA_CYCLE_COUNT(pAVCStrmExt->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;
// There are two cases for drop frames: (1) Starve of buffer; (2) no data
// If there is starving, status will be CIP_STATUS_FIRST_FRAME.
if(pDataEntry->Frame->Status & CIP_STATUS_FIRST_FRAME) {
// Convert packets (cycles) to time in 100 nanosecond unit; (one cycle = 1250 * 100 nsec)
// We could use the skip frame, but CycleCount is more accurate.
pDataStruc->CurrentStreamTime += ulDeltaCycleCounts * TIME_PER_CYCLE; // Use cycle count to be precise.
} else {
// Ignore all "drop frames" in the "no data" case
if(ulDeltaCycleCounts * TIME_PER_CYCLE > pAVCStrmExt->pAVCStrmFormatInfo->AvgTimePerFrame)
// There might be some frame(s) skipped due to no data or tape stopped playing, we skip this skipped data.
pDataStruc->CurrentStreamTime += pAVCStrmExt->pAVCStrmFormatInfo->AvgTimePerFrame;
else
pDataStruc->CurrentStreamTime += ulDeltaCycleCounts * TIME_PER_CYCLE; // Use cycle count to be precise.
}
}
// StreamTime start with 0;
pStrmHeader->PresentationTime.Time = pDataStruc->CurrentStreamTime;
// Use to adjust the queried stream time
pAVCStrmExt->LastSystemTime = GetSystemTime();
// Cache current CycleCount
pAVCStrmExt->CycleCount16bits = CALCULATE_CYCLE_COUNTS(pDataEntry->Frame->Timestamp);
#else // NT51_61883
// This is the old way when 61883 was not returning the correct CycleTime.
// This is the old way when 61883 was not returning the correct CycleTime.
pStrmHeader->PresentationTime.Time = pDataStruc->CurrentStreamTime;
pAVCStrmExt->LastSystemTime = GetSystemTime(); // Use to adjust the queried stream time
pDataStruc->CurrentStreamTime += pAVCStrmExt->pAVCStrmFormatInfo->AvgTimePerFrame;
#endif // NT51_61883
// no Clock so "free flowing!"
} else {
pStrmHeader->PresentationTime.Time = 0;
}
// Put in Timestamp info depending on clock provider
pStrmHeader->PresentationTime.Numerator = 1;
pStrmHeader->PresentationTime.Denominator = 1;
// 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.
//
// Here, we know the current stream time, and the picture number is calculated from that.
//
if(pDataEntry->ClockProvider) {
pStrmHeader->Duration =
pAVCStrmExt->pAVCStrmFormatInfo->AvgTimePerFrame;
pStrmHeader->OptionsFlags |=
(KSSTREAM_HEADER_OPTIONSF_TIMEVALID | // pStrmHeader->PresentationTime.Time is valid
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
if(pDataEntry->Frame->Status & CIP_STATUS_FIRST_FRAME)
pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
// 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 = pDataStruc->PictureNumber;
pDataStruc->PictureNumber =
1 + // Picture number start with 1.but PresetationTime start with 0.
(pStrmHeader->PresentationTime.Time + TIME_PER_CYCLE)
* (LONGLONG) GET_AVG_TIME_PER_FRAME_DENOM(pAVCStrmExt->pAVCStrmFormatInfo->AVCStrmFormat)
/ (LONGLONG) GET_AVG_TIME_PER_FRAME_NUM(pAVCStrmExt->pAVCStrmFormatInfo->AVCStrmFormat);
if(pDataStruc->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) pDataStruc->PictureNumber, (DWORD) pStrmHeader->PresentationTime.Time));
}
if(pDataStruc->PictureNumber <= LastPictureNumber) {
TRACE(TL_STRM_TRACE|TL_CIP_TRACE,("Same pic #:%d; LastPic:%d; tmPres:%d; OptionFlags:%x\n",
(DWORD) pDataStruc->PictureNumber,
(DWORD) LastPictureNumber,
(DWORD) pStrmHeader->PresentationTime.Time,
pStrmHeader->OptionsFlags));
pDataStruc->PictureNumber = LastPictureNumber + 1; // Picture number must progress !!!!
}
pDataStruc->FramesDropped = pDataStruc->PictureNumber - pDataStruc->FramesProcessed;
// no Clock so "free flowing!"
} else {
pStrmHeader->Duration = 0; // No clock so not valid.
pDataStruc->PictureNumber++;
TRACE(TL_STRM_TRACE,("No clock: PicNum:%d\n", (DWORD) pDataStruc->PictureNumber));
}
}
else {
// 61883 has not defined this yet!
pStrmHeader->OptionsFlags = 0;
Status = STATUS_SUCCESS;
pStrmHeader->DataUsed = 0;
pDataStruc->PictureNumber++; pDataStruc->FramesProcessed++;
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("Unexpected Frame->Status %x\n", pDataEntry->Frame->Status));
ASSERT(FALSE && "Unknown pDataEntry->Frame->Status");
}
#if 0
// For VidOnly which uses VideoInfoHeader and has
// an extended frame information (KS_FRAME_INFO) appended to KSSTREAM_HEADER
if(pStrmHeader->Size >= (sizeof(KSSTREAM_HEADER) + sizeof(PKS_FRAME_INFO)) ) {
pFrameInfo = (PKS_FRAME_INFO) (pStrmHeader + 1);
pFrameInfo->ExtendedHeaderSize = sizeof(KS_FRAME_INFO);
pFrameInfo->PictureNumber = pDataStruc->PictureNumber;
pFrameInfo->DropCount = pDataStruc->FramesDropped;
pFrameInfo->dwFrameFlags =
KS_VIDEO_FLAG_FRAME | // Complete frame
KS_VIDEO_FLAG_I_FRAME; // Every DV frame is an I frame
}
#endif
#if DBG
// Validate that the data is return in the right sequence
if(pDataEntry->FrameNumber != pDataStruc->FramesProcessed) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("ProcessRead: OOSequence %d != %d\n", (DWORD) pDataEntry->FrameNumber, (DWORD) pDataStruc->FramesProcessed));
};
#endif
return Status;
}
ULONG
AVCStrmCompleteRead(
PCIP_NOTIFY_INFO pInfo
)
/*++
Routine Description:
61883 has completed receiving data and callback to us to complete.
--*/
{
PAVCSTRM_DATA_ENTRY pDataEntry;
PAVC_STREAM_EXTENSION pAVCStrmExt;
PAVC_STREAM_DATA_STRUCT pDataStruc;
KIRQL oldIrql;
// Callback and in DISPATCH_LEVEL
// The called might have acquired spinlock as well!
TRACE(TL_STRM_INFO,("CompleteRead: pInfo:%x\n", pInfo));
pDataEntry = pInfo->Context;
if(!pDataEntry) {
ASSERT(pDataEntry && "Context is NULL!\n");
return 1;
}
pAVCStrmExt = pDataEntry->pAVCStrmExt;
if(!pAVCStrmExt) {
ASSERT(pAVCStrmExt && "pAVCStrmExt is NULL\n");
return 1;
}
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
if(!pDataStruc) {
ASSERT(pDataStruc && "pDataStruc is NULL\n");
return 1;
}
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
#if DBG
// It is possible that a buffer is completed before it is return from IoCallDriver to attach this buffer.
if(!IsStateSet(pDataEntry->State, DE_IRP_LOWER_ATTACHED_COMPLETED)) {
TRACE(TL_STRM_WARNING,("AVCStrmCompleteRead: pDataEntry:%x not yet attached but completed.\n", pDataEntry));
//
// This irp will be completed from its IoCallDriver to attach this frame.
//
}
#endif
// Can the cancel routione is ahead of us? Error condition.
if(pDataStruc->cntDataAttached <= 0) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("AVCStrmCompleteRead:pAVCStrmExt:%x, pDataEntry:%x, AQD[%d:%d:%d]\n",
pAVCStrmExt, pDataEntry, pDataStruc->cntDataAttached, pDataStruc->cntDataQueued,pDataStruc->cntDataDetached));
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
return 1;
}
//
// Process this completion based on the return status from 61883
//
pDataEntry->pIrpUpper->IoStatus.Status =
AVCStrmProcessReadComplete(
pDataEntry,
pAVCStrmExt,
pDataStruc
);
//
// There are two possible ways to complete the data request:
//
// (A) Normal case: attach data request (pIrpLower), attached completed, notify callback (here), and completion (pIrpUpper)
// (B) Rare/stress case: attach data request (pIrpLower), notify callback (here), attach complete (pIrpLower), and complete (pIrpUpper)
//
pDataEntry->State |= DE_IRP_LOWER_CALLBACK_COMPLETED;
//
// Case (A): If DE_IRP_LOWER_CALLBACK_COMPLETED is set and pIrpUpper is marked pending, complete the UpperIrp.
//
if(IsStateSet(pDataEntry->State, DE_IRP_LOWER_ATTACHED_COMPLETED)) {
if(IsStateSet(pDataEntry->State, DE_IRP_UPPER_PENDING_COMPLETED)) {
//
// This is the normal case: attached, IoMarkPending, then complete in the callback routine.
//
IoCompleteRequest( pDataEntry->pIrpUpper, IO_NO_INCREMENT ); pDataEntry->State |= DE_IRP_UPPER_COMPLETED;
//
// Transfer from attach to detach list
//
RemoveEntryList(&pDataEntry->ListEntry); InterlockedDecrement(&pDataStruc->cntDataAttached);
#if DBG
if(pDataStruc->cntDataAttached < 0) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("pDataStruc:%x; pDataEntry:%x\n", pDataStruc, pDataEntry));
ASSERT(pDataStruc->cntDataAttached >= 0);
}
#endif
InsertTailList(&pDataStruc->DataDetachedListHead, &pDataEntry->ListEntry); InterlockedIncrement(&pDataStruc->cntDataDetached);
//
// pDataEntry should not be referenced after this.
//
} else {
TRACE(TL_STRM_TRACE,("Watch out! pDataEntry:%x in between attach complete and IoMarkIrpPending!\n", pDataEntry));
//
// Case (B): Complete IrpUpper when return to IoCallDriver(IrpLower)
// Note: The IrpLower has not called IoMarkIrpPending(). (Protected with spinlock)
//
}
} else {
//
// Case (B): Complete IrpUpper when return to IoCallDriver(IrpLower)
//
}
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
return 0;
} // AVCStrmCompleteRead
#if DBG
PAVCSTRM_DATA_ENTRY pLastDataEntry;
LONGLONG LastFrameNumber;
#endif
ULONG
AVCStrmCompleteWrite(
PCIP_NOTIFY_INFO pInfo
)
/*++
Routine Description:
61883 has completed receiving data and callback to us to complete.
--*/
{
PAVCSTRM_DATA_ENTRY pDataEntry;
PAVC_STREAM_EXTENSION pAVCStrmExt;
PAVC_STREAM_DATA_STRUCT pDataStruc;
NTSTATUS irpStatus;
KIRQL oldIrql;
// Callback and in DISPATCH_LEVEL
// The called might have acquired spinlock as well!
TRACE(TL_STRM_INFO,("CompleteWrite: pInfo:%x\n", pInfo));
pDataEntry = pInfo->Context;
if(!pDataEntry) {
ASSERT(pDataEntry && "Context is NULL!\n");
return 1;
}
pAVCStrmExt = pDataEntry->pAVCStrmExt;
if(!pAVCStrmExt) {
ASSERT(pAVCStrmExt && "pAVCStrmExt is NULL\n");
return 1;
}
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
if(!pDataStruc) {
ASSERT(pDataStruc && "pDataStruc is NULL\n");
return 1;
}
#if 0 // Must complete it!
// If isoch is not active, then we are in the process of stopping; Let this be cancellable.
if(!pAVCStrmExt->IsochIsActive) {
TRACE(TL_STRM_ERROR,("AVCStrmCompleteRead: IsochActive:%d; pDataEntry:%x\n", pAVCStrmExt->IsochIsActive, pDataEntry));
ASSERT(pAVCStrmExt->IsochIsActive);
return 1;
}
#endif
irpStatus = STATUS_SUCCESS;
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
#if DBG
// It is possible that a buffer is completed before it is return from IoCallDriver to attach this buffer.
if(!IsStateSet(pDataEntry->State, DE_IRP_LOWER_ATTACHED_COMPLETED)) {
TRACE(TL_STRM_WARNING,("CompleteWrite: pDataEntry:%x not yet attached but completed.\n", pDataEntry));
//
// This irp will be completed from its IoCallDriver to attach this frame.
//
}
#endif
// Can the cancel routione is ahead of us? Error condition.
if(pDataStruc->cntDataAttached <= 0) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("AVCStrmCompleteWrite:pAVCStrmExt:%x, pDataEntry:%x, AQD[%d:%d:%d]\n",
pAVCStrmExt, pDataEntry, pDataStruc->cntDataAttached, pDataStruc->cntDataQueued,pDataStruc->cntDataDetached));
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
return 1;
}
//
// Process according to status for the frame
//
if(pDataEntry->Frame->Status & CIP_STATUS_CORRUPT_FRAME) {
pDataStruc->FramesProcessed++;
TRACE(TL_CIP_ERROR,("CIP_STATUS_CORRUPT_FRAME; pIrpUpper:%x; pIrpLower:%x\n", pDataEntry->pIrpUpper, pDataEntry->pIrpLower));
} else
if(pDataEntry->Frame->Status == CIP_STATUS_SUCCESS ||
pDataEntry->Frame->Status & CIP_STATUS_FIRST_FRAME) {
#if DBG
if(pDataEntry->Frame->Status & CIP_STATUS_FIRST_FRAME)
TRACE(TL_CIP_TRACE,("CIP_STATUS_FIRST_FRAME; pIrpUpper:%x; pIrpLower:%x\n", pDataEntry->pIrpUpper, pDataEntry->pIrpLower));
#endif
pDataStruc->FramesProcessed++;
} else {
pDataStruc->FramesProcessed++;
TRACE(TL_CIP_ERROR,("Unknown Status:%x\n", pDataEntry->Frame->Status));
}
pDataStruc->PictureNumber++;
#if DBG
//
// Validate that the data is return in the right sequence
//
if(pDataEntry->FrameNumber != pDataStruc->FramesProcessed) {
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("CompleteWrite: OOSequence FrameNum:%d != FrameProcessed:%d; pIrpUpper:%x; pIrpLower:%x; Last(%d:%x,%x)\n",
(DWORD) pDataEntry->FrameNumber, (DWORD) pDataStruc->FramesProcessed,
pDataEntry->pIrpUpper, pDataEntry->pIrpLower,
(DWORD) pLastDataEntry->FrameNumber, pLastDataEntry->pIrpUpper, pLastDataEntry->pIrpLower
));
// ASSERT(pDataEntry->FrameNumber == pDataStruc->FramesProcessed);
};
pLastDataEntry = pDataEntry;
LastFrameNumber = pDataEntry->FrameNumber;
#endif
//
// There are two possible ways to complete the data request:
//
// (A) Normal case: attach data request (pIrpLower), attached completed, notify callback (here), and completion (pIrpUpper)
// (B) Rare/stress case: attach data request (pIrpLower), notify callback (here), attach complete (pIrpLower), and complete (pIrpUpper)
//
pDataEntry->pIrpUpper->IoStatus.Status = irpStatus;
pDataEntry->State |= DE_IRP_LOWER_CALLBACK_COMPLETED;
//
// Case (A): If DE_IRP_LOWER_CALLBACK_COMPLETED is set and pIrpUpper is marked pending, complete the UpperIrp.
//
if(IsStateSet(pDataEntry->State, DE_IRP_LOWER_ATTACHED_COMPLETED)) {
if(IsStateSet(pDataEntry->State, DE_IRP_UPPER_PENDING_COMPLETED)) {
//
// This is the normal case: attached, IoMarkPending, then complete in the callback routine.
//
IoCompleteRequest( pDataEntry->pIrpUpper, IO_NO_INCREMENT ); pDataEntry->State |= DE_IRP_UPPER_COMPLETED;
//
// Transfer from attach to detach list
//
RemoveEntryList(&pDataEntry->ListEntry); InterlockedDecrement(&pDataStruc->cntDataAttached);
//
// Signal when there is no more data buffer attached.
//
if(pDataStruc->cntDataAttached == 0)
KeSetEvent(&pDataStruc->hNoAttachEvent, 0, FALSE);
#if DBG
if(pDataStruc->cntDataAttached < 0) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("pDataStruc:%x; pDataEntry:%x\n", pDataStruc, pDataEntry));
ASSERT(pDataStruc->cntDataAttached >= 0);
}
#endif
InsertTailList(&pDataStruc->DataDetachedListHead, &pDataEntry->ListEntry); InterlockedIncrement(&pDataStruc->cntDataDetached);
//
// pDataEntry should not be referenced after this.
//
} else {
TRACE(TL_STRM_TRACE,("Watch out! pDataEntry:%x in between attach complete and IoMarkIrpPending!\n", pDataEntry));
//
// Case (B): Complete IrpUpper when return to IoCallDriver(IrpLower);
// Note: The IrpLower has not called IoMarkIrpPending(). (Protected with spinlock)
//
}
} else {
//
// Case (B): Complete IrpUpper when return to IoCallDriver(IrpLower)
//
}
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
return 0;
} // AVCStrmCompleteWrite
NTSTATUS
AVCStrmAttachFrameCR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PAVCSTRM_DATA_ENTRY pDataEntry
)
/*++
Routine Description:
Completion routine for attaching a data request to 61883.
--*/
{
PAVC_STREAM_EXTENSION pAVCStrmExt;
PAVC_STREAM_DATA_STRUCT pDataStruc;
KIRQL oldIrql;
PAGED_CODE();
pAVCStrmExt = pDataEntry->pAVCStrmExt;
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
//
// Check for possible attaching data request error
//
if(!NT_SUCCESS(pIrp->IoStatus.Status)) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("AttachFrameCR: pDataEntry:%x; pIrp->IoStatus.Status:%x (Error!)\n", pDataEntry, pIrp->IoStatus.Status));
ASSERT(NT_SUCCESS(pIrp->IoStatus.Status));
pDataEntry->State |= DE_IRP_ERROR;
//
// If attach data request has failed, we complete the pIrpUpper with this error.
//
pDataEntry->pIrpUpper->IoStatus.Status = pIrp->IoStatus.Status; // or should we cancel (STATUS_CANCELLED) it?
IoCompleteRequest( pDataEntry->pIrpUpper, IO_NO_INCREMENT ); pDataEntry->State |= DE_IRP_UPPER_COMPLETED;
//
// Transfer from attach to detach list
//
RemoveEntryList(&pDataEntry->ListEntry); InterlockedDecrement(&pDataStruc->cntDataAttached);
//
// Signal completion event when all attached are completed.
//
if(pAVCStrmExt->DataFlow != KSPIN_DATAFLOW_IN && pDataStruc->cntDataAttached == 0)
KeSetEvent(&pDataStruc->hNoAttachEvent, 0, FALSE);
ASSERT(pDataStruc->cntDataAttached >= 0);
InsertTailList(&pDataStruc->DataDetachedListHead, &pDataEntry->ListEntry); InterlockedIncrement(&pDataStruc->cntDataDetached);
//
// No additional processing when return to IoCallDriver() with the error pIrp->IoStatus.Status.
//
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
return STATUS_MORE_PROCESSING_REQUIRED;
}
#if DBG
//
// Validate that the data is attached in the right sequence
//
pDataStruc->FramesAttached++;
if(pDataEntry->FrameNumber != pDataStruc->FramesAttached) {
TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("Attached completed OOSequence FrameNum:%d != FrameAttached:%d; pIrpUpper:%x; pIrpLower:%x; Last(%d:%x,%x)\n",
(DWORD) pDataEntry->FrameNumber, (DWORD) pDataStruc->FramesAttached
));
// ASSERT(pDataEntry->FrameNumber == pDataStruc->FramesAttached);
};
#endif
//
// Attached data reuqest to 61883 is completed (note: however, we do not know if callback is called.)
//
pDataEntry->State |= DE_IRP_LOWER_ATTACHED_COMPLETED;
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
AVCStrmFormatAttachFrame(
IN KSPIN_DATAFLOW DataFlow,
IN PAVC_STREAM_EXTENSION pAVCStrmExt,
IN AVCSTRM_FORMAT AVCStrmFormat,
IN PAV_61883_REQUEST pAVReq,
IN PAVCSTRM_DATA_ENTRY pDataEntry,
IN ULONG ulSourcePacketSize, // Packet length in bytes
IN ULONG ulFrameSize, // Buffer size; may contain one or multiple source packets
IN PIRP pIrpUpper,
IN PKSSTREAM_HEADER StreamHeader,
IN PVOID FrameBuffer
)
/*++
Routine Description:
Format an attach frame request.
--*/
{
InitializeListHead(&pDataEntry->ListEntry);
// A DataEntry must be previously completed!
ASSERT(IsStateSet(pDataEntry->State, DE_IRP_UPPER_COMPLETED) && "Reusing a data entry that was not completed!");
pDataEntry->State = DE_PREPARED; // Initial state of a resued DataEntry (start over!)
pDataEntry->pAVCStrmExt = pAVCStrmExt;
pDataEntry->pIrpUpper = pIrpUpper;
pDataEntry->StreamHeader = StreamHeader;
pDataEntry->FrameBuffer = FrameBuffer;
ASSERT(pDataEntry->FrameBuffer != NULL);
pDataEntry->Frame->pNext = NULL;
pDataEntry->Frame->Status = 0;
pDataEntry->Frame->Packet = (PUCHAR) FrameBuffer;
#if DBG
pDataEntry->FrameNumber = pAVCStrmExt->pAVCStrmDataStruc->cntDataReceived;
#endif
pDataEntry->Frame->Flags = 0;
if(DataFlow == KSPIN_DATAFLOW_OUT) {
// DV needs validation to determine the header section as the start of a DV frame
if(AVCStrmFormat == AVCSTRM_FORMAT_SDDV_NTSC ||
AVCStrmFormat == AVCSTRM_FORMAT_SDDV_PAL ||
AVCStrmFormat == AVCSTRM_FORMAT_HDDV_NTSC ||
AVCStrmFormat == AVCSTRM_FORMAT_HDDV_PAL ||
AVCStrmFormat == AVCSTRM_FORMAT_SDLDV_NTSC ||
AVCStrmFormat == AVCSTRM_FORMAT_SDLDV_PAL ) {
pDataEntry->Frame->pfnValidate = AVCStrmDVReadFrameValidate; // use to validate the 1st source packet
#ifdef NT51_61883
//
// 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)
//
pDataEntry->Frame->Flags |= ( CIP_VALIDATE_FIRST_SOURCE
| CIP_RESET_FRAME_ON_DISCONTINUITY); // Reset buffer pointer when encounter discontinuity
#endif
} else {
// MPEG2 specific flags
pDataEntry->Frame->pfnValidate = NULL;
if(pAVCStrmExt->pAVCStrmFormatInfo->OptionFlags & AVCSTRM_FORMAT_OPTION_STRIP_SPH)
pDataEntry->Frame->Flags |= CIP_STRIP_SOURCE_HEADER;
}
pDataEntry->Frame->ValidateContext = pDataEntry;
pDataEntry->Frame->pfnNotify = AVCStrmCompleteRead;
}
else {
// DV needs validation to determine the header section as the start of a DV frame
if(AVCStrmFormat == AVCSTRM_FORMAT_SDDV_NTSC ||
AVCStrmFormat == AVCSTRM_FORMAT_SDDV_PAL ||
AVCStrmFormat == AVCSTRM_FORMAT_HDDV_NTSC ||
AVCStrmFormat == AVCSTRM_FORMAT_HDDV_PAL ||
AVCStrmFormat == AVCSTRM_FORMAT_SDLDV_NTSC ||
AVCStrmFormat == AVCSTRM_FORMAT_SDLDV_PAL ) {
pDataEntry->Frame->Flags |= CIP_DV_STYLE_SYT;
}
else {
// MPEG2 specific flag
}
pDataEntry->Frame->pfnValidate = NULL;
pDataEntry->Frame->ValidateContext = NULL;
pDataEntry->Frame->pfnNotify = AVCStrmCompleteWrite;
}
pDataEntry->Frame->NotifyContext = pDataEntry;
//
// Av61883_AttachFrames
//
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_AttachFrame);
pAVReq->AttachFrame.hConnect = pAVCStrmExt->hConnect;
pAVReq->AttachFrame.FrameLength = ulFrameSize;
pAVReq->AttachFrame.SourceLength = ulSourcePacketSize;
pAVReq->AttachFrame.Frame = pDataEntry->Frame;
TRACE(TL_STRM_TRACE,("DataFlow:%d; pDataEntry:%x; pIrpUp:%x; hConnect:%x; FrameSz:%d; SrcPktSz:%d; Frame:%x;\n pfnVldt:(%x, %x); pfnNtfy:(%x, %x) \n", DataFlow,
pDataEntry, pIrpUpper, pAVCStrmExt->hConnect, ulFrameSize, ulSourcePacketSize, pDataEntry->Frame,
pAVReq->AttachFrame.Frame->pfnValidate, pAVReq->AttachFrame.Frame->ValidateContext,
pAVReq->AttachFrame.Frame->pfnNotify, pAVReq->AttachFrame.Frame->NotifyContext));
ASSERT(pAVCStrmExt->hConnect);
}
NTSTATUS
AVCStrmCancelOnePacketCR(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrpLower,
IN PAVCSTRM_DATA_ENTRY pDataEntry
)
/*++
Routine Description:
Completion routine for detach an isoch descriptor associate with a pending IO.
Will cancel the pending IO here if detaching descriptor has suceeded.
--*/
{
PAVC_STREAM_EXTENSION pAVCStrmExt;
PAVC_STREAM_DATA_STRUCT pDataStruc;
KIRQL oldIrql;
ENTER("AVCStrmCancelOnePacketCR");
if(!pDataEntry) {
ASSERT(pDataEntry);
return STATUS_MORE_PROCESSING_REQUIRED;
}
pAVCStrmExt = pDataEntry->pAVCStrmExt;
ASSERT(pAVCStrmExt);
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
ASSERT(pDataStruc);
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
if(!NT_SUCCESS(pIrpLower->IoStatus.Status)) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("CancelOnePacketCR: pIrpLower->IoStatus.Status %x (Error!)\n", pIrpLower->IoStatus.Status));
ASSERT(pIrpLower->IoStatus.Status != STATUS_NOT_FOUND); // Catch lost packet!
pDataEntry->State |= DE_IRP_ERROR;
//
// Even though there is an error, but we have a valid DataEntry.
// Go ahead complete and cancel it.
//
}
#ifdef NT51_61883
//
// Special case for MPEG2TS data since a data buffer contains multiple data packets
// (188*N or 192*N) in one data buffer. The first cancelled buffer may contain valid
// data packet that an application will need to completely present a video frame.
// So instead of cancelling it, it will be completed.
//
if( pAVCStrmExt->pAVCStrmFormatInfo->AVCStrmFormat == AVCSTRM_FORMAT_MPEG2TS
&& pDataEntry->Frame->CompletedBytes) {
pDataEntry->pIrpUpper->IoStatus.Status =
AVCStrmProcessReadComplete(
pDataEntry,
pAVCStrmExt,
pDataStruc
);
//
// CompletedBytes should be multiple of 188 or 192 bytes
//
ASSERT(pDataEntry->Frame->CompletedBytes % \
((pAVCStrmExt->pAVCStrmFormatInfo->OptionFlags & AVCSTRM_FORMAT_OPTION_STRIP_SPH) ? 188 : 192) == 0);
TRACE(TL_PNP_ERROR,("pDataEntry:%x; Cancelled buffer (MPEG2TS) has %d bytes; Status:%x\n",
pDataEntry, pDataEntry->Frame->CompletedBytes, pIrpLower->IoStatus.Status, pDataEntry->pIrpUpper->IoStatus.Status));
} else {
pDataStruc->cntFrameCancelled++;
pDataEntry->pIrpUpper->IoStatus.Status = STATUS_CANCELLED;
TRACE(TL_CIP_TRACE,("pDataEntry:%x; Cancelled buffer (MPEG2TS) has %d bytes; Status:%x\n",
pDataEntry, pDataEntry->Frame->CompletedBytes, pIrpLower->IoStatus.Status, pDataEntry->pIrpUpper->IoStatus.Status));
}
#else
pDataStruc->cntFrameCancelled++;
pDataEntry->pIrpUpper->IoStatus.Status = STATUS_CANCELLED;
#endif
IoCompleteRequest(pDataEntry->pIrpUpper, IO_NO_INCREMENT); pDataEntry->State |= DE_IRP_UPPER_COMPLETED;
pDataEntry->State |= DE_IRP_CANCELLED;
pDataEntry->pIrpUpper = NULL; // No more access of this!
//
// Note: pDataEntry is already dequed from DataAttachList
//
InsertTailList(&pDataStruc->DataDetachedListHead, &pDataEntry->ListEntry); InterlockedIncrement(&pDataStruc->cntDataDetached);
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
EXIT("AVCStrmCancelOnePacketCR", STATUS_MORE_PROCESSING_REQUIRED);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
AVCStrmCancelIO(
IN PDEVICE_OBJECT DeviceObject,
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
Cancel all pending IOs
--*/
{
NTSTATUS Status;
PAVC_STREAM_DATA_STRUCT pDataStruc;
KIRQL oldIrql;
PAVCSTRM_DATA_ENTRY pDataEntry;
PAV_61883_REQUEST pAVReq;
PIO_STACK_LOCATION NextIrpStack;
PAGED_CODE();
ENTER("AVCStrmCancelIO");
Status = STATUS_SUCCESS;
if(pAVCStrmExt->IsochIsActive) {
TRACE(TL_STRM_WARNING,("Isoch is active while trying to cancel IO!\n"));
// Try stop isoch and continue if success!
Status = AVCStrmStopIsoch(DeviceObject, pAVCStrmExt);
if(!NT_SUCCESS(Status) && Status != STATUS_NO_SUCH_DEVICE) {
TRACE(TL_STRM_ERROR,("Isoch stop failed! Cannnot cancelIO while isoch active.\n"));
return Status;
}
}
//
// Guard againt data attach completion
//
KeWaitForMutexObject(&pAVCStrmExt->hMutexControl, Executive, KernelMode, FALSE, NULL);
//
// Cancel all pending IOs
//
pDataStruc = pAVCStrmExt->pAVCStrmDataStruc;
TRACE(TL_STRM_WARNING,("CancelIO Starting: pDataStruc:%x; AQD [%d:%d:%d]\n", pDataStruc,
pDataStruc->cntDataAttached, pDataStruc->cntDataQueued, pDataStruc->cntDataDetached));
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
while (!IsListEmpty(&pDataStruc->DataAttachedListHead)) {
pDataEntry = (PAVCSTRM_DATA_ENTRY) \
RemoveHeadList(&pDataStruc->DataAttachedListHead); InterlockedDecrement(&pDataStruc->cntDataAttached);
#if DBG
if(!IsStateSet(pDataEntry->State, DE_IRP_LOWER_ATTACHED_COMPLETED)) {
TRACE(TL_STRM_ERROR|TL_CIP_ERROR,("CancelIO: pDataEntry:%x\n", pDataEntry));
// Must be already attached in order to cancel it.
ASSERT(IsStateSet(pDataEntry->State, DE_IRP_LOWER_ATTACHED_COMPLETED));
}
#endif
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
// Issue 61883 request to cancel this attach
pAVReq = &pDataEntry->AVReq;
RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
INIT_61883_HEADER(pAVReq, Av61883_CancelFrame);
pAVReq->CancelFrame.hConnect = pAVCStrmExt->hConnect;
pAVReq->CancelFrame.Frame = pDataEntry->Frame;
TRACE(TL_STRM_TRACE,("Canceling AttachList: pAvReq %x; pDataEntry:%x\n", pAVReq, pDataEntry));
NextIrpStack = IoGetNextIrpStackLocation(pDataEntry->pIrpLower);
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
NextIrpStack->Parameters.Others.Argument1 = pAVReq;
IoSetCompletionRoutine(
pDataEntry->pIrpLower,
AVCStrmCancelOnePacketCR,
pDataEntry,
TRUE,
TRUE,
TRUE
);
Status =
IoCallDriver(
DeviceObject,
pDataEntry->pIrpLower
);
ASSERT(Status == STATUS_PENDING || Status == STATUS_SUCCESS || Status == STATUS_NO_SUCH_DEVICE);
KeAcquireSpinLock(&pDataStruc->DataListLock, &oldIrql);
} // while
KeReleaseSpinLock(&pDataStruc->DataListLock, oldIrql);
TRACE(TL_61883_TRACE,("CancelIO complete: pDataStruc:%x; AQD [%d:%d:%d]\n", pDataStruc,
pDataStruc->cntDataAttached, pDataStruc->cntDataQueued, pDataStruc->cntDataDetached));
//
// Guard against data attach completion
//
KeReleaseMutex(&pAVCStrmExt->hMutexControl, FALSE);
EXIT("AVCStrmCancelIO", Status);
return Status;
}
NTSTATUS
AVCStrmValidateFormat(
PAVCSTRM_FORMAT_INFO pAVCFormatInfo
)
/*++
Routine Description:
Validate AVC format information.
--*/
{
NTSTATUS Status;
PAGED_CODE();
Status = STATUS_SUCCESS;
if(pAVCFormatInfo->SizeOfThisBlock != sizeof(AVCSTRM_FORMAT_INFO)) {
TRACE(TL_STRM_ERROR,("pAVCFormatInfo:%x; SizeOfThisBlock:%d != %d\n", pAVCFormatInfo, pAVCFormatInfo->SizeOfThisBlock, sizeof(AVCSTRM_FORMAT_INFO)));
ASSERT((pAVCFormatInfo->SizeOfThisBlock == sizeof(AVCSTRM_FORMAT_INFO)) && "Invalid format info parameter!");
return STATUS_INVALID_PARAMETER;
}
TRACE(TL_STRM_TRACE|TL_CIP_TRACE,("ValidateFormat: pAVCFormatInfo:%x; idx:%d; SrcPkt:%d; RcvBuf:%d; XmtBuf:%d; Strip:%d; AvgTm:%d; BlkPeriod:%d\n",
pAVCFormatInfo,
pAVCFormatInfo->AVCStrmFormat,
pAVCFormatInfo->SrcPacketsPerFrame,
pAVCFormatInfo->NumOfRcvBuffers,
pAVCFormatInfo->NumOfXmtBuffers,
pAVCFormatInfo->OptionFlags,
pAVCFormatInfo->AvgTimePerFrame,
pAVCFormatInfo->BlockPeriod
));
TRACE(TL_STRM_TRACE|TL_CIP_TRACE,("ValidateFormat: cip1(DBS:%d, FN:%x); cip2(FMT:%x, 50_60:%x, STYPE:%x, SYT:%x)\n",
pAVCFormatInfo->cipHdr1.DBS,
pAVCFormatInfo->cipHdr1.FN,
pAVCFormatInfo->cipHdr2.FMT,
pAVCFormatInfo->cipHdr2.F5060_OR_TSF,
pAVCFormatInfo->cipHdr2.STYPE,
pAVCFormatInfo->cipHdr2.SYT
));
if(pAVCFormatInfo->SrcPacketsPerFrame == 0 ||
(pAVCFormatInfo->NumOfRcvBuffers == 0 && pAVCFormatInfo->NumOfXmtBuffers == 0) ||
// pAVCFormatInfo->AvgTimePerFrame == 0 ||
pAVCFormatInfo->BlockPeriod == 0 ||
pAVCFormatInfo->cipHdr1.DBS == 0
) {
TRACE(TL_STRM_ERROR,("ValidateFormat: Invalid parametert!\n"));
return STATUS_INVALID_PARAMETER;
}
return Status;
}
NTSTATUS
AVCStrmAllocateQueues(
IN struct DEVICE_EXTENSION * pDevExt,
IN PAVC_STREAM_EXTENSION pAVCStrmExt,
IN KSPIN_DATAFLOW DataFlow,
IN PAVC_STREAM_DATA_STRUCT pDataStruc,
PAVCSTRM_FORMAT_INFO pAVCStrmFormatInfo
)
/*++
Routine Description:
Preallocated all nodes for the data queuding.
--*/
{
ULONG ulNumberOfNodes;
ULONG ulSizeOfOneNode; // Might combine multiple structures
ULONG ulSizeAllocated;
PBYTE pMemoryBlock;
PAVCSTRM_DATA_ENTRY pDataEntry;
ULONG i;
PCIP_HDR1 pCipHdr1;
PAGED_CODE();
ENTER("AVCStrmAllocateQueues");
//
// Pre-allcoate PC resource
//
ulNumberOfNodes = DataFlow == KSPIN_DATAFLOW_OUT ? \
pAVCStrmFormatInfo->NumOfRcvBuffers : pAVCStrmFormatInfo->NumOfXmtBuffers;
ASSERT(ulNumberOfNodes > 0);
ulSizeOfOneNode = sizeof(AVCSTRM_DATA_ENTRY) + sizeof(struct _CIP_FRAME);
ulSizeAllocated = ulNumberOfNodes * ulSizeOfOneNode;
pMemoryBlock = ExAllocatePool(NonPagedPool, ulSizeAllocated);
if(!pMemoryBlock) {
return STATUS_NO_MEMORY;
}
RtlZeroMemory(pMemoryBlock, ulSizeAllocated);
// Initialize data IO structure
InitializeListHead(&pDataStruc->DataAttachedListHead);
InitializeListHead(&pDataStruc->DataQueuedListHead);
InitializeListHead(&pDataStruc->DataDetachedListHead);
KeInitializeSpinLock(&pDataStruc->DataListLock);
KeInitializeEvent(&pDataStruc->hNoAttachEvent, NotificationEvent, FALSE);
// Cache it for freeing purpose;
pDataStruc->pMemoryBlock = pMemoryBlock;
pDataEntry = (PAVCSTRM_DATA_ENTRY) pMemoryBlock;
for (i=0; i < ulNumberOfNodes; i++) {
((PBYTE) pDataEntry->Frame) = ((PBYTE) pDataEntry) + sizeof(AVCSTRM_DATA_ENTRY);
pDataEntry->pIrpLower = IoAllocateIrp(pDevExt->physicalDevObj->StackSize, FALSE);
if(!pDataEntry->pIrpLower) {
while(!IsListEmpty(&pDataStruc->DataDetachedListHead)) {
pDataEntry = (PAVCSTRM_DATA_ENTRY) \
RemoveHeadList(&pDataStruc->DataDetachedListHead); InterlockedDecrement(&pDataStruc->cntDataDetached);
if(pDataEntry->pIrpLower) {
IoFreeIrp(pDataEntry->pIrpLower); pDataEntry->pIrpLower = NULL;
}
}
ExFreePool(pMemoryBlock); pMemoryBlock = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
pDataEntry->State = DE_IRP_UPPER_COMPLETED; // Inital state
InsertTailList(&pDataStruc->DataDetachedListHead, &pDataEntry->ListEntry); InterlockedIncrement(&pDataStruc->cntDataDetached);
((PBYTE) pDataEntry) += ulSizeOfOneNode;
}
pCipHdr1 = &pAVCStrmFormatInfo->cipHdr1;
// Calculate source packet size (if strip header, 4 bytes less).
pDataStruc->SourcePacketSize = \
pCipHdr1->DBS * 4 * (1 << pCipHdr1->FN) - \
((pAVCStrmFormatInfo->OptionFlags & AVCSTRM_FORMAT_OPTION_STRIP_SPH) ? 4 : 0);
pDataStruc->FrameSize = \
pDataStruc->SourcePacketSize * pAVCStrmFormatInfo->SrcPacketsPerFrame;
TRACE(TL_STRM_TRACE,("DBS:%d; FN:%d; SrcPktSz:%d; SrcPktPerFrame:%d; FrameSize:%d\n",
pCipHdr1->DBS, pCipHdr1->FN,
pDataStruc->SourcePacketSize, pAVCStrmFormatInfo->SrcPacketsPerFrame,
pDataStruc->FrameSize
));
TRACE(TL_STRM_TRACE,("pDataStruc:%x; A(%d,%x); Q(%d,%x); D(%d,%x)\n", pDataStruc,
pDataStruc->cntDataAttached, &pDataStruc->DataAttachedListHead,
pDataStruc->cntDataQueued, &pDataStruc->DataQueuedListHead,
pDataStruc->cntDataDetached, &pDataStruc->DataDetachedListHead
));
return STATUS_SUCCESS;
}
NTSTATUS
AVCStrmFreeQueues(
IN PAVC_STREAM_DATA_STRUCT pDataStruc
)
/*++
Routine Description:
Free nodes preallocated.
--*/
{
PAVCSTRM_DATA_ENTRY pDataEntry;
PAGED_CODE();
ENTER("AVCStrmFreeQueues");
while(!IsListEmpty(&pDataStruc->DataAttachedListHead)) {
pDataEntry = (PAVCSTRM_DATA_ENTRY) \
RemoveHeadList(&pDataStruc->DataAttachedListHead); InterlockedDecrement(&pDataStruc->cntDataAttached);
if(pDataEntry->pIrpLower) {
IoFreeIrp(pDataEntry->pIrpLower); pDataEntry->pIrpLower = NULL;
}
}
if(pDataStruc->cntDataAttached == 0) {
ExFreePool(pDataStruc->pMemoryBlock); pDataStruc->pMemoryBlock = NULL;
return STATUS_SUCCESS;
} else {
TRACE(TL_STRM_ERROR,("FreeQueue: pDataStruc:%x, cntDataAttached:%x\n", pDataStruc, pDataStruc->cntDataAttached));
ASSERT(pDataStruc->cntDataAttached == 0);
return STATUS_UNSUCCESSFUL;
}
}
void
AVCStrmAbortStreamingWorkItemRoutine(
#ifdef USE_WDM110 // Win2000 code base
// Extra parameter if using WDM10
PDEVICE_OBJECT DeviceObject,
#endif
IN PAVC_STREAM_EXTENSION pAVCStrmExt
)
/*++
Routine Description:
This work item routine will stop streaming and cancel all IOs while running at PASSIVE level.
--*/
{
PAGED_CODE();
ENTER("AVCStrmAbortStreamingWorkItemRoutine");
TRACE(TL_STRM_WARNING,("CancelWorkItem: StreamState:%d; lCancel:%d\n", pAVCStrmExt->StreamState, pAVCStrmExt->lAbortToken));
ASSERT(pAVCStrmExt->lAbortToken == 1);
#ifdef USE_WDM110 // Win2000 code base
ASSERT(pAVCStrmExt->pIoWorkItem);
#endif
if(pAVCStrmExt->StreamState == KSSTATE_STOP) {
ASSERT(pAVCStrmExt->StreamState == KSSTATE_STOP && "CancelWorkItem: Stream is already stopped!\n");
goto Done;
}
// Cancel all pending IOs
AVCStrmCancelIO(pAVCStrmExt->pDevExt->physicalDevObj, pAVCStrmExt);
Done:
#ifdef USE_WDM110 // Win2000 code base
// Release work item and release the cancel token
IoFreeWorkItem(pAVCStrmExt->pIoWorkItem); pAVCStrmExt->pIoWorkItem = NULL;
#endif
// Release token and indicate abort has completed.
InterlockedExchange(&pAVCStrmExt->lAbortToken, 0);
KeSetEvent(&pAVCStrmExt->hAbortDoneEvent, 0, FALSE);
}
/*****************************
* Property utility funcrtions
*****************************/
NTSTATUS
AVCStrmGetConnectionProperty(
IN struct DEVICE_EXTENSION * pDevExt,
IN PAVC_STREAM_EXTENSION pAVCStrmExt,
PSTREAM_PROPERTY_DESCRIPTOR pSPD,
PULONG pulActualBytesTransferred
)
/*++
Routine Description:
Handles KS_PROPERTY_CONNECTION* request. For now, only ALLOCATORFRAMING and
CONNECTION_STATE are supported.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
ENTER("AVCStrmGetConnectionProperty");
TRACE(TL_STRM_TRACE,("GetConnectionProperty: entered ...\n"));
switch (pSPD->Property->Id) {
case KSPROPERTY_CONNECTION_ALLOCATORFRAMING:
if (pDevExt != NULL && pDevExt->NumberOfStreams) {
PKSALLOCATOR_FRAMING pFraming = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo;
pFraming->RequirementsFlags =
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER |
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
pFraming->PoolType = NonPagedPool;
pFraming->Frames = \
pAVCStrmExt->DataFlow == KSPIN_DATAFLOW_OUT ? \
pAVCStrmExt->pAVCStrmFormatInfo->NumOfRcvBuffers : \
pAVCStrmExt->pAVCStrmFormatInfo->NumOfXmtBuffers;
// Note: we'll allocate the biggest frame. We need to make sure when we're
// passing the frame back up we also set the number of bytes in the frame.
pFraming->FrameSize = pAVCStrmExt->pAVCStrmDataStruc->FrameSize;
pFraming->FileAlignment = 0; // FILE_LONG_ALIGNMENT;
pFraming->Reserved = 0;
*pulActualBytesTransferred = sizeof (KSALLOCATOR_FRAMING);
TRACE(TL_STRM_TRACE,("*** AllocFraming: cntStrmOpen:%d; Frames %d; size:%d\n", \
pDevExt->NumberOfStreams, pFraming->Frames, pFraming->FrameSize));
} else {
TRACE(TL_STRM_ERROR,("*** AllocFraming: pDevExt:%x; cntStrmOpen:%d\n", pDevExt, pDevExt->NumberOfStreams));
Status = STATUS_INVALID_PARAMETER;
}
break;
default:
*pulActualBytesTransferred = 0;
Status = STATUS_NOT_SUPPORTED;
ASSERT(pSPD->Property->Id == KSPROPERTY_CONNECTION_ALLOCATORFRAMING);
break;
}
TRACE(TL_STRM_TRACE,("GetConnectionProperty: exit.\n"));
return Status;
}
NTSTATUS
AVCStrmGetDroppedFramesProperty(
IN struct DEVICE_EXTENSION * pDevExt,
IN PAVC_STREAM_EXTENSION pAVCStrmExt,
PSTREAM_PROPERTY_DESCRIPTOR pSPD,
PULONG pulBytesTransferred
)
/*++
Routine Description:
Return the dropped frame information while captureing.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
ENTER("AVCStrmGetDroppedFramesProperty");
switch (pSPD->Property->Id) {
case KSPROPERTY_DROPPEDFRAMES_CURRENT:
{
PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames =
(PKSPROPERTY_DROPPEDFRAMES_CURRENT_S) pSPD->PropertyInfo;
pDroppedFrames->AverageFrameSize = pAVCStrmExt->pAVCStrmDataStruc->FrameSize;
pDroppedFrames->PictureNumber = pAVCStrmExt->pAVCStrmDataStruc->PictureNumber;
pDroppedFrames->DropCount = pAVCStrmExt->pAVCStrmDataStruc->FramesDropped; // For transmit, this value includes both dropped and repeated.
TRACE(TL_STRM_TRACE,("*DroppedFP: Pic#(%d), Drp(%d)\n", (LONG) pDroppedFrames->PictureNumber, (LONG) pDroppedFrames->DropCount));
*pulBytesTransferred = sizeof (KSPROPERTY_DROPPEDFRAMES_CURRENT_S);
Status = STATUS_SUCCESS;
}
break;
default:
*pulBytesTransferred = 0;
Status = STATUS_NOT_SUPPORTED;
ASSERT(pSPD->Property->Id == KSPROPERTY_DROPPEDFRAMES_CURRENT);
break;
}
return Status;
}