C#使用ffmpeg录视频和拍照

c#使用ffmpeg调用aforge引用包实现摄像设备拍照及录像

1.添加引用

AForge.dll 是框架的核心基础类库,为其他类库提供服务。
AForge.Controls.dll 包含AForge.Net的UI控件,主要用于页面显示。
AForge.Imaging.dll 主要是框架中用于图像处理的类库,主要负责图像的处理
AForge.Video.dll 主要是框架中对视频处理的类库。
AForge.Video.DirectShow.dll 主要是通过DirectShow接口访问视频资源的类库。AForge.Video.FFMPEG.dll 是一个还未正式发布的类库,通过FFMPEG类库对视频进行读写。

但是特别注意,vs的NGet目前没有AForge.Video.FFMPEG.dll,你得去AForge官网或者第三方平台http://www.aforgenet.com/framework/downloads.html里下载,可以用迅雷之类的下载器下载,他们的离线下载是可以翻墙的。

选择了“Download Installer”,右键“复制链接地址”,然后放进迅雷下载。

下载下来之后是一个压缩包,AForge.Video.FFMPEG.dll就放在压缩包的Release文件夹中。

2.调用(注意有坑)

引用运行报错如下:

因为这个AForge.Video.FFMPEG使用VC++写的,编译的时候已经被编译成本地代码,而我们现在C#一般目标平台都是“Any CPU”,所以会发生这个问题。

解决办法不再使用“Any CPU”作为目标平台,改成“x86”或者“x64”。因为x86可以跑在x64上,而x64不能在x86上跑,所以我选择了x86。

 再按次调试,又报错如下:

4bad3f7428a4fb3373d4aec07ee0a83d.png

这个AForge.Video.FFMPEG其实是在内部调用FFMPEG来工作的。所以这个FileNotFoundException其实是AForge.Video.FFMPEG找不到FFMPEG的文件所以抛出来的。AForge.Video.FFMPEG依赖的FFMPEG组件其实已经放在了刚刚下载下来的压缩包的\Externals\ffmpeg\bin目录下:

de1e077ebfa72a66e8d76dabd6307273.png 

把这个8个文件复制到程序目录下,注意我们刚刚改过目标平台了,现在程序编译输出的目录已经是\bin\x86\Debug,不要复制错了。

再次调试又报错如下:

b92615bfcc07047a809f3f5f78fa103d.png 

因为本项目目标框架是.net Framework 4.0,而AForge官方在编译AForge.Video.FFMPEG.dll的时候,目标框架选的是.net Framework 2.0……

解决方案有三种:

1.降低自己项目的目标.net Framework版本;

2.修改Config文件;

3.重新编译Video.FFMPEG。

这里我就讲一下方法二,

在Visual Studio中按Ctrl+Shift+A,打开“添加新项”窗口,选择“应用程序配置文件”,再点击“添加”(vs2017创建的时候已经自带了App.config无需再次添加)

打开新建的App.Config文件,在<configuration>和</configuration>标签中加入以下内容:

<startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
  </startup>

4c86904d87e6c71a633ccaa03522717a.png 

3.界面UI设计:

这里解释以下界面组成及控件使用
此界面分上下两部分,其中上半部分分左,中,右三个(这里讲解左,其它类似)
上部分由一个GroupBox包裹一个AForge.NET工具包下VideoSourcePlayer控件命名为vsp_Panel组成
中间部分由一个Label,一个ComBox下拉框cb_CameraSelect,两个Button按钮btn_Connect、btn_Close组成
下部分由一个GroupBox包裹一个AForge.NET工具包下PictureBox控件命名为gb_CapturePanel组成
界面下部分由由一个GroupBox包裹5个Button按钮btn_StartVideo、btn_PauseVideo、btn_EndVideo、btn_Capture、btn_Save。以及两个label,其中录制时间: 这个label命名无所谓后续用不到,而另外一个默认显示为00:00:00的label命名为lab_Time

 4.完整代码如下:

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;


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

        #region 属性
        /// <summary>
        /// 设备源
        /// 用来操作摄像头
        /// </summary>
        private AForge.Video.DirectShow.VideoCaptureDevice videoCapture;
        private AForge.Video.DirectShow.VideoCaptureDevice videoCapture2;
        private AForge.Video.DirectShow.VideoCaptureDevice videoCapture3;
        /// <summary>
        /// 摄像头设备集合
        /// </summary>
        private AForge.Video.DirectShow.FilterInfoCollection infoCollection;
        /// <summary>
        /// 图片
        /// </summary>
        private System.Drawing.Bitmap imgMap;
        private System.Drawing.Bitmap imgMap2;
        private System.Drawing.Bitmap imgMap3;
        /// <summary>
        /// 文件保存路径
        /// </summary>
        private readonly string filePath = $"C:\\Users\\wang jun\\Desktop\\工作\\德富莱智能科技股份有限公司\\项目\\摄像头测通讯\\";
        /// <summary>
        /// 文件名称
        /// </summary>
        private  string fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}";
        private  string fileName2 = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}2";
        private  string fileName3 = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}3";
        /// <summary>
        /// 用与把每一帧图像写入到视频文件
        /// </summary>
        private AForge.Video.FFMPEG.VideoFileWriter videoWriter;
        private AForge.Video.FFMPEG.VideoFileWriter videoWriter2;
        private AForge.Video.FFMPEG.VideoFileWriter videoWriter3;
        /// <summary>
        /// 是否开始录像
        /// </summary>
        private bool IsStartVideo = false;
        /// <summary>
        /// 写入次数
        /// </summary>
        private int tick_num = 0;
        /// <summary>
        /// 录制多少小时,只是为了定时间计算录制时间使用
        /// </summary>
        private int Hour = 0;
        /// <summary>
        /// 计时器
        /// </summary>
        private System.Timers.Timer timer_count;
        #endregion
        
        #region 窗口加载与关闭
        /// <summary>
        /// 讲题加载事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            InitCamera();
            InitCameraSelect();
            this.btn_Capture.Enabled = false;
            this.btn_Save.Enabled = false;
            this.gb_CapturePanel.SizeMode = PictureBoxSizeMode.Zoom;//图片大小按比例适应控件,不加的话图片显示问题太大
            this.gb_CapturePanel.Visible = false;//默认不显示照片区域,拍照时在显示
                                                 //秒表
            this.gb_CapturePanel2.SizeMode = PictureBoxSizeMode.Zoom;
            this.gb_CapturePanel2.Visible = false;
            this.gb_CapturePanel3.SizeMode = PictureBoxSizeMode.Zoom;
            this.gb_CapturePanel3.Visible = false;
            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;
        }
        /// <summary>
        /// 窗口关闭时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            EndCamera();
        }
        #endregion

        #region 实例化
        /// <summary>
        /// 实例化摄像头
        /// </summary>
        public void InitCamera()
        {
            try
            {
                //检测电脑上的摄像头设备
                infoCollection = new AForge.Video.DirectShow.FilterInfoCollection(AForge.Video.DirectShow.FilterCategory.VideoInputDevice);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"没有找到设备:{ex.Message}", "Error");
            }

        }
        //加载摄像头选择
        public void InitCameraSelect()
        {
            this.cb_CameraSelect.DropDownStyle = ComboBoxStyle.DropDownList;
            this.cb_CameraSelect2.DropDownStyle = ComboBoxStyle.DropDownList;
            this.cb_CameraSelect3.DropDownStyle = ComboBoxStyle.DropDownList;
            //根据读取到的摄像头加载选择项
            foreach (AForge.Video.DirectShow.FilterInfo item in infoCollection)
            {
                this.cb_CameraSelect.Items.Add(item.Name);
                this.cb_CameraSelect2.Items.Add(item.Name);
                this.cb_CameraSelect3.Items.Add(item.Name);
            }
            cb_CameraSelect.Text = (string)cb_CameraSelect.Items[0];
            cb_CameraSelect2.Text = (string)cb_CameraSelect.Items[1];
            //需要改动cb_CameraSelect3.Text = (string)cb_CameraSelect.Items[2];
            cb_CameraSelect3.Text = (string)cb_CameraSelect.Items[0];
        }
        #endregion

        #region  摄像头的连接读取与关闭
        /// <summary>
        /// 连接按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            var CameraSelect = this.cb_CameraSelect.Text;
            var selectIndex = this.cb_CameraSelect.SelectedIndex;
            var selectIndex2 = this.cb_CameraSelect2.SelectedIndex;
            var selectIndex3 = this.cb_CameraSelect3.SelectedIndex;

            //已有连接的摄像头时先关闭
            if (videoCapture != null|| videoCapture2 !=null|| videoCapture3 !=null)
            {
                EndCamera();
            }
            videoCapture = new AForge.Video.DirectShow.VideoCaptureDevice(infoCollection[selectIndex].MonikerString);
            videoCapture2 = new AForge.Video.DirectShow.VideoCaptureDevice(infoCollection[selectIndex2].MonikerString);
            videoCapture3 = new AForge.Video.DirectShow.VideoCaptureDevice(infoCollection[selectIndex3].MonikerString);
            //启动摄像头
            this.vsp_Panel.VideoSource = videoCapture;
            this.vsp_Panel2.VideoSource = videoCapture2;
            this.vsp_Panel3.VideoSource = videoCapture3;
            this.vsp_Panel.Start();
            this.vsp_Panel2.Start();
            this.vsp_Panel3.Start();
            this.btn_Capture.Enabled = true;
            this.btn_Save.Enabled = false;
        }
        /// <summary>
        /// 关闭按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Close_Click(object sender, EventArgs e)
        {
            EndCamera();
        }
        /// <summary>
        /// 关闭摄像头
        /// </summary>
        public void EndCamera()
        {
            if (this.vsp_Panel.VideoSource != null)
            {
                //也可以用 Stop() 方法关闭
                //指示灯停止且等待
                this.vsp_Panel.SignalToStop();               
                this.vsp_Panel.WaitForStop();//停止且等待
                this.vsp_Panel.VideoSource = null;              
            }
            if (this.vsp_Panel2.VideoSource != null)
            {
                this.vsp_Panel2.SignalToStop();
                this.vsp_Panel2.WaitForStop();
                this.vsp_Panel2.VideoSource = null;
            }
            if (this.vsp_Panel3.VideoSource != null)
            {
                this.vsp_Panel3.SignalToStop();
                this.vsp_Panel3.WaitForStop();
                this.vsp_Panel3.VideoSource = null;
            }
        }

        #endregion

        #region 拍照与保存
        /// <summary>
        /// 拍照
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Capture_Click(object sender, EventArgs e)
        {
            imgMap = this.vsp_Panel.GetCurrentVideoFrame();
            imgMap2 = this.vsp_Panel2.GetCurrentVideoFrame();
            imgMap3 = this.vsp_Panel3.GetCurrentVideoFrame();
            this.gb_CapturePanel.Visible = true;
            this.gb_CapturePanel2.Visible = true;
            this.gb_CapturePanel3.Visible = true;
            this.gb_CapturePanel.Image = imgMap;
            this.gb_CapturePanel2.Image = imgMap2;
            this.gb_CapturePanel3.Image = imgMap3;
            this.btn_Save.Enabled = true;
        }
        /// <summary>
        /// 保存事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Save_Click(object sender, EventArgs e)
        {
            var saveName = $"{filePath}{fileName}.jpg";
            imgMap.Save(saveName);
            var saveName2 = $"{filePath}{fileName2}.jpg";
            imgMap2.Save(saveName2);
            var saveName3 = $"{filePath}{fileName3}.jpg";
            //需改动imgMap3.Save(saveName3);
            this.btn_Save.Enabled = false;
            fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}";
            fileName2 = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}2";
            fileName3 = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}3";
            //MessageBox.Show($"保存成功");
        }
        #endregion
        
        #region 录像
        /// <summary>
        /// 开始录像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_StartVideo_Click(object sender, EventArgs e)
        {
            this.lab_Time.Text="00:00:00";
            string videoName = $"{filePath}{fileName}.mp4";
            string videoName2 = $"{filePath}{fileName2}.mp4";
            string videoName3 = $"{filePath}{fileName3}.mp4";
            IsStartVideo = true;
            
            //开始计时
            timer_count.Enabled = true;
            //配置录像参数(宽,高,帧率,比特率等参数)VideoCapabilities这个属性会返回摄像头支持哪些配置,从这里面选一个赋值接即可
            videoCapture.VideoResolution = videoCapture.VideoCapabilities[0];
            videoCapture2.VideoResolution = videoCapture2.VideoCapabilities[0];
            videoCapture3.VideoResolution = videoCapture3.VideoCapabilities[0];
            //设置回调,aforge会不断从这个回调推出图像数据
            videoCapture.NewFrame += Camera_NewFrame;
            videoCapture2.NewFrame += Camera_NewFrame2;
            videoCapture3.NewFrame += Camera_NewFrame3;
            videoWriter = new AForge.Video.FFMPEG.VideoFileWriter();
            videoWriter2 = new AForge.Video.FFMPEG.VideoFileWriter();
            videoWriter3 = new AForge.Video.FFMPEG.VideoFileWriter();
            //打开摄像头
            //打开录像文件(如果没有则创建,如果有也会清空),这里还有关于视频宽高、帧率、格式、比特率
            videoWriter.Open(
               videoName,
               videoCapture.VideoResolution.FrameSize.Width,
               videoCapture.VideoResolution.FrameSize.Height,
               //videoCapture.VideoResolution.AverageFrameRate,
               6,//帧率
               AForge.Video.FFMPEG.VideoCodec.MPEG4,
               videoCapture.VideoResolution.BitCount
            );
            videoWriter2.Open(
               videoName2,
               videoCapture2.VideoResolution.FrameSize.Width,
               videoCapture2.VideoResolution.FrameSize.Height,
               //videoCapture.VideoResolution.AverageFrameRate,
               6,//帧率
               AForge.Video.FFMPEG.VideoCodec.MPEG4,
               videoCapture2.VideoResolution.BitCount
            );
            videoWriter3.Open(
             videoName3,
             videoCapture3.VideoResolution.FrameSize.Width,
             videoCapture3.VideoResolution.FrameSize.Height,
             //videoCapture.VideoResolution.AverageFrameRate,
             6,//帧率
             AForge.Video.FFMPEG.VideoCodec.MPEG4,
             videoCapture3.VideoResolution.BitCount
          );
        }
        //摄像头1输出回调
        private void Camera_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            imgMap = eventArgs.Frame;
            lock (imgMap)
            {
                if (eventArgs != null && eventArgs.Frame != null)
                {
                    try
                    {
                        //写到文件
                        videoWriter.WriteVideoFrame(eventArgs.Frame);
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
        }
        //摄像头2输出回调
        private void Camera_NewFrame2(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            imgMap2 = eventArgs.Frame;
            lock (imgMap2)
            {
                if (eventArgs != null && eventArgs.Frame != null)
                {
                    try
                    {
                        //写到文件
                        videoWriter2.WriteVideoFrame(eventArgs.Frame);
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
        }
        //摄像头3输出回调
        private void Camera_NewFrame3(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            imgMap3 = eventArgs.Frame;
            lock (imgMap3)
            {
                if (eventArgs != null && eventArgs.Frame != null)
                {
                    try
                    {
                        //写到文件
                        //需改动videoWriter3.WriteVideoFrame(eventArgs.Frame);
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
        }
        /// <summary>
        /// 停止录像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_EndVideo_Click(object sender, EventArgs e)
        {
            IsStartVideo = false;
            timer_count.Enabled = false;
            videoWriter.Close();
            videoWriter2.Close();
            videoWriter3.Close();
            fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}";
            fileName2 = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}2";
            fileName3 = $"{DateTime.Now.ToString("yyyyMMddhhmmssffff")}3";
            MessageBox.Show("停止录像");
            HourStr="00";
            MinuteStr = "00";
            SecondStr = "00";
            tick_num = 0;

        }
        #endregion
        string HourStr =null;
        string MinuteStr=null;
        string SecondStr=null;
        #region 计时器响应函数
        /// <summary>
        /// 计时器
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        public void tick_count(object source, System.Timers.ElapsedEventArgs e)
        {
            tick_num++;
            int Temp = tick_num;
            int Second = Temp % 60;
            int Minute = Temp / 60;
            if (Minute % 60 == 0)
            {
                Hour = Minute / 60;
                Minute = 0;
            }
            else
            {
                Minute = Minute - Hour * 60;
            }
            HourStr = Hour < 10 ? $"0{Hour}" : Hour.ToString();
            MinuteStr = Minute < 10 ? $"0{Minute}" : Minute.ToString();
            SecondStr = Second < 10 ? $"0{Second}" : Second.ToString();
            String tick = $"{HourStr}:{MinuteStr}:{SecondStr}";
            this.Invoke((EventHandler)(delegate
            {
                this.lab_Time.Text = tick;
            }));
        }
        #endregion
    }
}

 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值