|
|
/*++
Copyright (c) 1997 1998 PHILIPS I&C
Module Name: mcamdrv.c.c
Abstract: driver for the philips camera.
Author: Paul Oosterhof
Environment: Kernel mode only
Revision History:
Date Reason
Sept.22, 98 Optimized for NT5 Nov.30 , Frozen video frame for corrupted usb frames Nov.30 , properties added to deliver VID/PID actual used camera to app --*/
#include "mwarn.h"
#include "wdm.h"
#include "mcamdrv.h"
#include "strmini.h"
#include "mprpobj.h"
#include "mprpobjx.h"
#include "mprpftn.h"
#include "mcodec.h"
#include "mstreams.h"
#include "mssidef.h"
/*
* Local function definitions */ static USHORT MapFrPeriodFrRate(LONGLONG llFramePeriod);
static NTSTATUS PHILIPSCAM_SetFrRate_AltInterface(IN PVOID DeviceContext); /*
Here the mapping is defined to alternate interfaces dependent from picture format and framerate */ UCHAR InterfaceMap[9][10] = { // Size
//Framerate // CIF, QCIF, SQCIF, QQCIF, VGA, SIF, SSIF, QSIF, SQSIF, SCIF
/* VGA */ { 0 , 0 , 0 , 0, 1, 0 , 0 , 0 , 0 , 0 }, /* 3.75 */ { 4 , 0 , 0 , 0, 0, 4 , 4 , 0 , 0 , 4 }, /* 5 */ { 7 , 8 , 8 , 8, 0, 7 , 7 , 8 , 8 , 7 }, /* 7.5 */ { 6 , 7 , 7 , 7, 0, 6 , 6 , 7 , 7 , 6 }, /* 10 */ { 4 , 6 , 7 , 7, 0, 4 , 4 , 6 , 7 , 4 }, /* 12 */ { 3 , 5 , 6 , 6, 0, 3 , 3 , 5 , 6 , 3 }, /* 15 */ { 2 , 4 , 5 , 5, 0, 2 , 2 , 4 , 5 , 2 }, /* 20 */ { 0 , 1 , 3 , 3, 0, 0 , 0 , 1 , 3 , 0 }, /* 24 */ { 0 , 1 , 3 , 3, 0, 0 , 0 , 1 , 3 , 0 }, };
//QCIF20 alt.intfc. 2 is sufficient, however 20Fr/sec is asked as default by PM;
//to enable the user to select as well 24Fr/sec, also alt.intfc. 1 is selected
//SQCIF20 alt.intfc. 4 is sufficient, however 20Fr/sec is asked as default by PM;
//to enable the user to select as well 24Fr/sec, also alt.intfc. 3 is selected
ULONG PHILIPSCAM_DebugTraceLevel #ifdef MAX_DEBUG
= MAX_TRACE; #else
= MIN_TRACE; #endif
#ifndef mmioFOURCC
#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \ ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) ) #endif
KSPIN_MEDIUM StandardMedium = { STATIC_KSMEDIUMSETID_Standard, 0, 0 };
// ------------------------------------------------------------------------
// Property sets for all video capture streams
// ------------------------------------------------------------------------
DEFINE_KSPROPERTY_TABLE(VideoStreamConnectionProperties) { DEFINE_KSPROPERTY_ITEM ( KSPROPERTY_CONNECTION_ALLOCATORFRAMING, TRUE, // GetSupported or Handler
sizeof(KSPROPERTY), // MinProperty
sizeof(KSALLOCATOR_FRAMING), // MinData
FALSE, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
sizeof(ULONG) // SerializedSize
), };
DEFINE_KSPROPERTY_TABLE(VideoStreamDroppedFramesProperties) { DEFINE_KSPROPERTY_ITEM ( KSPROPERTY_DROPPEDFRAMES_CURRENT, TRUE, // GetSupported or Handler
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),// MinProperty
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),// MinData
FALSE, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
0 // SerializedSize
), };
// ------------------------------------------------------------------------
// Array of all of the property sets supported by video streams
// ------------------------------------------------------------------------
DEFINE_KSPROPERTY_SET_TABLE(VideoStreamProperties) { DEFINE_KSPROPERTY_SET ( &KSPROPSETID_Connection, // Set
SIZEOF_ARRAY(VideoStreamConnectionProperties), // PropertiesCount
VideoStreamConnectionProperties, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
), DEFINE_KSPROPERTY_SET ( &PROPSETID_VIDCAP_DROPPEDFRAMES, // Set
SIZEOF_ARRAY(VideoStreamDroppedFramesProperties), // PropertiesCount
VideoStreamDroppedFramesProperties, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
), }; #define NUMBER_VIDEO_STREAM_PROPERTIES (SIZEOF_ARRAY(VideoStreamProperties))
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_QCIF_I420 = STREAMFORMAT_QCIF_I420 ; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_CIF_I420 = STREAMFORMAT_CIF_I420; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SQCIF_I420 = STREAMFORMAT_SQCIF_I420; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_QQCIF_I420 = STREAMFORMAT_QQCIF_I420; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SIF_I420 = STREAMFORMAT_SIF_I420 ; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SSIF_I420 = STREAMFORMAT_SSIF_I420 ; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_QSIF_I420 = STREAMFORMAT_QSIF_I420 ; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SQSIF_I420 = STREAMFORMAT_SQSIF_I420 ; KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SCIF_I420 = STREAMFORMAT_SCIF_I420 ;
static PKSDATAFORMAT PHILIPSCAM_MovingStreamFormats[]={ (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_QCIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_CIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SQCIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_QQCIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SSIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_QSIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SQSIF_I420, (PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SCIF_I420 };
#define NUM_PHILIPSCAM_STREAM_FORMATS (SIZEOF_ARRAY(PHILIPSCAM_MovingStreamFormats))
//---------------------------------------------------------------------------
// Create an array that holds the list of all of the streams supported
//---------------------------------------------------------------------------
HW_STREAM_INFORMATION Streams [] = { // -----------------------------------------------------------------
// PHILIPSCAM_Moving_Stream
// -----------------------------------------------------------------
// HW_STREAM_INFORMATION -------------------------------------------
1, // NumberOfPossibleInstances
KSPIN_DATAFLOW_OUT, // DataFlow
TRUE, // DataAccessible
NUM_PHILIPSCAM_STREAM_FORMATS, // NumberOfFormatArrayEntries
PHILIPSCAM_MovingStreamFormats, // StreamFormatsArray
NULL, // ClassReserved[0]
NULL, // ClassReserved[1]
NULL, // ClassReserved[2]
NULL, // ClassReserved[3]
NUMBER_VIDEO_STREAM_PROPERTIES, // NumStreamPropArrayEntries
(PKSPROPERTY_SET) VideoStreamProperties,// StreamPropertiesArray
0, // NumStreamEventArrayEntries;
0, // StreamEventsArray;
(GUID *)&PINNAME_VIDEO_CAPTURE, // Category;
(GUID *)&PINNAME_VIDEO_CAPTURE, // Name;
0, // MediumsCount
&StandardMedium, // Mediums
FALSE, // BridgeStream
0, // Reserved[0]
0 // Reserved[1]
};
/*****************************************************************************/ /*****************************************************************************/ /************ Start of Function Blocks **********************/ /*****************************************************************************/ /*****************************************************************************/
/*
// This function searches the maximal framerate for a given picture format
// dependent from the USB bus load and selects the belonging alternate interface.
//
*/ NTSTATUS PHILIPSCAM_SetFrRate_AltInterface(IN PVOID DeviceContext){
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; NTSTATUS ntStatus = STATUS_SUCCESS; USHORT PhFormat = deviceContext->CamStatus.PictureFormat; USHORT PhFrameRate = deviceContext->CamStatus.PictureFrameRate; USHORT j;
// reset permitted framerates
for (j = FRRATEVGA; j <= FRRATE24; j++){ deviceContext->FrrSupported[j] = FALSE; } // set permitted framerates dependent on selected format and sensortype
switch (PhFormat) { case FORMATCIF: for ( j = FRRATE375 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATQCIF: for ( j = FRRATE5 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATSQCIF: for ( j = FRRATE5 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATQQCIF: for ( j = FRRATE5 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATSIF: for ( j = FRRATE375 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATSSIF: for ( j = FRRATE375 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATQSIF: for ( j = FRRATE5 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATSQSIF: for ( j = FRRATE5 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } break; case FORMATSCIF: for ( j = FRRATE375 ; j <= PhFrameRate; j++){ deviceContext->FrrSupported[j] = TRUE; } default: ; // no permitted framerates;
} // select framerate dependent on available USB bandwidth
ntStatus = STATUS_NOT_FOUND; for ( PhFrameRate ; (!NT_SUCCESS(ntStatus) && (PhFrameRate != FRRATEVGA)); PhFrameRate --) { if (deviceContext->FrrSupported[PhFrameRate]){ if ( InterfaceMap[PhFrameRate][PhFormat] != 0 ){ deviceContext->Interface->AlternateSetting = InterfaceMap[PhFrameRate][PhFormat]; ntStatus = USBCAMD_SelectAlternateInterface( deviceContext, deviceContext->Interface); } if (!NT_SUCCESS(ntStatus)){ deviceContext->FrrSupported[PhFrameRate]= FALSE; }else{ PHILIPSCAM_KdPrint (MIN_TRACE, ("Alt Setting # %d, Max.allowed FPS %s\n", InterfaceMap[PhFrameRate][PhFormat] , FRString(PhFrameRate))); deviceContext->CamStatus.PictureFrameRate = PhFrameRate ; } } } return ntStatus; }
/*
** AdapterCompareGUIDsAndFormatSize() ** ** Checks for a match on the three GUIDs and FormatSize ** ** Arguments: ** ** IN DataRange1 ** IN DataRange2 ** ** Returns: ** ** TRUE if all elements match ** FALSE if any are different ** ** Side Effects: none */
BOOLEAN AdapterCompareGUIDsAndFormatSize( IN PKSDATARANGE DataRange1, IN PKSDATARANGE DataRange2) { return ( IsEqualGUID ( &DataRange1->MajorFormat, &DataRange2->MajorFormat) && IsEqualGUID ( &DataRange1->SubFormat, &DataRange2->SubFormat) && IsEqualGUID ( &DataRange1->Specifier, &DataRange2->Specifier) && (DataRange1->FormatSize == DataRange2->FormatSize)); }
/*
** AdapterFormatFromRange() ** ** Returns a DATAFORMAT from a DATARANGE ** ** Arguments: ** ** IN PHW_STREAM_REQUEST_BLOCK pSrb ** ** Returns: ** ** STATUS_SUCCESS if format is supported ** ** Side Effects: none */
NTSTATUS AdapterFormatFromRange( IN PHW_STREAM_REQUEST_BLOCK Srb) { PSTREAM_DATA_INTERSECT_INFO intersectInfo; PKSDATARANGE dataRange; BOOL onlyWantsSize; ULONG formatSize = 0; ULONG streamNumber; ULONG j; ULONG numberOfFormatArrayEntries; PKSDATAFORMAT *availableFormats; NTSTATUS ntStatus = STATUS_NOT_FOUND; intersectInfo = Srb->CommandData.IntersectInfo; streamNumber = intersectInfo->StreamNumber; dataRange = intersectInfo->DataRange;
//
// Check that the stream number is valid
//
// ASSERT(streamNumber == 0);
numberOfFormatArrayEntries = Streams[0].NumberOfFormatArrayEntries;
//
// Get the pointer to the array of available formats
//
availableFormats = Streams[0].StreamFormatsArray;
//
// Is the caller trying to get the format, or the size of the format?
//
onlyWantsSize = (intersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG));
//
// Walk the formats supported by the stream searching for a match
// of the three GUIDs which together define a DATARANGE
//
for (j = 0; j < numberOfFormatArrayEntries; j++, availableFormats++) {
if (!AdapterCompareGUIDsAndFormatSize(dataRange, *availableFormats)) { // not the format we want
continue; }
//
// Now that the three GUIDs match, switch on the Specifier
// to do a further type specific check
//
// -------------------------------------------------------------------
// Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
// -------------------------------------------------------------------
if (IsEqualGUID (&dataRange->Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) {
PKS_DATARANGE_VIDEO dataRangeVideoToVerify = (PKS_DATARANGE_VIDEO) dataRange; PKS_DATARANGE_VIDEO dataRangeVideo = (PKS_DATARANGE_VIDEO) *availableFormats; PKS_DATAFORMAT_VIDEOINFOHEADER DataFormatVideoInfoHeaderOut; ULONG videoHeaderSize; ULONG rangeSize;
//
// Check that the other fields match
//
if ((dataRangeVideoToVerify->bFixedSizeSamples != dataRangeVideo->bFixedSizeSamples) || (dataRangeVideoToVerify->bTemporalCompression != dataRangeVideo->bTemporalCompression) || (dataRangeVideoToVerify->StreamDescriptionFlags != dataRangeVideo->StreamDescriptionFlags) || (dataRangeVideoToVerify->MemoryAllocationFlags != dataRangeVideo->MemoryAllocationFlags) || (RtlCompareMemory (&dataRangeVideoToVerify->ConfigCaps, &dataRangeVideo->ConfigCaps, sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) != sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))) { // not the format want
continue; }
if ((dataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biWidth != dataRangeVideo->VideoInfoHeader.bmiHeader.biWidth ) || (dataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biHeight != dataRangeVideo->VideoInfoHeader.bmiHeader.biHeight )) { continue; }
// Validate each step of the size calculations for arithmetic overflow,
// and verify that the specified sizes correlate
// (with unsigned math, a+b < b iff an arithmetic overflow occured)
videoHeaderSize = dataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biSize + FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader); rangeSize = videoHeaderSize + FIELD_OFFSET(KS_DATARANGE_VIDEO,VideoInfoHeader);
if (videoHeaderSize < FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader) || rangeSize < FIELD_OFFSET(KS_DATARANGE_VIDEO,VideoInfoHeader) || rangeSize > dataRangeVideoToVerify->DataRange.FormatSize) {
Srb->Status = ntStatus = STATUS_INVALID_PARAMETER; break; }
formatSize = sizeof(KSDATAFORMAT) + videoHeaderSize;
if (onlyWantsSize) { break; }
// Is the return buffer size = 0 ?
if(intersectInfo->SizeOfDataFormatBuffer == 0) {
ntStatus = Srb->Status = STATUS_BUFFER_OVERFLOW; // the proxy wants to know the actual buffer size to allocate.
Srb->ActualBytesTransferred = formatSize; break; } // Caller wants the full data format, make sure we have room
if (intersectInfo->SizeOfDataFormatBuffer < formatSize) { Srb->Status = ntStatus = STATUS_BUFFER_TOO_SMALL; break; }
DataFormatVideoInfoHeaderOut = (PKS_DATAFORMAT_VIDEOINFOHEADER) intersectInfo->DataFormatBuffer;
// Copy over the KSDATAFORMAT, followed by the
// actual VideoInfoHeader
RtlCopyMemory( &DataFormatVideoInfoHeaderOut->DataFormat, &dataRangeVideoToVerify->DataRange, sizeof (KSDATARANGE));
DataFormatVideoInfoHeaderOut->DataFormat.FormatSize = formatSize;
RtlCopyMemory( &DataFormatVideoInfoHeaderOut->VideoInfoHeader, &dataRangeVideoToVerify->VideoInfoHeader, videoHeaderSize);
// Calculate biSizeImage for this request, and put the result in both
// the biSizeImage field of the bmiHeader AND in the SampleSize field
// of the DataFormat.
//
// Note that for compressed sizes, this calculation will probably not
// be just width * height * bitdepth
DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader.biSizeImage = DataFormatVideoInfoHeaderOut->DataFormat.SampleSize = KS_DIBSIZE(DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader);
//
// Perform other validation such as cropping and scaling checks
//
// we will not allow setting FPS below our minimum FPS.
if ((DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame > dataRangeVideo->ConfigCaps.MaxFrameInterval) ) { DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame = dataRangeVideo->ConfigCaps.MaxFrameInterval; DataFormatVideoInfoHeaderOut->VideoInfoHeader.dwBitRate = dataRangeVideo->ConfigCaps.MinBitsPerSecond; }
// we will not allow setting FPS above our maximum FPS.
if ((DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame < dataRangeVideo->ConfigCaps.MinFrameInterval) ) { DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame = dataRangeVideo->ConfigCaps.MinFrameInterval; DataFormatVideoInfoHeaderOut->VideoInfoHeader.dwBitRate = dataRangeVideo->ConfigCaps.MaxBitsPerSecond; }
Srb->Status = ntStatus = STATUS_SUCCESS; break; }
} // End of loop on all formats for this stream
if (NT_SUCCESS(ntStatus)) { if (onlyWantsSize) { *(PULONG) intersectInfo->DataFormatBuffer = formatSize; Srb->ActualBytesTransferred = sizeof(ULONG); }else { Srb->ActualBytesTransferred = formatSize; } } return ntStatus; }
/*
** AdapterVerifyFormat() ** ** Checks the validity of a format request by walking through the ** array of supported KSDATA_RANGEs for a given stream. ** ** Arguments: ** ** pKSDataFormat - pointer of a KS_DATAFORMAT_VIDEOINFOHEADER structure. ** StreamNumber - index of the stream being queried / opened. ** ** Returns: ** ** TRUE if the format is supported ** FALSE if the format cannot be suppored ** ** Side Effects: none */
BOOL AdapterVerifyFormat( PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormatToVerify, int StreamNumber ) { PKSDATAFORMAT *pAvailableFormats; int NumberOfFormatArrayEntries; int j; // Make sure a format has been specified
if (!pKSDataFormatToVerify) { return FALSE; }
//
// Make sure the stream index is valid
//
if (StreamNumber >= 2 || StreamNumber < 0) { return FALSE; }
//
// How many formats does this stream support?
//
NumberOfFormatArrayEntries = Streams[StreamNumber].NumberOfFormatArrayEntries;
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: Stream=%d\n", StreamNumber));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: FormatSize=%d\n", pKSDataFormatToVerify->DataFormat.FormatSize));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: MajorFormat=%x\n", pKSDataFormatToVerify->DataFormat.MajorFormat));
//
// Get the pointer to the array of available formats
//
pAvailableFormats = Streams[StreamNumber].StreamFormatsArray;
//
// Walk the array, searching for a match
//
for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) {
PKS_DATARANGE_VIDEO pKSDataRange = (PKS_DATARANGE_VIDEO) *pAvailableFormats; PKS_VIDEOINFOHEADER pVideoInfoHdr = &pKSDataRange->VideoInfoHeader; KS_VIDEO_STREAM_CONFIG_CAPS *pConfigCaps = &pKSDataRange->ConfigCaps; //
// Check for matching size, Major Type, Sub Type, and Specifier
//
if (!IsEqualGUID (&pKSDataRange->DataRange.MajorFormat, &pKSDataFormatToVerify->DataFormat.MajorFormat)) { continue; } if (!IsEqualGUID (&pKSDataRange->DataRange.SubFormat, &pKSDataFormatToVerify->DataFormat.SubFormat)) { continue; }
if (!IsEqualGUID (&pKSDataRange->DataRange.Specifier, &pKSDataFormatToVerify->DataFormat.Specifier)) { continue; }
// -------------------------------------------------------------------
// Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
// -------------------------------------------------------------------
if (IsEqualGUID(&pKSDataRange->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) { PKS_VIDEOINFOHEADER pVideoInfoHdrToVerify;
if (pKSDataFormatToVerify->DataFormat.FormatSize < sizeof(KS_DATAFORMAT_VIDEOINFOHEADER)) { break; // considered a fatal error for this format
}
pVideoInfoHdrToVerify = &pKSDataFormatToVerify->VideoInfoHeader;
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: pVideoInfoHdrToVerify=%x\n", pVideoInfoHdrToVerify));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: Width=%d Height=%d biBitCount=%d\n", pVideoInfoHdrToVerify->bmiHeader.biWidth, pVideoInfoHdrToVerify->bmiHeader.biHeight, pVideoInfoHdrToVerify->bmiHeader.biBitCount));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: biSizeImage =%d\n", pVideoInfoHdrToVerify->bmiHeader.biSizeImage));
// Calculate the actual format buffer size (includes bmiHeader.biSize).
// Validate each step of the size calculations for arithmetic overflow,
// and verify that the specified sizes correlate
// (with unsigned math, a+b < b iff an arithmetic overflow occured).
{ ULONG VideoHeaderSize = pVideoInfoHdrToVerify->bmiHeader.biSize + FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader); ULONG FormatSize = VideoHeaderSize + FIELD_OFFSET(KS_DATAFORMAT_VIDEOINFOHEADER,VideoInfoHeader);
if (VideoHeaderSize < FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader) || FormatSize < FIELD_OFFSET(KS_DATAFORMAT_VIDEOINFOHEADER,VideoInfoHeader) || FormatSize > pKSDataFormatToVerify->DataFormat.FormatSize) {
break; // considered a fatal error for this format
} }
if ((pVideoInfoHdrToVerify->bmiHeader.biWidth != pVideoInfoHdr->bmiHeader.biWidth ) || (pVideoInfoHdrToVerify->bmiHeader.biHeight != pVideoInfoHdr->bmiHeader.biHeight )) { continue; }
if ( pVideoInfoHdrToVerify->bmiHeader.biSizeImage != pVideoInfoHdr->bmiHeader.biSizeImage || pVideoInfoHdrToVerify->bmiHeader.biSizeImage > pKSDataFormatToVerify->DataFormat.SampleSize) {
PHILIPSCAM_KdPrint (MIN_TRACE, ("***Error**:Format mismatch Width=%d Height=%d image size=%d\n", pVideoInfoHdrToVerify->bmiHeader.biWidth, pVideoInfoHdrToVerify->bmiHeader.biHeight, pVideoInfoHdrToVerify->bmiHeader.biSizeImage)); continue; }
//
// HOORAY, the format passed all of the tests, so we support it
//
return TRUE; } } //
// The format requested didn't match any of our listed ranges,
// so refuse the connection.
//
return FALSE;
}
//
// hooks for stream SRBs
//
VOID STREAMAPI PHILIPSCAM_ReceiveDataPacket( IN PHW_STREAM_REQUEST_BLOCK Srb, IN PVOID DeviceContext, IN PBOOLEAN Completed ) { // PHILIPSCAM_KdPrint (MAX_TRACE, ("P*_ReceiveDataPacket\n"));
}
VOID STREAMAPI PHILIPSCAM_ReceiveCtrlPacket( IN PHW_STREAM_REQUEST_BLOCK Srb, IN PVOID DeviceContext, IN PBOOLEAN Completed ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; PHILIPSCAM_KdPrint (ULTRA_TRACE, ("'PHILIPSCAM: Receive Ctrl SRB %x\n", Srb->Command)); *Completed = TRUE; Srb->Status = STATUS_SUCCESS;
switch (Srb->Command) {
case SRB_PROPOSE_DATA_FORMAT: PHILIPSCAM_KdPrint(MIN_TRACE, ("'Receiving SRB_PROPOSE_DATA_FORMAT SRB \n")); if ( !(AdapterVerifyFormat ( (PKS_DATAFORMAT_VIDEOINFOHEADER)Srb->CommandData.OpenFormat, Srb->StreamObject->StreamNumber))) { Srb->Status = STATUS_NO_MATCH; PHILIPSCAM_KdPrint(MIN_TRACE,("SRB_PROPOSE_DATA_FORMAT FAILED\n")); } break;
case SRB_SET_DATA_FORMAT: { PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormat = (PKS_DATAFORMAT_VIDEOINFOHEADER) Srb->CommandData.OpenFormat; PKS_VIDEOINFOHEADER pVideoInfoHdrRequested = &pKSDataFormat->VideoInfoHeader;
PHILIPSCAM_KdPrint(MIN_TRACE, ("'SRB_SET_DATA_FORMAT\n"));
if ((AdapterVerifyFormat(pKSDataFormat,Srb->StreamObject->StreamNumber))) { // if (deviceContext->UsbcamdInterface.USBCAMD_SetVideoFormat(DeviceContext,Srb)) {
// deviceContext->CurrentProperty.Format.lWidth =
// pVideoInfoHdrRequested->bmiHeader.biWidth;
// deviceContext->CurrentProperty.Format.lHeight =
// pVideoInfoHdrRequested->bmiHeader.biHeight;
// }
}else { Srb->Status = STATUS_NO_MATCH; PHILIPSCAM_KdPrint(MIN_TRACE,(" SRB_SET_DATA_FORMAT FAILED\n")); } } break; case SRB_GET_DATA_FORMAT: PHILIPSCAM_KdPrint(MIN_TRACE, ("' SRB_GET_DATA_FORMAT\n")); Srb->Status = STATUS_NOT_IMPLEMENTED; break;
case SRB_SET_STREAM_STATE:
case SRB_GET_STREAM_STATE:
case SRB_GET_STREAM_PROPERTY:
case SRB_SET_STREAM_PROPERTY:
case SRB_INDICATE_MASTER_CLOCK:
default:
*Completed = FALSE; // let USBCAMD handle these control SRBs
} if (*Completed == TRUE) { StreamClassStreamNotification(StreamRequestComplete,Srb->StreamObject,Srb); }
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_ReceiveCtrlPacket\n")); }
// **
// Describe the camera
//
USBCAMD_DEVICE_DATA PHILIPSCAM_DeviceData = { 0, PHILIPSCAM_Initialize, PHILIPSCAM_UnInitialize, PHILIPSCAM_ProcessUSBPacket, PHILIPSCAM_NewFrame, PHILIPSCAM_ProcessRawVideoFrame, PHILIPSCAM_StartVideoCapture, PHILIPSCAM_StopVideoCapture, PHILIPSCAM_Configure, PHILIPSCAM_SaveState, PHILIPSCAM_RestoreState, PHILIPSCAM_AllocateBandwidth, PHILIPSCAM_FreeBandwidth }; /* Function Caller
PHILIPSCAM_Initialize, USBCAMD.c : USBCAMD_ConfigureDevice() PHILIPSCAM_UnInitialize, USBCAMD.c : USBCAMD_RemoveDevice PHILIPSCAM_ProcessUSBPacket, iso.c : USBCAMD_TransferComplete() PHILIPSCAM_NewFrame, iso.c : USBCAMD_TransferComplete() PHILIPSCAM_ProcessRawVideoFrame, iso.c : USBCAMD_ProcessWorkItem() PHILIPSCAM_StartVideoCapture, USBCAMD.c : USBCAMD_PrepareChannel() reset.c USBCAMD_ResetPipes() PHILIPSCAM_StopVideoCapture, USBCAMD.c : USBCAMD_UnPrepareChannel() reset.c: USBCAMD_ResetPipes() PHILIPSCAM_Configure, USBCAMD.c : USBCAMD_SelectConfiguration() PHILIPSCAM_SaveState, PHILIPSCAM_RestoreState, PHILIPSCAM_AllocateBandwidth, <--+ USBCAMD.c : USBCAMD_PrepareChannel() -+ <--+ STREAM.c : AdapterOpenStream() -+ <--+ USBCAMD_AdapterReceivePacket(SRB = SRB_OPEN_STREAM) -+ PHILIPSCAM_FreeBandwidth USBCAMD.c : USBCAMD_UnPrepareChannel()
*/
VOID PHILIPSCAM_AdapterReceivePacket( IN PHW_STREAM_REQUEST_BLOCK Srb ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext; PHW_STREAM_INFORMATION streamInformation = &(Srb->CommandData.StreamBuffer->StreamInfo); PHW_STREAM_HEADER streamHeader = &(Srb->CommandData.StreamBuffer->StreamHeader); PDEVICE_OBJECT deviceObject; switch (Srb->Command) { case SRB_GET_STREAM_INFO: //
// this is a request for the driver to enumerate requested streams
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_GET_STREAM_INFO\n"));
// get our device ext. from USBCAMD.
deviceContext = USBCAMD_AdapterReceivePacket(Srb, NULL, NULL, FALSE); //
// we support one stream
//
streamHeader->NumberOfStreams = 1;
streamInformation->StreamFormatsArray = &PHILIPSCAM_MovingStreamFormats[0]; streamInformation->NumberOfFormatArrayEntries = Streams[0].NumberOfFormatArrayEntries; //
// set the property information for the video stream
//
streamHeader->DevicePropertiesArray = PHILIPSCAM_GetAdapterPropertyTable(&streamHeader-> NumDevPropArrayEntries) ;
// pass to usbcamd to finish the job
deviceContext = USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData, NULL, TRUE); ASSERT_DEVICE_CONTEXT(deviceContext); break;
case SRB_GET_DEVICE_PROPERTY: //
// we handle all the property stuff
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_GET_DEVICE_PROPERTY\n"));
deviceContext = USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData, &deviceObject, FALSE); ASSERT_DEVICE_CONTEXT(deviceContext);
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("SRB_GET_STREAM_INFO\n")); PHILIPSCAM_PropertyRequest( FALSE, deviceObject, deviceContext, Srb);
StreamClassDeviceNotification(DeviceRequestComplete, Srb->HwDeviceExtension, Srb); break; case SRB_SET_DEVICE_PROPERTY: //
// we handle all the property stuff
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_SET_DEVICE_PROPERTY\n"));
deviceContext = USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData, &deviceObject, FALSE); ASSERT_DEVICE_CONTEXT(deviceContext);
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("SRB_GET_STREAM_INFO\n")); PHILIPSCAM_PropertyRequest( TRUE, deviceObject, deviceContext, Srb);
StreamClassDeviceNotification(DeviceRequestComplete, Srb->HwDeviceExtension, Srb); break;
case SRB_OPEN_STREAM: { PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormat = (PKS_DATAFORMAT_VIDEOINFOHEADER) Srb->CommandData.OpenFormat; PKS_VIDEOINFOHEADER pVideoInfoHdrRequested = &pKSDataFormat->VideoInfoHeader; PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_OPEN_STREAM\n")); // pass to usbcamd to finish the job
Srb->StreamObject->ReceiveDataPacket = (PVOID) PHILIPSCAM_ReceiveDataPacket; Srb->StreamObject->ReceiveControlPacket = (PVOID) PHILIPSCAM_ReceiveCtrlPacket;
if (AdapterVerifyFormat(pKSDataFormat, Srb->StreamObject->StreamNumber)) { deviceContext = USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData, NULL, TRUE); // deviceContext->StreamOpen = TRUE;
}else{ Srb->Status = STATUS_INVALID_PARAMETER; StreamClassDeviceNotification(DeviceRequestComplete, Srb->HwDeviceExtension, Srb); } } break;
case SRB_GET_DATA_INTERSECTION: //
// Return a format, given a range
//
//deviceContext =
// USBCAMD_AdapterReceivePacket(Srb,
// &PHILIPSCAM_DeviceData,
// &deviceObject,
// FALSE);
PHILIPSCAM_KdPrint (MAX_TRACE, ("P*_AdapterReceivePacket: SRB_GET_DATA_INTERSECTION\n")); Srb->Status = AdapterFormatFromRange(Srb); StreamClassDeviceNotification(DeviceRequestComplete, Srb->HwDeviceExtension, Srb); break;
case SRB_CLOSE_STREAM: // close the specified stream
case SRB_CHANGE_POWER_STATE: // change power state
case SRB_SET_STREAM_RATE: // set the rate at which the stream should run
default: //
// let usbcamd handle it
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_HANDLED BY USBCAMD\n")); deviceContext = USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData, NULL, TRUE); ASSERT_DEVICE_CONTEXT(deviceContext); } }
/*
** DriverEntry() ** ** This routine is called when the mini driver is first loaded. The driver ** should then call the StreamClassRegisterAdapter function to register with ** the stream class driver ** ** Arguments: ** ** Context1: The context arguments are private plug and play structures ** used by the stream class driver to find the resources for this ** adapter ** Context2: ** ** Returns: ** ** This routine returns an NT_STATUS value indicating the result of the ** registration attempt. If a value other than STATUS_SUCCESS is returned, the ** minidriver will be unloaded. ** ** Side Effects: none */
ULONG DriverEntry( PVOID Context1, PVOID Context2 ){ PHILIPSCAM_KdPrint (MAX_TRACE, ("'Driver Entry\n")); return USBCAMD_DriverEntry(Context1, Context2, sizeof(PHILIPSCAM_DEVICE_CONTEXT), sizeof(PHILIPSCAM_FRAME_CONTEXT), PHILIPSCAM_AdapterReceivePacket); }
/*
** PHILIPSCAM_Initialize() ** ** On entry the device has been configured and the initial alt ** interface selected -- this is where we may send additional ** vendor commands to enable the device. ** ** Philips actions: ** 1. Find out what type of camera is available, VGA or medium-Res ** This has consequences for the available streamformats. ** ** Arguments: ** ** BusDeviceObject - pdo associated with this device ** ** DeviceContext - driver specific context ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_Initialize( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext=DeviceContext; NTSTATUS ntStatus = STATUS_SUCCESS; ASSERT_DEVICE_CONTEXT(deviceContext); //
// perform any hardware specific
// initialization
//
ntStatus = PHILIPSCAM_GetSensorType(deviceContext); if (NT_SUCCESS(ntStatus)) { ntStatus = PHILIPSCAM_GetReleaseNumber(deviceContext); } deviceContext->EmptyPacketCounter = 0; // (Initialize this counter)
if (NT_SUCCESS(ntStatus)) { ntStatus = PHILIPSCAM_InitPrpObj(deviceContext); } PHILIPSCAM_KdPrint (MIN_TRACE, ("'X P*_Initialize 0x%x\n", ntStatus)); ILOGENTRY("inHW", 0, 0, ntStatus); return ntStatus; }
/*
** PHILIPSCAM_UnInitialize() ** ** Assume the device hardware is gone -- all that needs to be done is to ** free any allocated resources (like memory). ** ** Arguments: ** ** BusDeviceObject - pdo associated with this device ** ** DeviceContext - driver specific context ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_UnInitialize( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext; NTSTATUS ntStatus = STATUS_SUCCESS;
deviceContext = DeviceContext; ASSERT_DEVICE_CONTEXT(deviceContext); if ( deviceContext->Interface) { ExFreePool(deviceContext->Interface); deviceContext->Interface = NULL; } PHILIPSCAM_KdPrint (MAX_TRACE, ("'P*_UnInitialize 0x%x\n", ntStatus)); return ntStatus; }
/*
** PHILIPSCAM_Configure() ** ** Configure the iso streaming Interface: ** ** Called just before the device is configured, this is where we tell ** usbcamd which interface and alternate setting to use for the idle state. ** ** NOTE: The assumption here is that the device will have a single interface ** with multiple alt settings and each alt setting has the same number of ** pipes. ** ** Arguments: ** ** BusDeviceObject - device object created by the hub whe can submit ** urbs to our device through this deviceObject ** ** DeviceContext - minidriver device context ** ** Interface - USBD interface structure initialized with the proper values ** for select_configuration. This Interface structure corresponds ** a single iso interafce on the device. This is the drivers ** chance to pick a particular alternate setting and pipe ** parameters. ** ** ** ConfigurationDescriptor - USB configuration Descriptor for ** this device. ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_Configure(IN PDEVICE_OBJECT BusDeviceObject, IN PVOID DeviceContext, IN OUT PUSBD_INTERFACE_INFORMATION Interface, IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN OUT PLONG DataPipeIndex, IN OUT PLONG SyncPipeIndex ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext; NTSTATUS ntStatus = STATUS_SUCCESS;
deviceContext = DeviceContext; deviceContext->Sig = PHILIPSCAM_DEVICE_SIG; //
// initilialize any other context stuff
//
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_Configure \n"));
if ( Interface == NULL) { //
// this is a signal from usbcamd that I need to free my previousely
// allocated space for interface descriptor due to error conditions
// during IRP_MN_START_DEVICE processing and driver will be unloaded soon.
//
if (deviceContext->Interface) { ExFreePool(deviceContext->Interface); deviceContext->Interface = NULL; } return ntStatus; }
deviceContext->Interface = ExAllocatePool(NonPagedPool, Interface->Length);
*DataPipeIndex = 1; *SyncPipeIndex = -1; // no sync pipe
if (deviceContext->Interface) { Interface->AlternateSetting = ALT_INTERFACE_0 ; // This interface has two pipes,
// initialize input parameters to USBD for both pipes.
// The MaximumTransferSize is the size of the largest
// buffer we want to submit for a single iso urb
// request.
//
Interface->Pipes[PHILIPSCAM_SYNC_PIPE].MaximumTransferSize = USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; // = PAGE SIZE ??
Interface->Pipes[PHILIPSCAM_DATA_PIPE].MaximumTransferSize = // 1024*32; // 32k transfer per urb ??
1024*198; // CIF: 352x288x16/8
RtlCopyMemory(deviceContext->Interface, Interface, Interface->Length); PHILIPSCAM_KdPrint (MAX_TRACE, ("'size of interface request = %d\n", Interface->Length)); }else{ ntStatus = STATUS_INSUFFICIENT_RESOURCES; } //
// return interface number and alternate setting
//
PHILIPSCAM_KdPrint (MIN_TRACE, ("'X P*_Configure 0x%x\n", ntStatus));
return ntStatus; }
/*
** PHILIPSCAM_StartVideoCapture() ** ** Arguments: ** ** BusDeviceObject - device object created by the hub we can submit ** urbs to our device through this deviceObject ** ** DeviceContext - minidriver device context ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_StartVideoCapture( IN PDEVICE_OBJECT BusDeviceObject, IN PVOID DeviceContext ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; NTSTATUS ntStatus= STATUS_SUCCESS; ASSERT_DEVICE_CONTEXT(deviceContext); //
// This is where we select the interface we need and send
// commands to start capturing
//
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_StartVideoCapture \n")); PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_StartVideocapture 0x%x\n", ntStatus));
return ntStatus; }
/*
** PHILIPSCAM_AllocateBandwidth() ** ** Called just before the iso video capture stream is ** started, here is where we select the appropriate ** alternate interface and set up the device to stream. ** ** Called in connection with the stream class RUN command ** ** Arguments: ** ** BusDeviceObject - device object created by the hub we can submit ** urbs to our device through this deviceObject ** ** DeviceContext - minidriver device context ** ** RawFrameLength - pointer to be filled in with size of buffer needed to ** receive the raw frame data from the packet stream. ** ** Format - pointer to PKS_DATAFORMAT_VIDEOINFOHEADER associated with this ** stream. ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_AllocateBandwidth( IN PDEVICE_OBJECT BusDeviceObject, IN PVOID DeviceContext, OUT PULONG RawFrameLength, IN PVOID Format ){ PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; NTSTATUS ntStatus = STATUS_SUCCESS; PKS_DATAFORMAT_VIDEOINFOHEADER pdataFormatHeader; PKS_BITMAPINFOHEADER bmInfoHeader; LONGLONG llDefaultFramePeriod ; USHORT usReqFrRate; ASSERT_DEVICE_CONTEXT(deviceContext); PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_AllocateBandwidth \n")); //
// This is where we select the interface we need and send
// commands to start capturing
//
*RawFrameLength = 0; pdataFormatHeader = Format; bmInfoHeader = &pdataFormatHeader->VideoInfoHeader.bmiHeader; // deviceContext->pSelectedStreamFormat = &pdataFormatHeader->DataFormat; // removed RMR
RtlCopyMemory (&deviceContext->CamStatus.PictureSubFormat, // added RMR
&pdataFormatHeader->DataFormat.SubFormat, sizeof (GUID));
PHILIPSCAM_KdPrint (MIN_TRACE, ("'req.format %d x %d\n", bmInfoHeader->biWidth, bmInfoHeader->biHeight));
switch (bmInfoHeader->biWidth) { case QQCIF_X: deviceContext->CamStatus.PictureFormat = FORMATQQCIF; *RawFrameLength = (SQCIF_X * SQCIF_Y * 12)/8; break; case SQCIF_X: deviceContext->CamStatus.PictureFormat = FORMATSQCIF; *RawFrameLength = (SQCIF_X * SQCIF_Y * 12)/8; break; case QCIF_X: deviceContext->CamStatus.PictureFormat = FORMATQCIF; *RawFrameLength = (QCIF_X * QCIF_Y * 12)/8; break; case CIF_X: deviceContext->CamStatus.PictureFormat = FORMATCIF; *RawFrameLength = (CIF_X * CIF_Y * 12)/8; break; case SQSIF_X: deviceContext->CamStatus.PictureFormat = FORMATSQSIF; *RawFrameLength = (SQCIF_X * SQCIF_Y * 12)/8; break; case QSIF_X: deviceContext->CamStatus.PictureFormat = FORMATQSIF; *RawFrameLength = (QCIF_X * QCIF_Y * 12)/8; break; case SSIF_X: if (bmInfoHeader->biHeight == SSIF_Y){ deviceContext->CamStatus.PictureFormat = FORMATSSIF; }else{ deviceContext->CamStatus.PictureFormat = FORMATSCIF; } *RawFrameLength = (CIF_X * CIF_Y * 12)/8; break; case SIF_X: deviceContext->CamStatus.PictureFormat = FORMATSIF; *RawFrameLength = (CIF_X * CIF_Y * 12)/8; break; default: deviceContext->CamStatus.PictureFormat = FORMATQCIF; *RawFrameLength = (QCIF_X * QCIF_Y * 12)/8; }
llDefaultFramePeriod = pdataFormatHeader->VideoInfoHeader.AvgTimePerFrame; // [100nS]
usReqFrRate = MapFrPeriodFrRate(llDefaultFramePeriod); deviceContext->CamStatus.PictureFrameRate = usReqFrRate;
PHILIPSCAM_KdPrint (MIN_TRACE,("Req.frperiod: %d us \n", llDefaultFramePeriod / 10)); PHILIPSCAM_KdPrint (MIN_TRACE,("Req.frperiod index: %d = %s fps\n", usReqFrRate, FRString(usReqFrRate)));
// Define framerate based on available USB=bandwidth
// if not suff.BW, frame rate is decreased.
ntStatus = PHILIPSCAM_SetFrRate_AltInterface(deviceContext);
// Send from here the format/framerate to the camera hardware:
if (NT_SUCCESS(ntStatus)) { ntStatus = PHILIPSCAM_SetFormatFramerate( deviceContext ); } if (NT_SUCCESS(ntStatus)) { ntStatus = PHILIPSCAM_StartCodec( deviceContext ); }
if (NT_SUCCESS(ntStatus)) { deviceContext->FrameLength = *RawFrameLength; } PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_AllocateBandwidth 0x%x\n", ntStatus));
return ntStatus; }
/*
** PHILIPSCAM_FreeBandwidth() ** ** Called after the iso video stream is stopped, this is where we ** select an alternate interface that uses no bandwidth. ** ** Arguments: ** ** BusDeviceObject - device object created by the hub we can submit ** urbs to our device through this deviceObject ** ** DeviceContext - minidriver device context ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */ NTSTATUS PHILIPSCAM_FreeBandwidth( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ){ NTSTATUS ntStatus; PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; // turn off streaming on the device
ASSERT_DEVICE_CONTEXT(deviceContext); ntStatus = PHILIPSCAM_StopCodec(deviceContext); deviceContext->Interface->AlternateSetting = ALT_INTERFACE_0 ; ntStatus = USBCAMD_SelectAlternateInterface( deviceContext, deviceContext->Interface);
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_FreeBandWidth 0x%x\n", ntStatus)); return ntStatus; }
/*
** PHILIPSCAM_StopVideoCapture() ** ** Called after the iso video stream is stopped, this is where we ** select an alternate interface that uses no bandwidth. ** ** Arguments: ** ** BusDeviceObject - device object created by the hub we can submit ** urbs to our device through this deviceObject ** ** DeviceContext - minidriver device context ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_StopVideoCapture( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; // turn off streaming on the device
ASSERT_DEVICE_CONTEXT(deviceContext); PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_StopVideoCapture 0x%x\n", ntStatus)); return ntStatus; }
/*
** PHILIPSCAM_NewFrame() ** ** called at DPC level to allow driver to initialize a new video frame ** context structure ** ** Arguments: ** ** DeviceContext - minidriver device context ** ** FrameContext - frame context to be initialized ** ** Returns: ** ** NTSTATUS code ** ** Side Effects: none */
VOID PHILIPSCAM_NewFrame( PVOID DeviceContext, PVOID FrameContext ){ PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; PPHILIPSCAM_FRAME_CONTEXT pFrameContext = FrameContext;
pFrameContext->USBByteCounter = 0;
// PHILIPSCAM_KdPrint (MAX_TRACE, ("'P*_NewFrame\n"));
ASSERT_DEVICE_CONTEXT(deviceContext); }
/*
** PHILIPSCAM_ProcessUSBPacket() ** ** called at DPC level to allow driver to determine if this packet is part ** of the current video frame or a new video frame. ** ** This function should complete as quickly as possible, any image processing ** should be deferred to the ProcessRawFrame routine. ** ** Arguments: ** ** BusDeviceObject - device object created by the hub we can submit ** urbs to our device through this deviceObject ** ** DeviceContext - minidriver device context ** ** CurrentFrameContext - some context for this particular frame ** ** SyncPacket - iso packet descriptor from sync pipe, not used if the interface ** has only one pipe. ** ** SyncBuffer - pointer to data for the sync packet ** ** DataPacket - iso packet descriptor from data pipe ** ** DataBuffer - pointer to data for the data packet ** ** FrameComplete - indicates to usbcamd that this is the first data packet ** for a new video frame ** ** Returns: ** ** number of bytes that should be copied in to the rawFrameBuffer of FrameBuffer. ** ** Side Effects: none
*/ ULONG PHILIPSCAM_ProcessUSBPacket( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext, PVOID CurrentFrameContext, PUSBD_ISO_PACKET_DESCRIPTOR SyncPacket, PVOID SyncBuffer, PUSBD_ISO_PACKET_DESCRIPTOR DataPacket, PVOID DataBuffer, PBOOLEAN FrameComplete, PBOOLEAN NextFrameIsStill ) { static BOOLEAN EndOfFrameFound = FALSE; static BOOLEAN StartOfFrameFound = FALSE; static ULONG previous_packetSize= 0; static ULONG ActualBytesReceived = 0 ;
#if DBG
#if DBGHARD
typedef struct { ULONG PSize; ULONG DeltaT; } PACKETINFO; #define MAXI 2048
static ULONG ulRcvdFrameSize[MAXI]; static ULONG ulPHistory[MAXI][2]; static ULONG ulPcktCntr = 0; static ULONG ulFrSCntr = 0; static LARGE_INTEGER liCurTicks, liPrevTicks; static ULONG ElapsedTicks; static ULONG TickPeriod ;
#endif
#endif
PUSBD_ISO_PACKET_DESCRIPTOR dataPacket = DataPacket; PPHILIPSCAM_FRAME_CONTEXT pFrameContext = CurrentFrameContext;
ULONG packetSize;
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; *NextFrameIsStill = FALSE; // PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_ProcessPacket\n"));
ASSERT_DEVICE_CONTEXT(deviceContext);
packetSize = dataPacket->Length ;
// Synchronization:
// ----------------
if (packetSize != previous_packetSize){ //end or start of frame
if (packetSize < previous_packetSize) { EndOfFrameFound = TRUE; }else{ StartOfFrameFound = TRUE; } }
if ( StartOfFrameFound == TRUE ){ *FrameComplete = TRUE; EndOfFrameFound = FALSE; StartOfFrameFound = FALSE;
#if DBG
#if DBGHARD
ulRcvdFrameSize[ulFrSCntr] = ActualBytesReceived; if (ulFrSCntr==MAXI) ulFrSCntr = 0; #endif
#endif
if (pFrameContext) pFrameContext->USBByteCounter = ActualBytesReceived; ActualBytesReceived = 0; }
ActualBytesReceived += packetSize;
#if DBG
#if DBGHARD
// KeQueryTickCount(&liCurTicks);
ElapsedTicks = (ULONG)( liCurTicks.QuadPart - liPrevTicks.QuadPart); ulPHistory[ulPcktCntr][0] = packetSize; ulPHistory[ulPcktCntr][1] = ElapsedTicks ; liPrevTicks.QuadPart = liCurTicks.QuadPart; ulPcktCntr++; if (ulPcktCntr==MAXI) ulPcktCntr = 0; #endif
#endif
// Added to improve robustness
if ( ActualBytesReceived > deviceContext->FrameLength){ *FrameComplete = TRUE; ActualBytesReceived = 0; } previous_packetSize = packetSize; return packetSize; }
/*
** PHILIPSCAM_ProcessRawVideoFrame() ** ** Called at PASSIVE level to allow driver to perform any decoding of the ** raw video frame. ** ** This routine will convert the packetized data in to the fromat ** the CODEC expects, ie y,u,v ** ** data is always of the form 256y 64u 64v (384 byte chunks) regardless of USB ** packet size. ** ** ** Arguments: ** ** DeviceContext - driver context ** ** FrameContext - driver context for this frame ** ** FrameBuffer - pointer to the buffer that should receive the final ** processed video frame. ** ** FrameLength - length of the Frame buffer (from the original read ** request) ** ** RawFrameBuffer - pointer to buffer containing the received USB packets ** ** RawFrameLength - length of the raw frame. ** ** NumberOfPackets - number of USB packets received in to the RawFrameBuffer ** ** BytesReturned - pointer to value to return for number of bytes read. ** ** Returns: ** ** NT status completion code for the read irp ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_ProcessRawVideoFrame( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext, PVOID FrameContext, PVOID FrameBuffer, ULONG FrameLength, PVOID RawFrameBuffer, ULONG RawFrameLength, ULONG NumberOfPackets, PULONG BytesReturned ) { NTSTATUS ntStatus = STATUS_SUCCESS; PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; PPHILIPSCAM_FRAME_CONTEXT frameContext = FrameContext; ULONG rawDataLength, processedDataLength; PUCHAR frameBuffer = FrameBuffer; PUCHAR rawFrameBuffer = RawFrameBuffer; ULONG rawFrameLength = RawFrameLength; ULONG frameLength = FrameLength; ULONG ExpectedNumberOfBytes;
//TEST_TRAP();
ASSERT_DEVICE_CONTEXT(deviceContext);
switch (deviceContext->CamStatus.PictureFormat){ case FORMATCIF: if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){ ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ; }else{ ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ; } break; case FORMATQCIF: ExpectedNumberOfBytes = QCIF_X * QCIF_Y * 3/2 ; break; case FORMATSQCIF: ExpectedNumberOfBytes = SQCIF_X * SQCIF_Y * 3/2 ; break; case FORMATQQCIF: ExpectedNumberOfBytes = SQCIF_X * SQCIF_Y * 3/2 ; break; case FORMATVGA: ExpectedNumberOfBytes = VGA_X * VGA_Y * 3/2 ; break; case FORMATSIF: if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){ ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ; }else{ ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ; } break; case FORMATSSIF: if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){ ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ; }else{ ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ; } break; case FORMATSCIF: if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){ ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ; }else{ ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ; } break; case FORMATQSIF: ExpectedNumberOfBytes = QCIF_X * QCIF_Y * 3/2 ; break; case FORMATSQSIF: ExpectedNumberOfBytes = SQCIF_X * SQCIF_Y * 3/2 ; break; default: ExpectedNumberOfBytes = 0; }
if (ExpectedNumberOfBytes == frameContext->USBByteCounter ) { ntStatus = PHILIPSCAM_DecodeUsbData(deviceContext, frameBuffer, frameLength, rawFrameBuffer, rawFrameLength); *BytesReturned = frameLength ; }else{ PHILIPSCAM_KdPrint (MIN_TRACE, ("Actual (%d) < Expected (%d) \n", frameContext->USBByteCounter,ExpectedNumberOfBytes));
// Green screen complaints bug fix : At the moment USBCAMD delivers a frame for
// processing, we check whether the size of that frame is correct.
// If not we return to USBCAMD a framelength to be copied of zero and we won't
// process the frame.
// The workaround is to let USBCAMD copy the buffer with the actual buffer length
// and not to process the frame. Apparantly, returning a bufferlength zero has as
// consequence that USB packets gets lost.
// This causes subsequent frames to be incorrect, returning again bufferlength
// zero. And so on. Not processing buffers has as consequence that the renderer
// sees empty buffers resulting in a green screen.
// Sometimes, if this happens during streaming, old buffers are being rerendered.
*BytesReturned = 0 ; // 2001/01/29: This workaround was causing the first few frames
// captured to remain uninitialized due to insufficient framelength.
// Returning 0 to indicate a dropped frame is the correct behavior.
//*BytesReturned = frameLength ;
}
return ntStatus; }
/*
** PHILIPSCAM_PropertyRequest() ** ** Arguments: ** ** DeviceContext - driver context ** ** Returns: ** ** NT status completion code for the read irp ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_PropertyRequest( BOOLEAN SetProperty, PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext, PVOID PropertyContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PHW_STREAM_REQUEST_BLOCK srb = (PHW_STREAM_REQUEST_BLOCK)PropertyContext; PSTREAM_PROPERTY_DESCRIPTOR propertyDescriptor;
propertyDescriptor = srb->CommandData.PropertyInfo; //
// identify the property to set
//
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_PropertyRequest\n"));
if (IsEqualGUID(&PROPSETID_VIDCAP_VIDEOPROCAMP, &propertyDescriptor->Property->Set)) if (SetProperty) ntStatus = PHILIPSCAM_SetCameraProperty(DeviceContext, srb); else ntStatus = PHILIPSCAM_GetCameraProperty(DeviceContext, srb); else if (IsEqualGUID(&PROPSETID_PHILIPS_CUSTOM_PROP, &propertyDescriptor->Property->Set)) if (SetProperty) ntStatus = PHILIPSCAM_SetCustomProperty(DeviceContext, srb); else ntStatus = PHILIPSCAM_GetCustomProperty(DeviceContext, srb); else if (IsEqualGUID(&PROPSETID_PHILIPS_FACTORY_PROP, &propertyDescriptor->Property->Set)) if (SetProperty) ntStatus = PHILIPSCAM_SetFactoryProperty(DeviceContext, srb); else ntStatus = PHILIPSCAM_GetFactoryProperty(DeviceContext, srb); else if (IsEqualGUID(&PROPSETID_VIDCAP_VIDEOCONTROL, &propertyDescriptor->Property->Set)) { if (SetProperty) ntStatus = PHILIPSCAM_SetVideoControlProperty(DeviceContext, srb); else ntStatus = PHILIPSCAM_GetVideoControlProperty(DeviceContext, srb); } else ntStatus = STATUS_NOT_SUPPORTED;
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_PropertyRequest 0x%x\n",ntStatus));
return ntStatus; }
/*
** PHILIPSCAM_SaveState() ** ** Arguments: ** ** Returns: ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_SaveState( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; PHILIPSCAM_KdPrint (MAX_TRACE, ("'P*_SaveState\n")); return STATUS_SUCCESS; }
/*
** PHILIPSCAM_RestoreState() ** ** Arguments: ** ** Returns: ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_RestoreState( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; PHILIPSCAM_KdPrint (MAX_TRACE, ("'RestoreState\n")); return STATUS_SUCCESS; }
/*
** PHILIPSCAM_ReadRegistry() ** ** Arguments: ** ** Returns: ** ** Side Effects: none */
NTSTATUS PHILIPSCAM_ReadRegistry( PDEVICE_OBJECT BusDeviceObject, PVOID DeviceContext ) { PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext; NTSTATUS ntStatus=STATUS_SUCCESS; HANDLE handle;
return ntStatus; }
USHORT MapFrPeriodFrRate(LONGLONG llFramePeriod) { USHORT FrameRate; if (llFramePeriod <= 420000 ){ // 41.6 rounded to 42 ms
FrameRate = FRRATE24; }else if (llFramePeriod <= 510000 ){ // 50.0 rounded to 51 ma
FrameRate = FRRATE20; }else if (llFramePeriod <= 670000 ){ // 66.6 rounded to 67 ms
FrameRate = FRRATE15; }else if (llFramePeriod <= 840000 ){ // 83.3 rounded to 84 ms
FrameRate = FRRATE12; }else if (llFramePeriod <= 1010000 ){ // 100.0 rounded to 101 ms
FrameRate = FRRATE10; // HR: changed from 134 to 143ms.
}else if (llFramePeriod <= 1430000 ){ // 133.3 rounded to 134 ms
FrameRate = FRRATE75; }else if (llFramePeriod <= 2010000 ){ // 200 rounded to 201 ms
FrameRate = FRRATE5; }else { FrameRate = FRRATE375; } // rounding was necessary as the OS returns e.g. #667.111 for 15 fps
return FrameRate; }
#if DBG
PCHAR FRString ( USHORT index ) { switch (index) { case FRRATEVGA: return "VGA"; case FRRATE375: return "3.75"; case FRRATE5: return "5"; case FRRATE75: return "7.5"; case FRRATE10: return "10"; case FRRATE12: return "12"; case FRRATE15: return "15"; case FRRATE20: return "20"; case FRRATE24:return "24"; default: return "";break; }
}
#endif
|