VidRecord example in C++

You may download the source code for this example. The VidRecord example software is released under terms of the Open Source Initiative BSD 2 - Clause license. Copy of the license for this software is at http://www.raben.com/sites/default/files/allsky/software/license.txt . If you have not already done so, download and install OpenCV on your local machine, see the installation notes. Unzip the VidRecordCpp.zip file somewhere in your local directory. It will create a directory called "VidRecord" containing the source files and license.

To compile on Ubuntu 12.04

unzip VidRecordCpp.zip
cd VidRecord
mkdir build
cd build
cmake ..
make
make install

To compile on MS Windows Vista or Windows 7

  • Download and install CMake from http://www.cmake.org
  • Start up CMake and set the source directory to the VidRecord directory you previously unzipped. Set the binaries directory to be just below the source in a directory called say "build", something like WHATEVER\VidRecord\build
  • Click on the "Configure" button.
  • Click on the "Build" button
  • Use Visual Studio 2010, 2011, 2012 edition if you already have it. If not, download and install MS Windows Visual Studio Express 2011 or 2012 from www.microsoft.com (Currently the free Express edition is at http://www.microsoft.com/visualstudio/eng/downloads#d-2012-express ).
  • Now run Visual Studio and then click on the "Project" button at the top and select the VidRecord\build directory and click on the project solution file.
  • Click the "Compile" button
  • Answer yes to popup to build additonal projects, ie, build-all and install
  • Note that OpenCV 2.4.2 is compatible with the VS 2010 compiler. If you are using the 2012 edition of VS, answer to "No" to dialog asking to convert project to 2012 (unless you like seeing lots of error messages)

VidRecord C++ source notes

The required includes for OpenCV are just "core" and "highgui".

#include < opencv2/core/core.hpp >
#include < opencv2/highgui/highgui.hpp >

Remainder of the includes are just standard cpp libraries for iostream, some string manipulations and time routines.

Included is simplistic class called "Config.cpp" for retrieving configuration parameters from the command line arguments or from a configuration file called (no surprise) ".vidrecordrc". It has a number overloaded function "getters" for retrieving various parameter types, int, double, bool, and string.

/**
  * Get configuration value for a parameter
  * @param name Name of the parameter
  * @param default Default value for the parameter if not set
  * @return the parameter's value as an integer
  */
int Config::getVal(string name, int defaultVal) {
	int retVal = defaultVal;

	if (vals.count(name) > 0) {
		istringstream iss(vals[name]);
		iss >> retVal;
	}

	return retVal;
}

We use get parameters previously set from command line arguments or previously loaded from a config file. For example, the configuration parameters for image writing are retrieved as follows:

    imgDir = config.getVal("imgdir", imgDir);
    imgFmt = config.getVal("imgfmt", imgFmt);
    imgInterval = config.getVal("imgint", imgInterval);
    imgNum = config.getVal("imgnum", imgNum);

We open the video device connected to our allsky camera as follows:

    // Open video device, set video frame width and height as driver often does not
    VideoCapture cap = VideoCapture(vidDevice);

    if (cap.isOpened()) {
        cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
        cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    } else {
    	cerr << "Error: Could not open video device "<< vidDevice << endl;
        return 1;   
    } 

Frames from the video device are moved to our image frame

    // Frame capture loop
    while(isEnabled) {
        cap >> frame;
        ....

We then write the frame to the video file, calculate the time interval passed and based on whether or not to create a new file:

        if (isRecordingEnabled) {
            writer.write(frame);
            vidDelta = sec - vidTime;
            cout << "vidDelta "<= "<= vidInterval) {
                isRecording = false;
                vidTotal = vidTotal + 1;
                ....
        if ((isRecordingEnabled) && (!isRecording)) {
            int width = (int)cap.get(CV_CAP_PROP_FRAME_WIDTH);
            int height = (int)cap.get(CV_CAP_PROP_FRAME_HEIGHT);
            writer = createVideoFile(vidDir, width, height, vidFps, fourcc, sec);
            vidTime = sec;
            isRecording = true;
            frameNum = 0;
        }

The "createVideoFile function creates a new VideoWriter object that starts writing passing it a file name with current time stamp.

VideoWriter createVideoFile(String vidDir, int width, int height, int fps, int fourcc, time_t sec) {

    string timeStr = currentTimeString(&sec);
    string fileName = vidDir + timeStr + ".avi";
	cout << "Video file name = " << fileName << endl;
	Size frameSize = Size(width, height);
    VideoWriter vidWriter = VideoWriter(fileName, fourcc, fps,
        frameSize);
	return vidWriter;
}

The "currentTimeString" function uses the current time in seconds and uses the gmtime function to return the current time.

string currentTimeString(time_t *sec) {
    struct tm *ptm = gmtime (sec);
    ostringstream ostr;
    ostr<tm_year + 1900)<< "-" << setw(2)<< (ptm->tm_mon+1)
            << "-" << setw(2)<tm_mday << "T"<tm_hour
            << "h" <tm_min << "m" << setw(2) << ptm->tm_sec;
    return ostr.str();
}

The writeImageFile uses the cuirrentTimeString as well to create new png, jpg, tiff, etc image files at periodic intervals. Logic as to when to write them is very similar to how its done for video. See source code referenced above for details.