|
|
/****************************************************************************
* @doc INTERNAL WDMDRIVER * * @module WDMDrivr.cpp | Include file for <c CWDMDriver> class used to * access the streaming class driver using IOctls. * * @comm This code is based on the VfW to WDM mapper code written by * FelixA and E-zu Wu. The original code can be found on * \\redrum\slmro\proj\wdm10\\src\image\vfw\win9x\raytube. * * Documentation by George Shaw on kernel streaming can be found in * \\popcorn\razzle1\src\spec\ks\ks.doc. * * WDM streaming capture is discussed by Jay Borseth in * \\blues\public\jaybo\WDMVCap.doc. ***************************************************************************/
#include "Precomp.h"
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc void | CWDMDriver | CWDMDriver | Driver class constructor. * * @parm DWORD | dwDeviceID | Capture device ID. ***************************************************************************/ CWDMDriver::CWDMDriver(DWORD dwDeviceID) { m_hDriver = (HANDLE)NULL; m_pDataRanges = (PDATA_RANGES)NULL;
m_dwDeviceID = dwDeviceID; }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc void | CWDMDriver | ~CWDMDriver | Driver class destructor. Closes * the driver file handle and releases the video data range memory. ***************************************************************************/ CWDMDriver::~CWDMDriver() { if (m_hDriver) CloseDriver();
if (m_pDataRanges) { delete [] m_pDataRanges; m_pDataRanges = (PDATA_RANGES)NULL; } }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc DWORD | CWDMDriver | CreateDriverSupportedDataRanges | This * function builds the list of video data ranges supported by the capture * device. * * @rdesc Returns the number of valid data ranges in the list. ***************************************************************************/ DWORD CWDMDriver::CreateDriverSupportedDataRanges() { FX_ENTRY("CWDMDriver::CreateDriverSupportedDataRanges");
DWORD cbReturned; DWORD dwSize = 0UL;
// Initialize property structure to get data ranges
KSP_PIN KsProperty = {0};
KsProperty.PinId = 0; // m_iPinNumber;
KsProperty.Property.Set = KSPROPSETID_Pin; KsProperty.Property.Id = KSPROPERTY_PIN_DATARANGES ; KsProperty.Property.Flags = KSPROPERTY_TYPE_GET;
// Get the size of the data range structure
if (DeviceIoControl(m_hDriver, IOCTL_KS_PROPERTY, &KsProperty, sizeof(KsProperty), &dwSize, sizeof(dwSize), &cbReturned) == FALSE) { ERRORMESSAGE(("%s: Couldn't get the size for the data ranges\r\n", _fx_)); return 0UL; }
DEBUGMSG(ZONE_INIT, ("%s: GetData ranges needs %d bytes\r\n", _fx_, dwSize));
// Allocate memory to hold data ranges
if (m_pDataRanges) delete [] m_pDataRanges; m_pDataRanges = (PDATA_RANGES) new BYTE[dwSize];
if (!m_pDataRanges) { ERRORMESSAGE(("%s: Couldn't allocate memory for the data ranges\r\n", _fx_)); return 0UL; }
// Really get the data ranges
if (DeviceIoControl(m_hDriver, IOCTL_KS_PROPERTY, &KsProperty, sizeof(KsProperty), m_pDataRanges, dwSize, &cbReturned) == 0) { ERRORMESSAGE(("%s: Problem getting the data ranges themselves\r\n", _fx_)); goto MyError1; }
// Sanity check
if (cbReturned < m_pDataRanges->Size || m_pDataRanges->Count == 0) { ERRORMESSAGE(("%s: cbReturned < m_pDataRanges->Size || m_pDataRanges->Count == 0\r\n", _fx_)); goto MyError1; }
return m_pDataRanges->Count;
MyError1: delete [] m_pDataRanges; m_pDataRanges = (PDATA_RANGES)NULL; return 0UL;
}
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc DWORD | CWDMDriver | OpenDriver | This function opens a driver * file handle to the capture device. * * @rdesc Returns TRUE if successful, or FALSE otherwise. ***************************************************************************/ BOOL CWDMDriver::OpenDriver() { FX_ENTRY("CWDMDriver::OpenDriver");
// Don't re-open the driver
if (m_hDriver) { DEBUGMSG(ZONE_INIT, ("%s: Class driver already opened\r\n", _fx_)); return TRUE; }
// Validate driver path
if (lstrlen(g_aCapDevices[m_dwDeviceID]->szDeviceName) == 0) { ERRORMESSAGE(("%s: Invalid driver path\r\n", _fx_)); return FALSE; }
DEBUGMSG(ZONE_INIT, ("%s: Opening class driver '%s'\r\n", _fx_, g_aCapDevices[m_dwDeviceID]->szDeviceName));
// All we care is to wet the hInheritHanle = TRUE;
SECURITY_ATTRIBUTES SecurityAttributes; SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); // use pointers
SecurityAttributes.bInheritHandle = TRUE; SecurityAttributes.lpSecurityDescriptor = NULL; // GetInitializedSecurityDescriptor();
// Really open the driver
if ((m_hDriver = CreateFile(g_aCapDevices[m_dwDeviceID]->szDeviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &SecurityAttributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)) == INVALID_HANDLE_VALUE) { ERRORMESSAGE(("%s: CreateFile failed with Path=%s GetLastError()=%d\r\n", _fx_, g_aCapDevices[m_dwDeviceID]->szDeviceName, GetLastError())); m_hDriver = (HANDLE)NULL; return FALSE; }
// If there is no valid data range, we cannot stream
if (!CreateDriverSupportedDataRanges()) { CloseDriver(); return FALSE; } else return TRUE; }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc DWORD | CWDMDriver | CloseDriver | This function closes a driver * file handle to the capture device. * * @rdesc Returns TRUE if successful, or FALSE otherwise. ***************************************************************************/ BOOL CWDMDriver::CloseDriver() { FX_ENTRY("CWDMDriver::CloseDriver");
BOOL bRet = TRUE;
if (m_hDriver && (m_hDriver != INVALID_HANDLE_VALUE)) { if (!(bRet = CloseHandle(m_hDriver))) { ERRORMESSAGE(("%s: CloseHandle() failed with GetLastError()=%d\r\n", _fx_, GetLastError())); } } else { DEBUGMSG(ZONE_INIT, ("%s: Nothing to close\r\n", _fx_)); }
m_hDriver = (HANDLE)NULL;
return bRet; }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc BOOL | CWDMDriver | DeviceIoControl | This function wraps around * ::DeviceIOControl. * * @parm HANDLE | hFile | Handle to the device that is to perform the * operation. * * @parm DWORD | dwIoControlCode | Specifies the control code for the * operation. * * @parm LPVOID | lpInBuffer | Pointer to a buffer that contains the data * required to perform the operation. * * @parm DWORD | nInBufferSize | Specifies the size, in bytes, of the buffer * pointed to by <p lpInBuffer>. * * @parm LPVOID | lpOutBuffer | Pointer to a buffer that receives the * operation's output data. * * @parm DWORD | nOutBufferSize | Specifies the size, in bytes, of the * buffer pointed to by <p lpOutBuffer>. * * @parm LPDWORD | lpBytesReturned | Pointer to a variable that receives the * size, in bytes, of the data stored into the buffer pointed to by * <p lpOutBuffer>. * * @parm BOOL | bOverlapped | If TRUE, the operation is performed * asynchronously, if FALSE, the operation is synchronous. * * @rdesc Returns TRUE if successful, or FALSE otherwise. ***************************************************************************/ BOOL CWDMDriver::DeviceIoControl(HANDLE hFile, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, BOOL bOverlapped) { FX_ENTRY("CWDMDriver::DeviceIoControl");
if (hFile && (hFile != INVALID_HANDLE_VALUE)) { LPOVERLAPPED lpOverlapped=NULL; BOOL bRet; OVERLAPPED ov; DWORD dwErr;
if (bOverlapped) { ov.Offset = 0; ov.OffsetHigh = 0; ov.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if (ov.hEvent == (HANDLE) 0) { ERRORMESSAGE(("%s: CreateEvent has failed\r\n", _fx_)); } lpOverlapped =&ov; }
bRet = ::DeviceIoControl(hFile, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped);
if (bOverlapped) { BOOL bShouldBlock=FALSE;
if (!bRet) { dwErr=GetLastError(); switch (dwErr) { case ERROR_IO_PENDING: // the overlapped IO is going to take place.
bShouldBlock=TRUE; break;
default: // some other strange error has happened.
ERRORMESSAGE(("%s: DevIoControl failed with GetLastError=%d\r\n", _fx_, dwErr)); break; } }
if (bShouldBlock) { #ifdef _DEBUG
DWORD tmStart, tmEnd, tmDelta; tmStart = timeGetTime(); #endif
DWORD dwRtn = WaitForSingleObject( ov.hEvent, 1000 * 10); // USB has a max of 5 SEC bus reset
#ifdef _DEBUG
tmEnd = timeGetTime(); tmDelta = tmEnd - tmStart; if (tmDelta >= 1000) { ERRORMESSAGE(("%s: WaitObj waited %d msec\r\n", _fx_, tmDelta)); } #endif
switch (dwRtn) { case WAIT_ABANDONED: ERRORMESSAGE(("%s: WaitObj: non-signaled ! WAIT_ABANDONED!\r\n", _fx_)); bRet = FALSE; break;
case WAIT_OBJECT_0: bRet = TRUE; break;
case WAIT_TIMEOUT: #ifdef _DEBUG
ERRORMESSAGE(("%s: WaitObj: TIMEOUT after %d msec! rtn FALSE\r\n", _fx_, tmDelta)); #endif
bRet = FALSE; break;
default: ERRORMESSAGE(("%s: WaitObj: unknown return ! rtn FALSE\r\n", _fx_)); bRet = FALSE; break; } }
CloseHandle(ov.hEvent); }
return bRet; }
return FALSE; }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc BOOL | CWDMDriver | GetPropertyValue | This function gets the * current value of a video property of a capture device. * * @parm GUID | guidPropertySet | GUID of the KS property set we are touching. It * is either PROPSETID_VIDCAP_VIDEOPROCAMP or PROPSETID_VIDCAP_CAMERACONTROL. * * @parm ULONG | ulPropertyId | ID of the property we are touching. It is * either KSPROPERTY_VIDEOPROCAMP_* or KSPROPERTY_CAMERACONTROL_*. * * @parm PLONG | plValue | Pointer to a LONG to receive the current value. * * @parm PULONG | pulFlags | Pointer to a ULONG to receive the current * flags. We only care about KSPROPERTY_*_FLAGS_MANUAL or * KSPROPERTY_*_FLAGS_AUTO. * * @parm PULONG | pulCapabilities | Pointer to a ULONG to receive the * capabilities. We only care about KSPROPERTY_*_FLAGS_MANUAL or * KSPROPERTY_*_FLAGS_AUTO. * * @rdesc Returns TRUE if successful, or FALSE otherwise. * * @devnote KSPROPERTY_VIDEOPROCAMP_S == KSPROPERTY_CAMERACONTROL_S. ***************************************************************************/ BOOL CWDMDriver::GetPropertyValue(GUID guidPropertySet, ULONG ulPropertyId, PLONG plValue, PULONG pulFlags, PULONG pulCapabilities) { FX_ENTRY("CWDMDriver::GetPropertyValue");
ULONG cbReturned;
// Inititalize video property structure
KSPROPERTY_VIDEOPROCAMP_S VideoProperty; ZeroMemory(&VideoProperty, sizeof(KSPROPERTY_VIDEOPROCAMP_S));
VideoProperty.Property.Set = guidPropertySet; // KSPROPERTY_VIDEOPROCAMP_S/CAMERACONTRO_S
VideoProperty.Property.Id = ulPropertyId; // KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
VideoProperty.Property.Flags = KSPROPERTY_TYPE_GET; VideoProperty.Flags = 0;
// Get property value from driver
if (DeviceIoControl(m_hDriver, IOCTL_KS_PROPERTY, &VideoProperty, sizeof(VideoProperty), &VideoProperty, sizeof(VideoProperty), &cbReturned, TRUE) == 0) { ERRORMESSAGE(("%s: This property is not supported by this minidriver/device\r\n", _fx_)); return FALSE; }
*plValue = VideoProperty.Value; *pulFlags = VideoProperty.Flags; *pulCapabilities = VideoProperty.Capabilities;
return TRUE; }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc BOOL | CWDMDriver | GetDefaultValue | This function gets the * default value of a video property of a capture device. * * @parm GUID | guidPropertySet | GUID of the KS property set we are touching. It * is either PROPSETID_VIDCAP_VIDEOPROCAMP or PROPSETID_VIDCAP_CAMERACONTROL. * * @parm ULONG | ulPropertyId | ID of the property we are touching. It is * either KSPROPERTY_VIDEOPROCAMP_* or KSPROPERTY_CAMERACONTROL_*. * * @parm PLONG | plDefValue | Pointer to a LONG to receive the default value. * * @rdesc Returns TRUE if successful, or FALSE otherwise. ***************************************************************************/ BOOL CWDMDriver::GetDefaultValue(GUID guidPropertySet, ULONG ulPropertyId, PLONG plDefValue) { FX_ENTRY("CWDMDriver::GetDefaultValue");
ULONG cbReturned;
KSPROPERTY Property; PROCAMP_MEMBERSLIST proList;
// Initialize property structures
ZeroMemory(&Property, sizeof(KSPROPERTY)); ZeroMemory(&proList, sizeof(PROCAMP_MEMBERSLIST));
Property.Set = guidPropertySet; Property.Id = ulPropertyId; // e.g. KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES;
// Get the default values from the driver
if (DeviceIoControl(m_hDriver, IOCTL_KS_PROPERTY, &(Property), sizeof(Property), &proList, sizeof(proList), &cbReturned, TRUE) == 0) { ERRORMESSAGE(("%s: Couldn't *get* the current property of the control\r\n", _fx_)); return FALSE; }
// Sanity check
if (proList.proDesc.DescriptionSize < sizeof(KSPROPERTY_DESCRIPTION)) return FALSE; else { *plDefValue = proList.ulData; return TRUE; } }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc BOOL | CWDMDriver | GetRangeValues | This function gets the * range values of a video property of a capture device. * * @parm GUID | guidPropertySet | GUID of the KS property set we are touching. It * is either PROPSETID_VIDCAP_VIDEOPROCAMP or PROPSETID_VIDCAP_CAMERACONTROL. * * @parm ULONG | ulPropertyId | ID of the property we are touching. It is * either KSPROPERTY_VIDEOPROCAMP_* or KSPROPERTY_CAMERACONTROL_*. * * @parm PLONG | plMin | Pointer to a LONG to receive the minimum value. * * @parm PLONG | plMax | Pointer to a LONG to receive the maximum value. * * @parm PLONG | plStep | Pointer to a LONG to receive the step value. * * @rdesc Returns TRUE if successful, or FALSE otherwise. ***************************************************************************/ BOOL CWDMDriver::GetRangeValues(GUID guidPropertySet, ULONG ulPropertyId, PLONG plMin, PLONG plMax, PLONG plStep) { FX_ENTRY("CWDMDriver::GetRangeValues");
ULONG cbReturned;
KSPROPERTY Property; PROCAMP_MEMBERSLIST proList;
// Initialize property structures
ZeroMemory(&Property, sizeof(KSPROPERTY)); ZeroMemory(&proList, sizeof(PROCAMP_MEMBERSLIST));
Property.Set = guidPropertySet; Property.Id = ulPropertyId; // e.g. KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
// Get range values from the driver
if (DeviceIoControl(m_hDriver, IOCTL_KS_PROPERTY, &(Property), sizeof(Property), &proList, sizeof(proList), &cbReturned, TRUE) == 0) { ERRORMESSAGE(("%s: Couldn't *get* the current property of the control\r\n", _fx_)); return FALSE; }
*plMin = proList.proData.Bounds.SignedMinimum; *plMax = proList.proData.Bounds.SignedMaximum; *plStep = proList.proData.SteppingDelta;
return TRUE; }
/****************************************************************************
* @doc INTERNAL CWDMDRIVERMETHOD * * @mfunc BOOL | CWDMDriver | SetPropertyValue | This function sets the * current value of a video property of a capture device. * * @parm GUID | guidPropertySet | GUID of the KS property set we are touching. It * is either PROPSETID_VIDCAP_VIDEOPROCAMP or PROPSETID_VIDCAP_CAMERACONTROL. * * @parm ULONG | ulPropertyId | ID of the property we are touching. It is * either KSPROPERTY_VIDEOPROCAMP_* or KSPROPERTY_CAMERACONTROL_*. * * @parm LONG | lValue | New value. * * @parm ULONG | ulFlags | New flags. We only care about KSPROPERTY_*_FLAGS_MANUAL * or KSPROPERTY_*_FLAGS_AUTO. * * @parm ULONG | ulCapabilities | New capabilities. We only care about * KSPROPERTY_*_FLAGS_MANUAL or KSPROPERTY_*_FLAGS_AUTO. * * @rdesc Returns TRUE if successful, or FALSE otherwise. * * @devnote KSPROPERTY_VIDEOPROCAMP_S == KSPROPERTY_CAMERACONTROL_S. ***************************************************************************/ BOOL CWDMDriver::SetPropertyValue(GUID guidPropertySet, ULONG ulPropertyId, LONG lValue, ULONG ulFlags, ULONG ulCapabilities) { FX_ENTRY("CWDMDriver::SetPropertyValue");
ULONG cbReturned;
// Initialize property structure
KSPROPERTY_VIDEOPROCAMP_S VideoProperty;
ZeroMemory(&VideoProperty, sizeof(KSPROPERTY_VIDEOPROCAMP_S) );
VideoProperty.Property.Set = guidPropertySet; // KSPROPERTY_VIDEOPROCAMP_S/CAMERACONTRO_S
VideoProperty.Property.Id = ulPropertyId; // KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
VideoProperty.Property.Flags = KSPROPERTY_TYPE_SET;
VideoProperty.Flags = ulFlags; VideoProperty.Value = lValue; VideoProperty.Capabilities = ulCapabilities;
// Set the property value on the driver
if (DeviceIoControl(m_hDriver, IOCTL_KS_PROPERTY, &VideoProperty, sizeof(VideoProperty), &VideoProperty, sizeof(VideoProperty), &cbReturned, TRUE) == 0) { ERRORMESSAGE(("%s: Couldn't *set* the current property of the control\r\n", _fx_)); return FALSE; }
return TRUE; }
|