WPF中使用第三方控件来直接进行录像的控件没有找到(aforgenet好像不维护了?WPFMediaKit好像只能实现摄像头拍照。收费的控件没有使用,不做评论。)

通过百度(感谢:https://www.cnblogs.com/giserlong88/p/11244779.html),确定了可以通过FFmpeg+Nginx+Vlc.DotNet.Wpf可以实现摄像头的录像保存、录像预览(有延时),实现方案是,通过FFmpeg来实现录像并推送到Nginx搭建的rtmp流媒体服务器,然后WPF通过Vlc.DotNet.Wpf来拉取rtmp流服务器的内容来实现视频预览。

具体代码如下:

首先去下载FFmpeg(http://ffmpeg.org/download.html),Nginx(http://nginx.org/en/download.html),Nuget上引用Vlc.DotNet.Wpf,下载其所需要的libvlc播放器

把下载的FFmpeg、Nginx和libvlc放到Debug目录下。

目录结构如下

Debug

    FFmpeg

         ffmpeg.exe

         ……

   Nginx

        nginx.exe

        ……

   libvlc

         win-x64

            ……

         win-x86

           ……

新建一个WPF项目,在MainWindow.xaml主要处理启动Nginx和进行推送

<Window x:Class="VideTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Loaded="MainWindow_OnLoaded">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <WrapPanel>
            <TextBox Name="SavePath" Text="D:\test.mp4" Width="94" HorizontalAlignment="Left"></TextBox>
            <TextBox Name="VideoName" Text="罗技高清网络摄像机 C930c" Width="94" HorizontalAlignment="Left"></TextBox>
            <TextBox Name="AudioName" Text="麦克风 (罗技高清网络摄像机 C930c)" Width="94" HorizontalAlignment="Left"></TextBox>
            <Button Content="1、启动视频监控" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="107" Click="ButtonStart_OnClick"/>
            <Button Content="2、开始录制" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="ButtonSase_OnClick"/>
            <TextBlock Text="开始录制后大概5秒主界面就可以看到监控视频"></TextBlock>
        </WrapPanel>
        <Border Grid.Row="1">
            <Image x:Name="img"></Image>
        </Border>
        
    </Grid>
</Window>

  

文本框中的摄像头和麦克风,是使用下发的Load中的命令检测到的。

后台代码:

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Vlc.DotNet.Core;
using Vlc.DotNet.Wpf;


namespace VideTest
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly string ffmpegPath = $"{AppDomain.CurrentDomain.BaseDirectory}FFmpeg/ffmpeg.exe";
        private readonly string nginxPath = @"nginx.exe -c conf\nginx-win-rtmp.conf &taskkill /f /im nginx.exe";
        private VlcVideoSourceProvider sourceProvider;
        public MainWindow()
        {
            InitializeComponent();
        }
        private void MediaPlayer_Log(object sender, VlcMediaPlayerLogEventArgs e)
        {
            var message = "libVlc : " + e.Level + e.Message + e.Module;
            Debug.WriteLine(message);
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
        {  
            //var ffmpegPath = $"{AppDomain.CurrentDomain.BaseDirectory}FFmpeg/ffmpeg.exe";
            //// 显示可用的音效设备
            //var ffmpegArgument = " -list_devices true -f dshow -i dummy";

            //var process = new System.Diagnostics.Process();
            //var startInfo = new System.Diagnostics.ProcessStartInfo();
            //startInfo.FileName = ffmpegPath;
            //startInfo.Arguments = ffmpegArgument;
            //startInfo.UseShellExecute = false;
            //startInfo.RedirectStandardOutput = true;
            //startInfo.RedirectStandardError = true;

            // 将 StandardErrorEncoding 改为 UTF-8后FFmpeg输出不会中文乱码
            //startInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;

            //process.EnableRaisingEvents = true;
            //process.StartInfo = startInfo;
            //process.Start();

            // 显示FFMpeg输出的内容,从中取出视频和音频设备名称
            //string output = process.StandardError.ReadToEnd();
            //Debug.WriteLine(output);
            //process.WaitForExit();
        }

        private void ButtonSase_OnClick(object sender, RoutedEventArgs e)
        {
            var file=new FileInfo(SavePath.Text);
            if(file.Exists) file.Delete();
            var ffmpegArgument = $" -f dshow -i video=\"{VideoName.Text}\" -f dshow -i audio=\"{AudioName.Text}\" -vcodec libx264 -acodec aac -strict -2 \"{SavePath.Text}\" -f flv rtmp://127.0.0.1:1935/live/home";
            Task.Run(() =>
            {
                var process = new Process();
                var startInfo = new ProcessStartInfo
                {
                    FileName = ffmpegPath,
                    Arguments = ffmpegArgument,
                    UseShellExecute = true,
                    RedirectStandardOutput = false

                };
                process.StartInfo = startInfo;
                process.Start();
                process.WaitForExit();
            });
        }

        private void ButtonStart_OnClick(object sender, RoutedEventArgs e)
        {
            Task.Run(() =>
            {
                var process = new Process();
                var startInfo = new ProcessStartInfo("cmd.exe")
                {
                    WorkingDirectory= $@"{AppDomain.CurrentDomain.BaseDirectory}nginx",
                    UseShellExecute = false,
                    RedirectStandardInput = true
                };
                process.StartInfo = startInfo;
                
                process.Start();
                process.StandardInput.WriteLine(nginxPath);
                process.StandardInput.AutoFlush = true;
                process.WaitForExit();
            });
            Dispatcher?.Invoke(() =>
            {
                var currentAssembly = Assembly.GetEntryAssembly();
                var currentDirectory = new FileInfo(currentAssembly.Location).DirectoryName;

                var libDirectory = new DirectoryInfo(System.IO.Path.Combine(currentDirectory, "libvlc",
                    IntPtr.Size == 4 ? "win-x86" : "win-x64"));

                sourceProvider = new VlcVideoSourceProvider(Dispatcher);
                sourceProvider.CreatePlayer(libDirectory);
                sourceProvider.MediaPlayer.Play("rtmp://127.0.0.1:1935/live/home");
                sourceProvider.MediaPlayer.Log += MediaPlayer_Log;
                sourceProvider.MediaPlayer.Manager.SetFullScreen(sourceProvider.MediaPlayer.Manager.CreateMediaPlayer(),
                    true);
                var bing = new Binding {Source = sourceProvider, Path = new PropertyPath("VideoSource")};
                img.SetBinding(Image.SourceProperty, bing);
            });
            MessageBox.Show("启动成功,请点击开始录制。");
        }
    }
}

 

这样按顺序点击1和2的按钮后,即可实现WPF的视频录制和预览录制的视频内容。

同时我们在APP.cs中重写退出事件,来在程序退出的时候结束Nginx进行。

 public partial class App : Application
    {
        protected override void OnExit(ExitEventArgs e)
        {
            var process = new Process();
            var startInfo = new ProcessStartInfo()
            {
                FileName = "taskkill",
                Arguments = " /f /im nginx.exe",
                UseShellExecute = false,
                RedirectStandardInput = true
            };
            process.StartInfo = startInfo;

            process.Start();
            process.WaitForExit();
        }
    }

  至此,我们就变现实现了WPF进行视频录制和预览录制的视频内容的功能。

 

版权声明:本文为wdw984原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/wdw984/p/12286414.html