📄 vfw.cxx
字号:
/* * vfw.cxx * * Classes to support streaming video input (grabbing) and output. * * Portable Windows Library * * Copyright (c) 1993-2000 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * Walter H Whitlock (twohives@nc.rr.com) * * $Log: vfw.cxx,v $ * Revision 1.30 2005/08/23 12:42:23 rjongbloed * Fixed problems with negative hight native flipping not working with all sizes. * * Revision 1.29 2005/08/10 23:52:56 rjongbloed * Changed so does not try many formats on opening camera, now uses the OS default. * Changed some of the logging messages. * * Revision 1.28 2005/08/09 09:08:12 rjongbloed * Merged new video code from branch back to the trunk. * * Revision 1.27.6.4 2005/08/04 08:39:43 rjongbloed * Fixed correct flipping of camera can do native mode YUV420P * * Revision 1.27.6.3 2005/08/04 08:10:50 rjongbloed * Fixed problem where if SetFrameSize() is called and window is already that size, the window is not brought to the front. * * Revision 1.27.6.2 2005/07/24 07:23:57 rjongbloed * Fixed correct use of ShowWindow() return value in video window device Start() * * Revision 1.27.6.1 2005/07/17 09:27:08 rjongbloed * Major revisions of the PWLib video subsystem including: * removal of F suffix on colour formats for vertical flipping, all done with existing bool * working through use of RGB and BGR formats so now consistent * cleaning up the plug in system to use virtuals instead of pointers to functions. * rewrite of SDL to be a plug in compatible video output device. * extensive enhancement of video test program * * Revision 1.27 2005/01/04 07:44:04 csoutheren * More changes to implement the new configuration methodology, and also to * attack the global static problem * * Revision 1.26 2004/10/23 10:50:52 ykiryanov * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port * * Revision 1.25 2003/12/14 10:01:03 rjongbloed * Resolved issue with name space conflict os static and virtual forms of GetDeviceNames() function. * * Revision 1.24 2003/11/18 06:46:59 csoutheren * Changed to support video input plugins * * Revision 1.23 2003/11/05 05:58:10 csoutheren * Added #pragma to include required libs * * Revision 1.22 2003/05/14 02:51:42 rjongbloed * Protected use of user data in video for windows calls. * * Revision 1.21 2003/03/17 07:52:15 robertj * Fixed return value if starting capture and already have it started. * * Revision 1.20 2002/10/24 20:01:53 dereks * Improve closure of windows capture device, with fix from Diego Tartara. Thanks! * * Revision 1.19 2002/09/01 23:54:33 dereks * Fix from Diego Tartara to handle (better) disconnection situation. * * Revision 1.18 2002/02/25 08:01:02 robertj * Changed to utilise preferred colour format, thanks Martijn Roest * * Revision 1.17 2002/01/15 23:52:07 robertj * Fixed some incorrect table entries for colout formats, thanks Martijn Roest * * Revision 1.16 2002/01/10 03:52:41 robertj * Fixed 8bpp problem, thanks Walter Whitlock. * * Revision 1.15 2002/01/08 01:42:06 robertj * Tidied up some PTRACE debug output. * Changed some code formatting. * Fixed SetFrameSize so propagates to ancestor and thus sets the the * converter size as well as the raw grabber. * * Revision 1.14 2002/01/04 04:11:45 dereks * Add video flip code from Walter Whitlock, which flips code at the grabber. * * Revision 1.13 2001/11/28 04:37:46 robertj * Added "flipped" colour formats, thanks Telefonica Spain. * Added support for grabbing at a frame rate (from Linux). * Adjusted thread priority causing starvation, thanks Telefonica Spain. * Fixed startup problem if initialise gets error, thanks Telefonica Spain. * * Revision 1.12 2001/03/30 07:20:37 robertj * Some drivers (QuickCam) use key frame bit to indicate grab complete. * * Revision 1.11 2001/03/08 22:57:15 robertj * Added new VerifyHardwareFrameSize() function * * Revision 1.10 2001/03/08 02:18:45 robertj * Added improved defaulting of video formats so Open() does not fail. * Removed the requirement that the device be open before you can set * formats such as colour, video, channel number etc. * * Revision 1.9 2001/03/06 23:34:20 robertj * Added static function to get input device names. * Moved some inline virtuals to non-inline. * * Revision 1.8 2001/03/03 05:06:31 robertj * Major upgrade of video conversion and grabbing classes. * * Revision 1.7 2000/12/19 22:20:26 dereks * Add video channel classes to connect to the PwLib PVideoInputDevice class. * Add PFakeVideoInput class to generate test images for video. * * Revision 1.6 2000/11/09 00:28:38 robertj * Changed video capture for step frame grab instead of streamed grabbing. * * Revision 1.5 2000/07/30 03:41:31 robertj * Added more colour formats to video device enum. * * Revision 1.4 2000/07/26 03:50:50 robertj * Added last error variable to video device. * * Revision 1.3 2000/07/25 13:38:26 robertj * Added frame rate parameter to video frame grabber. * * Revision 1.2 2000/07/25 13:14:07 robertj * Got the video capture stuff going! * * Revision 1.1 2000/07/15 09:47:35 robertj * Added video I/O device classes. * */#define P_FORCE_STATIC_PLUGIN#include <ptlib.h>#if defined(_WIN32) && !defined(P_FORCE_STATIC_PLUGIN)#error "vfw.cxx must be compiled without precompiled headers"#endif#include <ptlib/videoio.h>#include <ptlib/vconvert.h>#ifndef _WIN32_WCE#pragma comment(lib, "vfw32.lib")#endif#define STEP_GRAB_CAPTURE 1/**This class defines a video input device. */class PVideoInputDevice_VideoForWindows : public PVideoInputDevice{ PCLASSINFO(PVideoInputDevice_VideoForWindows, PVideoInputDevice); public: /** Create a new video input device. */ PVideoInputDevice_VideoForWindows(); /**Close the video input device on destruction. */ ~PVideoInputDevice_VideoForWindows() { Close(); } /** Is the device a camera, and obtain video */ static PStringList GetInputDeviceNames(); virtual PStringList GetDeviceNames() const { return GetInputDeviceNames(); } /**Open the device given the device name. */ virtual BOOL Open( const PString & deviceName, /// Device name 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. */ virtual BOOL Start(); /**Stop the video device I/O capture. */ virtual BOOL Stop(); /**Determine if the video device I/O capture is in progress. */ virtual BOOL IsCapturing(); /**Set the colour format to be used. Note that this function does not do any conversion. If it returns TRUE 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 TRUE. */ virtual BOOL SetColourFormat( const PString & colourFormat // New colour format for device. ); /**Set the video frame rate to be used on the device. Default behaviour sets the value of the frameRate variable and then returns TRUE. */ virtual BOOL SetFrameRate( unsigned rate /// Frames per second ); /**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 TRUE. */ virtual BOOL SetFrameSize( unsigned width, /// New width of frame unsigned height /// New height of frame ); /**Get the maximum frame size in bytes. Note a particular device may be able to provide variable length frames (eg motion JPEG) so will be the maximum size of all frames. */ virtual PINDEX GetMaxFrameBytes(); /**Grab a frame, after a delay as specified by the frame rate. */ virtual BOOL GetFrameData( BYTE * buffer, /// Buffer to receive frame PINDEX * bytesReturned = NULL /// OPtional bytes returned. ); /**Grab a frame. Do not delay according to the current frame rate parameter. */ virtual BOOL GetFrameDataNoDelay( BYTE * buffer, /// Buffer to receive frame PINDEX * bytesReturned = NULL /// OPtional bytes returned. ); /**Try all known video formats & see which ones are accepted by the video driver */ virtual BOOL TestAllFormats(); protected: /**Check the hardware can do the asked for size. Note that not all cameras can provide all frame sizes. */ virtual BOOL VerifyHardwareFrameSize(unsigned width, unsigned height); PDECLARE_NOTIFIER(PThread, PVideoInputDevice_VideoForWindows, HandleCapture); static LRESULT CALLBACK ErrorHandler(HWND hWnd, int id, LPCSTR err); LRESULT HandleError(int id, LPCSTR err); static LRESULT CALLBACK VideoHandler(HWND hWnd, LPVIDEOHDR vh); LRESULT HandleVideo(LPVIDEOHDR vh); BOOL InitialiseCapture(); PThread * captureThread; PSyncPoint threadStarted; HWND hCaptureWindow; PSyncPoint frameAvailable; LPBYTE lastFramePtr; unsigned lastFrameSize; PMutex lastFrameMutex; BOOL isCapturingNow;};///////////////////////////////////////////////////////////////////////////////class PCapStatus : public CAPSTATUS{ public: PCapStatus(HWND hWnd); BOOL IsOK() { return uiImageWidth != 0; }};///////////////////////////////////////////////////////////////////////////////static struct FormatTableEntry { const char * colourFormat; WORD bitCount; BOOL negHeight; // MS documentation suggests that negative height will request // top down scan direction from video driver // HOWEVER, not all drivers honor this request DWORD compression; } FormatTable[] = { { "BGR32", 32, TRUE, BI_RGB }, { "BGR24", 24, TRUE, BI_RGB }, { "Grey", 8, TRUE, BI_RGB }, { "Gray", 8, TRUE, BI_RGB }, { "RGB565", 16, TRUE, BI_BITFIELDS }, { "RGB555", 15, TRUE, BI_BITFIELDS }, // http://support.microsoft.com/support/kb/articles/q294/8/80.asp { "YUV420P", 12, FALSE, mmioFOURCC('I','Y','U','V') }, { "IYUV", 12, FALSE, mmioFOURCC('I','Y','U','V') }, // Synonym for IYUV { "I420", 12, FALSE, mmioFOURCC('I','4','2','0') }, // Synonym for IYUV { "YV12", 12, FALSE, mmioFOURCC('Y','V','1','2') }, // same as IYUV except that U and V planes are switched { "YUV422", 16, FALSE, mmioFOURCC('Y','U','Y','2') }, { "YUY2", 16, FALSE, mmioFOURCC('Y','U','Y','2') }, { "UYVY", 16, FALSE, mmioFOURCC('U','Y','V','Y') }, // Like YUY2 except for ordering { "YVYU", 16, FALSE, mmioFOURCC('Y','V','Y','U') }, // Like YUY2 except for ordering { "YVU9", 16, FALSE, mmioFOURCC('Y','V','U','9') }, { "MJPEG", 12, FALSE, mmioFOURCC('M','J','P','G') }, { NULL },};static struct { unsigned device_width, device_height;} winTestResTable[] = { { 176, 144 }, { 352, 288 }, { 320, 240 }, { 160, 120 }, { 640, 480 }, { 704, 576 }, {1024, 768 },};///////////////////////////////////////////////////////////////////////////////class PVideoDeviceBitmap : PBYTEArray{ public: // the following method is replaced by PVideoDeviceBitmap(HWND hWnd, WORD bpp) // PVideoDeviceBitmap(unsigned width, unsigned height, const PString & fmt); //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 BOOL 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;}BOOL 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: " << formatTableEntry.colourFormat << ' ' << bmi.bmiHeader.biWidth << "x" << bmi.bmiHeader.biHeight << " sz=" << bmi.bmiHeader.biSizeImage << " time=" << (PTimer::Tick() - startTime)); return TRUE; } if (formatTableEntry.negHeight) { bmi.bmiHeader.biHeight = height; if (capSetVideoFormat(hWnd, theArray, GetSize())) { PTRACE(3, "PVidInp\tcapSetVideoFormat succeeded: " << formatTableEntry.colourFormat << ' ' << bmi.bmiHeader.biWidth << "x" << bmi.bmiHeader.biHeight << " sz=" << bmi.bmiHeader.biSizeImage << " time=" << (PTimer::Tick() - startTime)); return TRUE; } } PTRACE(1, "PVidInp\tcapSetVideoFormat failed: " << formatTableEntry.colourFormat << ' ' << bmi.bmiHeader.biWidth << "x" << bmi.bmiHeader.biHeight << " sz=" << bmi.bmiHeader.biSizeImage << " time=" << (PTimer::Tick() - startTime) << " - lastError=" << ::GetLastError()); return FALSE;}///////////////////////////////////////////////////////////////////////////////PCapStatus::PCapStatus(HWND hWnd){ memset(this, 0, sizeof(*this)); if (capGetStatus(hWnd, this, sizeof(*this))) return; PTRACE(1, "PVidInp\tcapGetStatus: failed - " << ::GetLastError());}///////////////////////////////////////////////////////////////////////////////// PVideoInputDevice_VideoForWindowsPCREATE_VIDINPUT_PLUGIN(VideoForWindows);PVideoInputDevice_VideoForWindows::PVideoInputDevice_VideoForWindows(){ captureThread = NULL; hCaptureWindow = NULL; lastFramePtr = NULL; lastFrameSize = 0; isCapturingNow = FALSE;}BOOL PVideoInputDevice_VideoForWindows::Open(const PString & devName, BOOL startImmediate){ Close(); deviceName = devName; captureThread = PThread::Create(PCREATE_NOTIFIER(HandleCapture), 0, PThread::NoAutoDeleteThread, PThread::NormalPriority,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -