WPF另类实现摄像头录像
2021-01-13 23:10
标签:bucket cpu mp4 string lse header blend ons not 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和进行推送 文本框中的摄像头和麦克风,是使用下发的Load中的命令检测到的。 后台代码: 这样按顺序点击1和2的按钮后,即可实现WPF的视频录制和预览录制的视频内容。 同时我们在APP.cs中重写退出事件,来在程序退出的时候结束Nginx进行。 至此,我们就变现实现了WPF进行视频录制和预览录制的视频内容的功能。 WPF另类实现摄像头录像 标签:bucket cpu mp4 string lse header blend ons not 原文地址:https://www.cnblogs.com/wdw984/p/12286414.htmlnginx-win-rtmp.conf配置文件内容如下:
#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;
# }
#}
}
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
{
///
//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("启动成功,请点击开始录制。");
}
}
}
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();
}
}