Dear visitor, thanks for stopping by! If you want, you can follow all updates on Snowball.be via RSS. You can also follow me on Twitter or Facebook. More interesting posts from other Microsoft Regional Directors can be found at The Region.
Gill Cleeren     .net | Silverlight | Silverlight Advent Calendar | sl4     December 10, 2009    

Today, we are looking again at another new feature in Silverlight 4 which is the support for webcams and microphones.

Silverlight 4 gets support for microphones and webcams. It has access to the raw streams for both. The added support opens a lot of opportunities for new types of applications. For example, it becomes possible to write an application that reads barcodes of products you hold in front of the webcam, scans them and searches for product information.

The classes that expose this functionality live in the System.Windows.Media namespace. We’ll be using those to create a simple application that connects with the webcam and takes snapshots. Below is the interface of the application (a colleague of mine was just eating a banana :) )

image

The XAML for the application is shown below. The ComboBox displays the available webcams (only one on my machine), we are binding to the FriendlyName property. The ListBox is templated: both the ItemsTemplate and the ItemsPanel are overriden, to have the control display a horizontal list of images.

<Grid x:Name="LayoutRoot" Background="White">
  <Grid.RowDefinitions>
    <RowDefinition Height="330"></RowDefinition>
      <RowDefinition Height="50"></RowDefinition>
        <RowDefinition Height="140"></RowDefinition>
  </Grid.RowDefinitions>
  <Border BorderBrush="Black" BorderThickness="3" HorizontalAlignment="Center" 
    VerticalAlignment="Center">
    <Rectangle x:Name="WebcamRectangle" Fill="LightGray" Height="300" 
      Width="400"></Rectangle>
  </Border>
  <StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Center" 
    HorizontalAlignment="Center">
    <ComboBox x:Name="WebcamComboBox" Width="200" Margin="3" 
      SelectionChanged="WebcamComboBox_SelectionChanged">
      <ComboBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding FriendlyName}"></TextBlock>
        </DataTemplate>
      </ComboBox.ItemTemplate>
    </ComboBox>
    <Button x:Name="StartWebcamButton" Click="StartWebcamButton_Click" 
      Content="Start webcam" HorizontalAlignment="Center" Margin="3"></Button>
    <Button x:Name="TakePictureButton" Click="TakePictureButton_Click" 
      Content="Take picture" HorizontalAlignment="Center" Margin="3"></Button>
  </StackPanel>
  <ListBox x:Name="PicListBox"  Width="500" Height="120" 
    ScrollViewer.HorizontalScrollBarVisibility="Visible"  Grid.Row="2">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <Image Margin="5" Source="{Binding}" Stretch="UniformToFill" 
          Height="80" VerticalAlignment="Center"/>
      </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" 
          HorizontalAlignment="Left"/>
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
  </ListBox>
</Grid>

To fill the ComboBox with the available webcams, we can use the CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices(). This returns a Collection of VideoCaptureDevice instances. The VideoCaptureDevice class exposes the FriendlyName property we used in the data binding expression.

//fills the dropdown with all available webcams
WebcamComboBox.ItemsSource = 
  CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices();

We can instruct Silverlight to use the default capturing device, if nothing is selected by the user in the ComboBox:

//use the default
VideoCaptureDevice selectedVideoCaptureDevice = 
CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();

A little side note: we can change the default device in the Silverlight Configuration window as shown below.

image

Starting the webcam needs to be a user-initiated action. It’s impossible to start the webcam on load of the application for example. Therefore, we put this code in the event handler of the click on the Button. Whenever the webcam is started, a prompt is shown, asking the user if he wants to allow the application to access the device. This prompt can not be changed by the developer.

image

The following lines of code, located in the click event handler, check if the user has already granted permission in this particular session to access the webcam. If not, the prompt is shown following the RequestDeviceAccess() method call.

if (CaptureDeviceConfiguration.AllowedDeviceAccess 
    || CaptureDeviceConfiguration.RequestDeviceAccess())
{
...
}

To access the video capture of the webcam, we use the CaptureSource class.

VideoCaptureDevice videoCaptureDevice = selectedVideoCaptureDevice;
CaptureSource captureSource = new CaptureSource();
captureSource.VideoCaptureDevice = videoCaptureDevice;

This CaptureSource can then be used in combination with a VideoBrush to paint the video on any shape. Here, we used a Rectangle. To start the capturing of the device associated with the capture device (note that more than one device can be associated with one CaptureSource), we call its Start() method.

VideoBrush videoBrush = new VideoBrush();
videoBrush.SetSource(captureSource);
WebcamRectangle.Fill = videoBrush;
captureSource.Start();

If we want to capture a snapshot, we can use the AsyncCaptureImage method. It provides a WriteableBitmap to the Action(T) which is passed in as parameter. We add the image to the collection. Because of the applied binding, it is displayed automatically.

private void TakePictureButton_Click(object sender, RoutedEventArgs e)
{
    captureSource.AsyncCaptureImage((snapshot) =>
    {
        snapshots.Add(snapshot);
    });
}

The complete code for today’s article can be found here: SLWebcam.zip (60.67 KB)

  Posted on: Thursday, December 10, 2009 11:33:15 AM (Romance Standard Time, UTC+01:00)   |   Comments [1]
         
9/2/2010   9:19:08 PM