WPF:网络摄像头控件






4.92/5 (145投票s)
一个用于显示和录制网络摄像头视频的WPF控件
引言
WebcamControl
是一个 WPF 控件,用于使用 Expression Encoder SDK 显示和录制摄像头视频。它还支持拍摄摄像头视频快照。
特点
该控件具有以下功能:
- 显示摄像头视频;
- 支持保存摄像头视频(格式为 .wmv);
- 支持保存视频快照。
要求
- .NET Framework 4.5;
- Expression Encoder.
注意:要使用该控件,请确保您的项目生成平台设置为 x86。
网络摄像头
您可以通过在 NuGet 包管理器控制台中运行以下命令来通过 NuGet 安装该控件:
Install-Package WpfWebcamControl -Version 3.3.1
属性
名称 | 描述 | |
![]() | VideoFileFormat | 获取保存摄像头视频的格式。这是一个类型为 String 的依赖属性。 |
![]() | SnapshotFormat | 获取或设置保存摄像头预览快照的格式。这是一个类型为 ImageFormat 的依赖属性。 |
![]() | VideoDevice | 获取或设置要使用的摄像头。这是一个类型为 Microsoft.Expression.Encoder.Devices.EncoderDevice 的依赖属性。 |
![]() | AudioDevice | 获取或设置要使用的麦克风。这是一个类型为 Microsoft.Expression.Encoder.Devices.EncoderDevice 的依赖属性。 |
![]() | VideoName | 获取或设置视频文件的名称 – 不应包含文件扩展名。这是一个类型为 String 的依赖属性。 |
![]() | VideoDirectory | 获取或设置保存摄像头视频的文件夹。这是一个类型为 String 的依赖属性。 |
![]() | ImageDirectory | 获取或设置保存视频快照的文件夹。这是一个类型为 String 的依赖属性。 |
![]() | 比特率 | 获取或设置比特率。这是一个类型为 Integer 的依赖属性。(默认值为 2000)。 |
![]() | FrameRate | 获取或设置帧率,单位为每秒帧数。这是一个类型为 Integer 的依赖属性。(默认值为 15)。 |
![]() | FrameSize | 获取或设置视频配置文件的尺寸。这是一个类型为 System.Drawing.Size 的依赖属性。(默认值为 320x240)。 |
![]() | IsRecording | 获取一个值,指示是否正在进行视频录制。这是一个类型为 Boolean 的依赖属性。 |
方法
名称 | 描述 | |
![]() | StartPreview | 开始显示摄像头预览。(如果指定的设备已被另一个应用程序使用,则会引发 Microsoft.Expression.Encoder.SystemErrorException )。 |
![]() | StopPreview | 停止显示摄像头预览,并停止任何正在进行的录制。 |
![]() | StartRecording | 开始录制摄像头视频,并返回视频文件的完整路径。 |
![]() | StopRecording | 停止录制摄像头视频。 |
![]() | TakeSnapshot | 保存摄像头预览的快照,并返回图像文件的完整路径。 |
示例
以下示例展示了如何使用该控件。该示例包含一个 Webcam
控件、两个用于列出视频和音频设备的组合框,以及用于调用各种控件功能的按钮。
<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
在 MainWindow
的代码隐藏中,VideoDevices
和 AudioDevices
集合属性已设置为可用的音频和视频设备。其余代码不言自明,按钮单击事件的处理程序会调用各种控件功能。
网络摄像头
以下是用户控件的 XAML 标记:
<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>
要显示来自摄像头的视频,用户控件使用了 LiveJob
类,该类位于 Microsoft.Expression.Encoder.Live
命名空间下。LiveJob
提供了从摄像头等实时源编码视频和音频的例程。摄像头视频显示在 WinForms 的 Panel
中,该 Panel
托管在 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
LiveJob
对象用于使用 LiveJob.StartEncoding()
方法保存摄像头视频。
''' <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
摄像头视频的快照实际上只是 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
如果您想查看用户控件的其余代码,请查看源代码下载中的用户控件库项目。
结论
希望您觉得本文很有用。如有任何疑问,您可以留下评论,我会尽力回答。
历史
- 2011年11月18日:初次发布
- 2011年11月19日:更新代码
- 2012年3月31日:添加了快照功能。
- 2012年11月17日:添加了
FrameRate
和FrameSize
属性。 - 2013年10月30日:v3.0
- 2014年7月24日:v3.1,
- 摄像头预览现在会随控件一起缩放;
StartCapture()
重命名为StartPreview()
;StopCapture()
重命名为StopPreview()
。
- 2016年5月6日:添加了
Bitrate
和VideoName
属性。 - 2017年9月24日:更新代码 –
StartRecording()
和TakeSnapshot()
返回完整文件路径。