zl程序教程

您现在的位置是:首页 >  后端

当前栏目

基于AForge的C#摄像头视频录制

c# 基于 视频 摄像头 录制
2023-09-11 14:22:29 时间

1. 概述

最近搞华为的CDN(-_-||-_-||-_-||),写东西的时间比较少了。最近由于兴趣学习了下在C#上使用AForge录制摄像头视频并压缩编码。总体上来说这个第三方.net视觉开发库还是比较稳定的(AForge lib下载离线帮助文档下载)。但是由于这个第三方库维护不怎么样,导致会出现不兼容的问题。这里将这些与大家分享,希望对您有帮助。

在使用AForge第三方库录制本地视频所要使用到的类主要有这几个:FilterInfoCollection、VideoCaptureDevice、VideoSourcePlayer、VideoFileWriter。下面我就简单的介绍一下这几个类涉及到的方法等。

FilterInfoCollection:

该类主要是用于摄像头视频输入设备列表检测的。是继承自C#中的System.Collections.CollectionBase类。


这是离线帮助文档上对这个类的调用方式:


其中构造函数传递进去的参数是需要采集的信号的类型,他还有其他的输入类型(如声音等):


VideoCaptureDevice:

这是该类中的一些成员函数和变量



这个类便是要选择了视频输入的设备了,他的构造函数是


在实际的使用过程中可能会存在多个设备的情况,便可以通过第二个参数进行输入设备的指定。初始化是这样的


在本例子的实际使用过程中对上面该类事件NewFrame函数进行了响应,然后提取出当前帧。

VideoSourcePlayer:

该类是AForge.Control中的类,是控件中调用的,这里将它添加进来是为了作为拍照功能使用的,这里就不做介绍了。

VideoFileWriter:

该类是视频写操作类,主要实现视频文件的压缩和写入到文件中。

本例子中先使用VideoFileWriter.Open()函数设定录制视频的高度、宽度、帧率、编码类型。


这是该第三方类库支持的视频编码格式


然后使用下面这个函数就可以将当前帧写入到视频文件中了。


2. 实现

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;

//using AForge
using AForge;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
using AForge.Controls;

namespace video_record
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //关闭窗口响应函数
        private void button2_Click(object sender, EventArgs e)
        {
            if (this.writer.IsOpen)
            {
                MessageBox.Show("视频流还没有写完,请点击结束录制。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            this.videoSource.SignalToStop();
            this.videoSource.WaitForStop();
            this.videoSourcePlayer.SignalToStop();
            this.videoSourcePlayer.WaitForStop();
            this.Hide();
            this.Close();
            this.Dispose();
        }

        private FilterInfoCollection videoDevices;  //摄像头设备
        private VideoCaptureDevice videoSource;     //视频的来源选择
        private VideoSourcePlayer videoSourcePlayer;    //AForge控制控件
        private VideoFileWriter writer;     //写入到视频
        private bool is_record_video = false;   //是否开始录像
        System.Timers.Timer timer_count;
        int tick_num = 0;

        //窗体初始化函数
        private void Form1_Load(object sender, EventArgs e)
        {
            this.label5.Visible = false;

            this.videoSourcePlayer = new AForge.Controls.VideoSourcePlayer();
            this.videoSource = new VideoCaptureDevice();
            this.writer = new VideoFileWriter();

            //设置视频编码格式
            this.comboBox_videoecode.Items.Add("Raw");
            this.comboBox_videoecode.Items.Add("MPEG2");
            this.comboBox_videoecode.Items.Add("FLV1");
            this.comboBox_videoecode.Items.Add("H263p");
            this.comboBox_videoecode.Items.Add("MSMPEG4v3");
            this.comboBox_videoecode.Items.Add("MSMPEG4v2");
            this.comboBox_videoecode.Items.Add("WMV2");
            this.comboBox_videoecode.Items.Add("WMV1");
            this.comboBox_videoecode.Items.Add("MPEG4");
            this.comboBox_videoecode.SelectedIndex = 1;

            //设置视频来源
            try
            {
                // 枚举所有视频输入设备
                videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

                if (videoDevices.Count == 0)
                    throw new ApplicationException();   //没有找到摄像头设备

                foreach (FilterInfo device in videoDevices)
                {
                    this.comboBox_camera.Items.Add(device.Name);
                }
                //this.comboBox_camera.SelectedIndex = 0;   //注释掉,选择摄像头来源的时候才会才会触发显示摄像头信息
            }
            catch (ApplicationException)
            {
                videoDevices = null;
                MessageBox.Show("没有找到摄像头设备", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            //秒表
            this.timer_count = new System.Timers.Timer();   //实例化Timer类,设置间隔时间为10000毫秒;
            this.timer_count.Elapsed += new System.Timers.ElapsedEventHandler(tick_count);   //到达时间的时候执行事件;
            this.timer_count.AutoReset = true;   //设置是执行一次(false)还是一直执行(true);
            this.timer_count.Interval = 1000;
        }

        //视频源选择下拉框选择之后的响应函数
        private void comboBox_camera_SelectedIndexChanged(object sender, EventArgs e)
        {
            int selected_index = this.comboBox_camera.SelectedIndex;
            this.videoSource = new VideoCaptureDevice(videoDevices[selected_index].MonikerString);
            // set NewFrame event handler
            videoSource.NewFrame += new NewFrameEventHandler(show_video);
            videoSource.Start();
            videoSourcePlayer.VideoSource = videoSource;
            videoSourcePlayer.Start();
            this.label5.Text = "连接中...";
            this.label5.Visible = true;
            isshowed = true;
        }

        bool isshowed = true;
        //新帧的触发函数
        private void show_video(object sender, NewFrameEventArgs eventArgs)
        {
            if (isshowed)
            {
                this.label5.Visible = false;
                isshowed = false;
            }
            Bitmap bitmap = eventArgs.Frame;    //获取到一帧图像
            pictureBox1.Image = Image.FromHbitmap(bitmap.GetHbitmap());
            if (is_record_video)
            {
                writer.WriteVideoFrame(bitmap);
            }
        }

        //拍摄图像按钮响应函数
        private void button1_Click(object sender, EventArgs e)
        {
            if (this.videoSource.IsRunning && this.videoSourcePlayer.IsRunning)
            {
                Bitmap bitmap = this.videoSourcePlayer.GetCurrentVideoFrame();
                bitmap.Save("img.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else
                MessageBox.Show("摄像头没有运行", "错误", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        //开始录像按钮响应函数
        private void button_start_Click(object sender, EventArgs e)
        {
            int width = 640;    //录制视频的宽度
            int height = 480;   //录制视频的高度
            int fps = 9;

            //创建一个视频文件
            String video_format = this.comboBox_videoecode.Text.Trim(); //获取选中的视频编码
            if (this.videoSource.IsRunning && this.videoSourcePlayer.IsRunning)
            {
                if (-1 != video_format.IndexOf("MPEG"))
                {
                    writer.Open("test.avi", width, height, fps, VideoCodec.MPEG4);
                }
                else if (-1 != video_format.IndexOf("WMV"))
                {
                    writer.Open("test.wmv", width, height, fps, VideoCodec.WMV1);
                }
                else
                {
                    writer.Open("test.mkv", width, height, fps, VideoCodec.Default);
                }
            }
            else
                MessageBox.Show("没有视频源输入,无法录制视频。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

            timer_count.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;
            this.label5.Visible = true;
            this.label5.Text = "REC";
            this.is_record_video = true;
        }


        //停止录制视频响应函数
        private void button_stop_Click(object sender, EventArgs e)
        {
            this.label5.Visible = false;
            this.is_record_video = false;
            this.writer.Close();
            this.timer_count.Enabled = false;
            tick_num = 0;
        }

        //暂停按钮响应函数
        private void button3_Click(object sender, EventArgs e)
        {
            if (this.button3.Text.Trim() == "暂停录像")
            {
                this.is_record_video = false;
                this.label5.Visible = false;
                this.button3.Text = "恢复录像";
                timer_count.Enabled = false;    //暂停计时
                return;
            }
            if (this.button3.Text.Trim() == "恢复录像")
            {
                this.is_record_video = true;
                timer_count.Enabled = true;     //恢复计时
                this.label5.Visible = true;
                this.button3.Text = "暂停录像";
            }
        }

        //计时器响应函数
        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 (60 == min)
            {
                min = 0;
                min++;
            }

            int hour = min / 60;

            String tick = hour.ToString() + ":" + min.ToString() + ":" + sec.ToString();
            this.label4.Text = tick;
        }
        

    }
}

3. 结果



4. 错误和注意事项

1. 在使用AForge这个软件过程中需要的不仅仅是将Release文件夹下对应的lib添加到项目的引用中,在进行视频压缩编码的时候需要将External文件夹下的相关lib添加到程序运行的Debug目录下

2. 在使用的时候会遇到这个错误“混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况”的错误。这是因为.net框架不兼容的问题,AForge使用的比较老好像是2.0的。。。-_-||。所以需要在App.config对其进行配置,使其对前版本的兼容,配置如下(这是我添加的配置):
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
    <supportedRuntime version="v2.0.50727"/>
    </startup>
这里是我做的 Demo,有兴趣的可以看看....