Wednesday, July 28, 2010

Capture Web Cam in Silver light

Hello All,
The New Exciting feature of the Silver light is we can also capture the Audio/Video from the user machine. There is a new object named "CaptureSource" , this allows you to get the Microphone and the Video device of the machine.. Here I am going to show you a small example where we are capturing the web camera and displaying the captured image in the screen..

The code which I have used is a fairly simple code, I have taken a a rectangle in which the image which is captured by the camera will be display. The CaptureSource object return us a Writable Bitmap which I will use to fill the rectangle area.

Here is the code for the MainPage.xaml
<UserControl x:Class="VideoCam.MainPage"
xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d=
"http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc=
"http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable=
"d" Height="353" Width="607">

<Grid x:Name="LayoutRoot" Background="White" Height="auto" Width="auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="346*" />
<ColumnDefinition Width="261*" />
</Grid.ColumnDefinitions>
<Rectangle Name="rectVideo" Width="320" Height="228" Fill="Black" VerticalAlignment="Top" Margin="40,12,40,0" />
<Rectangle x:Name="capturedDisplay" Margin="267,16,-329,17" Grid.Column="1" />
<Image Margin="12,348,45,-286" Name="MyImage" />
<!--<Rectangle x:Name="MyImage" Margin="12,348,45,-286" />-->
<Button x:Name="btnCapture" Content="Capture" Height="23" HorizontalAlignment="Left" Margin="186,272,0,0" VerticalAlignment="Top" Width="75"Click="btnCapture_Click" Grid.Column="1" />
<Button x:Name="btnSnap" Content="Snap" Height="23" HorizontalAlignment="Left" Margin="186,301,0,0" VerticalAlignment="Top" Width="75"Click="btnSnap_Click" Grid.Column="1" />
<Button x:Name="btnSave" Content="Save Snap" Height="23" HorizontalAlignment="Left" Margin="186,330,0,0" VerticalAlignment="Top" Width="75" Grid.Column="1" Click="btnSave_Click" />
<TextBlock x:Name="reply" Grid.ColumnSpan="2" Margin="219,11,42,-11" />
</Grid>
</UserControl>



Here in this code the "rectVideo" is the place where the image will be displayed. An image is used to display the image if we want to save the source as a still Image. and the three buttons for starting camera, taking snap & to save the still image.


Now move on to the code part first of all we need to Use the CaptureSource object. As we click on the "Capture" button we must take the user permission to access the device using "CaptureDeviceConfiguration.AllowedDeviceAccess" property.. As the code executes this line one dialogue box appears on the user screen, after getting the user permission we can start capturing the web camera image. Image for the Home Screen as follows




Here is the Code file for the MainPage.xaml..cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using VideoCam.WebCamService;
using FluxJpeg.Core;
using FluxJpeg.Core.Encoder;
using System.ComponentModel;


namespace VideoCam
{

public partial class MainPage : UserControl
{
#region "Global Variable"
CaptureSource _capture
= new CaptureSource();
public ImageBrush capturedImage = new ImageBrush();
private SaveFileDialog saveFileDlg;
#endregion

public MainPage()
{
InitializeComponent
();

// async capture failed event handler
_capture
.CaptureFailed += new EventHandler<ExceptionRoutedEventArgs>(_capture_CaptureFailed);

// async capture completed event handler
_capture
.CaptureImageCompleted += new EventHandler<CaptureImageCompletedEventArgs>(_capture_CaptureImageCompleted);


S
aveFileDlg = new SaveFileDialog { DefaultExt = ".jpg", Filter = "JPEG Images (*jpeg *.jpg)|*.jpeg;*.jpg", };
}

private void btnCapture_Click(object sender, RoutedEventArgs e)
{
if (btnCapture.Content.ToString() == "Capture")
{
_capture
.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();

VideoBrush vBrush
= new VideoBrush();
vBrush
.Stretch = Stretch.Uniform;
vBrush
.SetSource(_capture);
rectVideo
.Fill = vBrush;
if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
{
_capture
.Start();
btnCapture
.Content = "Stop";
myDispatcherTimer
.Start();
}
}
else
{
_capture
.Stop();
btnCapture
.Content = "Capture";
myDispatcherTimer
.Stop();
}
}



private void btnSnap_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog saveFileDlg
= new SaveFileDialog();

if (_capture.VideoCaptureDevice != null &&
_capture
.State == CaptureState.Started)
{
_capture
.CaptureImageAsync();
}
}

void _capture_CaptureImageCompleted(object sender, CaptureImageCompletedEventArgs e)
{
// Set the Image object to the WriteableBitmap passed in through the event arguments
capturedImage
.ImageSource = e.Result;
capturedDisplay
.Fill = capturedImage;
}

void _capture_CaptureFailed(object sender, ExceptionRoutedEventArgs e)
{
// For the sake of this example, simply show a messagebox
MessageBox
.Show(string.Format("Failed to capture image: {0}", e.ErrorException.Message));
}

public static WriteableBitmap DecodeJpeg(Stream srcStream)
{
// Decode JPEG
var decoder
= new FluxJpeg.Core.Decoder.JpegDecoder(srcStream);
var jpegDecoded
= decoder.Decode();
var img
= jpegDecoded.Image;
img
.ChangeColorSpace(ColorSpace.RGB);

// Init Buffer
int w = img.Width;
int h = img.Height;
var result
= new WriteableBitmap(w, h);
int[] p = result.Pixels;
byte[][,] pixelsFromJpeg = img.Raster;
// Copy FluxJpeg buffer into WriteableBitmap
int i = 0;
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
p
[i++] = (0xFF << 24) // A
| (pixelsFromJpeg[0][x, y] << 16) // R
| (pixelsFromJpeg[1][x, y] << 8) // G
| pixelsFromJpeg[2][x, y]; // B
}
}

return result;
}



#region Encoding/Decoding Methods

public static void EncodeJpeg(WriteableBitmap bmp, Stream dstStream)
{
// Init buffer in FluxJpeg format
int w = bmp.PixelWidth;
int h = bmp.PixelHeight;
int[] p = bmp.Pixels;
byte[][,] pixelsForJpeg = new byte[3][,]; // RGB colors
pixelsForJpeg
[0] = new byte[w, h];
pixelsForJpeg
[1] = new byte[w, h];
pixelsForJpeg
[2] = new byte[w, h];

// Copy WriteableBitmap data into buffer for FluxJpeg
int i = 0;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int color = p[i++];
pixelsForJpeg
[0][x, y] = (byte)(color >> 16); // R
pixelsForJpeg
[1][x, y] = (byte)(color >> 8); // G
pixelsForJpeg
[2][x, y] = (byte)(color); // B
}
}
//Encode Image as JPEG
var jpegImage
= new FluxJpeg.Core.Image(new ColorModel { colorspace = ColorSpace.RGB }, pixelsForJpeg);
var encoder
= new JpegEncoder(jpegImage, 50, dstStream);
encoder
.Encode();
}


private void SaveSnapshot(Stream dstStream)
{
try
{
// Encoding The Snapshot
WriteableBitmap bmp
= new WriteableBitmap(rectVideo, null);
EncodeJpeg
(bmp, dstStream);
}
catch (Exception ex)
{
MessageBox
.Show(ex.Message, "Error saving snapshot", MessageBoxButton.OK);
}
}


#endregion Encoding/Decoding Methods

private void btnSave_Click(object sender, RoutedEventArgs e)
{
// Take Snapshot
if (saveFileDlg.ShowDialog().Value)
{
using (Stream dstStream = saveFileDlg.OpenFile())
{
SaveSnapshot
(dstStream);
}
}
}
}
}

Image for the Capture start as follows.


Here in this code For taking the snap of the image I have used a DLL that is using

FluxJpeg.Core;
using FluxJpeg.Core.Encoder;

Image for the Snap option as follows.


The function for encoding and decoding the image is present in the code, you can have a look. AsyncCaptureImage() return a WriteableBitmap containing the still image from the camera. So get Silverlight 4 runtime and create the sample application.


I hope you have like the sample code.. Please feel free to post the comments on this..


Thanks
Anil Kumar Pandey

Kontera