Capture Images from an Internet Camera on Windows Phone 7


--Copyright 2010 Travis Feirtag


Introduction

Since Microsoft first gave everyone access to Windows Phone developer tools, there has been a lot of buzz and excitement for developing on the new phone.  Unfortunately, once people started digging into the tools and running the emulator, they realized that there is a lot still missing from the dev tools.  The fact is that this is an early preview to generate excitement about the phone.  There are many more great features coming to the dev tools, eventually.  Until then, we need to make due and use what we've got.

One feature that is currently missing is being able to take pictures from the Windows Phone emulator.  So that gave me the idea to write a simple article to capture images on your Windows Phone emulator using an IP Camera.  This will give you the ability to get bitmap images onto the phone from a camera and then you can use your creativity to manipulate the images however you want.


Download WPSLCamera Source Files for this Article


TRENDnet Internet Camera

I used the TRENDnet SecurView Wireless Internet Camera (TV-IP110W) which is an excellent product for the price ($150).  Plug it into your network, plug it into power and you can start getting images from it.  You can log onto the device which has a built-in web server for the admin pages.  You can set it up to use your wireless network as well.  It can take still images and video with full audio support.  If that isn't enough, you can get access to the entire source code running on the device.  TRENDnet makes all the source code freely available to you.

Accessing the image is easy.  It is simply an HTTP request and the camera returns a current image in the response.

Silverlight Application for Windows Phone

I started by creating a Silverlight application for Windows Phone in Visual Studio 2010 using the Windows Phone developer tools.  I've included all the source code for the project in this article for download.   In the MainPage.xaml, I added a textbox for the camera's IP address, a capture button to initiate the request, an image control to display the bitmap from the camera and a textbox at the botton to display the amount of time elapsed. 

Capture Request

Let's start with the code to request the image.  We start by setting a timer value so we can measure the roundtrip time to get the image.  Then we need to build the URL string for the camera image request using the IP address in the textbox.  To get a single image from the camera you request the file: /cgi/jpg/image.cgi from the cgi resource.  Next we need to set the NetworkCredentials of the web request.  The TRENDnet camera is a secure camera which requires credentials to access the images.  Finally we need to begin an asynchronous request.  This will run on a separate background thread from the main UI thread.  This way the user interface will not hang waiting for the response from the camera.



/// <summary>
/// This button handler creates a web request using the IP address in the textbox.
/// Be certain to properly set the network credentials of the request of the camera will not allow you
/// to capture an image.  
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCapture_Click(object sender, RoutedEventArgs e)
{
    this._nStart = Environment.TickCount;
    string strAddress = string.Format("http://{0}/cgi/jpg/image.cgi", this.txtAddress.Text);
    WebRequest request = WebRequest.Create(strAddress);

    // Set network credentials for the TrendNET internet camera
    request.Credentials = new NetworkCredential("admin", PASSWORD);

    // Begin an asynchronous call for the request
    // This is launched in another thread.
    request.BeginGetResponse(new AsyncCallback(this.RespCallback), request);
}

Handle the Response

Once the camera responds with an HTTP response, the asynchronous callback method will be invoked.  Keep in mind that we are still on a backgroung thread so you cannot make changes to any UI elements in this method.  We start by resetting our MemoryStream so we can write a new bitmap image into it.  Then we get the ResponseStream coming back from the camera.  We need to write the data into our local MemoryStream using a byte buffer to extract the data.  We loop thru all the data in the HTTP stream depending on the size of data returned during a Read operation.  Once we have all the image data stored in our MemoryStream, we use a Dispatcher to invoke a method on the main UI thread.  The UpdateUI method simply sets the stream source of the bitmap image, sets the bitmap source of the Image control on the page and updates the time elapsed.



/// <summary>
/// Set up class members that are used by the app
/// Create bitmap, memorystream, and buffer at the class level
/// so that they are not created and destroyed every time you capture images
/// </summary>
private int _nStart = 0;
private BitmapImage _bmpImage = new BitmapImage();
private MemoryStream _memStream = new MemoryStream();
private byte[] _buffer = new byte[50 * 1024];

/// <summary>
/// This method responds to the asynchronous request.  This is being called from another thread,
/// so you cannot make changes to UI elements of the page.
/// </summary>
/// <param name="ar"></param>
private void RespCallback(IAsyncResult ar)
{
    this._memStream.Position = 0;
    this._memStream.SetLength(0);
    WebRequest request = (WebRequest)ar.AsyncState;
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
    using (Stream myStream = response.GetResponseStream())
    {
        int nTotal = 0;
        int nRead = myStream.Read(this._buffer, 0, this._buffer.Count());
        while (nRead > 0)
        {
            nTotal += nRead;
            this._memStream.Write(this._buffer, (int)this._memStream.Position, nRead);
            nRead = myStream.Read(this._buffer, 0, this._buffer.Count());
        }
        this._memStream.Position = 0;
        this._memStream.SetLength(nTotal);
    }

    // This call is required to update the UI elements on the main UI thread.
    this.Dispatcher.BeginInvoke(new Action(UpdateUI));
}

/// <summary>
/// Update the UI elements in the main UI thread.
/// </summary>
private void UpdateUI()
{
    this._bmpImage.SetSource(this._memStream);
    this.imgMain.Source = this._bmpImage;

    this.txtTime.Text = string.Format("{0} msecs", Environment.TickCount - this._nStart);
}


Conclusion

If you're looking for a way to get camera data into your Windows Phone application running on the emulator, consider using an Internet Camera.  Once you have the bitmap image data, you can manipulate it, save it, edit it, or do whatever you want with it.  I'm going to see what else I can do with the camera using the Windows Phone.  Watch for more articles :)