Click here to Skip to main content
13,297,547 members (44,813 online)
Click here to Skip to main content
Add your own
alternative version

Stats

680.3K views
76.2K downloads
356 bookmarked
Posted 17 Nov 2011

WPF: Webcam Control

, 25 Sep 2017
Rate this:
Please Sign up or sign in to vote.
A WPF control for displaying and recording video from a webcam

WPF_WebcamControl/Screenshot_1.png

Introduction

WebcamControl is a WPF control for displaying and recording webcam videos using the Expression Encoder SDK. It also enables taking of webcam video snapshots.

Features

The control has the following features,

  • Displays webcam video,
  • Enables saving of webcam video (in .wmv format),
  • Enables saving of video snapshots.

Requirements

NB: To use the control ensure that your project's build platform is set to x86.

Webcam

You can install the control via NuGet by running the following command in the NuGet Package Manager console,

Install-Package WpfWebcamControl -Version 3.3.1

Properties

 NameDescription
WPF_WebcamControl/Property.pngVideoFileFormatGets the format in which webcam videos will be saved. This is a dependency property of type String.
WPF_WebcamControl/Property.pngSnapshotFormatGets or sets the format used when saving snapshots of webcam preview. This is a dependency property of type ImageFormat.
WPF_WebcamControl/Property.pngVideoDeviceGets or sets the webcam to be used. This is a dependency property of type Microsoft.Expression.Encoder.Devices.EncoderDevice.
WPF_WebcamControl/Property.pngAudioDeviceGets or sets the microphone to be used. This is a dependency property of type Microsoft.Expression.Encoder.Devices.EncoderDevice
WPF_WebcamControl/Property.pngVideoNameGets or sets the name of the video file – which should not include the file extension. This is a dependency property of type String.
WPF_WebcamControl/Property.pngVideoDirectoryGets or sets the folder where the webcam video will be saved. This is a dependency property of type String.
WPF_WebcamControl/Property.pngImageDirectoryGets or sets the folder where video snapshots will be saved. This is a dependency property of type String.
WPF_WebcamControl/Property.pngBitrateGets or sets the bitrate. This is a dependency property of type Integer. (The default value is 2000).
WPF_WebcamControl/Property.pngFrameRateGets or sets the frame rate, in frames per second. This is a dependency property of type Integer. (The default value is 15).
WPF_WebcamControl/Property.pngFrameSizeGets or sets the size of the video profile. This is a dependency property of type System.Drawing.Size. (The default value is 320x240).
WPF_WebcamControl/Property.pngIsRecordingGets a value indicating whether video recording is taking place. This is a dependency property of type Boolean.

Methods

 NameDescription
WPF_WebcamControl/Method.pngStartPreviewStarts the display of the webcam preview. (Throws a Microsoft.Expression.Encoder.SystemErrorException if a specified device is already in use by another application)
WPF_WebcamControl/Method.pngStopPreviewStops the display of the webcam preview and also stops any ongoing recording.
WPF_WebcamControl/Method.pngStartRecordingStarts recording of webcam video and returns the full path of the video file.
WPF_WebcamControl/Method.pngStopRecordingStops the recording of webcam video.
WPF_WebcamControl/Method.pngTakeSnapshotSaves a snapshot of webcam preview and returns the full path of the image file.

Example

The following example shows how to use the control. The example contains a Webcam control, two combo boxes for listing video and audio devices, and buttons for calling the various control functions.

<Window x:Class="WPF_Webcam_CS.MainWindow"

        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"

        xmlns:local="clr-namespace:WPF_Webcam_CS"

        xmlns:cam="clr-namespace:WebcamControl;assembly=WebcamControl"

        Title="WPF Webcam" Height="495" Width="353">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="75"/>
            <RowDefinition Height="132"/>
        </Grid.RowDefinitions>

        <cam:Webcam x:Name="WebcamViewer" Margin="10"

                    FrameRate="30"

                    FrameSize="640, 480"                    

                    ImageDirectory="C:\WebcamSnapshots"

                    VideoDirectory="C:\VideoClips"

                    VideoDevice="{Binding SelectedItem, ElementName=VidDevices}"

                    AudioDevice="{Binding SelectedItem, ElementName=AudDevices}"/>

        <Grid Grid.Row="1" HorizontalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="Video Device" VerticalAlignment="Center"/>
            <ComboBox x:Name="VidDevices" Grid.Column="1" Margin="10,0,0,0"

                      Width="210" Height="24"

                      ItemsSource="{Binding VideoDevices}"

                      DisplayMemberPath="Name"

                      SelectedIndex="0"/>
            
            <TextBlock Text="Audio Device" Grid.Row="1" VerticalAlignment="Center"/>
            <ComboBox x:Name="AudDevices" Grid.Row="1" Grid.Column="1"

                      Width="210" Height="24" Margin="10,0,0,0"

                      ItemsSource="{Binding AudioDevices}"

                      DisplayMemberPath="Name"

                      SelectedIndex="0"/>            
        </Grid>

        <Grid Grid.Row="2" HorizontalAlignment="Center" Margin="0,10">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Button Content="Start Capture" 

                    Height="24" Width="112" HorizontalAlignment="Right" Margin="0,0,10,0"

                    Click="StartCaptureButton_Click"/>
            
            <Button Grid.Column="1" Content="Stop Capture"

                    Height="24" Width="112" HorizontalAlignment="Left" Margin="10,0,0,0"  

                    Click="StopCaptureButton_Click"/>

            <Button Grid.Row="1" Content="Start Recording"

                    Height="24" Width="112" HorizontalAlignment="Right" Margin="0,0,10,0"

                    Click="StartRecordingButton_Click"/>

            <Button Grid.Row="1" Grid.Column="1" Content="Stop Recording" 

                    Height="24" Width="115" HorizontalAlignment="Left" Margin="10,0,0,0"

                    Click="StopRecordingButton_Click"/>

            <Button Grid.Row="2" Grid.ColumnSpan="2" Content="Take Snapshot"

                    Height="24" Width="120" HorizontalAlignment="Center" 

                    Click="TakeSnapshotButton_Click"/>
        </Grid>       
    </Grid>
</Window>
using System.Windows;
using Microsoft.Expression.Encoder.Devices;
using System.Collections.ObjectModel;

namespace WPF_Webcam_CS
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {       
        public Collection<EncoderDevice> VideoDevices { get; set; }
        public Collection<EncoderDevice> AudioDevices { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;

            VideoDevices = EncoderDevices.FindDevices(EncoderDeviceType.Video);
            AudioDevices = EncoderDevices.FindDevices(EncoderDeviceType.Audio);
        }

        private void StartCaptureButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Display webcam video
                WebcamViewer.StartPreview();
            }
            catch (Microsoft.Expression.Encoder.SystemErrorException ex)
            {
                MessageBox.Show("Device is in use by another application");
            }
        }

        private void StopCaptureButton_Click(object sender, RoutedEventArgs e)
        {
            // Stop the display of webcam video.
            WebcamViewer.StopPreview();
        }

        private void StartRecordingButton_Click(object sender, RoutedEventArgs e)
        {
            // Start recording of webcam video to harddisk.
            WebcamViewer.StartRecording();
        }

        private void StopRecordingButton_Click(object sender, RoutedEventArgs e)
        {
            // Stop recording of webcam video to harddisk.
            WebcamViewer.StopRecording();
        }

        private void TakeSnapshotButton_Click(object sender, RoutedEventArgs e)
        {
            // Take snapshot of webcam video.
            WebcamViewer.TakeSnapshot();
        }
    }
}
Imports Microsoft.Expression.Encoder.Devices
Imports System.Collections.ObjectModel

Public Class MainWindow

    Public Property VideoDevices As Collection(Of EncoderDevice)
    Public Property AudioDevices As Collection(Of EncoderDevice)

    Public Sub New()
        InitializeComponent()

        DataContext = Me

        VideoDevices = EncoderDevices.FindDevices(EncoderDeviceType.Video)
        AudioDevices = EncoderDevices.FindDevices(EncoderDeviceType.Audio)
    End Sub

    Private Sub StartCaptureButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        ' Display webcam video
        Try
            WebcamViewer.StartPreview()
        Catch ex As Microsoft.Expression.Encoder.SystemErrorException
            MessageBox.Show("Device is in use by another application")
        End Try
    End Sub

    Private Sub StopCaptureButton_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
        ' Stop the display of webcam video
        WebcamViewer.StopPreview()
    End Sub

    Private Sub StartRecordingButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        ' Start recording of webcam video
        WebcamViewer.StartRecording()
    End Sub

    Private Sub StopRecordingButton_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
        ' Stop recording of webcam video
        WebcamViewer.StopRecording()
    End Sub

    Private Sub TakeSnapshotButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        ' Take snapshot of webcam video
        WebcamViewer.TakeSnapshot()
    End Sub
End Class

In the code behind for MainWindow the collection properties, VideoDevices and AudioDevices, are set with the available audio and video devices. The rest of the code is self-explanatory, the event handlers for the button click events call various control functions.

Webcam

The following is the XAML markup for the user control,

<UserControl x:Class="Webcam" 

             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"

             xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

             MinHeight="100" MinWidth="100"

             mc:Ignorable="d">
    <Grid>
        <WindowsFormsHost Name="WinFormsHost" Margin="0" Background="{x:Null}">
            <wf:Panel x:Name="WebcamPanel"/>
        </WindowsFormsHost>
    </Grid>
</UserControl>

To display video from a webcam the user control makes use of the LiveJob class, which is in the Microsoft.Expression.Encoder.Live namespace. LiveJob expose routines for encoding video and audio from a live source such as a webcam. The webcam video is displayed in a WinForms Panel which is hosted in a WindowsFormsHost.

''' <summary>
''' Displays webcam video.
''' </summary>
Public Sub StartPreview()
    Try
        If isPreviewing Then StopPreview()

        Job = New LiveJob
        Dim frameDuration As Long = CLng(FrameRate * Math.Pow(10, 7))

        deviceSource = Job.AddDeviceSource(_videoDevice, _audioDevice)
        deviceSource.PickBestVideoFormat(FrameSize, frameDuration)
        deviceSource.PreviewWindow = New PreviewWindow(New HandleRef(WebcamPanel, WebcamPanel.Handle))

        Job.OutputFormat.VideoProfile = New AdvancedVC1VideoProfile With {.Size = FrameSize,
                .FrameRate = FrameRate, .Bitrate = New ConstantBitrate(Bitrate)}

        Job.ActivateSource(deviceSource)

        isPreviewing = True
    Catch ex As SystemErrorException
        Throw New SystemErrorException
    End Try
End Sub

The LiveJob object is used to save webcam videos using the LiveJob.StartEncoding() method.

''' <summary>
''' Starts the recording of webcam images to a video file.
''' </summary>
Public Function StartRecording() As String
    If Not isPreviewing Then Throw New PreviewNotStartedException("Recording can't be done without previewing.")
    If String.IsNullOrEmpty(VideoDirectory) Then Throw New DirectoryNotSpecifiedException("Video directory has not been specified.")
    If Not Directory.Exists(VideoDirectory) Then Directory.CreateDirectory(VideoDirectory)
    If IsRecording Then StopRecording()

    Dim filePath As String
    If String.IsNullOrEmpty(VideoName) Then
        filePath = Path.Combine(VideoDirectory, "Webcam " & TimeStamp() & VideoFileFormat)
    Else
        filePath = Path.Combine(VideoDirectory, VideoName & VideoFileFormat)
    End If

    Dim archiveFormat As New FileArchivePublishFormat(filePath)

    If Job.PublishFormats.Count > 0 Then Job.PublishFormats.Clear()

    Job.PublishFormats.Add(archiveFormat)
    Job.StartEncoding()

    SetValue(IsRecordingPropertyKey, True)
    Return filePath
End Function

A snapshot of a webcam video is actually just a snapshot of the WinForms Panel.

''' <summary>
''' Takes a snapshot of an webcam image.
''' The size of the image will be equal to the size of the control.
''' </summary>
Public Function TakeSnapshot() As String
    If Not isPreviewing Then Throw New PreviewNotStartedException("Recording can't be done before previewing.")
    If String.IsNullOrEmpty(ImageDirectory) Then Throw New DirectoryNotSpecifiedException("Image directory has not been specified")
    If Not Directory.Exists(ImageDirectory) Then Directory.CreateDirectory(ImageDirectory)

    Dim panelWidth As Integer = WebcamPanel.Width
    Dim panelHeight As Integer = WebcamPanel.Height
    Dim filePath As String = Path.Combine(ImageDirectory, "Snapshot " & TimeStamp() & "." & SnapshotFormat.ToString())
    Dim pnt As Point = WebcamPanel.PointToScreen(New Point(WebcamPanel.ClientRectangle.X, WebcamPanel.ClientRectangle.Y))

    Using bmp As New Bitmap(panelWidth, panelHeight)
        Using grx As Graphics = Graphics.FromImage(bmp)
            grx.CopyFromScreen(pnt, Point.Empty, New Size(panelWidth, panelHeight))
        End Using
        bmp.Save(filePath, SnapshotFormat)
    End Using

    Return filePath
End Function

Public Function TakeSnapshot(ByVal name As String) As String
    If String.IsNullOrEmpty(name) Then Throw New ArgumentNullException()
    If Not isPreviewing Then Throw New PreviewNotStartedException("Recording can't be done before previewing.")
    If String.IsNullOrEmpty(ImageDirectory) Then Throw New DirectoryNotSpecifiedException("Image directory has not been specified")
    If Not Directory.Exists(ImageDirectory) Then Directory.CreateDirectory(ImageDirectory)

    Dim panelWidth As Integer = WebcamPanel.Width
    Dim panelHeight As Integer = WebcamPanel.Height
    Dim filePath As String = Path.Combine(ImageDirectory, name & "." & SnapshotFormat.ToString())
    Dim pnt As Point = WebcamPanel.PointToScreen(New Point(WebcamPanel.ClientRectangle.X, WebcamPanel.ClientRectangle.Y))

    Using bmp As New Bitmap(panelWidth, panelHeight)
        Using grx As Graphics = Graphics.FromImage(bmp)
            grx.CopyFromScreen(pnt, Point.Empty, New Size(panelWidth, panelHeight))
        End Using
        bmp.Save(filePath, SnapshotFormat)
    End Using

    Return filePath
End Function

If you want to take a look at the rest of the code for the usercontrol check out the user control library project in the source download.

Conclusion

I hope you found this article useful. In case of any queries you can leave a comment and I'll do my best to answer.

History

  • 18th Nov, 2011: Initial post
  • 19th Nov, 2011: Updated code
  • 31st Mar, 2012: Added snapshot feature.
  • 17th Nov, 2012: Added FrameRate and FrameSize properties.
  • 30th Oct, 2013: v3.0
  • 24th July, 2014: v3.1,
    • Webcam preview now resizes with control,
    • StartCapture() renamed to StartPreview(),
    • StopCapture() renamed to StopPreview().
  • 6th May, 2016: Added Bitrate and VideoName properties.
  • 24th Sep, 2017: Updated code – StartRecording() and TakeSnapshot() return full file path.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Meshack Musundi
Software Developer
Kenya Kenya
Meshack is a software developer with a passion for WPF.

Awards,

  • CodeProject MVP 2013
  • CodeProject MVP 2012

You may also be interested in...

Pro

Comments and Discussions

 
AnswerRe: Detect webcams possible frame rates Pin
Meshack Musundi26-Sep-17 0:36
professionalMeshack Musundi26-Sep-17 0:36 
Questionreturn file name after snapshot Pin
Member 1195436722-Sep-17 13:28
memberMember 1195436722-Sep-17 13:28 
AnswerRe: return file name after snapshot Pin
Meshack Musundi24-Sep-17 7:55
professionalMeshack Musundi24-Sep-17 7:55 
QuestionDoesn't work, EE4 issues Pin
KEKKEN8-Sep-17 2:32
memberKEKKEN8-Sep-17 2:32 
AnswerRe: Doesn't work, EE4 issues Pin
Meshack Musundi8-Sep-17 5:09
professionalMeshack Musundi8-Sep-17 5:09 
GeneralRe: Doesn't work, EE4 issues Pin
KEKKEN11-Sep-17 3:32
memberKEKKEN11-Sep-17 3:32 
QuestionIn webcam video click on object then it should give real Geo location coordinate e.g. longitude and latitudehould give Pin
Sunil Kantesaria31-May-17 9:38
memberSunil Kantesaria31-May-17 9:38 
BugDoesn't seem to handle multiple cameras with the same device name Pin
Dave Matsumoto8-May-17 9:31
memberDave Matsumoto8-May-17 9:31 
GeneralRe: Doesn't seem to handle multiple cameras with the same device name Pin
Meshack Musundi1-Jun-17 6:22
professionalMeshack Musundi1-Jun-17 6:22 
QuestionReturn filename after snapshot Pin
Member 108021537-Apr-17 5:39
memberMember 108021537-Apr-17 5:39 
AnswerRe: Return filename after snapshot Pin
RajZilla4-May-17 7:56
memberRajZilla4-May-17 7:56 
QuestionOverlay shape Pin
Member 1286250610-Mar-17 10:17
memberMember 1286250610-Mar-17 10:17 
AnswerRe: Overlay shape Pin
Meshack Musundi10-Mar-17 20:26
professionalMeshack Musundi10-Mar-17 20:26 
QuestionSystem.NullReferenceException when using WPF tabs Pin
Member 1125681016-Feb-17 10:42
memberMember 1125681016-Feb-17 10:42 
AnswerRe: System.NullReferenceException when using WPF tabs Pin
Meshack Musundi17-Feb-17 3:32
professionalMeshack Musundi17-Feb-17 3:32 
GeneralRe: System.NullReferenceException when using WPF tabs Pin
Member 1125681017-Feb-17 10:36
memberMember 1125681017-Feb-17 10:36 
GeneralRe: System.NullReferenceException when using WPF tabs Pin
Meshack Musundi18-Feb-17 3:10
professionalMeshack Musundi18-Feb-17 3:10 
QuestionReturn filename after snapshot or video Pin
Member 1231566316-Jan-17 7:13
memberMember 1231566316-Jan-17 7:13 
AnswerRe: Return filename after snapshot or video Pin
Meshack Musundi17-Jan-17 21:05
professionalMeshack Musundi17-Jan-17 21:05 
QuestionProblem with Microsoft.Expression.Encoder Pin
Andrey_Smolensk9-Jan-17 20:44
memberAndrey_Smolensk9-Jan-17 20:44 
AnswerRe: Problem with Microsoft.Expression.Encoder Pin
Meshack Musundi11-Jan-17 4:25
professionalMeshack Musundi11-Jan-17 4:25 
GeneralMy vote of 5 Pin
Member 1276138229-Sep-16 17:41
memberMember 1276138229-Sep-16 17:41 
QuestionTake snapshot to Image control Pin
Member 119749981-Jul-16 8:35
memberMember 119749981-Jul-16 8:35 
QuestionUsers have to install the Expression Encoder app to use this. Pin
jonavark6-Jun-16 9:09
memberjonavark6-Jun-16 9:09 
Questionpreview window always got still image or black image Pin
arfken030917-May-16 21:43
memberarfken030917-May-16 21:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171207.1 | Last Updated 25 Sep 2017
Article Copyright 2011 by Meshack Musundi
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid