📄 vfw.cxx
字号:
//returns object with gray color pallet if needed for 8 bpp formats
PVideoDeviceBitmap(HWND hWnd, WORD bpp);
// does not build color pallet
PVideoDeviceBitmap(HWND hWnd);
// apply video format to capture device
PBoolean ApplyFormat(HWND hWnd, const FormatTableEntry & formatTableEntry);
BITMAPINFO * operator->() const
{ return (BITMAPINFO *)theArray; }
};
PVideoDeviceBitmap::PVideoDeviceBitmap(HWND hCaptureWindow)
{
PINDEX sz = capGetVideoFormatSize(hCaptureWindow);
SetSize(sz);
if (!capGetVideoFormat(hCaptureWindow, theArray, sz)) {
PTRACE(1, "PVidInp\tcapGetVideoFormat(hCaptureWindow) failed - " << ::GetLastError());
SetSize(0);
return;
}
}
PVideoDeviceBitmap::PVideoDeviceBitmap(HWND hCaptureWindow, WORD bpp)
{
PINDEX sz = capGetVideoFormatSize(hCaptureWindow);
SetSize(sz);
if (!capGetVideoFormat(hCaptureWindow, theArray, sz)) {
PTRACE(1, "PVidInp\tcapGetVideoFormat(hCaptureWindow) failed - " << ::GetLastError());
SetSize(0);
return;
}
if (8 == bpp && bpp != ((BITMAPINFO*)theArray)->bmiHeader.biBitCount) {
SetSize(sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);
RGBQUAD * bmiColors = ((BITMAPINFO*)theArray)->bmiColors;
for (int i = 0; i < 256; i++)
bmiColors[i].rgbBlue = bmiColors[i].rgbGreen = bmiColors[i].rgbRed = (BYTE)i;
}
((BITMAPINFO*)theArray)->bmiHeader.biBitCount = bpp;
}
PBoolean PVideoDeviceBitmap::ApplyFormat(HWND hWnd, const FormatTableEntry & formatTableEntry)
{
// NB it is necessary to set the biSizeImage value appropriate to frame size
// assume bmiHeader.biBitCount has already been set appropriatly for format
BITMAPINFO & bmi = *(BITMAPINFO*)theArray;
bmi.bmiHeader.biPlanes = 1;
int height = bmi.bmiHeader.biHeight<0 ? -bmi.bmiHeader.biHeight : bmi.bmiHeader.biHeight;
bmi.bmiHeader.biSizeImage = height*4*((bmi.bmiHeader.biBitCount * bmi.bmiHeader.biWidth + 31)/32);
// set .biHeight according to .negHeight value
if (formatTableEntry.negHeight)
bmi.bmiHeader.biHeight = -height;
#if PTRACING
PTimeInterval startTime = PTimer::Tick();
#endif
if (capSetVideoFormat(hWnd, theArray, GetSize())) {
PTRACE(3, "PVidInp\tcapSetVideoFormat succeeded: "
<< PString(formatTableEntry.colourFormat) << ' '
<< bmi.bmiHeader.biWidth << "x" << bmi.bmiHeader.biHeight
<< " sz=" << bmi.bmiHeader.biSizeImage << " time=" << (PTimer::Tick() - startTime));
return PTrue;
}
if (formatTableEntry.negHeight) {
bmi.bmiHeader.biHeight = height;
if (capSetVideoFormat(hWnd, theArray, GetSize())) {
PTRACE(3, "PVidInp\tcapSetVideoFormat succeeded: "
<< PString(formatTableEntry.colourFormat) << ' '
<< bmi.bmiHeader.biWidth << "x" << bmi.bmiHeader.biHeight
<< " sz=" << bmi.bmiHeader.biSizeImage << " time=" << (PTimer::Tick() - startTime));
return PTrue;
}
}
PTRACE(1, "PVidInp\tcapSetVideoFormat failed: "
<< (formatTableEntry.colourFormat != NULL ? formatTableEntry.colourFormat : "NO-COLOUR-FORMAT") << ' '
<< bmi.bmiHeader.biWidth << "x" << bmi.bmiHeader.biHeight
<< " sz=" << bmi.bmiHeader.biSizeImage << " time=" << (PTimer::Tick() - startTime)
<< " - lastError=" << ::GetLastError());
return PFalse;
}
///////////////////////////////////////////////////////////////////////////////
PCapStatus::PCapStatus(HWND hWnd)
{
memset(this, 0, sizeof(*this));
if (capGetStatus(hWnd, this, sizeof(*this)))
return;
PTRACE(1, "PVidInp\tcapGetStatus: failed - " << ::GetLastError());
}
///////////////////////////////////////////////////////////////////////////////
// PVideoInputDevice_VideoForWindows
PCREATE_VIDINPUT_PLUGIN(VideoForWindows);
PVideoInputDevice_VideoForWindows::PVideoInputDevice_VideoForWindows()
{
captureThread = NULL;
hCaptureWindow = NULL;
lastFramePtr = NULL;
lastFrameSize = 0;
isCapturingNow = PFalse;
}
PBoolean PVideoInputDevice_VideoForWindows::Open(const PString & devName, PBoolean startImmediate)
{
Close();
operationMutex.Wait();
deviceName = devName;
captureThread = PThread::Create(PCREATE_NOTIFIER(HandleCapture), 0,
PThread::NoAutoDeleteThread, PThread::NormalPriority,
"VidIn:%x");
operationMutex.Signal();
threadStarted.Wait();
PWaitAndSignal mutex(operationMutex);
if (hCaptureWindow == NULL) {
delete captureThread;
captureThread = NULL;
return PFalse;
}
if (startImmediate)
return Start();
return PTrue;
}
PBoolean PVideoInputDevice_VideoForWindows::IsOpen()
{
return hCaptureWindow != NULL;
}
PBoolean PVideoInputDevice_VideoForWindows::Close()
{
PWaitAndSignal mutex(operationMutex);
if (!IsOpen())
return PFalse;
Stop();
::PostThreadMessage(captureThread->GetThreadId(), WM_QUIT, 0, 0L);
// Some brain dead drivers may hang so we provide a timeout.
if (!captureThread->WaitForTermination(5000))
{
// Two things may happen if we are forced to terminate the capture thread:
// 1. As the VIDCAP window is associated to that thread the OS itself will
// close the window and release the driver
// 2. the driver will not be released and we will not have video until we
// terminate the process
// Any of the two ios better than just hanging
captureThread->Terminate();
hCaptureWindow = NULL;
PTRACE(1, "PVidInp\tCapture thread failed to stop. Terminated");
}
delete captureThread;
captureThread = NULL;
return PTrue;
}
PBoolean PVideoInputDevice_VideoForWindows::Start()
{
PWaitAndSignal mutex(operationMutex);
if (IsCapturing())
return PTrue;
#if STEP_GRAB_CAPTURE
isCapturingNow = PTrue;
return capGrabFrameNoStop(hCaptureWindow);
#else
if (capCaptureSequenceNoFile(hCaptureWindow)) {
PCapStatus status(hCaptureWindow);
isCapturingNow = status.fCapturingNow;
return isCapturingNow;
}
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapCaptureSequenceNoFile: failed - " << lastError);
return PFalse;
#endif
}
PBoolean PVideoInputDevice_VideoForWindows::Stop()
{
PWaitAndSignal mutex(operationMutex);
if (!IsCapturing())
return PFalse;
isCapturingNow = PFalse;
#if STEP_GRAB_CAPTURE
return IsOpen() && frameAvailable.Wait(1000);
#else
if (capCaptureStop(hCaptureWindow))
return PTrue;
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapCaptureStop: failed - " << lastError);
return PFalse;
#endif
}
PBoolean PVideoInputDevice_VideoForWindows::IsCapturing()
{
return isCapturingNow;
}
PBoolean PVideoInputDevice_VideoForWindows::SetColourFormat(const PString & colourFmt)
{
PWaitAndSignal mutex(operationMutex);
if (!IsOpen())
return PVideoDevice::SetColourFormat(colourFmt); // Not open yet, just set internal variables
PBoolean running = IsCapturing();
if (running)
Stop();
PString oldFormat = colourFormat;
if (!PVideoDevice::SetColourFormat(colourFmt))
return PFalse;
PINDEX i = 0;
while (FormatTable[i].colourFormat != NULL && !(colourFmt *= FormatTable[i].colourFormat))
i++;
PVideoDeviceBitmap bi(hCaptureWindow, FormatTable[i].bitCount);
if (FormatTable[i].colourFormat != NULL)
bi->bmiHeader.biCompression = FormatTable[i].compression;
else if (colourFmt.GetLength() == 4)
bi->bmiHeader.biCompression = mmioFOURCC(colourFmt[0],colourFmt[1],colourFmt[2],colourFmt[3]);
else {
bi->bmiHeader.biCompression = 0xffffffff; // Indicate invalid colour format
PVideoDevice::SetColourFormat(oldFormat);
return PFalse;
}
// set frame width and height
bi->bmiHeader.biWidth = frameWidth;
bi->bmiHeader.biHeight = frameHeight;
if (!bi.ApplyFormat(hCaptureWindow, FormatTable[i])) {
lastError = ::GetLastError();
PVideoDevice::SetColourFormat(oldFormat);
return PFalse;
}
// Didn't do top down, tell everything we are up side down
nativeVerticalFlip = FormatTable[i].negHeight && bi->bmiHeader.biHeight > 0;
if (running)
return Start();
return PTrue;
}
PBoolean PVideoInputDevice_VideoForWindows::SetFrameRate(unsigned rate)
{
PWaitAndSignal mutex(operationMutex);
if (!PVideoDevice::SetFrameRate(rate))
return PFalse;
if (!IsOpen())
return PTrue; // Not open yet, just set internal variables
PBoolean running = IsCapturing();
if (running)
Stop();
CAPTUREPARMS parms;
memset(&parms, 0, sizeof(parms));
if (!capCaptureGetSetup(hCaptureWindow, &parms, sizeof(parms))) {
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapCaptureGetSetup: failed - " << lastError);
return PFalse;
}
// keep current (default) framerate if 0==frameRate
if (0 != frameRate)
parms.dwRequestMicroSecPerFrame = 1000000 / frameRate;
parms.fMakeUserHitOKToCapture = PFalse;
parms.wPercentDropForError = 100;
parms.fCaptureAudio = PFalse;
parms.fAbortLeftMouse = PFalse;
parms.fAbortRightMouse = PFalse;
parms.fLimitEnabled = PFalse;
if (!capCaptureSetSetup(hCaptureWindow, &parms, sizeof(parms))) {
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapCaptureSetSetup: failed - " << lastError);
return PFalse;
}
if (running)
return Start();
return PTrue;
}
PBoolean PVideoInputDevice_VideoForWindows::SetFrameSize(unsigned width, unsigned height)
{
PWaitAndSignal mutex(operationMutex);
if (!IsOpen())
return PVideoDevice::SetFrameSize(width, height); // Not open yet, just set internal variables
PBoolean running = IsCapturing();
if (running)
Stop();
PVideoDeviceBitmap bi(hCaptureWindow);
PTRACE(5, "PVidInp\tChanging frame size from "
<< bi->bmiHeader.biWidth << 'x' << bi->bmiHeader.biHeight << " to " << width << 'x' << height);
PINDEX i = 0;
while (FormatTable[i].colourFormat != NULL && !(colourFormat *= FormatTable[i].colourFormat))
i++;
bi->bmiHeader.biWidth = width;
bi->bmiHeader.biHeight = height;
if (!bi.ApplyFormat(hCaptureWindow, FormatTable[i])) {
lastError = ::GetLastError();
return PFalse;
}
// Didn't do top down, tell everything we are up side down
nativeVerticalFlip = FormatTable[i].negHeight && bi->bmiHeader.biHeight > 0;
// verify that the driver really took the frame size
if (!VerifyHardwareFrameSize(width, height))
return PFalse;
// frameHeight must be positive regardlesss of what the driver says
if (0 > (int)height)
height = (unsigned)-(int)height;
if (!PVideoDevice::SetFrameSize(width, height))
return PFalse;
if (running)
return Start();
return PTrue;
}
PBoolean PVideoInputDevice_VideoForWindows::TestAllFormats()
{
PBoolean running = IsCapturing();
if (running)
Stop();
for (PINDEX prefFormatIdx = 0; FormatTable[prefFormatIdx].colourFormat != NULL; prefFormatIdx++) {
PVideoDeviceBitmap bi(hCaptureWindow, FormatTable[prefFormatIdx].bitCount);
bi->bmiHeader.biCompression = FormatTable[prefFormatIdx].compression;
for (PINDEX prefResizeIdx = 0; prefResizeIdx < PARRAYSIZE(winTestResTable); prefResizeIdx++) {
bi->bmiHeader.biWidth = winTestResTable[prefResizeIdx].device_width;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -