
Just a quickie..
I wrote the original version of this in vb6 about 4 years ago, and published it as freeware, (might even be floating around the wild somewhere still..), and decided it was a good starter app for learning C#, when I began migrating my skills almost two years ago. So, the uncompleted version of this has been sitting in a folder on my dev box for some time, just waiting for a few tweaks -which I got around to the other day. I thought this would be a good target freeware, because unfortunately, many of us have had the misfortune of being robbed at some point in our lives, and students, young working people or someone in an apartment may not be able to afford or install a proper alarm system.
I use a creative 5.1 speaker rig, and with the amp cranked, the siren this sounds is at least as loud as a conventional alarm system, and would probably cause an intruder to bolt rather then attempt to find the source and disarm.
The original used the avicap32.dll library, which seemed to work fine on my older Logitech camera, but will not work on newer devices, (this was tested with both an Acer notebook camera, and an MS Lifecam). At this point I realized I had to go to the DirectShow library to capture video from a wider range of input devices. A search on Codeproject turned up the Motion Detection project by Andrew Kirillov. I removed dependencies on the AForge library, and reworked the avi reader/writer classes, but the directshow wrappers and detection algorithms are his work, (thanks Andrew).
The Highlights
When the application loads, it tests for the wmv avi recording codec by enumerating the installed codecs, if it isn't found, a dialog is launched, asking the user to install it. The installation executable is an embedded resource, which is pulled from the resource assembly, and recreated as a file in the temp directory, then launched with the ShellExecute
api.
private void codecTest()
{
FilterCollection filters = new FilterCollection(FilterCategory.VideoCompressorCategory);
bool found = false;
foreach (Filter filter in filters)
{
found = filter.Name.Contains("Media Video 9");
if (found)
break;
}
if (!found)
{
if (MessageBox.Show("The video capture feature requires the Microsoft WMV9 codec. Do you want to install this now?", "Codec Installation Required",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
{
executeCodec();
}
else
{
_bCanRecord = false;
}
}
}
private bool executeCodec()
{
try
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream("CamAlarm.Resources.wmv9VCMsetup.exe"))
{
if (stream != null)
{
BinaryReader br = new BinaryReader(stream);
using (FileStream fs = new FileStream(Environment.GetEnvironmentVariable("TEMP") + "// {
BinaryWriter bw = new BinaryWriter(fs);
byte[] bt = new byte[stream.Length];
stream.Read(bt, 0, bt.Length);
bw.Write(bt);
br.Close();
bw.Close();
fs.Close();
}
executeProgram(Environment.GetEnvironmentVariable("TEMP") + "// }
}
return true;
}
catch { return false; }
}
A timer is run that waits for the camera to focus in, then the control panels are activated. Settings like the keycode and option control states are stored in the applications default properties. When first run, or if the keycode property is cleared, the arm/disarm button acts as the keycode set button. The sounds used in the application are instances of the System.Media.SoundPlayer
class, instanced and loaded with a sound file when the app initializes:
private void loadWarning()
{
if (_cWarningSound != null)
_cWarningSound.Dispose();
_cWarningSound = new SoundPlayer(CamAlarm.Resource1.beep);
_cWarningSound.Load();
}
The cameras motion trigger-state is polled periodically using a custom timer class, if motion has occured, an alarm timer is fired, which will loop until the alarm is deactivated, or the max alarm timeout occurs:
private void _cAlarmTimer_Tick(object sender)
{
if (_eAlarmState == AlarmState.Arming)
{
_iTimerTick++;
if (_iTimerTick > stringToInt(txtArmingDelay.Text))
armAlarm();
else
updateStatus();
}
else if (_eAlarmState == AlarmState.Armed)
{
if (_iActiveTick > 5)
triggerAlarm();
}
else if (_eAlarmState == AlarmState.Sounding)
{
_iTimerTick++;
if (_iTimerTick > stringToInt(txtDuration.Text))
{
if (_iActiveTick < 5)
disarmAlarm();
else
soundAlarm();
}
else
{
soundAlarm();
}
}
else if (_eAlarmState == AlarmState.Standby)
{
stopAlarm();
}
else if (_eAlarmState == AlarmState.Triggered)
{
_iTimerTick++;
if (_iTimerTick > stringToInt(txtAlarmDelay.Text))
{
soundAlarm();
}
else
{
if (!chkSilent.Checked)
playWarning();
}
}
}
When the alarm is in armed mode all but the keypad and disarm switch are disabled, this is done by disabling the groupbox that houses the controls. The main form close button also needs to be deactivated, this is done both by cancelling the forms exit in the FormClosing event, and by disabling the close button using the GetSystemMenu
/EnableMenuItem
api:
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (_bCloseDisabled)
{
e.Cancel = true;
}
else
{
closeCamera();
closeFile();
saveSettings();
if (_cAlarmTimer != null)
_cAlarmTimer.Dispose();
}
}
private void enableClose(bool enable)
{
if (enable)
EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_ENABLED);
else
EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_GRAYED);
_bCloseDisabled = !enable;
}
All in all, fairly simple approach, though I wasn't all that generous with comments in code, it is fairly straightforward..
Change Log
May 17, 2010
- -First time loading of help page creates page in user app folder.
-Alarm volume raised after trigger warning beeps
-Fixed lock when capturing video, changed from Monitor.Enter to TryEnter in Camera.cs
-Added tooltip to clear and video buttons
-Added menu buttons to disabled items when alarm is activated
June 16, 2010
- -Fixed codec url in executeCodec()
- -Fixed disabled OK button in Device selection form
Using the application..
Keep the camera view up where pets won't trigger it, and away from windows. Crank the volume on your speakers, and adjust application volumes through the mixer, CamAlarm has an option to push to maximum volume when the alarm is activated, but this won't mean much if the master volume is down low.
Well.. enjoy! If you find any bugs, be sure to leave a message.