WPF使用AForge实现Webcam预览(一)

本文简略地介绍一下如果使用AForge来实现前置/后置摄像头的预览功能。

要使用AForge,就需要添加AForge NuGet相关包的引用,这些包依赖的其他包会自动安装。

  • AForge.Controls
  • AForge.Video.DirectShow

接下来需要添加另外两个引用,主要是为了使用VideoSourcePlayer Windows Forms 控件。

  • System.Windows.Forms
  • WindowsFormsIntergration

UI界面比较简单,Xaml code 如下:

<Window x:Class="WebcamPreview.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:controls="clr-namespace:AForge.Controls;assembly=AForge.Controls"
        mc:Ignorable="d"
        Title="Webcam" Height="240" Width="640" MinHeight="240" MinWidth="640" ResizeMode="CanMinimize">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <WindowsFormsHost Background="Transparent">
            <controls:VideoSourcePlayer x:Name="VideoSourcePlayer1" />
        </WindowsFormsHost>
        <WindowsFormsHost Background="Transparent" Grid.Column="1" >
            <controls:VideoSourcePlayer x:Name="VideoSourcePlayer2" />
        </WindowsFormsHost>
    </Grid>
</Window>

定义一个描述video device的类。

    /// <summary>
    ///  Represents class that contains media information for video device source.
    /// </summary>
    public sealed class MediaInformation
    {
        /// <summary>
        /// Gets or sets the display name of the video device source.
        /// </summary>
        public string DisplayName
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Moniker string of the video device source.
        /// </summary>
        public string MonikerString
        {
            get;
            set;
        }
    }

实现一个WebcamDevice类,主要是用来初始化前置/后置摄像头的。

using AForge.Controls;
using AForge.Video.DirectShow;
using System;
using System.Collections.Generic;
using System.Linq;

namespace WebcamPreview
{
    public class WebcamDevice
    {
        // <summary>
        /// Instance of video capture device.
        /// </summary>
        private VideoCaptureDevice videoCaptureDevice;
        private VideoSourcePlayer videoPlayer;
        private string deviceMoniker;

        public WebcamDevice(VideoSourcePlayer player, string deviceMoniker)
        {
            this.videoPlayer = player;
            this.deviceMoniker = deviceMoniker;
        }

        public void Init()
        {
            try
            {
                this.videoCaptureDevice = new VideoCaptureDevice(deviceMoniker);
                this.videoPlayer.VideoSource = this.videoCaptureDevice;
                this.videoPlayer.Start();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
            }
        }

        /// <summary>
        /// Gets video device source collection current available.
        /// </summary>
        public static IReadOnlyList<MediaInformation> GetVideoDevices()
        {
            var filterVideoDeviceCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            return (from FilterInfo filterInfo
                    in filterVideoDeviceCollection
                    select new MediaInformation
                    {
                        DisplayName = filterInfo.Name,
                        MonikerString = filterInfo.MonikerString
                    }).ToList();

        }
    }
}

GetVideoDevices方法用来获取所有的摄像头。

Init方法,制定VideoSourcePlayer的VideoCaptureDevice是前置,还是后置摄像头。然后调用VideoSourcePlayer.Start方法就可以实现预览效果了。

最后就可以在MainWindow调用这个类了。

public partial class MainWindow : Window
    {
        private IReadOnlyList<MediaInformation> mediaDeviceList;

        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
            this.Closed += MainWindow_Closed;
            this.Deactivated += MainWindow_Deactivated;
            this.Topmost = true;
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            //防止视频关闭时画面延迟闪烁
            this.Height = 0;
            this.Width = 0;
            if (!this.VideoSourcePlayer1.IsDisposed)
            {
                this.VideoSourcePlayer1.SignalToStop();
                this.VideoSourcePlayer1.WaitForStop();
                this.VideoSourcePlayer1.Stop();
                this.VideoSourcePlayer1.VideoSource = null;
                this.VideoSourcePlayer1.Dispose();
            }

            if (!this.VideoSourcePlayer2.IsDisposed)
            {
                this.VideoSourcePlayer2.SignalToStop();
                this.VideoSourcePlayer2.WaitForStop();
                this.VideoSourcePlayer2.Stop();
                this.VideoSourcePlayer2.VideoSource = null;
                this.VideoSourcePlayer2.Dispose();
            }
        }

        private void MainWindow_Deactivated(object sender, EventArgs e)
        {
            this.Topmost = true;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            this.mediaDeviceList = WebcamDevice.GetVideoDevices();
            InitFront();
            InitBack();
        }

        private void InitFront()
        {
            if (mediaDeviceList.Count() == 0)
                return;

            var webCamDevice = new WebcamDevice(this.VideoSourcePlayer1, mediaDeviceList.First().MonikerString);
            webCamDevice.Init();
        }

        private void InitBack()
        {
            if (mediaDeviceList.Count() <= 1)
                return;

            var webCamDevice = new WebcamDevice(this.VideoSourcePlayer2, mediaDeviceList[1].MonikerString);
            webCamDevice.Init();
        }
    }

在Window的Closed事件,需要销毁VideoSourcePlayer对象。

另外指定Topmost=true,可以使这个窗口始终在最前面。

 

posted @ 2019-04-23 14:27  supperwu  阅读(1506)  评论(0编辑  收藏  举报