Click here to Skip to main content
15,867,316 members
Articles / Programming Languages / C#

MicroDVR - Simple Video Security Using Webcams

Rate me:
Please Sign up or sign in to vote.
5.00/5 (23 votes)
2 Mar 2012CPOL3 min read 109.4K   70   46
A simple video-security application that allows video capture from PC webcams, detect motion, record videos on local storage using .NET 3.5, AForge and FFMpeg
In this article, you will see a simple application that allows the user to use the available VideoCaptureDevices as security cameras. For each camera, we can enable the Motion Detection, Beep on motion and Automatic recording on motion.

Image 1

Introduction

This is a simple application that allows the user to use the available VideoCaptureDevices (Webcams) as security cameras. The interface allows the user to record the videocapture of a specific camera to a video file (.avi) to local storage (the recording path also can be set via the interface). The user can at anytime set the focus on any camera. For each camera, we can enable the Motion Detection, Beep on motion and Automatic recording on motion.

Background

The basic idea of this application is to create a low cost/cost free video security program for a rather small place (a small store in my case) that covers the basic DVR functionalities (Motion detection, recording).

Code Explanation

a. The CameraMonitor Class

The "CameraMonitor" class is the essential core of this application, as it provides the interface to control the "VideoCaptureDevice" as well as the other functions like Video Recording and motion detection.

Here are the class' public members and properties:

Image 2

The way we can create "CameraMonitor" object is through its constructor:

C#
new CameraMonitor(
		PictureBox display,   // a PictureBox where we will be displaying the incoming frames
		string monikerString, // the monikerSring is the WMI Object Path of 
                              // our VideoCaptureDevice
		String  cameraName    // a camera name (used for naming the video files recorded)
		);

The CameraMonitor first creates the "VideoCaptureDevice" using the monikerString passed to it, then sets the event handler for new incoming frames and finally it starts the Video capture.

C#
cam = new VideoCaptureDevice(monikerString);
cam.NewFrame += new NewFrameEventHandler(cam_NewFrame); // the method "cam_NewFrame" 
                                                        // is called when a new frame arrives
cam.Start(); // starts the videoCapture 

It also creates the MotionDetector:

C#
md = new MotionDetector(new TwoFramesDifferenceDetector(), 
     new MotionAreaHighlighting());           // creates the motion detector

Now when a NewFrameEvent is detected, the "cam_NewFrame" method is ready to handle it, first it gets the BitMap from the new frame , then it displays it on the PictureBox for the user.

C#
Bitmap bit = (Bitmap)eventArgs.Frame.Clone(); // get a copy of the BitMap 
                                              // from the VideoCaptureDevice
this.display.Image = (Bitmap)bit.Clone();     // displays the current frame on the main form

The Motion Detection Algorithm

If the motion detection is activated by the user, "cam_NewFrame" executes the code below:

C#
if (this.MotionDetection && !this.motionDetected)
{
    // if motion detection is enabled and there werent any previous motion detected
    Bitmap bit2 = (Bitmap)bit.Clone();    // clone the bits from the current frame

    if (md.ProcessFrame(bit2) > 0.001)    // feed the bits to the MD 
    {
        if (this.calibrateAndResume > 3)
        {
            // if motion was detected in 3 subsequent frames
            Thread th = new Thread(MotionReaction);
            th.Start();                   // start the motion reaction thread
        }
        else this.calibrateAndResume++;
    }
}

Note: The "calibrateAndResume" counter is added to make sure that there is a real motion going on (within three subsequent frames). Earlier, the motion detector would trigger even for a small change in the room lighting.

If Motion is detected, a new Thread is launched to do whatever needs to done (display a message and/or beep and/or start recording).

C#
private void MotionReaction()
        {
            this.motionDetected = true;  // pauses motion detection for a while
            if (this.RecordOnMotion)
            {
                this.StartRecording();   // record if Autorecord is toggled
            }
            if (this.BeepOnMotion)
            {
                // beep if BeepOnMotion is toggled
                System.Console.Beep(400, 500);
                System.Console.Beep(800, 500);
            }
            
            Thread.Sleep(10000);         // the user is notified for 10 seconds
            calibrateAndResume = 0;
            this.motionDetected = false; // resumes motion detection
            Thread.Sleep(3000);
            // the thread waits 3 seconds if there is no motion detected we stop the AutoRecord
            if (!this.forceRecord && this.motionDetected == false)
            {	
				// if the motion has totally stopped we stop AutoRecording
                this.StopRecording();
            }

        }

Video Recording

To record videos, we're using a Bitmap Queue to store the frames coming from the camera, then the recorder thread will dequeue frame by frame and write it to a file using a "VideoFileWriter".

C#
private void DoRecord()
        {
            // we set our VideoFileWriter as well as the file name, resolution and fps
            VideoFileWriter writer = new VideoFileWriter();
            writer.Open(RecordingPath+"\\" + this.cameraName +
                        String.Format("{0:_dd-M-yyyy_hh-mm-ss}",DateTime.Now) +".avi", 
                        this.Width, this.Height, 30);
            
            // as long as we're recording 
            // we dequeue the BitMaps waiting in the Queue and write them to the file
            while (IsRecording)
            {
                if (frames.Count > 0)
                {
                    Bitmap bmp = frames.Dequeue();
                    writer.WriteVideoFrame(bmp);
                }
            }
            writer.Close();
        }

Note: We can always set the recording path via the public property "RecordingPath". Note: Here, the FrameRate is not properly set as it must be retrieved from the camera FrameRate, this will be noticed in the output videofile (speed not accurate).

b. The User Interface (MainForm Class)

Using the CameraMonitor

When the form loads, it fetches the FilterInfoCollection array which contains the monikerString strings required to start the VideoCaptureDevice in the CameraMonitor. At this point, the available cameras will be working and displaying video on the PictureBox controls we passed to them.

C#
webcam = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            // we create our CameraMonitors
            for (int i = 0; i < webcam.Count && i<4; i++)
            {
                this.CamMonitor[i] = new CameraMonitor
                     (this.DisplayReference[i],webcam[i].MonikerString,"Camera"+(i+1));
                // Enable the user controls corresponding to the CameraMonitor
                this.camPanels[i].Enabled = true;
                this.camOptions[i].Enabled = true;
            }

Saving and Loading User Options

The last part is making the application remember stuff like the recording path or which cam was detecting motion, etc., so when the user runs the application, he would not have to RESET all options manually. To do this, I've created a Config DataSet that stores associations ( KEY => VALUE ) where we'll save user option upon application exit, and reload them at application run using the DataSet.WriteXml() and DataSet.ReadXml().

Example: Fetching options from the user interface and saving them to an XML file:

C#
try
    {
        // we try to get the option record by key
        DataRow r = this.config.Options.Select("Key = 'Camera1'")[0];
        // then we retrieve the value from the user control
        r[1] = ((!this.MotionDetection1.Checked) ? "0" : "1") +
            ((!this.AutoRecord1.Checked) ? "0" : "1") +
            ((!this.BeepOnMotionCheck1.Checked) ? "0" : "1");
    }
    catch (Exception ex) // if something goes wrong (i.e., Option key is not found)
    {
        // we create a new Option record
        this.config.Options.AddOptionsRow("Camera1",
            ((!this.MotionDetection1.Checked) ? "0" : "1") +
            ((!this.AutoRecord1.Checked) ? "0" : "1") +
            ((!this.BeepOnMotionCheck1.Checked) ? "0" : "1"));
    }
// finally we write everything to an XML file
    this.config.WriteXml("config.xml");

Example: Fetching options from XML File and applying them to the user interface:

C#
this.config.ReadXml("config.xml");
	try
            {
                // we try to get the option by its Key
                DataRow r = this.config.Options.Select("Key = 'Camera1'")[0];
                string option = r[1].ToString();
                // we apply changes to the user interface
                this.MotionDetection1.Checked = (option[0] == '0') ? false : true;
                this.AutoRecord1.Checked = (option[1] == '0') ? false : true;
                this.BeepOnMotionCheck1.Checked = (option[2] == '0') ? false : true;
            }
            catch (Exception ex) { }

Points of Interest

As a programmer, this application enabled me to scratch the surface to working with Video using AForge, writing video files (FFMpeg), playing with some image processing, so all in all, it's good programming experience!

History

  • February 2012: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Smart Solutions Médéa
Algeria Algeria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionFrom source webcam images do not show, but using given exe they work fine Pin
Member 1128818019-May-21 1:31
Member 1128818019-May-21 1:31 
QuestionIf your experiencing out of memory issues use this function Pin
Patrick Eckler21-May-20 3:41
Patrick Eckler21-May-20 3:41 
QuestionCouldn't locate my cam, here's what I had to do Pin
Gadget-Doss-Jr12-Jan-18 19:45
Gadget-Doss-Jr12-Jan-18 19:45 
QuestionIs there a way to pause and resume recording in single file? Pin
docLiv13-Jan-16 18:05
docLiv13-Jan-16 18:05 
Questionispy.Video.ffmpeg Pin
Member 24522045-Apr-15 13:20
Member 24522045-Apr-15 13:20 
Questionmemory leak (picturebox) Pin
coderaw11-Mar-15 4:02
coderaw11-Mar-15 4:02 
Questionthank Pin
saajan123453-Jul-14 15:53
saajan123453-Jul-14 15:53 
QuestionAforge.Video.Ffmpeg error Pin
Member 1066213130-Apr-14 14:15
Member 1066213130-Apr-14 14:15 
GeneralMy vote of 5 Pin
Ahmed Bensaid27-Feb-14 23:02
professionalAhmed Bensaid27-Feb-14 23:02 
Generalthanks Pin
whble14-Nov-13 1:19
whble14-Nov-13 1:19 
QuestionUnknown DLLs Pin
Tuner-Test-Coder24-Oct-13 3:09
Tuner-Test-Coder24-Oct-13 3:09 
AnswerRe: Unknown DLLs Pin
Osman Kalache3-Nov-13 5:30
Osman Kalache3-Nov-13 5:30 
GeneralMy vote of 5 Pin
Tuner-Test-Coder24-Oct-13 2:19
Tuner-Test-Coder24-Oct-13 2:19 
Exactly what I'm looking for.
Thanks!

By the way...: AForge-Online-Doku
QuestionCamera's URL Pin
briccardo95619-Sep-13 4:03
briccardo95619-Sep-13 4:03 
AnswerRe: Camera's URL Pin
Osman Kalache19-Sep-13 4:29
Osman Kalache19-Sep-13 4:29 
GeneralRe: Camera's URL Pin
briccardo95619-Sep-13 4:35
briccardo95619-Sep-13 4:35 
GeneralRe: Camera's URL Pin
Osman Kalache19-Sep-13 4:50
Osman Kalache19-Sep-13 4:50 
AnswerRe: Camera's URL Pin
briccardo95619-Sep-13 5:23
briccardo95619-Sep-13 5:23 
GeneralMy vote of 5 Pin
hendi29-Jun-13 11:09
hendi29-Jun-13 11:09 
QuestionDisplay properties for cameras Pin
BoringPortlander8-Apr-13 16:28
BoringPortlander8-Apr-13 16:28 
AnswerRe: Display properties for cameras Pin
Osman Kalache8-Apr-13 23:32
Osman Kalache8-Apr-13 23:32 
GeneralRe: Display properties for cameras Pin
BoringPortlander9-Apr-13 10:41
BoringPortlander9-Apr-13 10:41 
GeneralRe: Display properties for cameras Pin
BoringPortlander9-Apr-13 11:36
BoringPortlander9-Apr-13 11:36 
QuestioncalibrateAndResume question Pin
Jacob Pachansky4-Nov-12 11:12
Jacob Pachansky4-Nov-12 11:12 
AnswerRe: calibrateAndResume question Pin
Osman Kalache28-Nov-12 15:26
Osman Kalache28-Nov-12 15:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.