WPF alternative to achieve video camera and preview

Use a third-party WPF controls to direct the video controls do not find (aforgenet does not seem maintained? WPFMediaKit seems only to realize the camera to take pictures and costs of controls is not used, no comment.)

By Baidu (thanks to: https: //www.cnblogs.com/giserlong88/p/11244779.html), we can determine the FFmpeg + Nginx + Vlc.DotNet.Wpf can be implemented to save the video camera, video preview through (there is a delay ), implementation is achieved by recording and pushed to Nginx FFmpeg built rtmp streaming media server, and then to pull content WPF rtmp streaming server video preview is achieved by Vlc.DotNet.Wpf.

Specific code as follows:

First to download FFmpeg (http://ffmpeg.org/download.html), Nginx (http://nginx.org/en/download.html), cited Vlc.DotNet.Wpf, libvlc they need to download the Nuget player.

nginx-win-rtmp.conf profile as follows:
#user  nobody;
# multiple workers works !
worker_processes  2;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;
#worker_rlimit_nofile 100000;   #更改worker进程的最大打开文件数限制
                                               #如果没设置的话, 这个值为操作系统的限制.
                                               #设置后你的操作系统和Nginx可以处理比“ulimit -a”更多的文件
                                               #所以把这个值设高, 这样nginx就不会有“too many open files”问题了


events {
    worker_connections  8192;#设置可由一个worker进程同时打开的最大连接数
                              #如果设置了上面提到的worker_rlimit_nofile, 我们可以将这个值设得很高
    # max value 32768, nginx recycling connections+registry optimization = 
    #   this.value * 20 = max concurrent connections currently tested with one worker
    #   C1000K should be possible depending there is enough ram/cpu power
    # multi_accept on;
}

rtmp {
    server {
        listen 1935;#监听端口,若被占用,可以更改
        chunk_size 4000;#上传flv文件块儿的大小
        application live { #创建一个叫live的应用
             live on;#开启live的应用
             allow publish 127.0.0.1;#
             allow play all;
        }
    }
}

http {
    #include      /nginx/conf/naxsi_core.rules;
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr:$remote_port - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

#     # loadbalancing PHP
#     upstream myLoadBalancer {
#         server 127.0.0.1:9001 weight=1 fail_timeout=5;
#         server 127.0.0.1:9002 weight=1 fail_timeout=5;
#         server 127.0.0.1:9003 weight=1 fail_timeout=5;
#         server 127.0.0.1:9004 weight=1 fail_timeout=5;
#         server 127.0.0.1:9005 weight=1 fail_timeout=5;
#         server 127.0.0.1:9006 weight=1 fail_timeout=5;
#         server 127.0.0.1:9007 weight=1 fail_timeout=5;
#         server 127.0.0.1:9008 weight=1 fail_timeout=5;
#         server 127.0.0.1:9009 weight=1 fail_timeout=5;
#         server 127.0.0.1:9010 weight=1 fail_timeout=5;
#         least_conn;
#     }

    sendfile        off;
    #tcp_nopush     on;

    server_names_hash_bucket_size 128;

## Start: Timeouts ##
    client_body_timeout   10;
    client_header_timeout 10;
    keepalive_timeout     30;
    send_timeout          10;
    keepalive_requests    10;
## End: Timeouts ##

    #gzip  on;

    server {
        listen       8088;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        ## Caching Static Files, put before first location
        #location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        #    expires 14d;
        #    add_header Vary Accept-Encoding;
        #}

# For Naxsi remove the single # line for learn mode, or the ## lines for full WAF mode
        location / {
            #include    /nginx/conf/mysite.rules; # see also http block naxsi include line
            ##SecRulesEnabled;
              ##DeniedUrl "/RequestDenied";
              ##CheckRule "$SQL >= 8" BLOCK;
              ##CheckRule "$RFI >= 8" BLOCK;
              ##CheckRule "$TRAVERSAL >= 4" BLOCK;
              ##CheckRule "$XSS >= 8" BLOCK;
            root   html;
            index  index.html index.htm;
        }

# For Naxsi remove the ## lines for full WAF mode, redirect location block used by naxsi
        ##location /RequestDenied {
        ##    return 412;
        ##}

## Lua examples !
#         location /robots.txt {
#           rewrite_by_lua '
#             if ngx.var.http_host ~= "localhost" then
#               return ngx.exec("/robots_disallow.txt");
#             end
#           ';
#         }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000; # single backend process
        #    fastcgi_pass   myLoadBalancer; # or multiple, see example above
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl spdy;
    #    server_name  localhost;

    #    ssl                  on;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_timeout  5m;

    #    ssl_prefer_server_ciphers On;
    #    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    #    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:ECDH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!eNULL:!MD5:!DSS:!EXP:!ADH:!LOW:!MEDIUM;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

The downloaded FFmpeg, Nginx and libvlc into the Debug directory.

Directory structure is as follows

Debug

    FFmpeg

         ffmpeg.exe

         ……

   Nginx

        nginx.exe

        ……

   libvlc

         win-x64

            ……

         win-x86

           ……

Create a new WPF project, started in MainWindow.xaml mainly deal with Nginx and be pushed

<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>

Camera and microphone in the text box, using issued Load command detected.

Background Code:

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";
        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("启动成功,请点击开始录制。");
        }
    }
}

After this sequence click on buttons 1 and 2, you can achieve video content recorded video recording and preview of WPF.

We rewrite the exit event in APP.cs to end Nginx carried out when the program exits.

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();
        }
    }

At this point, we realized realized the function of video content WPF video recording and preview recording.

发布了85 篇原创文章 · 获赞 31 · 访问量 26万+

Guess you like

Origin blog.csdn.net/5653325/article/details/104232322