📄 vfw.cxx
字号:
bi->bmiHeader.biHeight = winTestResTable[prefResizeIdx].device_height;
bi.ApplyFormat(hCaptureWindow, FormatTable[prefFormatIdx]);
} // for prefResizeIdx
} // for prefFormatIdx
if (running)
return Start();
return PTrue;
}
//return PTrue 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
PBoolean PVideoInputDevice_VideoForWindows::VerifyHardwareFrameSize(unsigned width, unsigned height)
{
PCapStatus status(hCaptureWindow);
if (!status.IsOK())
return PFalse;
if (width != status.uiImageWidth)
return PFalse;
if (0 > (int)height)
height = (unsigned)-(int)height;
if (0 > (int)status.uiImageHeight)
status.uiImageHeight = (unsigned)-(int)status.uiImageHeight;
return (height == status.uiImageHeight);
}
PStringArray PVideoInputDevice_VideoForWindows::GetInputDeviceNames()
{
PStringArray devices;
for (WORD devId = 0; devId < 10; devId++) {
char name[100];
char version[200];
if (capGetDriverDescription(devId, name, sizeof(name), version, sizeof(version)))
devices.AppendString(name);
}
return devices;
}
PINDEX PVideoInputDevice_VideoForWindows::GetMaxFrameBytes()
{
PWaitAndSignal mutex(operationMutex);
if (!IsOpen())
return 0;
return GetMaxFrameBytesConverted(PVideoDeviceBitmap(hCaptureWindow)->bmiHeader.biSizeImage);
}
PBoolean PVideoInputDevice_VideoForWindows::GetFrameData(BYTE * buffer, PINDEX * bytesReturned)
{
// Some camera drivers ignore the frame rate set in the CAPTUREPARMS structure,
// so we have a fail safe delay here.
m_Pacing.Delay(1000/GetFrameRate());
return GetFrameDataNoDelay(buffer, bytesReturned);
}
PBoolean PVideoInputDevice_VideoForWindows::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned)
{
if (!frameAvailable.Wait(1000))
return PFalse;
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 PFalse;
return ((PVideoInputDevice_VideoForWindows *)capGetUserData(hWnd))->HandleError(id, err);
}
LRESULT PVideoInputDevice_VideoForWindows::HandleError(int id, LPCSTR PTRACE_PARAM(err))
{
if (id != 0) {
PTRACE(1, "PVidInp\tErrorHandler: [id="<< id << "] " << err);
}
return PTrue;
}
LRESULT CALLBACK PVideoInputDevice_VideoForWindows::VideoHandler(HWND hWnd, LPVIDEOHDR vh)
{
if (hWnd == NULL || capGetUserData(hWnd) == NULL)
return PFalse;
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 PTrue;
}
PBoolean 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 PFalse;
}
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 PFalse;
}
WORD devId;
#if PTRACING
if (PTrace::CanTrace(4)) { // list available video capture drivers
ostream & trace = PTrace::Begin(5, __FILE__, __LINE__);
trace << "PVidInp\tEnumerating available video capture drivers:\n";
for (devId = 0; devId < 10; devId++) {
char name[100];
char version[200];
if (capGetDriverDescription(devId, name, sizeof(name), version, sizeof(version)) )
trace << " Video device[" << devId << "] = " << name << ", " << version << '\n';
}
trace << PTrace::End;
}
#endif
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 PFalse;
}
CAPDRIVERCAPS driverCaps;
memset(&driverCaps, 0, sizeof(driverCaps));
if (!capDriverGetCaps(hCaptureWindow, &driverCaps, sizeof(driverCaps))) {
lastError = ::GetLastError();
PTRACE(1, "PVidInp\tcapGetDriverCaps failed - " << lastError);
return PFalse;
}
PTRACE(6, "PVidInp\tEnumerating 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, PTrue);
else {
capPreviewRate(hCaptureWindow, 66);
capPreview(hCaptureWindow, PTrue);
}
*/
capPreview(hCaptureWindow, PFalse);
#if PTRACING
if (PTrace::CanTrace(6))
TestAllFormats(); // list acceptable formats and frame resolutions for video capture driver
#endif
return SetFrameRate(frameRate) && SetColourFormatConverter(colourFormat.IsEmpty() ? PString("YUV420P") : colourFormat);
}
void PVideoInputDevice_VideoForWindows::HandleCapture(PThread &, INT)
{
PBoolean 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 PBoolean Open(
const PString & deviceName, /// Device name (filename base) to open
PBoolean startImmediate = PTrue /// Immediately start device
);
/**Determine if the device is currently open.
*/
virtual PBoolean IsOpen();
/**Close the device.
*/
virtual PBoolean Close();
/**Start the video device I/O display.
*/
virtual PBoolean Start();
/**Stop the video device I/O display.
*/
virtual PBoolean Stop();
/**Get a list of all of the devices available.
*/
static PStringArray GetOutputDeviceNames();
/**Get a list of all of the devices available.
*/
virtual PStringArray GetDeviceNames() const
{ return GetOutputDeviceNames(); }
/**Set the colour format to be used.
Note that this function does not do any conversion. If it returns PTrue
then the video device does the colour format in native mode.
To utilise an internal converter use the SetColourFormatConverter()
function.
Default behaviour sets the value of the colourFormat variable and then
returns PTrue.
*/
virtual PBoolean SetColourFormat(
const PString & colourFormat // New colour format for device.
);
/**Get the video conversion vertical flip state.
Default action is to return PFalse.
*/
virtual PBoolean GetVFlipState();
/**Set the video conversion vertical flip state.
Default action is to return PFalse.
*/
virtual PBoolean SetVFlipState(
PBoolean newVFlipState /// New vertical flip state
);
/**Set the frame size to be used.
Note that devices may not be able to produce the requested size, and
this function will fail. See SetFrameSizeConverter().
Default behaviour sets the frameWidth and frameHeight variables and
returns PTrue.
*/
virtual PBoolean SetFrameSize(
unsigned width, /// New width of frame
unsigned height /// New height of frame
);
/**Set a section of the output frame buffer.
*/
virtual PBoolean FrameComplete();
/**Get the position of the output device, where relevant. For devices such as
files, this always returns zeros. For devices such as Windows, this is the
position of the window on the screen.
*/
virtual PBoolean GetPosition(
int & x, // X position of device surface
int & y // Y position of device surface
) const;
LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
PDECLARE_NOTIFIER(PThread, PVideoOutputDevice_Window, HandleDisplay);
void Draw(HDC hDC);
HWND m_hWnd;
PThread * m_thread;
PMutex m_openCloseMutex;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -