目录
一、写在前面
本文所用例子为个人学习的小结,如有不足之处请各位多多海涵,欢迎小伙伴一起学习进步,如果想法可在评论区指出,我会尽快回复您,不胜感激!
所公布代码或截图均为运行成功后展示。
嘿嘿,小小免责声明一下!部分代码可能与其他网络例子相似,如原作者看到有不满,请联系我修改,感谢理解与支持!
二、本文内容
客户在某个医疗项目升级版本中提出需求,希望在病人进行数据测量的同时录制测量过程的视频,并且老版项目也要从32位操作系统迁移到64位操作系统,由此决定使用Accord.net作为视频采集的工具。
AForge.NET仅支持32位操作系统,但使用方式和Accord几乎没有区别,可按需引用工具。
三、开发环境
1.开发语言:C#
2.开发框架:.Net Framework 4.8
2.界面框架:Winform
3.开发工具:Visual Studio 2022
四、工具安装
1.点开VS的工具Tools --> NuGet包管理 --> 管理解决方案的NuGet程序包
2.Accord Accord.Video Accord.Video.DirectShow Accord.Controls
3.添加引用
五、界面搭建
1.左侧listbox为获取摄像头所有资源模式并展示的列表
2.右侧方框为videoSourcePlayer,引入相应dll后,工具栏中会出现该工具。
3.构建几个功能按钮,开启摄像头、关闭摄像头、开始录制、结束录制等。
六、代码实现
6.1定义参数
private FilterInfoCollection videoDevices = null;
private VideoCaptureDevice videoSource = null;
private VideoCapabilities[] VideoCapabilitiesList;
private VideoFileWriter videoFileWriter;
int count = 0;
long timestamp = 0L;
String picName;
private Thread workerThread = null;
private int mFrameCount = 0;
Queue<Bitmap> mVideoFrameList = null;
private bool is_record_video = false;
private readonly object balanceLock = new object();
6.2 获取可选像素按钮实现
获取摄像头所有像素模式,并添加至列表中
listBox1.Items.Clear();
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (videoDevices.Count != 0)
{
for (int i = 0; i < videoDevices.Count; i++)
{
videoSource = new VideoCaptureDevice(videoDevices[i].MonikerString);
VideoCapabilitiesList = videoSource.VideoCapabilities;
//wxf 获取摄像头所有像素模式
for (int j = 0; j < VideoCapabilitiesList.Count(); j++)
{
String itemStr = ("FrameSize:" + VideoCapabilitiesList[j].FrameSize.Width
+ " * " + VideoCapabilitiesList[j].FrameSize.Height
+ " FrameRate:" + VideoCapabilitiesList[j].AverageFrameRate
+ " MaxFrameRate:" + VideoCapabilitiesList[j].MaximumFrameRate).ToString();
listBox1.Items.Add(itemStr);
}
}
}
6.3 打开摄像头按钮实现
选择列表某项,并点击按钮,以此资源模式打开摄像头
CloseVideoSource();
int frame_index = listBox1.SelectedIndex;
if (frame_index >= 0)
{
videoSource.VideoResolution = new VideoCaptureDevice(videoDevices[0].MonikerString).VideoCapabilities[frame_index];
videoSourcePlayer1.VideoSource = videoSource;
videoFileWriter = new VideoFileWriter();
videoSourcePlayer1.Start();
}
6.4 开始录制按钮实现
录制画面并存储
private void button3_Click(object sender, EventArgs e)
{
if (videoSourcePlayer1.IsRunning)
{
StarVideo();
}
}
private void StarVideo()
{
try
{
if (count <= 0)
{
videoSourcePlayer1.NewFrame += NewFrame;
count += 1;
}
is_record_video = true;
String fileName = string.Format("{0:yyyyMMdd_HHmmss}.MP4", DateTime.Now);
String path = Directory.GetCurrentDirectory();
picName = $"{path}{fileName}";
if (videoSource.IsRunning && videoSourcePlayer1.IsRunning)
{
VideoCapabilities vc = videoSource.VideoResolution;
videoFileWriter.Close();
videoFileWriter.Open(picName, vc.FrameSize.Width, vc.FrameSize.Height, vc.MaximumFrameRate, VideoCodec.MPEG4);
mVideoFrameList = new Queue<Bitmap>();
workerThread = new Thread(new ThreadStart(backgroundWriteVideoToFile));
timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
workerThread.Start();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
6.5 结束录制按钮实现
结束录制并保存最后一帧
private void button4_Click(object sender, EventArgs e)
{
StopVideo();
}
private void StopVideo()
{
try
{
is_record_video = false;
if (videoFileWriter != null)
{
videoFileWriter.Close();
}
if (videoSourcePlayer1 != null)
{
videoSourcePlayer1.NewFrame -= NewFrame;
count -= 1;
}
}
catch (Exception ex)
{
Console.WriteLine("StopVideo " + ex.Message);
}
}
6.6关闭摄像头实现
private void button5_Click(object sender, EventArgs e)
{
videoSourcePlayer1.NewFrame -= NewFrame;
count -= 1;
CloseVideoSource();
}
private void CloseVideoSource()
{
if (!(videoSource == null))
{
videoSourcePlayer1.Stop();
videoSource.SignalToStop();
videoSource.WaitForStop();
}
}
七、录制视频结果
录制目录保存在设定目录下
八、完整代码
using Accord.Controls;
using Accord.Statistics;
using Accord.Video;
using Accord.Video.DirectShow;
using Accord.Video.FFMPEG;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace AccordDemo
{
public partial class Form1 : Form
{
private FilterInfoCollection videoDevices = null;
private VideoCaptureDevice videoSource = null;
private VideoCapabilities[] VideoCapabilitiesList;
private VideoFileWriter videoFileWriter;
int count = 0;
long timestamp = 0L;
String picName;
private Thread workerThread = null;
private int mFrameCount = 0;
Queue<Bitmap> mVideoFrameList = null;
private bool is_record_video = false;
private readonly object balanceLock = new object();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (videoDevices.Count != 0)
{
for (int i = 0; i < videoDevices.Count; i++)
{
videoSource = new VideoCaptureDevice(videoDevices[i].MonikerString);
VideoCapabilitiesList = videoSource.VideoCapabilities;
//wxf 获取摄像头所有像素模式
for (int j = 0; j < VideoCapabilitiesList.Count(); j++)
{
String itemStr = ("FrameSize:" + VideoCapabilitiesList[j].FrameSize.Width
+ " * " + VideoCapabilitiesList[j].FrameSize.Height
+ " FrameRate:" + VideoCapabilitiesList[j].AverageFrameRate
+ " MaxFrameRate:" + VideoCapabilitiesList[j].MaximumFrameRate).ToString();
listBox1.Items.Add(itemStr);
}
}
}
}
private void button2_Click(object sender, EventArgs e)
{
CloseVideoSource();
int frame_index = listBox1.SelectedIndex;
if (frame_index >= 0)
{
videoSource.VideoResolution = new VideoCaptureDevice(videoDevices[0].MonikerString).VideoCapabilities[frame_index];
videoSourcePlayer1.VideoSource = videoSource;
videoFileWriter = new VideoFileWriter();
videoSourcePlayer1.Start();
}
}
private void StarVideo()
{
try
{
if (count <= 0)
{
videoSourcePlayer1.NewFrame += NewFrame;
count += 1;
}
is_record_video = true;
String fileName = string.Format("{0:yyyyMMdd_HHmmss}.MP4", DateTime.Now);
String path = Directory.GetCurrentDirectory();
picName = $"{path}{fileName}";
if (videoSource.IsRunning && videoSourcePlayer1.IsRunning)
{
VideoCapabilities vc = videoSource.VideoResolution;
videoFileWriter.Close();
videoFileWriter.Open(picName, vc.FrameSize.Width, vc.FrameSize.Height, vc.MaximumFrameRate, VideoCodec.MPEG4);
mVideoFrameList = new Queue<Bitmap>();
workerThread = new Thread(new ThreadStart(backgroundWriteVideoToFile));
timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
workerThread.Start();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//[HandleProcessCorruptedStateExceptions]
private void NewFrame(object sender, ref Bitmap bit)
{
/* try
{*/
if (is_record_video)
{
if (videoFileWriter.IsOpen && mVideoFrameList != null)
{
mVideoFrameList.Enqueue((Bitmap)bit.Clone());
Console.WriteLine("NewFrame CallBack Now = " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff") + ",FrameCount = " + mFrameCount + ",mVideoFrameList.Count = " + mVideoFrameList.Count);
}
}
}
[HandleProcessCorruptedStateExceptions]
private void backgroundWriteVideoToFile()
{
try
{
while (is_record_video)
{
if (mVideoFrameList != null && mVideoFrameList.Count > 0 && videoFileWriter != null && videoFileWriter.IsOpen)
{
lock (balanceLock)
{
Bitmap bitmap = mVideoFrameList.Dequeue();
videoFileWriter.WriteVideoFrame(bitmap);
bitmap.Dispose();
}
}
else
{
Thread.Sleep(5);
}
}
if (videoFileWriter != null && videoFileWriter.IsOpen)
{
videoFileWriter.Close();
}
workerThread.Abort();
}
catch (Exception ex)
{
Console.WriteLine("NewFrame " + ex.Message);
}
}
private void StopVideo()
{
try
{
is_record_video = false;
if (videoFileWriter != null)
{
videoFileWriter.Close();
}
if (videoSourcePlayer1 != null)
{
videoSourcePlayer1.NewFrame -= NewFrame;
count -= 1;
}
}
catch (Exception ex)
{
Console.WriteLine("StopVideo " + ex.Message);
}
}
private void CloseVideoSource()
{
if (!(videoSource == null))
{
videoSourcePlayer1.Stop();
videoSource.SignalToStop();
videoSource.WaitForStop();
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
videoSourcePlayer1.NewFrame -= NewFrame;
count -= 1;
CloseVideoSource();
}
private void button5_Click(object sender, EventArgs e)
{
videoSourcePlayer1.NewFrame -= NewFrame;
count -= 1;
CloseVideoSource();
}
private void button3_Click(object sender, EventArgs e)
{
if (videoSourcePlayer1.IsRunning)
{
StarVideo();
}
}
private void button4_Click(object sender, EventArgs e)
{
StopVideo();
}
}
}
九、小结
C# 64位系统通过Accord实现摄像头的资源获取、录制视频等功能就是这样,有更好的想法请在评论区交流哦,感谢大家的观看!
十、感谢
感谢各位大佬的莅临,学习之路漫漫,吾将上下而求索。有任何想法请在评论区留言哦!
再次感谢!