Tuesday, October 11, 2005

Webcam Fetcher Application

Here's the source code for a little console application that I built to automatically download the current image from a webcam so that you can build a directory full of stills (with the goal of later animating the stills to get one of those time-lapsed [fast-moving] movies).

I'm not sure if Carl's going to appreciate the drain on his bandwidth, but the DNR webcam URL is hardcoded in this code.

FWIW: I created this app originally so that I could capture Mount Saint Helens erupting last year. I dusted it off again last night because I'd like to see if I can later merge the GPS/mapping data from the roadtrip with the archived webcam images.

This code performs a couple of tricks:

1. It automatically adjusts the interval between downloads between a minimum value (10 seconds here) and a maximum value (10 minutes). This way, when the webcam is turned off, you don't continue to flood the web server with requests for the exact same picture. As soon as a new frame is detected, the interval resets to the minimum so that you don't miss any more of the action.

2. It uses a hash value on the image to see if it was the same as the previously retrieved image (in which case, the application does not save the current image).



class Class1
{
private static readonly int MINIMUM_WAIT = 10000;
private static readonly int MAXIMUM_WAIT = 600000;
private static int _CURRENT_WAIT = 10000;

[STAThread]
static void Main(string[] args)
{
for (;;)
{
FetchIt();
System.Threading.Thread.Sleep(_CURRENT_WAIT);
}
}

static void FetchIt()
{
WebClient web = new WebClient();

string hash1 = "";
string hash2 = "";

System.Security.Cryptography.MD5CryptoServiceProvider hasher =
new System.Security.Cryptography.MD5CryptoServiceProvider();

if (System.IO.File.Exists(@"c:\dnr\latest.jpg"))
{
System.IO.FileStream fs =
System.IO.File.OpenRead(@"c:\dnr\latest.jpg");

byte[] hash = hasher.ComputeHash(fs);

fs.Close();

foreach (byte b in hash)
hash1 += b.ToString("X2");
}

try
{
web.DownloadFile(
@"http://www.dotnetrocks.com/roadtrip/cam/webcam.jpg?random=" +
new Random().Next(9999999).ToString(), @"c:\dnr\latest.jpg");

System.IO.FileStream fs = System.IO.File.OpenRead(@"c:\dnr\latest.jpg");

byte[] hash = hasher.ComputeHash(fs);

long len = fs.Length;

fs.Close();

foreach (byte b in hash)
hash2 += b.ToString("X2");

if (hash1 != hash2 && len > 12000)
{
_CURRENT_WAIT = MINIMUM_WAIT;

string fn = @"c:\dnr\" +
DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg";

Console.WriteLine(fn + " " + len.ToString());

System.IO.File.Copy(@"c:\dnr\latest.jpg", fn);
}
else
{
_CURRENT_WAIT += (3 * MINIMUM_WAIT);

if (_CURRENT_WAIT > MAXIMUM_WAIT)
_CURRENT_WAIT = MAXIMUM_WAIT;
}
}
catch (Exception)
{}
finally
{
web = null;
}
}
}