386 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef _VIDEOINPUT
 | 
						|
#define _VIDEOINPUT
 | 
						|
 | 
						|
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						|
//THE SOFTWARE.
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////
 | 
						|
//Written by Theodore Watson - theo.watson@gmail.com    //
 | 
						|
//Do whatever you want with this code but if you find   //
 | 
						|
//a bug or make an improvement I would love to know!    //
 | 
						|
//														//
 | 
						|
//Warning This code is experimental 					//
 | 
						|
//use at your own risk :)								//
 | 
						|
//////////////////////////////////////////////////////////
 | 
						|
/////////////////////////////////////////////////////////
 | 
						|
/*                     Shoutouts 
 | 
						|
 | 
						|
Thanks to: 
 | 
						|
			
 | 
						|
		   Dillip Kumar Kara for crossbar code.
 | 
						|
		   Zachary Lieberman for getting me into this stuff
 | 
						|
		   and for being so generous with time and code.
 | 
						|
		   The guys at Potion Design for helping me with VC++
 | 
						|
		   Josh Fisher for being a serious C++ nerd :)
 | 
						|
		   Golan Levin for helping me debug the strangest 
 | 
						|
		   and slowest bug in the world!
 | 
						|
		   
 | 
						|
		   And all the people using this library who send in 
 | 
						|
		   bugs, suggestions and improvements who keep me working on 
 | 
						|
		   the next version - yeah thanks a lot ;)
 | 
						|
		   
 | 
						|
*/
 | 
						|
/////////////////////////////////////////////////////////
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <math.h>
 | 
						|
#include <string.h>
 | 
						|
#include <wchar.h>
 | 
						|
 | 
						|
//this is for TryEnterCriticalSection
 | 
						|
#ifndef _WIN32_WINNT
 | 
						|
	#   define _WIN32_WINNT 0x400
 | 
						|
#endif
 | 
						|
#include <windows.h>
 | 
						|
 | 
						|
 | 
						|
//Example Usage
 | 
						|
/*
 | 
						|
	//create a videoInput object
 | 
						|
	videoInput VI;
 | 
						|
	
 | 
						|
	//Prints out a list of available devices and returns num of devices found
 | 
						|
	int numDevices = VI.listDevices();	
 | 
						|
	
 | 
						|
	int device1 = 0;  //this could be any deviceID that shows up in listDevices
 | 
						|
	int device2 = 1;  //this could be any deviceID that shows up in listDevices
 | 
						|
	
 | 
						|
	//if you want to capture at a different frame rate (default is 30) 
 | 
						|
	//specify it here, you are not guaranteed to get this fps though.
 | 
						|
	//VI.setIdealFramerate(dev, 60);	
 | 
						|
	
 | 
						|
	//setup the first device - there are a number of options:
 | 
						|
	
 | 
						|
	VI.setupDevice(device1); 						  //setup the first device with the default settings
 | 
						|
	//VI.setupDevice(device1, VI_COMPOSITE); 			  //or setup device with specific connection type
 | 
						|
	//VI.setupDevice(device1, 320, 240);				  //or setup device with specified video size
 | 
						|
	//VI.setupDevice(device1, 320, 240, VI_COMPOSITE);  //or setup device with video size and connection type
 | 
						|
 | 
						|
	//VI.setFormat(device1, VI_NTSC_M);					//if your card doesn't remember what format it should be
 | 
						|
														//call this with the appropriate format listed above
 | 
						|
														//NOTE: must be called after setupDevice!
 | 
						|
	
 | 
						|
	//optionally setup a second (or third, fourth ...) device - same options as above
 | 
						|
	VI.setupDevice(device2); 						  
 | 
						|
 | 
						|
	//As requested width and height can not always be accomodated
 | 
						|
	//make sure to check the size once the device is setup
 | 
						|
 | 
						|
	int width 	= VI.getWidth(device1);
 | 
						|
	int height 	= VI.getHeight(device1);
 | 
						|
	int size	= VI.getSize(device1);
 | 
						|
	
 | 
						|
	unsigned char * yourBuffer1 = new unsigned char[size];
 | 
						|
	unsigned char * yourBuffer2 = new unsigned char[size];
 | 
						|
	
 | 
						|
	//to get the data from the device first check if the data is new
 | 
						|
	if(VI.isFrameNew(device1)){
 | 
						|
		VI.getPixels(device1, yourBuffer1, false, false);	//fills pixels as a BGR (for openCV) unsigned char array - no flipping
 | 
						|
		VI.getPixels(device1, yourBuffer2, true, true); 	//fills pixels as a RGB (for openGL) unsigned char array - flipping!
 | 
						|
	}
 | 
						|
	
 | 
						|
	//same applies to device2 etc
 | 
						|
	
 | 
						|
	//to get a settings dialog for the device
 | 
						|
	VI.showSettingsWindow(device1);
 | 
						|
	
 | 
						|
	
 | 
						|
	//Shut down devices properly
 | 
						|
	VI.stopDevice(device1);
 | 
						|
	VI.stopDevice(device2);
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
//////////////////////////////////////   VARS AND DEFS   //////////////////////////////////
 | 
						|
 | 
						|
 | 
						|
//STUFF YOU CAN CHANGE
 | 
						|
 | 
						|
//change for verbose debug info
 | 
						|
static bool verbose = true;
 | 
						|
 | 
						|
//if you need VI to use multi threaded com
 | 
						|
//#define VI_COM_MULTI_THREADED
 | 
						|
 | 
						|
//STUFF YOU DON'T CHANGE
 | 
						|
 | 
						|
//videoInput defines
 | 
						|
#define VI_VERSION	 0.1995
 | 
						|
#define VI_MAX_CAMERAS  20
 | 
						|
#define VI_NUM_TYPES    18 //DON'T TOUCH
 | 
						|
#define VI_NUM_FORMATS  18 //DON'T TOUCH
 | 
						|
 | 
						|
//defines for setPhyCon - tuner is not as well supported as composite and s-video 
 | 
						|
#define VI_COMPOSITE 0
 | 
						|
#define VI_S_VIDEO   1
 | 
						|
#define VI_TUNER     2
 | 
						|
#define VI_USB       3
 | 
						|
#define VI_1394		 4
 | 
						|
 | 
						|
//defines for formats
 | 
						|
#define VI_NTSC_M	0
 | 
						|
#define VI_PAL_B	1
 | 
						|
#define VI_PAL_D	2
 | 
						|
#define VI_PAL_G	3
 | 
						|
#define VI_PAL_H	4
 | 
						|
#define VI_PAL_I	5
 | 
						|
#define VI_PAL_M	6
 | 
						|
#define VI_PAL_N	7
 | 
						|
#define VI_PAL_NC	8
 | 
						|
#define VI_SECAM_B	9
 | 
						|
#define VI_SECAM_D	10
 | 
						|
#define VI_SECAM_G	11
 | 
						|
#define VI_SECAM_H	12
 | 
						|
#define VI_SECAM_K	13
 | 
						|
#define VI_SECAM_K1	14
 | 
						|
#define VI_SECAM_L	15
 | 
						|
#define VI_NTSC_M_J	16
 | 
						|
#define VI_NTSC_433	17
 | 
						|
 | 
						|
 | 
						|
//allows us to directShow classes here with the includes in the cpp
 | 
						|
struct ICaptureGraphBuilder2;
 | 
						|
struct IGraphBuilder;
 | 
						|
struct IBaseFilter;
 | 
						|
struct IAMCrossbar;
 | 
						|
struct IMediaControl;
 | 
						|
struct ISampleGrabber;
 | 
						|
struct IMediaEventEx;
 | 
						|
struct IAMStreamConfig;
 | 
						|
struct _AMMediaType;
 | 
						|
class SampleGrabberCallback;
 | 
						|
typedef _AMMediaType AM_MEDIA_TYPE;
 | 
						|
 | 
						|
//keeps track of how many instances of VI are being used
 | 
						|
//don't touch
 | 
						|
static int comInitCount = 0;
 | 
						|
 | 
						|
 | 
						|
////////////////////////////////////////   VIDEO DEVICE   ///////////////////////////////////
 | 
						|
 | 
						|
class videoDevice{
 | 
						|
 | 
						|
	
 | 
						|
	public:
 | 
						|
		 
 | 
						|
		videoDevice();
 | 
						|
		void setSize(int w, int h);
 | 
						|
		void NukeDownstream(IBaseFilter *pBF);
 | 
						|
		void destroyGraph();
 | 
						|
		~videoDevice();
 | 
						|
		
 | 
						|
		int videoSize;
 | 
						|
		int width;
 | 
						|
		int height;
 | 
						|
		int tryWidth;
 | 
						|
		int tryHeight;
 | 
						|
		
 | 
						|
		ICaptureGraphBuilder2 *pCaptureGraph;	// Capture graph builder object
 | 
						|
		IGraphBuilder *pGraph;					// Graph builder object
 | 
						|
	    IMediaControl *pControl;				// Media control object
 | 
						|
		IBaseFilter *pVideoInputFilter;  		// Video Capture filter
 | 
						|
		IBaseFilter *pGrabberF;
 | 
						|
		IBaseFilter * pDestFilter;
 | 
						|
		IAMStreamConfig *streamConf;
 | 
						|
		ISampleGrabber * pGrabber;    			// Grabs frame
 | 
						|
		AM_MEDIA_TYPE * pAmMediaType;
 | 
						|
		
 | 
						|
		IMediaEventEx * pMediaEvent;
 | 
						|
		
 | 
						|
		GUID videoType;
 | 
						|
		long formatType;
 | 
						|
		
 | 
						|
		SampleGrabberCallback * sgCallback;				
 | 
						|
		
 | 
						|
		bool tryDiffSize;
 | 
						|
		bool useCrossbar;
 | 
						|
		bool readyToCapture;
 | 
						|
		bool sizeSet;
 | 
						|
		bool setupStarted;
 | 
						|
		bool specificFormat;
 | 
						|
		bool autoReconnect;
 | 
						|
		int  nFramesForReconnect;
 | 
						|
		unsigned long nFramesRunning;
 | 
						|
		int  connection;
 | 
						|
		int	 storeConn;
 | 
						|
		int  myID;
 | 
						|
		long requestedFrameTime; //ie fps
 | 
						|
		
 | 
						|
		char 	nDeviceName[255];
 | 
						|
		WCHAR 	wDeviceName[255];
 | 
						|
		
 | 
						|
		unsigned char * pixels;
 | 
						|
		char * pBuffer;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//////////////////////////////////////   VIDEO INPUT   /////////////////////////////////////
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class videoInput{
 | 
						|
 | 
						|
	public:
 | 
						|
		videoInput();
 | 
						|
		~videoInput();
 | 
						|
				
 | 
						|
		//turns off console messages - default is to print messages
 | 
						|
		static void setVerbose(bool _verbose);
 | 
						|
		
 | 
						|
		//Functions in rough order they should be used.
 | 
						|
		static int listDevices(bool silent = false);
 | 
						|
 | 
						|
		//needs to be called after listDevices - otherwise returns NULL
 | 
						|
		static char * getDeviceName(int deviceID);
 | 
						|
		
 | 
						|
		//choose to use callback based capture - or single threaded
 | 
						|
		void setUseCallback(bool useCallback);	
 | 
						|
		
 | 
						|
		//call before setupDevice
 | 
						|
		//directshow will try and get the closest possible framerate to what is requested
 | 
						|
		void setIdealFramerate(int deviceID, int idealFramerate);
 | 
						|
 | 
						|
		//some devices will stop delivering frames after a while - this method gives you the option to try and reconnect
 | 
						|
		//to a device if videoInput detects that a device has stopped delivering frames. 
 | 
						|
		//you MUST CALL isFrameNew every app loop for this to have any effect
 | 
						|
		void setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect);
 | 
						|
		
 | 
						|
		//Choose one of these four to setup your device
 | 
						|
		bool setupDevice(int deviceID);
 | 
						|
		bool setupDevice(int deviceID, int w, int h);
 | 
						|
 | 
						|
		//These two are only for capture cards
 | 
						|
		//USB and Firewire cameras souldn't specify connection 
 | 
						|
		bool setupDevice(int deviceID, int connection);	
 | 
						|
		bool setupDevice(int deviceID, int w, int h, int connection); 
 | 
						|
		
 | 
						|
		//If you need to you can set your NTSC/PAL/SECAM
 | 
						|
		//preference here. if it is available it will be used.
 | 
						|
		//see #defines above for available formats - eg VI_NTSC_M or VI_PAL_B
 | 
						|
		//should be called after setupDevice
 | 
						|
		//can be called multiple times
 | 
						|
		bool setFormat(int deviceNumber, int format);	
 | 
						|
				
 | 
						|
		//Tells you when a new frame has arrived - you should call this if you have specified setAutoReconnectOnFreeze to true
 | 
						|
		bool isFrameNew(int deviceID); 
 | 
						|
		
 | 
						|
		bool isDeviceSetup(int deviceID);
 | 
						|
		    
 | 
						|
		//Returns the pixels - flipRedAndBlue toggles RGB/BGR flipping - and you can flip the image too
 | 
						|
		unsigned char * getPixels(int deviceID, bool flipRedAndBlue = true, bool flipImage = false);
 | 
						|
		
 | 
						|
		//Or pass in a buffer for getPixels to fill returns true if successful.
 | 
						|
		bool getPixels(int id, unsigned char * pixels, bool flipRedAndBlue = true, bool flipImage = false);
 | 
						|
		
 | 
						|
		//Launches a pop up settings window
 | 
						|
		//For some reason in GLUT you have to call it twice each time. 
 | 
						|
		void showSettingsWindow(int deviceID);
 | 
						|
		
 | 
						|
		//Manual control over settings thanks..... 
 | 
						|
		//These are experimental for now.
 | 
						|
		bool setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags = NULL, bool useDefaultValue = false);
 | 
						|
		bool setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags = NULL);
 | 
						|
		bool getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue);
 | 
						|
 | 
						|
		bool setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags = NULL, bool useDefaultValue = false);
 | 
						|
		bool setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags = NULL);
 | 
						|
		bool getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue);
 | 
						|
 | 
						|
		//bool setVideoSettingCam(int deviceID, long Property, long lValue, long Flags = NULL, bool useDefaultValue = false);
 | 
						|
 | 
						|
		//get width, height and number of pixels
 | 
						|
		int  getWidth(int deviceID);
 | 
						|
		int  getHeight(int deviceID);
 | 
						|
		int  getSize(int deviceID);
 | 
						|
		
 | 
						|
		//completely stops and frees a device
 | 
						|
		void stopDevice(int deviceID);
 | 
						|
		
 | 
						|
		//as above but then sets it up with same settings
 | 
						|
		bool restartDevice(int deviceID);
 | 
						|
		
 | 
						|
		//number of devices available
 | 
						|
		int  devicesFound;
 | 
						|
		
 | 
						|
		long propBrightness;
 | 
						|
		long propContrast;
 | 
						|
		long propHue;
 | 
						|
		long propSaturation;
 | 
						|
		long propSharpness;
 | 
						|
		long propGamma;
 | 
						|
		long propColorEnable;
 | 
						|
		long propWhiteBalance;
 | 
						|
		long propBacklightCompensation;
 | 
						|
		long propGain;
 | 
						|
 | 
						|
		long propPan;
 | 
						|
		long propTilt;
 | 
						|
		long propRoll;
 | 
						|
		long propZoom;
 | 
						|
		long propExposure;
 | 
						|
		long propIris;
 | 
						|
		long propFocus;
 | 
						|
				
 | 
						|
		
 | 
						|
	private:		
 | 
						|
		void setPhyCon(int deviceID, int conn);                   
 | 
						|
		void setAttemptCaptureSize(int deviceID, int w, int h);   
 | 
						|
		bool setup(int deviceID);
 | 
						|
		void processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip);
 | 
						|
		int  start(int deviceID, videoDevice * VD);                   
 | 
						|
		int  getDeviceCount();
 | 
						|
		void getMediaSubtypeAsString(GUID type, char * typeAsString);
 | 
						|
		
 | 
						|
		HRESULT getDevice(IBaseFilter **pSrcFilter, int deviceID, WCHAR * wDeviceName, char * nDeviceName);
 | 
						|
		static HRESULT ShowFilterPropertyPages(IBaseFilter *pFilter);
 | 
						|
		HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath);
 | 
						|
		HRESULT routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode);
 | 
						|
			
 | 
						|
		//don't touch
 | 
						|
		static bool comInit();
 | 
						|
		static bool comUnInit();
 | 
						|
 | 
						|
		int  connection;
 | 
						|
		int  callbackSetCount;
 | 
						|
		bool bCallback;
 | 
						|
		
 | 
						|
		GUID CAPTURE_MODE;
 | 
						|
		
 | 
						|
		//Extra video subtypes
 | 
						|
		GUID MEDIASUBTYPE_Y800;
 | 
						|
		GUID MEDIASUBTYPE_Y8;
 | 
						|
		GUID MEDIASUBTYPE_GREY;
 | 
						|
 | 
						|
		videoDevice * VDList[VI_MAX_CAMERAS];
 | 
						|
		GUID mediaSubtypes[VI_NUM_TYPES];
 | 
						|
		long formatTypes[VI_NUM_FORMATS];
 | 
						|
 | 
						|
		static void __cdecl basicThread(void * objPtr);
 | 
						|
 | 
						|
		static char deviceNames[VI_MAX_CAMERAS][255];
 | 
						|
 | 
						|
}; 
 | 
						|
  
 | 
						|
 #endif
 |