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.
1019 lines
34 KiB
1019 lines
34 KiB
//==========================================================================;
|
|
//
|
|
// WDM Video Decoder common SRB dispatcher
|
|
//
|
|
// $Date: 02 Oct 1998 23:00:24 $
|
|
// $Revision: 1.2 $
|
|
// $Author: KLEBANOV $
|
|
//
|
|
// $Copyright: (c) 1997 - 1998 ATI Technologies Inc. All Rights Reserved. $
|
|
//
|
|
//==========================================================================;
|
|
|
|
extern "C"
|
|
{
|
|
#include "strmini.h"
|
|
#include "ksmedia.h"
|
|
}
|
|
|
|
|
|
#include "wdmvdec.h"
|
|
#include "wdmdrv.h"
|
|
#include "capdebug.h"
|
|
#include "VidStrm.h"
|
|
|
|
#include "DecProp.h"
|
|
#include "StrmInfo.h"
|
|
|
|
#include "Mediums.h"
|
|
#include "mytypes.h"
|
|
|
|
extern NTSTATUS STREAMAPI DeviceEventProc( PHW_EVENT_DESCRIPTOR pEventDescriptor);
|
|
|
|
CWDMVideoDecoder::CWDMVideoDecoder(PPORT_CONFIGURATION_INFORMATION pConfigInfo,
|
|
CVideoDecoderDevice* pDevice)
|
|
: m_pDeviceObject(pConfigInfo->RealPhysicalDeviceObject),
|
|
m_CDecoderVPort(pConfigInfo->RealPhysicalDeviceObject),
|
|
m_pDevice(pDevice),
|
|
m_TVTunerChangedSrb( NULL)
|
|
{
|
|
DBGTRACE(("CWDMVideoDecoder:CWDMVideoDecoder() enter\n"));
|
|
DBGINFO(("Physical Device Object = %lx\n", m_pDeviceObject));
|
|
|
|
pConfigInfo->StreamDescriptorSize = sizeof (HW_STREAM_HEADER) +
|
|
NumStreams * sizeof (HW_STREAM_INFORMATION);
|
|
|
|
InitializeListHead(&m_srbQueue);
|
|
KeInitializeSpinLock(&m_spinLock);
|
|
m_bSrbInProcess = FALSE;
|
|
if (pDevice)
|
|
{
|
|
pDevice->SetVideoDecoder(this);
|
|
}
|
|
}
|
|
|
|
|
|
CWDMVideoDecoder::~CWDMVideoDecoder()
|
|
{
|
|
|
|
DBGTRACE(("CWDMVideoDecoder:~CWDMVideoDecoder()\n"));
|
|
}
|
|
|
|
|
|
void CWDMVideoDecoder::ReceivePacket(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
KIRQL Irql;
|
|
PSRB_DATA_EXTENSION pSrbExt;
|
|
|
|
KeAcquireSpinLock(&m_spinLock, &Irql);
|
|
if (m_bSrbInProcess)
|
|
{
|
|
pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
|
|
pSrbExt->pSrb = pSrb;
|
|
InsertTailList(&m_srbQueue, &pSrbExt->srbListEntry);
|
|
KeReleaseSpinLock(&m_spinLock, Irql);
|
|
return;
|
|
}
|
|
|
|
m_bSrbInProcess = TRUE;
|
|
KeReleaseSpinLock(&m_spinLock, Irql);
|
|
|
|
|
|
for (;;) {
|
|
|
|
// Assume success. Might be changed below
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
BOOL notify = TRUE;
|
|
|
|
// determine the type of packet.
|
|
switch(pSrb->Command)
|
|
{
|
|
case SRB_INITIALIZATION_COMPLETE:
|
|
DBGTRACE(("SRB_INITIALIZATION_COMPLETE; SRB=%x\n", pSrb));
|
|
|
|
// Stream class has finished initialization.
|
|
// Now create DShow Medium interface BLOBs.
|
|
// This needs to be done at low priority since it uses the registry
|
|
//
|
|
// Do we need to worry about synchronization here?
|
|
|
|
SrbInitializationComplete(pSrb);
|
|
break;
|
|
case SRB_UNINITIALIZE_DEVICE:
|
|
DBGTRACE(("SRB_UNINITIALIZE_DEVICE; SRB=%x\n", pSrb));
|
|
// close the device.
|
|
|
|
break;
|
|
case SRB_PAGING_OUT_DRIVER:
|
|
DBGTRACE(("SRB_PAGING_OUT_DRIVER; SRB=%x\n", pSrb));
|
|
//
|
|
// The driver is being paged out
|
|
// Disable Interrupts if you have them!
|
|
//
|
|
break;
|
|
case SRB_CHANGE_POWER_STATE:
|
|
DBGTRACE(("SRB_CHANGE_POWER_STATE. SRB=%x. State=%d\n",
|
|
pSrb, pSrb->CommandData.DeviceState));
|
|
|
|
SrbChangePowerState(pSrb);
|
|
break;
|
|
|
|
case SRB_OPEN_STREAM:
|
|
DBGTRACE(("SRB_OPEN_STREAM; SRB=%x\n", pSrb));
|
|
|
|
SrbOpenStream(pSrb);
|
|
break;
|
|
|
|
case SRB_CLOSE_STREAM:
|
|
DBGTRACE(("SRB_CLOSE_STREAM; SRB=%x\n", pSrb));
|
|
|
|
if (!IsListEmpty(&m_srbQueue)) // is this necessary ???
|
|
{
|
|
TRAP();
|
|
}
|
|
|
|
SrbCloseStream(pSrb);
|
|
break;
|
|
case SRB_GET_DATA_INTERSECTION:
|
|
DBGTRACE(("SRB_GET_DATA_INTERSECTION; SRB=%x\n", pSrb));
|
|
|
|
SrbGetDataIntersection(pSrb);
|
|
break;
|
|
|
|
case SRB_GET_STREAM_INFO:
|
|
SrbGetStreamInfo(pSrb);
|
|
break;
|
|
|
|
case SRB_GET_DEVICE_PROPERTY:
|
|
SrbGetProperty(pSrb);
|
|
break;
|
|
|
|
case SRB_SET_DEVICE_PROPERTY:
|
|
SrbSetProperty(pSrb);
|
|
break;
|
|
|
|
case SRB_WRITE_DATA:
|
|
|
|
DBGTRACE(("SRB_WRITE_DATA; SRB=%x\n", pSrb));
|
|
|
|
SetTunerInfo(pSrb);
|
|
StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
|
|
notify = FALSE;
|
|
break;
|
|
|
|
case SRB_UNKNOWN_DEVICE_COMMAND:
|
|
// not sure why this gets called every time.
|
|
DBGTRACE(("SRB_UNKNOWN_DEVICE_COMMAND; SRB=%x\n", pSrb));
|
|
|
|
// TRAP()();
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SRB_OPEN_DEVICE_INSTANCE:
|
|
case SRB_CLOSE_DEVICE_INSTANCE:
|
|
default:
|
|
TRAP();
|
|
// this is a request that we do not understand. Indicate invalid command and complete the request
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
if (notify)
|
|
StreamClassDeviceNotification(DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb);
|
|
|
|
KeAcquireSpinLock(&m_spinLock, &Irql);
|
|
if (IsListEmpty(&m_srbQueue))
|
|
{
|
|
m_bSrbInProcess = FALSE;
|
|
KeReleaseSpinLock(&m_spinLock, Irql);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
pSrbExt = (PSRB_DATA_EXTENSION)RemoveHeadList(&m_srbQueue);
|
|
KeReleaseSpinLock(&m_spinLock, Irql);
|
|
pSrb = pSrbExt->pSrb;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CWDMVideoDecoder::CancelPacket( PHW_STREAM_REQUEST_BLOCK pSrbToCancel)
|
|
{
|
|
CWDMVideoStream* pVideoStream = ( CWDMVideoStream*)pSrbToCancel->StreamObject->HwStreamExtension;
|
|
|
|
DBGINFO(( "Bt829: AdapterCancelPacket, Starting attempting to cancel Srb 0x%x\n",
|
|
pSrbToCancel));
|
|
|
|
if( pVideoStream == NULL)
|
|
{
|
|
//
|
|
// Device command IRPs are not queued, so nothing to do
|
|
//
|
|
DBGINFO(( "Bt829: AdapterCancelPacketStart, no pVideoStream Srb 0x%x\n",
|
|
pSrbToCancel));
|
|
|
|
return;
|
|
}
|
|
|
|
pVideoStream->CancelPacket( pSrbToCancel);
|
|
|
|
DBGINFO(( "Bt829: AdapterCancelPacket, Exiting\n"));
|
|
}
|
|
|
|
|
|
|
|
void CWDMVideoDecoder::TimeoutPacket(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
CWDMVideoStream * pVideoStream = (CWDMVideoStream *)pSrb->StreamObject->HwStreamExtension;
|
|
|
|
DBGTRACE(("Timeout. SRB %8x. \n", pSrb));
|
|
pVideoStream->TimeoutPacket(pSrb);
|
|
|
|
DBGTRACE(("TimeoutPacket: SRB %8x. Resetting.\n", pSrb));
|
|
pSrb->TimeoutCounter = pSrb->TimeoutOriginal;
|
|
}
|
|
|
|
|
|
BOOL CWDMVideoDecoder::SrbInitializationComplete(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG *tmp = (ULONG *) &CrossbarPinDirection[0];
|
|
|
|
// Create the Registry blobs that DShow uses to create
|
|
// graphs via Mediums
|
|
|
|
Status = StreamClassRegisterFilterWithNoKSPins (
|
|
m_pDeviceObject, // IN PDEVICE_OBJECT DeviceObject,
|
|
&KSCATEGORY_CROSSBAR, // IN GUID * InterfaceClassGUID,
|
|
CrossbarPins(), // IN ULONG PinCount,
|
|
(int *) CrossbarPinDirection, // IN ULONG * Flags,
|
|
(KSPIN_MEDIUM *) CrossbarMediums, // IN KSPIN_MEDIUM * MediumList,
|
|
NULL // IN GUID * CategoryList
|
|
);
|
|
|
|
// Register the Capture filter
|
|
// Note: This should be done automatically be MSKsSrv.sys,
|
|
// when that component comes on line (if ever) ...
|
|
Status = StreamClassRegisterFilterWithNoKSPins (
|
|
m_pDeviceObject, // IN PDEVICE_OBJECT DeviceObject,
|
|
&KSCATEGORY_CAPTURE, // IN GUID * InterfaceClassGUID,
|
|
CapturePins(), // IN ULONG PinCount,
|
|
(int *) CapturePinDirection, // IN ULONG * Flags,
|
|
(KSPIN_MEDIUM *) CaptureMediums, // IN KSPIN_MEDIUM * MediumList,
|
|
NULL // IN GUID * CategoryList
|
|
);
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL CWDMVideoDecoder::SrbOpenStream(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
DBGTRACE(("CWDMVideoDecoder:SrbOpenStream()\n"));
|
|
PHW_STREAM_OBJECT pStreamObject = pSrb->StreamObject;
|
|
void * pStrmEx = pStreamObject->HwStreamExtension;
|
|
int StreamNumber = pStreamObject->StreamNumber;
|
|
PKSDATAFORMAT pKSDataFormat = pSrb->CommandData.OpenFormat;
|
|
CWDMVideoStream * pVideoStream;
|
|
CWDMVideoPortStream * pVPVBIStream;
|
|
UINT nErrorCode;
|
|
|
|
RtlZeroMemory(pStrmEx, streamDataExtensionSize);
|
|
|
|
DBGINFO(("SRBOPENSTREAM ------- StreamNumber=%d\n", StreamNumber));
|
|
|
|
//
|
|
// check that the stream index requested isn't too high
|
|
// or that the maximum number of instances hasn't been exceeded
|
|
//
|
|
|
|
if (StreamNumber >= (int)NumStreams || StreamNumber < 0) {
|
|
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Check the validity of the format being requested
|
|
//
|
|
|
|
if (!AdapterVerifyFormat (pKSDataFormat, StreamNumber)) {
|
|
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Set up pointers to the handlers for the stream data and control handlers
|
|
//
|
|
|
|
pStreamObject->ReceiveDataPacket = VideoReceiveDataPacket;
|
|
pStreamObject->ReceiveControlPacket = VideoReceiveCtrlPacket;
|
|
|
|
//
|
|
// Indicate the clock support available on this stream
|
|
//
|
|
|
|
pStreamObject->HwClockObject.HwClockFunction = NULL;
|
|
pStreamObject->HwClockObject.ClockSupportFlags = 0;
|
|
|
|
//
|
|
// The DMA flag must be set when the device will be performing DMA directly
|
|
// to the data buffer addresses passed in to the ReceiceDataPacket routines.
|
|
//
|
|
pStreamObject->Dma = Streams[StreamNumber].hwStreamObjectInfo.Dma;
|
|
|
|
//
|
|
// The PIO flag must be set when the mini driver will be accessing the data
|
|
// buffers passed in using logical addressing
|
|
//
|
|
pStreamObject->Pio = Streams[StreamNumber].hwStreamObjectInfo.Pio;
|
|
|
|
//
|
|
// How many extra bytes will be passed up from the driver for each frame?
|
|
//
|
|
pStreamObject->StreamHeaderMediaSpecific =
|
|
Streams[StreamNumber].hwStreamObjectInfo.StreamHeaderMediaSpecific;
|
|
|
|
pStreamObject->StreamHeaderWorkspace =
|
|
Streams[StreamNumber].hwStreamObjectInfo.StreamHeaderWorkspace;
|
|
|
|
//
|
|
// Indicate the allocator support available on this stream
|
|
//
|
|
|
|
pStreamObject->Allocator = Streams[StreamNumber].hwStreamObjectInfo.Allocator;
|
|
|
|
//
|
|
// Indicate the event support available on this stream
|
|
//
|
|
|
|
pStreamObject->HwEventRoutine =
|
|
Streams[StreamNumber].hwStreamObjectInfo.HwEventRoutine;
|
|
|
|
switch (StreamNumber)
|
|
{
|
|
case STREAM_AnalogVideoInput:
|
|
ASSERT(IsEqualGUID(pKSDataFormat->Specifier, KSDATAFORMAT_SPECIFIER_ANALOGVIDEO));
|
|
pVideoStream = (CWDMVideoStream *)new(pStrmEx)
|
|
CWDMVideoStream(pStreamObject, this, &nErrorCode);
|
|
break;
|
|
case STREAM_VideoCapture:
|
|
ASSERT(IsEqualGUID(pKSDataFormat->Specifier, KSDATAFORMAT_SPECIFIER_VIDEOINFO));
|
|
m_pVideoCaptureStream = (CWDMVideoCaptureStream *)new(pStrmEx)
|
|
CWDMVideoCaptureStream(pStreamObject, this, pKSDataFormat, &nErrorCode);
|
|
if (m_pVideoPortStream)
|
|
{
|
|
m_pVideoPortStream->AttemptRenegotiation();
|
|
}
|
|
break;
|
|
case STREAM_VBICapture:
|
|
ASSERT(IsEqualGUID(pKSDataFormat->Specifier, KSDATAFORMAT_SPECIFIER_VBI));
|
|
m_pVBICaptureStream = (CWDMVBICaptureStream *)new(pStrmEx)
|
|
CWDMVBICaptureStream(pStreamObject, this, pKSDataFormat, &nErrorCode);
|
|
break;
|
|
case STREAM_VPVideo:
|
|
ASSERT(IsEqualGUID(pKSDataFormat->Specifier, KSDATAFORMAT_SPECIFIER_NONE) &&
|
|
IsEqualGUID(pKSDataFormat->SubFormat, KSDATAFORMAT_SUBTYPE_VPVideo));
|
|
m_pVideoPortStream = (CWDMVideoPortStream *)new(pStrmEx)
|
|
CWDMVideoPortStream(pStreamObject, this, &nErrorCode);
|
|
if (m_pVideoCaptureStream == NULL)
|
|
{
|
|
MRect t(0, 0, m_pDevice->GetDefaultDecoderWidth(),
|
|
m_pDevice->GetDefaultDecoderHeight());
|
|
m_pDevice->SetRect(t);
|
|
}
|
|
break;
|
|
case STREAM_VPVBI:
|
|
ASSERT(IsEqualGUID(pKSDataFormat->Specifier, KSDATAFORMAT_SPECIFIER_NONE) &&
|
|
IsEqualGUID(pKSDataFormat->SubFormat, KSDATAFORMAT_SUBTYPE_VPVBI));
|
|
pVPVBIStream = (CWDMVideoPortStream *)new(pStrmEx)
|
|
CWDMVideoPortStream(pStreamObject, this, &nErrorCode);
|
|
m_pDevice->SetVBIEN(TRUE);
|
|
m_pDevice->SetVBIFMT(TRUE);
|
|
break;
|
|
default:
|
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
|
goto Exit;
|
|
}
|
|
|
|
if(nErrorCode == WDMMINI_NOERROR)
|
|
m_OpenStreams++;
|
|
else
|
|
pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Exit:
|
|
|
|
DBGTRACE(("SrbOpenStream Exit\n"));
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL CWDMVideoDecoder::SrbCloseStream(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
int StreamNumber = pSrb->StreamObject->StreamNumber;
|
|
|
|
DBGTRACE(("CWDMVideoDecoder:SrbCloseStream()\n"));
|
|
DBGINFO(("SRBCLOSESTREAM ------- StreamNumber=%d\n", StreamNumber));
|
|
|
|
//
|
|
// the minidriver may wish to free any resources that were allocated at
|
|
// open stream time etc.
|
|
//
|
|
|
|
CWDMVideoStream * pVideoStream = (CWDMVideoStream *)pSrb->StreamObject->HwStreamExtension;
|
|
|
|
delete pVideoStream;
|
|
|
|
switch (StreamNumber)
|
|
{
|
|
case STREAM_AnalogVideoInput:
|
|
break;
|
|
case STREAM_VideoCapture:
|
|
m_pVideoCaptureStream = NULL;
|
|
break;
|
|
case STREAM_VBICapture:
|
|
m_pVBICaptureStream = NULL;
|
|
break;
|
|
case STREAM_VPVideo:
|
|
m_pVideoPortStream = NULL;
|
|
break;
|
|
case STREAM_VPVBI:
|
|
m_pDevice->SetVBIEN(FALSE);
|
|
m_pDevice->SetVBIFMT(FALSE);
|
|
break;
|
|
default:
|
|
pSrb->Status = STATUS_UNSUCCESSFUL;
|
|
return FALSE;
|
|
}
|
|
|
|
if (--m_OpenStreams == 0)
|
|
{
|
|
DBGINFO(("Last one out turns off the lights\n"));
|
|
|
|
m_CDecoderVPort.Close();
|
|
|
|
m_preEventOccurred = FALSE;
|
|
m_postEventOccurred = FALSE;
|
|
|
|
m_pDevice->SaveState();
|
|
}
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CWDMVideoDecoder::SrbGetDataIntersection(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
|
|
DBGTRACE(("CWDMVideoDecoder:SrbGetDataIntersection()\n"));
|
|
|
|
PSTREAM_DATA_INTERSECT_INFO IntersectInfo;
|
|
PKSDATARANGE DataRange;
|
|
BOOL OnlyWantsSize;
|
|
BOOL MatchFound = FALSE;
|
|
ULONG FormatSize;
|
|
ULONG StreamNumber;
|
|
ULONG j;
|
|
ULONG NumberOfFormatArrayEntries;
|
|
PKSDATAFORMAT *pAvailableFormats;
|
|
|
|
IntersectInfo = pSrb->CommandData.IntersectInfo;
|
|
StreamNumber = IntersectInfo->StreamNumber;
|
|
DataRange = IntersectInfo->DataRange;
|
|
|
|
//
|
|
// Check that the stream number is valid
|
|
//
|
|
|
|
if (StreamNumber >= NumStreams) {
|
|
pSrb->Status = STATUS_NOT_IMPLEMENTED;
|
|
TRAP();
|
|
return FALSE;
|
|
}
|
|
|
|
NumberOfFormatArrayEntries =
|
|
Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries;
|
|
|
|
//
|
|
// Get the pointer to the array of available formats
|
|
//
|
|
|
|
pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray;
|
|
|
|
//
|
|
// Is the caller trying to get the format, or the size of the format?
|
|
//
|
|
|
|
OnlyWantsSize = ( (IntersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG)) ||
|
|
(IntersectInfo->SizeOfDataFormatBuffer == 0) );
|
|
|
|
//
|
|
// 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++, pAvailableFormats++) {
|
|
|
|
if (!AdapterCompareGUIDsAndFormatSize(
|
|
DataRange,
|
|
*pAvailableFormats,
|
|
TRUE /* CompareFormatSize */)) {
|
|
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) *pAvailableFormats;
|
|
PKS_DATAFORMAT_VIDEOINFOHEADER DataFormatVideoInfoHeaderOut;
|
|
|
|
//
|
|
// 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))) {
|
|
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)
|
|
ULONG VideoHeaderSize = DataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biSize +
|
|
FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader);
|
|
ULONG 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) {
|
|
|
|
pSrb->Status = STATUS_INVALID_PARAMETER;
|
|
return FALSE;
|
|
}
|
|
|
|
// MATCH FOUND!
|
|
MatchFound = TRUE;
|
|
FormatSize = sizeof (KSDATAFORMAT) +
|
|
VideoHeaderSize;
|
|
|
|
if (OnlyWantsSize) {
|
|
break;
|
|
}
|
|
|
|
// Caller wants the full data format
|
|
if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy over the KSDATAFORMAT, followed by the
|
|
// actual VideoInfoHeader
|
|
|
|
DataFormatVideoInfoHeaderOut = (PKS_DATAFORMAT_VIDEOINFOHEADER) IntersectInfo->DataFormatBuffer;
|
|
|
|
// Copy over the KSDATAFORMAT
|
|
RtlCopyMemory(
|
|
&DataFormatVideoInfoHeaderOut->DataFormat,
|
|
&DataRangeVideoToVerify->DataRange,
|
|
sizeof (KSDATARANGE));
|
|
|
|
DataFormatVideoInfoHeaderOut->DataFormat.FormatSize = FormatSize;
|
|
|
|
// Copy over the caller's requested VIDEOINFOHEADER
|
|
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
|
|
//
|
|
|
|
break;
|
|
|
|
} // End of VIDEOINFOHEADER specifier
|
|
|
|
// -------------------------------------------------------------------
|
|
// Specifier FORMAT_AnalogVideo for KS_ANALOGVIDEOINFO
|
|
// -------------------------------------------------------------------
|
|
|
|
else if (IsEqualGUID (DataRange->Specifier,
|
|
KSDATAFORMAT_SPECIFIER_ANALOGVIDEO)) {
|
|
|
|
//
|
|
// For analog video, the DataRange and DataFormat
|
|
// are identical, so just copy the whole structure
|
|
//
|
|
|
|
PKS_DATARANGE_ANALOGVIDEO DataRangeVideo =
|
|
(PKS_DATARANGE_ANALOGVIDEO) *pAvailableFormats;
|
|
|
|
// MATCH FOUND!
|
|
MatchFound = TRUE;
|
|
FormatSize = sizeof (KS_DATARANGE_ANALOGVIDEO);
|
|
|
|
if (OnlyWantsSize) {
|
|
break;
|
|
}
|
|
|
|
// Caller wants the full data format
|
|
if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
IntersectInfo->DataFormatBuffer,
|
|
DataRangeVideo,
|
|
sizeof (KS_DATARANGE_ANALOGVIDEO));
|
|
|
|
((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize;
|
|
|
|
break;
|
|
|
|
} // End of KS_ANALOGVIDEOINFO specifier
|
|
|
|
// -------------------------------------------------------------------
|
|
// Specifier STATIC_KSDATAFORMAT_TYPE_VIDEO for Video Port
|
|
// -------------------------------------------------------------------
|
|
|
|
else if (IsEqualGUID (DataRange->Specifier,
|
|
KSDATAFORMAT_SPECIFIER_NONE) &&
|
|
IsEqualGUID (DataRange->SubFormat, KSDATAFORMAT_SUBTYPE_VPVideo)) {
|
|
|
|
|
|
// MATCH FOUND!
|
|
MatchFound = TRUE;
|
|
FormatSize = sizeof (KSDATAFORMAT);
|
|
|
|
if (OnlyWantsSize) {
|
|
break;
|
|
}
|
|
|
|
// Caller wants the full data format
|
|
if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
RtlCopyMemory(
|
|
IntersectInfo->DataFormatBuffer,
|
|
&StreamFormatVideoPort,
|
|
sizeof (KSDATAFORMAT));
|
|
|
|
((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize;
|
|
|
|
break;
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Specifier KSDATAFORMAT_SPECIFIER_NONE for VP VBI
|
|
// -------------------------------------------------------------------
|
|
|
|
else if (IsEqualGUID (DataRange->Specifier,
|
|
KSDATAFORMAT_SPECIFIER_NONE) &&
|
|
IsEqualGUID (DataRange->SubFormat, KSDATAFORMAT_SUBTYPE_VPVBI)) {
|
|
|
|
// MATCH FOUND!
|
|
MatchFound = TRUE;
|
|
FormatSize = sizeof (KSDATAFORMAT);
|
|
|
|
if (OnlyWantsSize) {
|
|
break;
|
|
}
|
|
|
|
// Caller wants the full data format
|
|
if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
RtlCopyMemory(
|
|
IntersectInfo->DataFormatBuffer,
|
|
&StreamFormatVideoPortVBI,
|
|
sizeof (KSDATAFORMAT));
|
|
|
|
((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize;
|
|
|
|
break;
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Specifier STATIC_KSDATAFORMAT_TYPE_NONE for VBI capture stream
|
|
// -------------------------------------------------------------------
|
|
|
|
else if (IsEqualGUID (DataRange->Specifier,
|
|
KSDATAFORMAT_SPECIFIER_VBI)) {
|
|
|
|
PKS_DATARANGE_VIDEO_VBI DataRangeVBIToVerify =
|
|
(PKS_DATARANGE_VIDEO_VBI) DataRange;
|
|
PKS_DATARANGE_VIDEO_VBI DataRangeVBI =
|
|
(PKS_DATARANGE_VIDEO_VBI) *pAvailableFormats;
|
|
|
|
//
|
|
// Check that the other fields match
|
|
//
|
|
if ((DataRangeVBIToVerify->bFixedSizeSamples != DataRangeVBI->bFixedSizeSamples) ||
|
|
(DataRangeVBIToVerify->bTemporalCompression != DataRangeVBI->bTemporalCompression) ||
|
|
(DataRangeVBIToVerify->StreamDescriptionFlags != DataRangeVBI->StreamDescriptionFlags) ||
|
|
(DataRangeVBIToVerify->MemoryAllocationFlags != DataRangeVBI->MemoryAllocationFlags) ||
|
|
(RtlCompareMemory (&DataRangeVBIToVerify->ConfigCaps,
|
|
&DataRangeVBI->ConfigCaps,
|
|
sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) !=
|
|
sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))) {
|
|
continue;
|
|
}
|
|
|
|
// MATCH FOUND!
|
|
MatchFound = TRUE;
|
|
FormatSize = sizeof (KS_DATAFORMAT_VBIINFOHEADER);
|
|
|
|
if (OnlyWantsSize) {
|
|
break;
|
|
}
|
|
|
|
// Caller wants the full data format
|
|
if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) {
|
|
pSrb->Status = STATUS_BUFFER_TOO_SMALL;
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy over the KSDATAFORMAT, followed by the
|
|
// actual VBIInfoHeader
|
|
|
|
RtlCopyMemory(
|
|
&((PKS_DATAFORMAT_VBIINFOHEADER)IntersectInfo->DataFormatBuffer)->DataFormat,
|
|
&DataRangeVBIToVerify->DataRange,
|
|
sizeof (KSDATARANGE));
|
|
|
|
((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize;
|
|
|
|
RtlCopyMemory(
|
|
&((PKS_DATAFORMAT_VBIINFOHEADER) IntersectInfo->DataFormatBuffer)->VBIInfoHeader,
|
|
&DataRangeVBIToVerify->VBIInfoHeader,
|
|
sizeof (KS_VBIINFOHEADER));
|
|
}
|
|
|
|
} // End of loop on all formats for this stream
|
|
|
|
if (!MatchFound) {
|
|
|
|
pSrb->Status = STATUS_NO_MATCH;
|
|
return FALSE;
|
|
}
|
|
|
|
if (OnlyWantsSize) {
|
|
|
|
// Check for special case where there is no buffer being passed
|
|
if ( IntersectInfo->SizeOfDataFormatBuffer == 0 ) {
|
|
|
|
pSrb->Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else {
|
|
|
|
*(PULONG) IntersectInfo->DataFormatBuffer = FormatSize;
|
|
FormatSize = sizeof(ULONG);
|
|
}
|
|
}
|
|
|
|
pSrb->ActualBytesTransferred = FormatSize;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void CWDMVideoDecoder::SrbGetStreamInfo(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
DBGTRACE(("CWDMVideoDecoder:SrbGetStreamInfo()\n"));
|
|
|
|
//
|
|
// verify that the buffer is large enough to hold our return data
|
|
//
|
|
DEBUG_ASSERT (pSrb->NumberOfBytesToTransfer >=
|
|
sizeof (HW_STREAM_HEADER) +
|
|
sizeof (HW_STREAM_INFORMATION) * NumStreams);
|
|
|
|
//
|
|
// Set the header
|
|
//
|
|
|
|
PHW_STREAM_HEADER pstrhdr =
|
|
(PHW_STREAM_HEADER)&(pSrb->CommandData.StreamBuffer->StreamHeader);
|
|
|
|
pstrhdr->NumberOfStreams = NumStreams;
|
|
pstrhdr->SizeOfHwStreamInformation = sizeof (HW_STREAM_INFORMATION);
|
|
pstrhdr->NumDevPropArrayEntries = NumAdapterProperties();
|
|
pstrhdr->DevicePropertiesArray = (PKSPROPERTY_SET)AdapterProperties;
|
|
pstrhdr->Topology = &Topology;
|
|
|
|
//
|
|
// stuff the contents of each HW_STREAM_INFORMATION struct
|
|
//
|
|
PHW_STREAM_INFORMATION pstrinfo =
|
|
(PHW_STREAM_INFORMATION)&(pSrb->CommandData.StreamBuffer->StreamInfo);
|
|
|
|
for (unsigned j = 0; j < NumStreams; j++) {
|
|
*pstrinfo++ = Streams[j].hwStreamInfo;
|
|
}
|
|
|
|
DBGTRACE(("Exit: CWDMVideoDecoder:SrbGetStreamInfo()\n"));
|
|
}
|
|
|
|
|
|
VOID CWDMVideoDecoder::SrbSetProperty (PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
|
|
|
|
if (IsEqualGUID(PROPSETID_VIDCAP_CROSSBAR, pSPD->Property->Set)) {
|
|
m_pDevice->SetCrossbarProperty (pSrb);
|
|
}
|
|
else if (IsEqualGUID(PROPSETID_VIDCAP_VIDEOPROCAMP, pSPD->Property->Set)) {
|
|
ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_VIDEOPROCAMP_S));
|
|
|
|
ULONG Id = pSPD->Property->Id; // index of the property
|
|
PKSPROPERTY_VIDEOPROCAMP_S pS = (PKSPROPERTY_VIDEOPROCAMP_S) pSPD->PropertyInfo; // pointer to the data
|
|
|
|
pSrb->Status = m_pDevice->SetProcAmpProperty(Id, pS->Value);
|
|
}
|
|
else if (IsEqualGUID(PROPSETID_VIDCAP_VIDEODECODER, pSPD->Property->Set)) {
|
|
m_pDevice->SetDecoderProperty (pSrb);
|
|
}
|
|
else
|
|
DBGERROR(("CWDMVideoDecoder:SrbSetProperty() unknown property\n"));
|
|
}
|
|
|
|
|
|
VOID CWDMVideoDecoder::SrbGetProperty (PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
|
|
|
|
if (IsEqualGUID (PROPSETID_VIDCAP_CROSSBAR, pSPD->Property->Set)) {
|
|
m_pDevice->GetCrossbarProperty (pSrb);
|
|
}
|
|
else if (IsEqualGUID(PROPSETID_VIDCAP_VIDEOPROCAMP, pSPD->Property->Set)) {
|
|
ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_VIDEOPROCAMP_S));
|
|
|
|
ULONG Id = pSPD->Property->Id; // index of the property
|
|
PKSPROPERTY_VIDEOPROCAMP_S pS = (PKSPROPERTY_VIDEOPROCAMP_S) pSPD->PropertyInfo; // pointer to the data
|
|
|
|
RtlCopyMemory(pS, pSPD->Property, sizeof(KSPROPERTY));
|
|
|
|
pS->Capabilities = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
|
|
pSrb->Status = m_pDevice->GetProcAmpProperty(Id, &pS->Value);
|
|
pSrb->ActualBytesTransferred = pSrb->Status == STATUS_SUCCESS ?
|
|
sizeof (KSPROPERTY_VIDEOPROCAMP_S) : 0;
|
|
}
|
|
else if (IsEqualGUID(PROPSETID_VIDCAP_VIDEODECODER, pSPD->Property->Set)) {
|
|
m_pDevice->GetDecoderProperty (pSrb);
|
|
}
|
|
else
|
|
DBGERROR(("CWDMVideoDecoder:SrbGetProperty() unknown property\n"));
|
|
}
|
|
|
|
|
|
void CWDMVideoDecoder::SetTunerInfo( PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
PKSSTREAM_HEADER pDataPacket = pSrb->CommandData.DataBufferArray;
|
|
|
|
ASSERT (pDataPacket->FrameExtent == sizeof (KS_TVTUNER_CHANGE_INFO));
|
|
|
|
KIRQL Irql;
|
|
|
|
if (m_pVBICaptureStream)
|
|
m_pVBICaptureStream->DataLock(&Irql);
|
|
|
|
RtlCopyMemory( &m_TVTunerChangeInfo,
|
|
pDataPacket->Data,
|
|
sizeof (KS_TVTUNER_CHANGE_INFO));
|
|
|
|
m_TVTunerChanged = TRUE;
|
|
|
|
if (m_pVBICaptureStream)
|
|
m_pVBICaptureStream->DataUnLock(Irql);
|
|
}
|
|
|
|
|
|
BOOL CWDMVideoDecoder::GetTunerInfo(KS_TVTUNER_CHANGE_INFO* pTVChangeInfo)
|
|
{
|
|
if (m_TVTunerChanged) {
|
|
KIRQL Irql;
|
|
m_pVBICaptureStream->DataLock(&Irql);
|
|
RtlCopyMemory(pTVChangeInfo, &m_TVTunerChangeInfo, sizeof (KS_TVTUNER_CHANGE_INFO));
|
|
m_TVTunerChanged = FALSE;
|
|
m_pVBICaptureStream->DataUnLock(Irql);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL CWDMVideoDecoder::SrbChangePowerState(PHW_STREAM_REQUEST_BLOCK pSrb)
|
|
{
|
|
|
|
DBGTRACE(("CWDMVideoDecoder:SrbChangePowerState()\n"));
|
|
|
|
switch (pSrb->CommandData.DeviceState)
|
|
{
|
|
case PowerDeviceD3:
|
|
m_preEventOccurred = TRUE;
|
|
m_pDevice->SaveState();
|
|
break;
|
|
case PowerDeviceD2:
|
|
m_preEventOccurred = TRUE;
|
|
m_pDevice->SaveState();
|
|
break;
|
|
case PowerDeviceD1:
|
|
m_preEventOccurred = TRUE;
|
|
m_pDevice->SaveState();
|
|
break;
|
|
case PowerDeviceD0:
|
|
m_postEventOccurred = TRUE;
|
|
m_pDevice->RestoreState(m_OpenStreams);
|
|
break;
|
|
}
|
|
|
|
pSrb->Status = STATUS_SUCCESS;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
VOID CWDMVideoPortStream::AttemptRenegotiation()
|
|
{
|
|
int streamNumber = m_pStreamObject->StreamNumber;
|
|
if (m_EventCount)
|
|
{
|
|
DBGINFO(("Attempting renegotiation on stream %d\n", streamNumber));
|
|
|
|
if (streamNumber == STREAM_VPVideo)
|
|
{
|
|
StreamClassStreamNotification(
|
|
SignalMultipleStreamEvents,
|
|
m_pStreamObject,
|
|
&MY_KSEVENTSETID_VPNOTIFY,
|
|
KSEVENT_VPNOTIFY_FORMATCHANGE);
|
|
}
|
|
else if (streamNumber == STREAM_VPVBI)
|
|
{
|
|
StreamClassStreamNotification(
|
|
SignalMultipleStreamEvents,
|
|
m_pStreamObject,
|
|
&MY_KSEVENTSETID_VPVBINOTIFY,
|
|
KSEVENT_VPVBINOTIFY_FORMATCHANGE);
|
|
}
|
|
else
|
|
ASSERT(0);
|
|
}
|
|
else
|
|
{
|
|
DBGINFO(("NOT attempting renegotiation on stream %d\n", streamNumber));
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS CWDMVideoDecoder::EventProc( IN PHW_EVENT_DESCRIPTOR pEventDescriptor)
|
|
{
|
|
|
|
if( pEventDescriptor->Enable)
|
|
m_nMVDetectionEventCount++;
|
|
else
|
|
m_nMVDetectionEventCount--;
|
|
|
|
return( STATUS_SUCCESS);
|
|
}
|