📄 vfw.cxx
字号:
return FALSE;
}
if (running)
return Start();
return TRUE;
}
BOOL PVideoInputDevice_VideoForWindows::SetFrameSize(unsigned width, unsigned height)
{
BOOL 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 FALSE;
}
// 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 FALSE;
// frameHeight must be positive regardlesss of what the driver says
if (0 > (int)height)
height = (unsigned)-(int)height;
if (!PVideoDevice::SetFrameSize(width, height))
return FALSE;
if (running)
return Start();
return TRUE;
}
BOOL PVideoInputDevice_VideoForWindows::TestAllFormats()
{
BOOL 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;
bi->bmiHeader.biHeight = winTestResTable[prefResizeIdx].device_height;
bi.ApplyFormat(hCaptureWindow, FormatTable[prefFormatIdx]);
} // for prefResizeIdx
} // for prefFormatIdx
if (running)
return Start();
return TRUE;
}
//return TRUE if absolute value of height reported by driver
// is equal to absolute value of current frame height AND
// width reported by driver is equal to current frame width
BOOL PVideoInputDevice_VideoForWindows::VerifyHardwareFrameSize(unsigned width, unsigned height)
{
PCapStatus status(hCaptureWindow);
if (!status.IsOK())
return FALSE;
if (width != status.uiImageWidth)
return FALSE;
if (0 > (int)height)
height = (unsigned)-(int)height;
if (0 > (int)status.uiImageHeight)
status.uiImageHeight = (unsigned)-(int)status.uiImageHeight;
return (height == status.uiImageHeight);
}
PStringList PVideoInputDevice_VideoForWindows::GetInputDeviceNames()
{
PStringList list;
for (WORD devId = 0; devId < 10; devId++) {
char name[100];
char version[200];
if (capGetDriverDescription(devId, name, sizeof(name), version, sizeof(version)))
list.AppendString(name);
}
return list;
}
PINDEX PVideoInputDevice_VideoForWindows::GetMaxFrameBytes()
{
if (!IsOpen())
return 0;
return GetMaxFrameBytesConverted(PVideoDeviceBitmap(hCaptureWindow)->bmiHeader.biSizeImage);
}
BOOL PVideoInputDevice_VideoForWindows::GetFrameData(BYTE * buffer, PINDEX * bytesReturned)
{
return GetFrameDataNoDelay(buffer, bytesReturned);
}
BOOL PVideoInputDevice_VideoForWindows::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned)
{
if (!frameAvailable.Wait(1000))
return FALSE;
bool retval = false;
lastFrameMutex.Wait();
if (lastFramePtr != NULL) {
if (NULL != converter)
retval = converter->Convert(lastFramePtr, buffer, bytesReturned);
else {
memcpy(buffer, lastFramePtr, lastFrameSize);
if (bytesReturned != NULL)
*bytesReturned = lastFrameSize;
retval = true;
}
}
lastFrameMutex.Signal();
#if STEP_GRAB_CAPTURE
if (isCapturingNow)
capGrabFrameNoStop(hCaptureWindow);
#endif
return retval;
}
LRESULT CALLBACK PVideoInputDevice_VideoForWindows::ErrorHandler(HWND hWnd, int id, LPCSTR err)
{
if (hWnd == NULL)
return FALSE;
return ((PVideoInputDevice_VideoForWindows *)capGetUserData(hWnd))->HandleError(id, err);
}
LRESULT PVideoInputDevice_VideoForWindows::HandleError(int id, LPCSTR err)
{
if (id != 0) {
PTRACE(1, "PVidInp\tErrorHandler: [id="<< id << "] " << err);
}
return TRUE;
}
LRESULT CALLBACK PVideoInputDevice_VideoForWindows::VideoHandler(HWND hWnd, LPVIDEOHDR vh)
{
if (hWnd == NULL || capGetUserData(hWnd) == NULL)
return FALSE;
return ((PVideoInputDevice_VideoForWindows *)capGetUserData(hWnd))->HandleVideo(vh);
}
LRESULT PVideoInputDevice_VideoForWindows::HandleVideo(LPVIDEOHDR vh)
{
if ((vh->dwFlags&(VHDR_DONE|VHDR_KEYFRAME)) != 0) {
lastFrameMutex.Wait();
lastFramePtr = vh->lpData;
lastFrameSize = vh->dwBytesUsed;
if (lastFrameSize == 0)
lastFrameSize = vh->dwBufferLength;
lastFrameMutex.Signal();
frameAvailable.Signal();
}
return TRUE;
}
BOOL PVideoInputDevice_VideoForWindows::InitialiseCapture()
{
if ((hCaptureWindow = capCreateCaptureWindow("Capture Window",
WS_POPUP | WS_CAPTION,
CW_USEDEFAULT, CW_USEDEFAULT,
frameWidth + GetSystemMetrics(SM_CXFIXEDFRAME),
frameHeight + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFIXEDFRAME),
(HWND)0,
0)) == NULL) {
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapCreateCaptureWindow failed - " << lastError);
return FALSE;
}
capSetCallbackOnError(hCaptureWindow, ErrorHandler);
#if STEP_GRAB_CAPTURE
if (!capSetCallbackOnFrame(hCaptureWindow, VideoHandler)) { //} balance braces
#else
if (!capSetCallbackOnVideoStream(hCaptureWindow, VideoHandler)) {
#endif
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapSetCallbackOnVideoStream failed - " << lastError);
return FALSE;
}
WORD devId;
if (PTrace::CanTrace(6)) { // list available video capture drivers
PTRACE(5, "PVidInp\tEnumerating available video capture drivers");
for (devId = 0; devId < 10; devId++) {
char name[100];
char version[200];
if (capGetDriverDescription(devId, name, sizeof(name), version, sizeof(version)) )
{
PTRACE(5, "PVidInp\tVideo device[" << devId << "] = " << name << ", " << version);
}
}
}
if (deviceName.GetLength() == 1 && isdigit(deviceName[0]))
devId = (WORD)(deviceName[0] - '0');
else {
for (devId = 0; devId < 10; devId++) {
char name[100];
char version[200];
if (capGetDriverDescription(devId, name, sizeof(name), version, sizeof(version)) &&
(deviceName *= name))
break;
}
}
capSetUserData(hCaptureWindow, this);
// Use first driver available.
if (!capDriverConnect(hCaptureWindow, devId)) {
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapDriverConnect failed - " << lastError);
return FALSE;
}
CAPDRIVERCAPS driverCaps;
memset(&driverCaps, 0, sizeof(driverCaps));
if (!capDriverGetCaps(hCaptureWindow, &driverCaps, sizeof(driverCaps))) {
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapGetDriverCaps failed - " << lastError);
return FALSE;
}
PTRACE(6, "Enumerating CAPDRIVERCAPS values:\n"
" driverCaps.wDeviceIndex = " << driverCaps.wDeviceIndex << "\n"
" driverCaps.fHasOverlay = " << driverCaps.fHasOverlay << "\n"
" driverCaps.fHasDlgVideoSource = " << driverCaps.fHasDlgVideoSource << "\n"
" driverCaps.fHasDlgVideoFormat = " << driverCaps.fHasDlgVideoFormat << "\n"
" driverCaps.fHasDlgVideoDisplay = " << driverCaps.fHasDlgVideoDisplay << "\n"
" driverCaps.fCaptureInitialized = " << driverCaps.fCaptureInitialized << "\n"
" driverCaps.fDriverSuppliesPalettes= " << driverCaps.fDriverSuppliesPalettes);
/*
if (driverCaps.fHasOverlay)
capOverlay(hCaptureWindow, TRUE);
else {
capPreviewRate(hCaptureWindow, 66);
capPreview(hCaptureWindow, TRUE);
}
*/
capPreview(hCaptureWindow, FALSE);
#if PTRACING
if (PTrace::CanTrace(6))
TestAllFormats(); // list acceptable formats and frame resolutions for video capture driver
#endif
if (!SetFrameRate(frameRate))
return FALSE;
if (!preferredColourFormat.IsEmpty())
return SetColourFormat(preferredColourFormat);
if (!colourFormat.IsEmpty())
return SetColourFormat(colourFormat);
PVideoDeviceBitmap bi(hCaptureWindow);
PINDEX i = 0;
while (FormatTable[i].colourFormat != NULL) {
if (bi->bmiHeader.biCompression == FormatTable[i].compression) {
colourFormat = FormatTable[i].colourFormat;
frameWidth = bi->bmiHeader.biWidth;
frameHeight = bi->bmiHeader.biHeight < 0 ? -bi->bmiHeader.biHeight : bi->bmiHeader.biHeight;
return TRUE;
}
i++;
}
// Don't know what is going on here, so set it to something known ...
return SetColourFormat("");
}
void PVideoInputDevice_VideoForWindows::HandleCapture(PThread &, INT)
{
BOOL initSucceeded = InitialiseCapture();
if (initSucceeded) {
threadStarted.Signal();
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0))
::DispatchMessage(&msg);
}
PTRACE(5, "PVidInp\tDisconnecting driver");
capDriverDisconnect(hCaptureWindow);
capSetUserData(hCaptureWindow, NULL);
capSetCallbackOnError(hCaptureWindow, NULL);
capSetCallbackOnVideoStream(hCaptureWindow, NULL);
PTRACE(5, "PVidInp\tDestroying VIDCAP window");
DestroyWindow(hCaptureWindow);
hCaptureWindow = NULL;
// Signal the other thread we have completed, even if have error
if (!initSucceeded)
threadStarted.Signal();
}
///////////////////////////////////////////////////////////////////////////////
// PVideoOutputDevice_Window
/**This class defines a video output device for RGB in a frame store.
*/
class PVideoOutputDevice_Window : public PVideoOutputDeviceRGB
{
PCLASSINFO(PVideoOutputDevice_Window, PVideoOutputDeviceRGB);
public:
/** Create a new video output device.
*/
PVideoOutputDevice_Window();
/** Destroy a video output device.
*/
~PVideoOutputDevice_Window();
/**Open the device given the device name.
*/
virtual BOOL Open(
const PString & deviceName, /// Device name (filename base) to open
BOOL startImmediate = TRUE /// Immediately start device
);
/**Determine if the device is currently open.
*/
virtual BOOL IsOpen();
/**Close the device.
*/
virtual BOOL Close();
/**Start the video device I/O display.
*/
virtual BOOL Start();
/**Stop the video device I/O display.
*/
virtual BOOL Stop();
/**Get a list of all of the devices available.
*/
static PStringList GetOutputDeviceNames();
/**Get a list of all of the devices available.
*/
virtual PStringList GetDeviceNames() const
{ return GetOutputDeviceNames(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -