📄 pddvclas.cpp
字号:
// Find an interface that has the packet size we need
lpIF = FindStreamInterface (pPDD, nInterface, TRUE, wPacketSize);
// See if interface not found
if (lpIF == 0)
return -1;
hTransfer = pDrv->lpUsbFuncs->lpSetInterface (pDrv->hDevice, NULL, NULL, 0, nInterface,
lpIF->ifDesc.bAlternateSetting);
if (hTransfer == 0)
{
DEBUGMSG (ZONE_ERROR, (TEXT("Error calling SetInterface rc=%d\r\n"), GetLastError()));
return GetLastError();
}
if (!CloseTransferHandle (pDrv->lpUsbFuncs, hTransfer))
rc = GetLastError();
rc = 0;
// Open a pipe to the end point
if (lpIF->fEndpoint)
{
// Open the pipe
pPDD->pipeStream.hPipe = pDrv->lpUsbFuncs->lpOpenPipe (pDrv->hDevice, &lpIF->epDesc);
// Check for sucessful open
if (pPDD->pipeStream.hPipe)
{
// Copy some pipe attributes
pPDD->pipeStream.ucAddr = lpIF->epDesc.bEndpointAddress;
pPDD->pipeStream.wPacketSize = lpIF->epDesc.wMaxPacketSize;
// First, create an event for handshaking
pPDD->pipeStream.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
}
else
{
rc = GetLastError();
if (rc == 0) rc = ERROR_NOT_ENOUGH_MEMORY; // Sometimes, there isn't an extended error here
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Error opening pipe rc: %d\r\n"), rc));
}
}
if (rc)
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Error in SetStreamInterface rc: %d ExtErr: %d\r\n"), rc, GetLastError()));
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("SetStreamInterface-- rc %d\r\n"), rc));
return rc;
}
//-----------------------------------------------------------------------
// ParseStreamInterfaces - Walks the camera's USB interface descriptors
// to determine the supported freaturs of the camera.
//
BOOL ParseStreamInterfaces (PPDDCONTEXT pPDD, LPCUSB_DEVICE lpUsbDev, BYTE bIFCtl,
BYTE bIFSubCtl, BYTE bIFStrm, BYTE bIFSubStrm)
{
DEBUGMSG (ZONE_USBLOAD, (DTAG TEXT("ParseStreamInterfaces++\r\n")));
DEBUGMSG (ZONE_USBLOAD, (DTAG TEXT("Looking for Ctl IF %d %d and Stream IF %d %d\r\n"), bIFCtl, bIFSubCtl, bIFStrm, bIFSubStrm));
__try {
if (lpUsbDev->lpConfigs->dwCount != sizeof (USB_CONFIGURATION))
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Unexpected CUSB_CONFIGURATION dwCount: %d ***********\r\n"), lpUsbDev->lpConfigs->dwCount));
return FALSE;
}
DWORD i;
LPCUSB_INTERFACE lpIF;
int nStreamAlts = 0;
int nOtherStreams = 0;
int nStreamID = -1;
// Walk interface table to find the number of Video stream interface alternates and if there are
// other video streams that aren't alts.
for (i = 0; i < lpUsbDev->lpConfigs->dwNumInterfaces; i++)
{
lpIF = &lpUsbDev->lpConfigs->lpInterfaces[i];
if ((lpIF->Descriptor.bInterfaceClass == bIFStrm) && (lpIF->Descriptor.bInterfaceSubClass == bIFSubStrm))
{
// Is first stream?
if (nStreamID == -1)
nStreamID = lpIF->Descriptor.bInterfaceNumber;
else if (nStreamID == lpIF->Descriptor.bInterfaceNumber)
nStreamAlts++;
else
nOtherStreams++;
}
}
if (nStreamID == -1)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("No stream interfaces\r\n")));
return FALSE;
}
pPDD->nStreamInterfaces = nStreamAlts + 1;
DEBUGMSG (ZONE_USBLOAD, (DTAG TEXT("Found %d stream interfaces. ID %d\r\n"), pPDD->nStreamInterfaces, nStreamID));
if (nOtherStreams)
{
DEBUGMSG (ZONE_WARNING, (DTAG TEXT("Multiple stream interfaces found on device. Using first one.\r\n")));
}
// Allocate the array for the stream interface descriptors
if (pPDD->nStreamInterfaces)
{
pPDD->usbstrmIF = (PUSBSTRMIF)LocalAlloc (LPTR, pPDD->nStreamInterfaces * sizeof (USBSTRMIF));
}
nStreamAlts = 0; // We'll use this to keep track of which stream and alt we've found.
// Walk interface table again to get the info we need
for (i = 0; i < lpUsbDev->lpConfigs->dwNumInterfaces; i++)
{
lpIF = &lpUsbDev->lpConfigs->lpInterfaces[i];
//
// See if this is the video control interface
//
if ((lpIF->Descriptor.bInterfaceClass == bIFCtl) && (lpIF->Descriptor.bInterfaceSubClass == bIFSubCtl))
{
// Copy descriptor info
pPDD->usbctlIF.ifDesc = lpIF->Descriptor;
if (lpIF->lpvExtended)
{
// Cast the extended ptr as a video control extended header ptr
PUSBVIDCTLIFDESCRIPTOR lpExDesc = (PUSBVIDCTLIFDESCRIPTOR)lpIF->lpvExtended;
// Verify the header length
if (lpExDesc->bLen > 0x0a)
{
// Allocate the space for the descriptor
pPDD->usbctlIF.lpepExtDesc = LocalAlloc (LPTR, lpExDesc->wTotalLen);
if (pPDD->usbctlIF.lpepExtDesc)
{
// Copy over the extended descriptor
memcpy (pPDD->usbctlIF.lpepExtDesc, lpExDesc, lpExDesc->wTotalLen);
}
else
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Out of memory allocating extended if descriptor\r\n")));
return FALSE;
}
}
else
{
DEBUGMSG (ZONE_ERROR | ZONE_USBLOAD,
(DTAG TEXT("Unexpected extended Ctl header format")));
return FALSE;
}
}
else
pPDD->usbctlIF.lpifExtDesc = 0;
// Grab the interrupt end point if specified
if (lpIF->lpEndpoints)
{
pPDD->usbctlIF.epDesc = lpIF->lpEndpoints->Descriptor;
pPDD->usbctlIF.fEndpoint = TRUE;
}
else
pPDD->usbctlIF.fEndpoint = FALSE;
}
//
// See if this is the video stream interface
//
if ((lpIF->Descriptor.bInterfaceClass == bIFStrm) &&
(lpIF->Descriptor.bInterfaceSubClass == bIFSubStrm) &&
(lpIF->Descriptor.bInterfaceNumber == nStreamID)) // Also check for matching interface number found above
{
// Copy descriptor info
pPDD->usbstrmIF[nStreamAlts].ifDesc = lpIF->Descriptor;
if (lpIF->lpvExtended)
{
// Cast the extended ptr as a video control extended header ptr
PUSBVIDSTREAMIFDESCRIPTOR lpExDesc = (PUSBVIDSTREAMIFDESCRIPTOR)lpIF->lpvExtended;
// Verify the header length
if (lpExDesc->bLen > 0x0a)
{
// Allocate the space for the descriptor
pPDD->usbstrmIF[nStreamAlts].lpepExtDesc = LocalAlloc (LPTR, lpExDesc->wTotalLen);
if (pPDD->usbstrmIF[nStreamAlts].lpepExtDesc)
{
// Copy over the extended descriptor
memcpy (pPDD->usbstrmIF[nStreamAlts].lpepExtDesc, lpExDesc, lpExDesc->wTotalLen);
}
else
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Out of memory allocating extended if descriptor\r\n")));
return FALSE;
}
}
else
{
DEBUGMSG (ZONE_ERROR | ZONE_USBLOAD,
(DTAG TEXT("Unexpected extended Stream header format")));
return FALSE;
}
}
else
pPDD->usbstrmIF[nStreamAlts].lpifExtDesc = 0;
// Grab the interrupt end point if specified
if (lpIF->lpEndpoints)
{
pPDD->usbstrmIF[nStreamAlts].epDesc = lpIF->lpEndpoints->Descriptor;
pPDD->usbstrmIF[nStreamAlts].fEndpoint = TRUE;
}
else
pPDD->usbstrmIF[nStreamAlts].fEndpoint = FALSE;
nStreamAlts++; // Inc index into stream interface array
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Exception walking device interfaces\r\n")));
return FALSE;
}
DEBUGMSG (ZONE_USBLOAD, (DTAG TEXT("ParseStreamInterfaces--\r\n")));
return TRUE;
}
//-----------------------------------------------------------------------
// GetCameraError - Queries the error code from the device
//
int GetCameraError (PDRVCONTEXT pDrv, BYTE *pErr)
{
int rc = 0;
BYTE bInterface = VID_IF_STREAM;
BYTE bUnit = 0;
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("GetCameraError++\r\n")));
// Get our pdd specific context
PPDDCONTEXT pPDD = (PPDDCONTEXT)pDrv->dwPddContext;
*pErr = 0;
rc = DoVendorTransfer (pDrv, USBVID_SET_CUR, USB_VIDEO_VS_CS_PROBE_CTL,
bInterface, bUnit, pErr, 1);
if (rc)
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Error reading error code from camera rc %d\r\n"), rc));
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("GetCameraError++ rc %d error code %d\r\n"), rc, *pErr));
return rc;
}
//=========================================================================
// ReadIsocThread - Thread that calls the Iscoh transfer function to
// read the image data from the camera.
//
#define MAXFRAMES 1
DWORD WINAPI ReadIsocThread (PVOID pArg) {
PDRVCONTEXT pDrv = (PDRVCONTEXT)pArg;
PPDDCONTEXT pPDD = (PPDDCONTEXT)pDrv->dwPddContext;
PBYTE pDataBuff, pEnd;
int nNumFrames;
DWORD dw;
DWORD dwFrameLen[MAXFRAMES];
DWORD dwUsbRc[MAXFRAMES];
DWORD dwBytes;
#ifdef DEBUG
DWORD dwTicksAtFrameEnd = 0;
#endif
BYTE bSaveBytes[16];
DWORD dwFrameBytes;
BYTE bError;
DEBUGMSG (ZONE_FUNC | ZONE_THREAD,
(DTAG TEXT("ReaReadIsocThreaddThread++ ID:%08x\r\n"), GetCurrentThread()));
// Tweak the thread priority since we need priority over apps
// to read the pipe on time.
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
// Initialize the ptrs
pPDD->pstrStream->dwCurrBuff = 0;
pPDD->pstrStream->dwValidFrames = 0; // No valid frames yet...
pDataBuff = pPDD->pstrStream->pFrame[pPDD->pstrStream->dwCurrBuff].pBuff;
pEnd = pDataBuff + pPDD->pstrStream->dwBuffSize;
memset (dwFrameLen, 0, sizeof (dwFrameLen));
memset (dwUsbRc, 0, sizeof (dwUsbRc));
// Compare the buffer size with the packet size to make sure we at least can
// read something.
if (pPDD->pstrStream->dwBuffSize < pPDD->pipeStream.wPacketSize)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("ReadThread failure, read buff size smaller than packet size\r\n")));
return -1;
}
#if MAXFRAMES > 1
// See if we need multiple packets because stream packet size is > 1024
{
nNumFrames = (pPDD->pipeStream.wPacketSize / 1024) + 1;
if (nNumFrames > MAXFRAMES)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Packetsize %d > larger than supported\r\n"), pPDD->pipeStream.wPacketSize));
return -2;
}
}
#endif
//
// Isoc pipe read loop
//
while (pPDD->wReadThreadState != STREAMTHD_STOPPED)
{
// If we're looking for the first frame, reset ptr to start of first buffer
if (pPDD->wReadThreadState == STREAMTHD_FRAMESYNC)
{
pDataBuff = pPDD->pstrStream->pFrame[pPDD->pstrStream->dwCurrBuff].pBuff;
pEnd = pDataBuff + pPDD->pstrStream->dwBuffSize;
}
// Init size of frame buffers
#if MAXFRAMES > 1
int nPacket = pPDD->pipeStream.wPacketSize;
for (nNumFrames = 0; (nPacket > 0) && (nNumFrames < MAXFRAMES); nNumFrames++)
{
// Max transfer in USB is 1K
dwFrameLen[nNumFrames] = min (nPacket, 1024);
nPacket -= dwFrameLen[nNumFrames];
}
#else
dwFrameLen[0] = min (pPDD->pipeStream.wPacketSize, 1024);
nNumFrames = 1;
#endif
// Limit check on buffer
if (pDataBuff + dwFrameLen[0] >= pEnd)
{
DEBUGMSG (ZONE_ERROR | ZONE_THREAD, (DTAG TEXT("Buffer too small for next isoc data packet!\r\n")));
break;
}
__try {
dw = IssueIsochTransfer (pDrv->lpUsbFuncs, pPDD->pipeStream.hPipe,
DefaultTransferComplete, pPDD->pipeStream.hEvent,
USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK | USB_START_ISOCH_ASAP | USB_COMPRESS_ISOCH,
0, // Using USB_START_ISOCH_ASAP precludes the need for a start frame
nNumFrames, // Number of frames to read
dwFrameLen, // Array that receives the length of each frame
pDataBuff, // Pointer to transfer buffer
0, // Specifies the physical address, which may be NULL, of the data buffer
&dwBytes, // Number of bytes transferred by USB
1500, // Timeout in msec
dwUsbRc); // Returns USB_ERROR or USB_TRANSFER
DEBUGMSG (ZONE_READDATA && (dwBytes > 12), (DTAG TEXT("Read %5d bytes at %x dw: %d\r\n"), dwBytes, pDataBuff, dw));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG (ZONE_ERROR | ZONE_THREAD, (DTAG TEXT ("Exception calling IssueIsochTransfer %d %d\r\n"), dw, GetLastError()));
break;
}
if (dw)
{
DEBUGMSG (ZONE_ERROR | ZONE_THREAD, (DTAG TEXT ("Error calling IssueIsochTransfer %d %d\r\n"), dw, GetLastError()));
if ((dw == 8) || (dw == 9)) // USB overrun and underrun errors.
continue;
// else
// break;
int rc = GetCameraError (pDrv, &bError);
if (rc)
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Can't read camera error code rc %d\r\n"), rc));
else
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Camera error code %d\r\n"), bError));
}
// See if we read at least the header
if (dwBytes == 0)
{
DEBUGMSG (ZONE_READDATA, (DTAG TEXT("packet size read if %d bytes smaller than standard header\r\n"), dwBytes));
continue;
}
// Look at payload header
PUSBVIDPAYLOADHDR pPktHdr = (PUSBVIDPAYLOADHDR)pDataBuff;
BYTE bPktFlags;
if (pPktHdr->bLen != sizeof (USBVIDPAYLOADHDR))
{
DEBUGMSG (ZONE_PACKETS, (DTAG TEXT("===============
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -