1 Star 0 Fork 2

DoD / 摄像头捕捉转码慢放

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
MainWindow.xaml.cs 14.19 KB
一键复制 编辑 原始数据 按行查看 历史
using Accord.Video.DirectShow;
using Accord.Video.FFMPEG;
using log4net;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using Vlc.DotNet.Core;
namespace CameraCaptureDemo
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
// 已经打开文件
private string _fileName = "";
// 暂停
private volatile bool _pause = false;
#region USB摄像头相关
// 获取视频采集设备
protected VideoFileWriter _videoWriter;
protected volatile object _lock = new object();
protected volatile bool _recording = false;
#endregion
private VideoCapture _videoCapture;
private Model.VideoDevice _videoDevice;
private Model.VideoCapabilities _videoCapabilities;
public MainWindow()
{
InitializeComponent();
this.Closed += delegate { _videoCapture?.Dispose(); };
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// 显示摄像头画面,隐藏播放器画面
this.CameraPanel.Visibility = Visibility.Visible;
this.VlcPanel.Visibility = Visibility.Collapsed;
// 初始化摄像头
InitCamera();
// 初始化播放器
InitPlayer();
}
/// <summary>
/// 初始化摄像头
/// </summary>
private void InitCamera()
{
// 获取视频采集设备
var filterInfoCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (filterInfoCollection.Count > 0)
{
// 默认选定第一个摄像头路
var filterInfo = filterInfoCollection[0];
VideoCaptureDevice videoCaptureDevice = new VideoCaptureDevice(filterInfo.MonikerString);
// 分辨率和帧率选定
videoCaptureDevice.VideoResolution = videoCaptureDevice.VideoCapabilities[0];
foreach (VideoCapabilities vc in videoCaptureDevice.VideoCapabilities)
{
log.Debug("vc => " + JsonConvert.SerializeObject(vc));
/*int vw = vc.FrameSize.Width;
int fw = videoCaptureDevice.VideoResolution.FrameSize.Width;
int vf = vc.AverageFrameRate;
int ff = videoCaptureDevice.VideoResolution.AverageFrameRate;
if (vw > fw || (vw == fw && vf > ff))
{
videoCaptureDevice.VideoResolution = vc;
}*/
if (vc.FrameSize.Width == 1920 && vc.AverageFrameRate == 30 && vc.MaximumFrameRate == 30)
{
videoCaptureDevice.VideoResolution = vc;
}
}
log.Debug("VideoCapabilities => " + JsonConvert.SerializeObject(videoCaptureDevice.VideoResolution));
_videoDevice = new Model.VideoDevice()
{
// 设备友好名称
FriendlyName = filterInfo.Name,
// 设备的唯一标识符,用于区分哪个设备
MonikerName = filterInfo.MonikerString
};
_videoCapabilities = new Model.VideoCapabilities()
{
// 帧宽
FrameWidth = videoCaptureDevice.VideoResolution.FrameSize.Width,
// 帧高
FrameHeight = videoCaptureDevice.VideoResolution.FrameSize.Height,
// 平均帧率
AverageFrameRate = videoCaptureDevice.VideoResolution.AverageFrameRate,
// 最大帧率
MaximumFrameRate = videoCaptureDevice.VideoResolution.MaximumFrameRate
};
// 初始化视频采集接口
_videoCapture = new VideoCapture(_videoDevice, _videoCapabilities);
// 实时显示
_videoCapture.ImageSourceChanged = p => { CameraPlayer.Source = p; };
if (!_videoCapture.Start(out string errMsg)) {
MessageBox.Show(errMsg);
return;
}
}
}
/// <summary>
/// 初始化播放器
/// </summary>
private void InitPlayer()
{
ThreadPool.QueueUserWorkItem(_ => {
this.Dispatcher.BeginInvoke(new Action(() =>
{
//VLC播放器的安装位置,我的VLC播放器安装在D:\Program Files (x86)\VideoLAN\VLC文件夹下。
var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory() + @"\VLC\" + (Environment.Is64BitProcess ? "x64" : "x86"));
var options = new string[]
{
//添加日志
"--file-logging", "-vvv", "--logfile=/logs/vlc_logs.log"
// VLC options can be given here. Please refer to the VLC command line documentation.
};
// 初始化播放器
this.VlcPlayer.SourceProvider.CreatePlayer(currentDirectory, options);
this.VlcPlayer.SourceProvider.MediaPlayer.LengthChanged += MediaPlayer_LengthChanged;
this.VlcPlayer.SourceProvider.MediaPlayer.TimeChanged += MediaPlayer_TimeChanged;
// 初始化进度条
this.VlcProgress.MouseMove += VlcProgress_MouseMove;
this.VlcProgress.TouchMove += VlcProgress_TouchMove;
this.VlcProgress.IsMoveToPointEnabled = true;
}));
});
}
private void MediaPlayer_TimeChanged(object sender, VlcMediaPlayerTimeChangedEventArgs e)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
VlcProgress.Value = VlcPlayer.SourceProvider.MediaPlayer.Time;
if (_pause)
{
VlcPlayer.SourceProvider.MediaPlayer.Pause();
}
}));
}
private void MediaPlayer_LengthChanged(object sender, VlcMediaPlayerLengthChangedEventArgs e)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
VlcProgress.Maximum = VlcPlayer.SourceProvider.MediaPlayer.Length;
VlcProgress.TickFrequency = 10;
}));
}
private void VlcProgress_TouchMove(object sender, TouchEventArgs e)
{
VlcPlayer.SourceProvider.MediaPlayer.Position = (float)VlcProgress.Value / (float)VlcProgress.Maximum;
_pause = true;
}
private void VlcProgress_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)
{
VlcPlayer.SourceProvider.MediaPlayer.Position = (float)VlcProgress.Value / (float)VlcProgress.Maximum;
_pause = true;
}
}
private void OpenFile_Click(object sender, RoutedEventArgs e)
{
var openFileDialog = new OpenFileDialog()
{
Filter = "Video File|*.mp4;*.avi;*.mkv;*.ts"
};
var result = openFileDialog.ShowDialog();
if (result == true)
{
ThreadPool.QueueUserWorkItem(_ =>
{
_fileName = Path.Combine(Environment.CurrentDirectory, "Videos", DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".mp4");
Convert(openFileDialog.FileName, _fileName);
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.VlcPlayer.SourceProvider.MediaPlayer.Play(new Uri(_fileName));
// this.VlcPlayer.SourceProvider.MediaPlayer.Rate = 0.3f;
// this.VlcPlayer.SourceProvider.MediaPlayer.Length;
}));
});
}
}
private void Reload_Click(object sender, RoutedEventArgs e)
{
_pause = false;
if (!string.IsNullOrWhiteSpace(_fileName))
{
this.VlcPlayer.SourceProvider.MediaPlayer.Play(new Uri(_fileName));
// this.VlcPlayer.SourceProvider.MediaPlayer.Rate = 0.3f;
}
}
private void Goon_Click(object sender, RoutedEventArgs e)
{
_pause = false;
VlcPlayer.SourceProvider.MediaPlayer.Play();
}
#region FFMPEG
/// <summary>
/// 转换视频文件
/// </summary>
/// <param name="srcFile"></param>
/// <param name="destFile"></param>
/// <returns></returns>
private string Convert(string srcFile, string destFile)
{
Process p = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = Directory.GetCurrentDirectory() + @"\FFMPEG\" + (Environment.Is64BitProcess ? "x64" : "x86") + "\\" + "ffmpeg.exe";
startInfo.Arguments = BuildArgs(srcFile, destFile);
startInfo.UseShellExecute = false; // 不使用系统外壳程序启动进程
startInfo.CreateNoWindow = true; // 不显示dos程序窗口
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
// startInfo.RedirectStandardError = true; // 把外部程序错误输出写入到StandardError流中
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo = startInfo;
p.Start();
p.WaitForExit();
try
{
// p.BeginErrorReadLine();
string rst = p.StandardOutput.ReadToEnd();
Console.WriteLine(rst);
string err = p.StandardError.ReadToEnd();
Console.WriteLine("err => " + err);
}
catch { }
p.Close();
p.Dispose();
return destFile;
}
private string BuildArgs(string srcFile, string destFile)
{
StringBuilder builder = new StringBuilder("");
//builder.Append(" -hwaccel cuvid"); // 显卡加速
//builder.Append(" -c:v h264_cuvid"); // 显卡加速
//builder.Append(" -c:v h264_nvenc"); // 显卡加速
builder.Append(" -i " + srcFile); // 输入文件
builder.Append(" -vf \"setpts=5.0*PTS\""); // 慢速
builder.Append(" -s 1920x1080"); // 分辨率
/*builder.Append(" -r 60"); // 帧率
//builder.Append(" -bufsize 1024"); // 码率控制缓冲区大小
builder.Append(" -b:v 8000k"); // 比特率
builder.Append(" -pix_fmt yuv444p"); // 内存中展开大小
builder.Append(" -vcodec h264"); // 解码器*/
builder.Append(" " + destFile); // 输出文件
return builder.ToString();
}
#endregion
#region RECORD
/// <summary>
/// 录制
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Record_Click(object sender, EventArgs e)
{
if (!_recording)
{
_fileName = Path.Combine(Environment.CurrentDirectory, "Videos", DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".avi");
if (_videoCapture.BeginRecord(_fileName, out string errMsg))
{
this.Record.Content = "停止";
} else
{
MessageBox.Show(errMsg);
}
// 标记为录制中
_recording = true;
}
else
{
// 标记为停止录像
_recording = false;
if (_videoCapture.EndRecord(out string videoFile, out string errMsg))
{
this.Record.Content = "录制";
ThreadPool.QueueUserWorkItem(_ =>
{
// 设置转码接收文件
string destFile = Path.Combine(Environment.CurrentDirectory, "Videos", DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".mp4");
// 开始转码
Convert(videoFile, destFile);
// 转码文件回传
_fileName = destFile;
// 预览播放
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.CameraPanel.Visibility = Visibility.Collapsed;
this.VlcPanel.Visibility = Visibility.Visible;
this.VlcPlayer.SourceProvider.MediaPlayer.Play(new Uri(_fileName));
//this.VlcPlayer.SourceProvider.MediaPlayer.Rate = 0.5f;
}));
});
}
else
{
MessageBox.Show(errMsg);
}
}
}
#endregion
/// <summary>
/// 显示播放器画面
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GotoPlayer_Click(object sender, EventArgs e)
{
this.CameraPanel.Visibility = Visibility.Collapsed;
this.VlcPanel.Visibility = Visibility.Visible;
}
/// <summary>
/// 显示摄像头预览
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GotoCamera_Click(object sender, RoutedEventArgs e)
{
this.CameraPanel.Visibility = Visibility.Visible;
this.VlcPanel.Visibility = Visibility.Collapsed;
}
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C#
1
https://gitee.com/dcxin/CameraCaptureDemo.git
git@gitee.com:dcxin/CameraCaptureDemo.git
dcxin
CameraCaptureDemo
摄像头捕捉转码慢放
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891