📄 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)
*
* $Revision: 19426 $
* $Author: rjongbloed $
* $Date: 2008-02-09 03:19:51 +0000 (Sat, 09 Feb 2008) $
*/
#include <ptlib.h>
#if P_VIDEO
#include <ptlib/videoio.h>
#include <ptlib/vconvert.h>
#include <ptlib/pluginmgr.h>
#include <ptclib/delaychan.h>
#ifdef _MSC_VER
#ifndef _WIN32_WCE
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "gdi32.lib")
#endif
#endif
#ifdef __MINGW32__
#define VHDR_DONE 0x00000001
#define VHDR_KEYFRAME 0x00000008
typedef struct videohdr_tag {
LPBYTE lpData;
DWORD dwBufferLength;
DWORD dwBytesUsed;
DWORD dwTimeCaptured;
DWORD dwUser;
DWORD dwFlags;
DWORD dwReserved[4];
} *LPVIDEOHDR;
typedef struct tagCapDriverCaps {
UINT wDeviceIndex;
BOOL fHasOverlay;
BOOL fHasDlgVideoSource;
BOOL fHasDlgVideoFormat;
BOOL fHasDlgVideoDisplay;
BOOL fCaptureInitialized;
BOOL fDriverSuppliesPalettes;
HANDLE hVideoIn;
HANDLE hVideoOut;
HANDLE hVideoExtIn;
HANDLE hVideoExtOut;
} CAPDRIVERCAPS, *LPCAPDRIVERCAPS;
typedef struct tagCaptureParms {
DWORD dwRequestMicroSecPerFrame; // Requested capture rate
BOOL fMakeUserHitOKToCapture; // Show "Hit OK to cap" dlg?
WORD wPercentDropForError; // Give error msg if > (10%)
BOOL fYield; // Capture via background task?
DWORD dwIndexSize; // Max index size in frames (32K)
WORD wChunkGranularity; // Junk chunk granularity (2K)
BOOL fUsingDOSMemory; // Use DOS buffers?
WORD wNumVideoRequested; // # video buffers, If 0, autocalc
BOOL fCaptureAudio; // Capture audio?
WORD wNumAudioRequested; // # audio buffers, If 0, autocalc
WORD vKeyAbort; // Virtual key causing abort
BOOL fAbortLeftMouse; // Abort on left mouse?
BOOL fAbortRightMouse; // Abort on right mouse?
BOOL fLimitEnabled; // Use wTimeLimit?
WORD wTimeLimit; // Seconds to capture
BOOL fMCIControl; // Use MCI video source?
BOOL fStepMCIDevice; // Step MCI device?
DWORD dwMCIStartTime; // Time to start in MS
DWORD dwMCIStopTime; // Time to stop in MS
BOOL fStepCaptureAt2x; // Perform spatial averaging 2x
WORD wStepCaptureAverageFrames; // Temporal average n Frames
DWORD dwAudioBufferSize; // Size of audio bufs (0 = default)
BOOL fDisableWriteCache; // Attempt to disable write cache
} CAPTUREPARMS, FAR *LPCAPTUREPARMS;
typedef struct tagCapStatus {
UINT uiImageWidth; // Width of the image
UINT uiImageHeight; // Height of the image
BOOL fLiveWindow; // Now Previewing video?
BOOL fOverlayWindow; // Now Overlaying video?
BOOL fScale; // Scale image to client?
POINT ptScroll; // Scroll position
BOOL fUsingDefaultPalette; // Using default driver palette?
BOOL fAudioHardware; // Audio hardware present?
BOOL fCapFileExists; // Does capture file exist?
DWORD dwCurrentVideoFrame; // # of video frames cap'td
DWORD dwCurrentVideoFramesDropped;// # of video frames dropped
DWORD dwCurrentWaveSamples; // # of wave samples cap'td
DWORD dwCurrentTimeElapsedMS; // Elapsed capture duration
HPALETTE hPalCurrent; // Current palette in use
BOOL fCapturingNow; // Capture in progress?
DWORD dwReturn; // Error value after any operation
WORD wNumVideoAllocated; // Actual number of video buffers
WORD wNumAudioAllocated; // Actual number of audio buffers
} CAPSTATUS, FAR *LPCAPSTATUS;
#define WM_CAP_START WM_USER
#define WM_CAP_SET_CALLBACK_ERROR (WM_CAP_START+ 2)
#define WM_CAP_SET_CALLBACK_FRAME (WM_CAP_START+ 5)
#define WM_CAP_SET_CALLBACK_VIDEOSTREAM (WM_CAP_START+ 6)
#define WM_CAP_GET_USER_DATA (WM_CAP_START+ 8)
#define WM_CAP_SET_USER_DATA (WM_CAP_START+ 9)
#define WM_CAP_DRIVER_CONNECT (WM_CAP_START+ 10)
#define WM_CAP_DRIVER_DISCONNECT (WM_CAP_START+ 11)
#define WM_CAP_DRIVER_GET_CAPS (WM_CAP_START+ 14)
#define WM_CAP_GET_VIDEOFORMAT (WM_CAP_START+ 44)
#define WM_CAP_SET_VIDEOFORMAT (WM_CAP_START+ 45)
#define WM_CAP_SET_PREVIEW (WM_CAP_START+ 50)
#define WM_CAP_GET_STATUS (WM_CAP_START+ 54)
#define WM_CAP_GRAB_FRAME_NOSTOP (WM_CAP_START+ 61)
#define WM_CAP_SET_SEQUENCE_SETUP (WM_CAP_START+ 64)
#define WM_CAP_GET_SEQUENCE_SETUP (WM_CAP_START+ 65)
#define capSetCallbackOnError(hwnd, fpProc) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_CALLBACK_ERROR, 0, (LPARAM)(LPVOID)(fpProc)))
#define capSetCallbackOnFrame(hwnd, fpProc) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_CALLBACK_FRAME, 0, (LPARAM)(LPVOID)(fpProc)))
#define capSetCallbackOnVideoStream(hwnd, fpProc) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, (LPARAM)(LPVOID)(fpProc)))
#define capGetUserData(hwnd) (::SendMessage(hwnd, WM_CAP_GET_USER_DATA, 0, 0))
#define capSetUserData(hwnd, lUser) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_USER_DATA, 0, (LPARAM)lUser))
#define capDriverConnect(hwnd, i) ((BOOL)::SendMessage(hwnd, WM_CAP_DRIVER_CONNECT, (WPARAM)(i), 0L))
#define capDriverDisconnect(hwnd) ((BOOL)::SendMessage(hwnd, WM_CAP_DRIVER_DISCONNECT, (WPARAM)0, 0L))
#define capDriverGetCaps(hwnd, s, wSize) ((BOOL)::SendMessage(hwnd, WM_CAP_DRIVER_GET_CAPS, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPDRIVERCAPS)(s)))
#define capGetVideoFormat(hwnd, s, wSize) ((DWORD)::SendMessage(hwnd, WM_CAP_GET_VIDEOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(s)))
#define capGetVideoFormatSize(hwnd) ((DWORD)::SendMessage(hwnd, WM_CAP_GET_VIDEOFORMAT, 0, NULL))
#define capSetVideoFormat(hwnd, s, wSize) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_VIDEOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(s)))
#define capPreview(hwnd, f) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_PREVIEW, (WPARAM)(BOOL)(f), 0L))
#define capGetStatus(hwnd, s, wSize) ((BOOL)::SendMessage(hwnd, WM_CAP_GET_STATUS, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPSTATUS)(s)))
#define capGrabFrameNoStop(hwnd) ((BOOL)::SendMessage(hwnd, WM_CAP_GRAB_FRAME_NOSTOP, (WPARAM)0, (LPARAM)0L))
#define capCaptureSetSetup(hwnd, s, wSize) ((BOOL)::SendMessage(hwnd, WM_CAP_SET_SEQUENCE_SETUP, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPTUREPARMS)(s)))
#define capCaptureGetSetup(hwnd, s, wSize) ((BOOL)::SendMessage(hwnd, WM_CAP_GET_SEQUENCE_SETUP, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPTUREPARMS)(s)))
extern "C" {
HWND VFWAPI capCreateCaptureWindowA (LPCSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hwndParent, int nID);
BOOL VFWAPI capGetDriverDescriptionA (WORD wDriverIndex, LPSTR lpszName,
int cbName, LPSTR lpszVer, int cbVer);
}
#define capGetDriverDescription capGetDriverDescriptionA
#define capCreateCaptureWindow capCreateCaptureWindowA
#endif // __MINGW32
#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 PStringArray GetInputDeviceNames();
virtual PStringArray GetDeviceNames() const
{ return GetInputDeviceNames(); }
/**Retrieve a list of Device Capabilities
*/
static bool GetDeviceCapabilities(
const PString & /*deviceName*/, ///< Name of device
Capabilities * /*caps*/ ///< List of supported capabilities
) { return false; }
/**Open the device given the device name.
*/
virtual PBoolean Open(
const PString & deviceName, /// Device name 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.
*/
virtual PBoolean Start();
/**Stop the video device I/O capture.
*/
virtual PBoolean Stop();
/**Determine if the video device I/O capture is in progress.
*/
virtual PBoolean IsCapturing();
/**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.
);
/**Set the video frame rate to be used on the device.
Default behaviour sets the value of the frameRate variable and then
returns PTrue.
*/
virtual PBoolean 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 PTrue.
*/
virtual PBoolean 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 PBoolean 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 PBoolean 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 PBoolean TestAllFormats();
protected:
/**Check the hardware can do the asked for size.
Note that not all cameras can provide all frame sizes.
*/
virtual PBoolean 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);
PBoolean InitialiseCapture();
PThread * captureThread;
PSyncPoint threadStarted;
HWND hCaptureWindow;
PMutex operationMutex;
PSyncPoint frameAvailable;
LPBYTE lastFramePtr;
unsigned lastFrameSize;
PMutex lastFrameMutex;
bool isCapturingNow;
PAdaptiveDelay m_Pacing;
};
///////////////////////////////////////////////////////////////////////////////
class PCapStatus : public CAPSTATUS
{
public:
PCapStatus(HWND hWnd);
PBoolean IsOK()
{ return uiImageWidth != 0; }
};
///////////////////////////////////////////////////////////////////////////////
static struct FormatTableEntry {
const char * colourFormat;
WORD bitCount;
PBoolean 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -