用C#做了一个简单的摄像头录像项目,记录一下。
实现功能
- 打开、关闭摄像头并显示相应画面
- 实现拍照功能
- 实现录像功能
- 实现保存图片、录像的功能
运行界面效果
winForm控件
首先安装NuGet程序包
右键解决方案
点击红圈处
在搜索框中搜索“Aforge”,安装下面所有打勾的程序包(虽然没有全部用到)
引用和定义:
using System;
using System.Windows.Forms;
using System.IO;
using System.Windows.Media.Imaging;
using AForge.Video.DirectShow;
using Size = System.Drawing.Size;
using System.Windows;
using AForge.Video.FFMPEG;
namespace xxxx
{
public partial class Form1 : Form
{
private delegate void MyDelegateUI();//多线程问题
private VideoFileWriter videoWriter = null; //写入到视频
private bool is_record_video = false; //是否开始录像
private FilterInfoCollection videoDevices;
private VideoCaptureDevice videoSource;
System.Drawing.Bitmap bmp1 = null;
System.Timers.Timer timer_count;
int tick_num = 0;
int hour = 0;
int i = 1; //统计摄像头个数
int width = 640; //录制视频的宽度
int height = 480; //录制视频的高度
int fps = 20; //正常速率,fps越大速率越快,相当于快进
public Form1()
{
InitializeComponent();
}
........
}
}
窗体加载事件
private void Form1_Load(object sender, EventArgs e)
{
//初始化按钮状态
btnClose.Enabled = false;
Photograph.Enabled = false;
btnStarVideo.Enabled = false;
btnPuaseVideo.Enabled = false;
btnStopVideo.Enabled = false;
try
{
// 枚举所有视频输入设备
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (videoDevices.Count == 0)
throw new ApplicationException();
foreach (FilterInfo device in videoDevices)
{
int i = 1;
tscbxCameras.Items.Add(device.Name);
textBoxC.AppendText("摄像头" + i + "初始化完毕..." + "\n");
textBoxC.ScrollToCaret();
i++;
Console.WriteLine(device.Name);
}
tscbxCameras.SelectedIndex = 0;
}
catch (ApplicationException)
{
tscbxCameras.Items.Add("没有本地设备");
videoDevices = null;
}
//秒表
timer_count = new System.Timers.Timer(); //实例化Timer类,设置间隔时间为1000毫秒;
timer_count.Elapsed += new System.Timers.ElapsedEventHandler(tick_count); //到达时间的时候执行事件;
timer_count.AutoReset = true; //设置是执行一次(false)还是一直执行(true);
timer_count.Interval = 1000;
}
计时器响应函数
public void tick_count(object source, System.Timers.ElapsedEventArgs e)
{
tick_num++;
int temp = tick_num;
int sec = temp % 60;
int min = temp / 60;
if (min % 60 == 0)
{
hour = min / 60;
min = 0;
}
else
{
min = min - hour * 60;
}
String tick = hour.ToString() + ":" + min.ToString() + ":" + sec.ToString();
MyDelegateUI d = delegate
{
this.labelTime.Text = tick;
};
this.labelTime.Invoke(d);
}
在“连接”(btnConnect)按钮中调用,连接摄像头的方法CameraConn()
private void CameraConn()
{
VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[tscbxCameras.SelectedIndex].MonikerString);
videoSource.DesiredFrameSize = new Size(320, 240);
videoSource.DesiredFrameRate = 1;
videoSourcePlayer.VideoSource = videoSource;
videoSourcePlayer.Start();
}
private void btnConnect_Click(object sender, EventArgs e)
{
CameraConn();
//激活初始化按钮状态
btnClose.Enabled = true;
Photograph.Enabled = true;
btnStarVideo.Enabled = true;
btnPuaseVideo.Enabled = true;
btnStopVideo.Enabled = true;
}
关闭摄像头
private void btnClose_Click(object sender, EventArgs e)
{
videoSourcePlayer.SignalToStop();
videoSourcePlayer.WaitForStop();
}
拍照,拍完直接保存
通过获取
private string GetImagePath()
{
string personImgPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)
+ Path.DirectorySeparatorChar.ToString() + "PersonImg";
if (!Directory.Exists(personImgPath))
{
Directory.CreateDirectory(personImgPath);
}
return personImgPath;
}
private void Photograph_Click(object sender, EventArgs e){
try
{
if (videoSourcePlayer.IsRunning)
{
//System.Windows.Media.Imaging
BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
videoSourcePlayer.GetCurrentVideoFrame().GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,//System.Drawing.Imaging;
BitmapSizeOptions.FromEmptyOptions());
PngBitmapEncoder pE = new PngBitmapEncoder();
pE.Frames.Add(BitmapFrame.Create(bitmapSource));
string picName = GetImagePath() + "\\" + "ceshiT" + ".jpg";
textBoxC.AppendText("保存路径:" + picName + "\n");
textBoxC.ScrollToCaret();
if (File.Exists(picName))
{
File.Delete(picName);
}
using (Stream stream = File.Create(picName))
{
pE.Save(stream);
}
}
}
catch (Exception ex)
{
MessageBox.Show("摄像头异常:" + ex.Message);
}
}
退出按钮
private void btnExit_Click(object sender, EventArgs e)
{
if (this.videoWriter == null)
{
videoWriter = new VideoFileWriter();
}
if (this.videoWriter.IsOpen)
{
MessageBox.Show("视频流还没有写完,请点击结束录制。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//拍照完成后关摄像头并刷新,同时关窗体
if (videoSourcePlayer != null && videoSourcePlayer.IsRunning)
{
videoSourcePlayer.SignalToStop();
videoSourcePlayer.WaitForStop();
}
this.Close();
}
录像前先获取路径,因为开始录像后会要创建一个.avi的文件
private String GetVideoPath()
{
String personImgPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)
+ Path.DirectorySeparatorChar.ToString() + "MyVideo";
if (!Directory.Exists(personImgPath))
{
Directory.CreateDirectory(personImgPath);
}
return personImgPath;
}
视频写入方法
private void show_video(object sender, NewFrameEventArgs eventArgs)
{
try
{
Bitmap bitmap = AutomaticDestroyForm.automaticDestroyForm.videoSourcePlayer.GetCurrentVideoFrame();
if (is_record_video)
{
videoWriter.WriteVideoFrame(bitmap);
}
}
catch(Exception ex)
{
MessageBox.Show("视频写入问题:","错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
“开始录像”(btnStarVideo)按钮绑定事件
private void btnStarVideo_Click(object sender, EventArgs e)
{
try
{
//创建一个视频文件
String picName = GetVideoPath() + "\\" + DateTime.Now.ToString("yyyyMMdd HH-mm-ss") + ".avi";
textBoxC.AppendText("Video保存地址:" + picName + "\n");
textBoxC.ScrollToCaret();
timer_count.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;
textBoxC.AppendText("录制中...\n");
is_record_video = true;
videoWriter = new VideoFileWriter();
if (videoSourcePlayer.IsRunning)
{
//视频写入
videoSourcePlayer.NewFrame += new NewFrameEventHandler(show_video);
videoWriter.Open(picName, width, height, fps, VideoCodec.MPEG4);
}
else
{
MessageBox.Show("没有视频源输入,无法录制视频。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show("摄像头异常:" + ex.Message);
}
}
“暂停录像”(btnPuaseVideo)按钮绑定事件
private void btnPuaseVideo_Click(object sender, EventArgs e)
{
if (this.btnPuaseVideo.Text.Trim() == "暂停录像")
{
is_record_video = false;
this.btnPuaseVideo.Text = "恢复录像";
timer_count.Enabled = false; //暂停计时
return;
}
if (this.btnPuaseVideo.Text.Trim() == "恢复录像")
{
is_record_video = true;
this.btnPuaseVideo.Text = "暂停录像";
timer_count.Enabled = true; //恢复计时
}
}
“停止录像”(btnStopVideo)按钮绑定事件
private void btnStopVideo_Click(object sender, EventArgs e)
{
this.is_record_video = false;
this.videoWriter.Close();
this.timer_count.Enabled = false;
tick_num = 0;
textBoxC.AppendText("录制停止!\n");
textBoxC.ScrollToCaret();
}