📄 pddvclas.cpp
字号:
}
else
rc = ERROR_NOT_SUPPORTED;
DEBUGMSG (ZONE_FUNC | ZONE_FEATURE,
(DTAG TEXT("pdd_SetParameter-- rc %d\r\n"), rc));
return rc;
}
//-----------------------------------------------------------------------
// GetFormatParameters - This routine parses the video class control
// interface descriptor to find information on the requested format
//
int pdd_GetFormatParameters (PDRVCONTEXT pDrv, BYTE bFormatIndex, BYTE bFrameIndex,
BOOL fStill, PFORMATPROPS pProps)
{
int rc;
BYTE bLastSubType = USB_VIDEO_VS_UNDEFINED;
BOOL fFound = FALSE;
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("pdd_GetFormatParameters++\r\n")));
// Get our pdd specific contextlpex
PPDDCONTEXT pPDD = (PPDDCONTEXT)pDrv->dwPddContext;
// Find the Frame descriptors
PUSBVIDSTREAMIFDESCRIPTOR pHdr = (PUSBVIDSTREAMIFDESCRIPTOR)pPDD->usbstrmIF->lpepExtDesc;
__try {
// Sanity check on header IDs
if ((pHdr->bType != 0x24) || (pHdr->bSubtype != 1))
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Bad Extended Stream Descriptor\r\n")));
return -1;
}
PBYTE pData = (PBYTE)pPDD->usbstrmIF->lpepExtDesc;
PBYTE pEnd = (PBYTE)pPDD->usbstrmIF->lpepExtDesc + pHdr->wTotalLen;
PUSBVIDSTDDESCHDR pStd = (PUSBVIDSTDDESCHDR)pHdr;
// Loop through all the descriptors
while (pData + pStd->bLen < pEnd)
{
pData += pStd->bLen;
pStd = (PUSBVIDSTDDESCHDR)pData;
if (pStd->bType != USB_VIDEO_CS_INTERFACE)
{
DEBUGMSG (1, (TEXT("Unexpected header type %xh\r\n"), pStd->bType));
break;
}
// Are we looking for still formats or stream?
if (!fStill)
{
switch (pStd->bSubtype)
{
//TODO:: Need to support other formats
case USB_VIDEO_VS_FORMAT_MJPEG:
rc = ProcessFrameFormats (pPDD, pStd, VIDFORMAT_MJPEG,
bFormatIndex, bFrameIndex, pProps, &fFound);
break;
case USB_VIDEO_VS_FORMAT_UNCOMPRESSED:
rc = ProcessFrameFormats (pPDD, pStd, VIDFORMAT_UNCOMPRESSED,
bFormatIndex, bFrameIndex, pProps, &fFound);
break;
case USB_VIDEO_VS_FORMAT_FRAME_BASED:
rc = ProcessFrameFormats (pPDD, pStd, USB_VIDEO_VS_FRAME_FRAME_BASED,
bFormatIndex, bFrameIndex, pProps, &fFound);
break;
case USB_VIDEO_VS_FORMAT_MPEG2TS:
break;
case USB_VIDEO_VS_FORMAT_DV:
break;
default:
break;
}
if (fFound)
return rc;
}
else
{
if (pStd->bSubtype == USB_VIDEO_VS_STILL_IMAGE_FRAME)
{
PUSBVIDSTREAMIF_STILLIMGDESCRIPTOR pFrmStill = (PUSBVIDSTREAMIF_STILLIMGDESCRIPTOR)pStd;
// See if index is within range
if (bFrameIndex < pFrmStill->bNumImageSizePatterns)
{
memset (pProps, 0, sizeof (FORMATPROPS));
pProps->cbSize = sizeof (FORMATPROPS);
pProps->wFormatType = bLastSubType;
pProps->wFormatIndex = bFormatIndex;
pProps->wFrameIndex = bFrameIndex;
pProps->dwHeight = pFrmStill->sStillFmt[bFrameIndex].wHeight;
pProps->dwWidth = pFrmStill->sStillFmt[bFrameIndex].wWidth;
//Maxbuff below assumes worst case 32bpp
pProps->dwMaxBuff = pProps->dwHeight * pProps->dwWidth * 4;
return 0;
}
return -4;
}
}
// Save the last format type
bLastSubType = pStd->bSubtype;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG (1, (TEXT("Exception scanning extended stream descriptor\r\n")));
return -2;
}
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("pdd_GetFormatParameters--\r\n")));
return -3;
}
//-----------------------------------------------------------------------
// pdd_GetCurrentFormat - Returns the format of the current stream
// but only if the stream is not internal.
//
int pdd_GetCurrentFormat (PDRVCONTEXT pDrv, PFORMATPROPS pProps)
{
int rc = ERROR_VC_DISCONNECTED;
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("pdd_GetCurrentFormat++\r\n")));
// Get our pdd specific context
PPDDCONTEXT pPDD = (PPDDCONTEXT)pDrv->dwPddContext;
// See if stream running
if (pPDD->wReadThreadState != STREAMTHD_STOPPED)
{
// Make sure its not an internal stream for still capture
if ((DWORD)pPDD->pstrStream != (DWORD)&pPDD->strStreamDefault)
{
rc = pdd_GetFormatParameters (pDrv, (BYTE)pPDD->wCurrFormatIndex,
(BYTE)pPDD->wCurrFrameIndex, FALSE,
pProps);
// Save the stream rate
pProps->nNumInterval = 1;
pProps->dwInterval[0] = pPDD->dwCurrValidInterval;
}
}
if (rc == ERROR_VC_DISCONNECTED)
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Error No stream active\r\n")));
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("pdd_GetCurrentFormat-- rc %d\r\n"), rc));
return rc;
}
//-----------------------------------------------------------------------
// pdd_StartVidStream - Set streaming video from camera
//
int pdd_StartVidStream (PDRVCONTEXT pDrv, BYTE bFormatIndex, BYTE bFrameIndex,
PVIDSTREAMSTRUCT pstrStream, DWORD dwFrameInterval)
{
int i, rc = 0;
BYTE bInterface = VID_IF_STREAM;
BYTE bUnit = 0;
DWORD dwValidInterval;
int nIntIndex;
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("pdd_StartVidStream++ Fmt %d\r\n"), bFrameIndex));
// Get our pdd specific context
PPDDCONTEXT pPDD = (PPDDCONTEXT)pDrv->dwPddContext;
//
// If we're starting just for a still capture, if any streaming is going
// on, we'll take it and return.
//
if ((bFormatIndex == 0xff) && (bFrameIndex == 0xff))
{
if (pPDD->pstrStream != 0)
{
DEBUGMSG (ZONE_STILL, (DTAG TEXT("StartVidStream already running. Exiting\r\n")));
return ERROR_STREAM_ALREADY_RUNNING;
}
bFormatIndex = 1;
bFrameIndex = 1;
dwFrameInterval = 0;
}
//
// Query the parameters for the new format. This validates format and frame values
//
FORMATPROPS Props;
rc = pdd_GetFormatParameters (pDrv, bFormatIndex, bFrameIndex, FALSE, &Props);
if (rc)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Bad format or frame fmt:%d frame:%d rc %d\r\n"),
bFormatIndex, bFrameIndex, rc));
return ERROR_INVALID_PARAMETER;
}
//
// Validate the frame interval
//
// Discrete intervals?
if (Props.nNumInterval != 0)
{
// See if min
if (dwFrameInterval == -1)
nIntIndex = Props.nNumInterval-1;
// If 0, set to fastest interval
else if (dwFrameInterval == 0)
nIntIndex = 0;
// Else look up to see if valid
else
{
// Loop through the allowed descrete intervals
for (nIntIndex = 0; nIntIndex < Props.nNumInterval; nIntIndex++)
{
if (dwFrameInterval == Props.dwInterval[nIntIndex])
break;
}
if (nIntIndex == Props.nNumInterval)
rc = ERROR_INVALID_PARAMETER;
}
}
else
{
// See if min
if (dwFrameInterval == -1)
dwValidInterval = Props.dwInterval[0]; //Min value
// If 0, set to fastest interval
else if (dwFrameInterval == 0)
dwValidInterval = Props.dwInterval[1]; //Max value
// Else see if in proper range
else
if ((dwFrameInterval >= Props.dwInterval[0]) && (dwFrameInterval <= Props.dwInterval[1]))
dwValidInterval = dwFrameInterval;
else
rc = ERROR_INVALID_PARAMETER;
}
if (rc)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT ("Bad frame interval %d specified\r\n"), dwFrameInterval));
return rc;
}
//
// Do probe commit for video stream
//
// Discrete intervals?
if (Props.nNumInterval != 0)
{
// Try all frame intervals for a given Format/Frame size setting
for (i = nIntIndex; i < Props.nNumInterval; i++)
{
// See if any quality setting for these parameters can work
rc = NegotiateQuality (pDrv, bFormatIndex, bFrameIndex, Props.dwInterval[i]);
if (rc == 0)
break;
}
}
else
{
// Starting with specified interval increment until over max
while (dwValidInterval <= Props.dwInterval[1])
{
// See if any quality setting for these parameters can work
rc = NegotiateQuality (pDrv, bFormatIndex, bFrameIndex, dwValidInterval);
if (rc == 0)
break;
// Increment by granularity
dwValidInterval += Props.dwInterval[2]; // rate granularity
}
}
if (rc)
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Probe/Commit failed. Not enough bandwidth for Fmt: %d Frm: %d\r\n"),
bFormatIndex, bFrameIndex));
//
// Allocate the streaming buffers if an internal stream just for a still
//
if (rc == 0)
{
// See if we need to set up a default stream or if we're changing the dest buffers
if (pstrStream == 0)
{
// Allocate buffers internally for the stream
rc = AllocateInternalStreamBuffers (pPDD, Props.dwMaxBuff);
if (rc == 0)
{
pPDD->pstrStream = (PVIDSTREAMSTRUCT)&pPDD->strStreamDefault;
}
}
// Else, we have a stream strcture passed to us. Use it.
else
{
pPDD->pstrStream = pstrStream;
}
}
//
// Start the read thread to get the data
//
if (rc == 0)
{
// Start of read thread if not already started
if (pPDD->wReadThreadState == STREAMTHD_STOPPED)
{
// Create the thread
pPDD->wReadThreadState = 1;
pPDD->hReadThread = CreateThread (NULL, 0, ReadIsocThread, (PVOID)pDrv, 0, NULL);
if (pPDD->hReadThread == 0)
{
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Error creating read thread ExtErr: %d\r\n"), GetLastError()));
pPDD->wReadThreadState = 0;
rc = -1;
} else
Sleep (10);
}
}
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("StartVidStream-- rc %d\r\n"), rc));
return rc;
}
//---------------------------------------------------------------------------------------
// pdd_GetNextVideoFrame - Returns the latest valid frame in the frame buffer.
//
int pdd_GetNextVideoFrame (PDRVCONTEXT pDrv, BOOL fGetLatest, PBYTE *ppFrameBuff,
DWORD *pdwFrameBytes, DWORD *pdwValidFrames, PBYTE pFrameReturn,
DWORD dwTimeout)
{
int rc = 0;
DWORD i;
BOOL fLeaveCS = TRUE;
DEBUGMSG (ZONE_FUNC, (DTAG TEXT("pdd_GetNextVideoFrame++\r\n")));
PPDDCONTEXT pPDD = (PPDDCONTEXT)pDrv->dwPddContext;
// Sync with read thread
EnterCriticalSection (&pPDD->pstrStream->csBuffSync);
__try
{
//
// See if there is a frame to return
//
if (pFrameReturn != 0)
{
// Trivial sanity check for returned buffer. Buffer addresses will always
// be above the first entry in the buffer array.
if ((DWORD)pFrameReturn < (DWORD)&pPDD->pstrStream->pFrame[0].pBuff)
{
rc = ERROR_INVALID_PARAMETER;
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Returned buffer pointer %08x not valid \r\n"),
pFrameReturn));
__leave;
}
// Find a free slot in the array
for (i = 0; i < pPDD->pstrStream->dwNumBuffs; i++)
{
// If slot free, add the buffer back. Correct for packet header offset
if (pPDD->pstrStream->pFrame[i].pBuff == 0)
pPDD->pstrStream->pFrame[i].pBuff = pFrameReturn - sizeof (USBVIDPAYLOADHDR);
}
}
//
// See if they want a new frame
//
if (ppFrameBuff != 0)
{
int nCnt = 0;
// See if we have enough buffers remaining for this task. We
// need to leave at least 2 buffers in the list
for (i = 0; (i < pPDD->pstrStream->dwNumBuffs) && (nCnt < 2); i++)
{
// If slot free, add the buffer back
if (pPDD->pstrStream->pFrame[i].pBuff != 0)
nCnt++;
}
if (nCnt < 2)
{
rc = ERROR_NOT_ENOUGH_MEMORY;
DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Not enough free buffers to return one\r\n")));
__leave;
}
// We need to leave the CS to allow the isoc thread to complete
// a frame.
LeaveCriticalSection (&pPDD->pstrStream->csBuffSync);
fLeaveCS = FALSE;
// Wait for new frame event
rc = WaitForSingleObject ((HANDLE)pPDD->pstrStream->dwReserved, dwTimeout);
if (rc == WAIT_OBJECT_0)
{
// Retake the CS so we can access the struct again
EnterCriticalSection (&pPDD->pstrStream->csBuffSync);
fLeaveCS = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -