AForge处理视频和拍照(暂时没有音频)
AForge处理视频和拍照
下载AForge相关的dll: AForge, AForge.Controls ,AForge.Video ,AForge.Video.DirectShow, AForge.Video.FFMPEG
包括如下:
using AForge;
using AForge.Controls;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
相关dll类库下载地址:http://www.aforgenet.com/framework/downloads.htm
通过下载地址下载,显示如下,提示下载错误,食了很多次都是如此,因此我是用了nuget package下载,就是上图 右小角标记的 NuGet packages 通过指令安装(注:本人在NuGet 包管理器界面中输入搜索AForge.Video.FFMPEG,却无法搜索到对应的包,但在程序包管理器控制台中去可以安装)
)
在下载界面http://www.aforgenet.com/framework/downloads.html,右下角 点击NuGet packages,或者直接使用网址(AForge.Video.FFMPEG下载地址:https://www.nuget.org/packages?q=AForge.NET)也可以,打开以后下划找到ffmpeg,点击即可。
安装以后界面
注意:使用前,需要将Externals文件夹下的所有文件拷贝到项目输出路径下。如:bin\x86\Debug。
下面只要在项目中添加引用即可使用对应的dll进行音视频的开发了
项目运行报错,如下:
是因为虽然将Externals文件夹下的所有文件拷贝到项目输出路径下,本人是吧需要的库放到Library中了,然后设置了覅知道输出目录:始终复制,并没有放到bin\Debug下
如下就可以了
添加视频播放控件,操作如下:
添加组件以后如下:
代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using AForge; using AForge.Controls; using AForge.Video; using AForge.Video.DirectShow; using AForge.Video.FFMPEG; namespace WindowsFormsTestVideo { /// <summary> /// 测试视频和拍照 /// </summary> public partial class Frmmain : Form { /// <summary> /// 构造函数 /// </summary> public Frmmain() { InitializeComponent(); } #region Fields and Propertities 字段和属性 /// <summary> /// 摄像头实时显示控件对象,窗体上没有控件,只是用了该对象来截图 /// </summary> private VideoSourcePlayer VideoSourcePlayerTest = null; /// <summary> /// 摄像头捕获对象 /// </summary> private VideoCaptureDevice videoCaptureDevice = null; /// <summary> /// 摄像头图片写入文件对象,其实视频写入只不过是是写入的一张张图片而已 /// </summary> private VideoFileWriter videoFileWriter = null; /// <summary> /// 摄像头设备集合 /// </summary> FilterInfoCollection filterInfoCollection = null; /// <summary> /// 是否开始录像,开始录像标记 /// </summary> bool isStartRecordVideo = false; /// <summary> /// 图像分辨率 /// </summary> VideoCapabilities[] videoCapabilities = null; #endregion #region Methods 方法 /// <summary> /// 记录日志 /// </summary> /// <param name="message">日志信息</param> private static void Log(string message, MessageType messageType = MessageType.info) { try { switch (messageType) { default: case MessageType.info: //WindowsFormsTestVideo.exe Information: 0 : 启动日志记录 Trace.TraceInformation($"{DateTime.Now}:{message}"); break; case MessageType.error: //WindowsFormsTestVideo.exe Error: 启动日志记录 Trace.TraceError($"{DateTime.Now}:{message}"); break; case MessageType.fail: //失败: 启动日志记录 Trace.Fail($"{DateTime.Now}:{message}"); break; } } catch (Exception ex) { Log(ex.Message, MessageType.error); } } #endregion #region Events 事件 private void Frmmain_Load(object sender, EventArgs e) { #region log日志 System.Diagnostics.Trace.Listeners.Clear(); System.Diagnostics.Trace.AutoFlush = true; System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener("log日志.log")); Log($"{DateTime.Now}:启动日志记录"); #endregion //初始化 //摄像头捕获器 videoCaptureDevice = new VideoCaptureDevice(); //视频录像器 videoFileWriter = new VideoFileWriter(); #region 添加摄像头,添加添加分辨率,添加视频格式 try { //清空摄像头,视频格式,分辨率集合 cbxSelectVideoCapture.Items.Clear(); cbxSelectVideoSaveFormat.Items.Clear(); cbxSelectResolution.Items.Clear(); //分辨率集合 videoCapabilities = null; //添加摄像头 filterInfoCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice); foreach (FilterInfo item in filterInfoCollection) { cbxSelectVideoCapture.Items.Add(item.Name); } //默认选择第一个摄像头设备 cbxSelectVideoCapture.SelectedIndex = 0; //添加视频格式 foreach (var item in Enum.GetNames(typeof(VideoCodec))) { cbxSelectVideoSaveFormat.Items.Add(item); } cbxSelectVideoSaveFormat.SelectedIndex = 0; } catch (Exception ex) { Log(ex.Message, MessageType.error); } #endregion } /// <summary> /// 选择不同的摄像头 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cbxSelectVideoCapture_SelectedIndexChanged(object sender, EventArgs e) { try { //添加添加分辨率 videoCaptureDevice = new VideoCaptureDevice(filterInfoCollection[cbxSelectVideoCapture.SelectedIndex].MonikerString); videoCaptureDevice.NewFrame += VideoCaptureDevice_NewFrame; //分辨率集合 videoCapabilities = videoCaptureDevice.VideoCapabilities; //清空,不同的摄像头有不同的分辨率 cbxSelectResolution.Items.Clear(); foreach (var item in videoCapabilities) { cbxSelectResolution.Items.Add(item.FrameSize); } //默认当前摄像头的第一个分辨率 cbxSelectResolution.SelectedIndex = 0; //videoCaptureDevice.VideoResolution = videoCaptureDevice.VideoCapabilities[1]; //videoCaptureDevice.Start(); ////视频显示 //vspPlayer.VideoSource = videoCaptureDevice; //vspPlayer.Start(); } catch (Exception ex) { Log(ex.Message, MessageType.error); } } /// <summary> /// 选择不同的分辨率 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cbxSelectResolution_SelectedIndexChanged(object sender, EventArgs e) { try { if (videoCaptureDevice.IsRunning || vspPlayer.IsRunning) { videoCaptureDevice.SignalToStop(); videoCaptureDevice.WaitForStop(); vspPlayer.SignalToStop(); vspPlayer.WaitForStop(); VideoSourcePlayerTest.SignalToStop(); VideoSourcePlayerTest.WaitForStop(); } videoCaptureDevice.VideoResolution = videoCaptureDevice.VideoCapabilities[cbxSelectResolution.SelectedIndex]; videoCaptureDevice.Start(); //视频显示 vspPlayer.VideoSource = videoCaptureDevice; vspPlayer.Start(); VideoSourcePlayerTest = new AForge.Controls.VideoSourcePlayer(); VideoSourcePlayerTest.VideoSource = videoCaptureDevice; VideoSourcePlayerTest.Start(); } catch (Exception ex) { Log(ex.Message, MessageType.error); } } /// <summary> /// 获取摄像头的当前帧,可以属实现实时动态的效果 /// </summary> /// <param name="sender"></param> /// <param name="eventArgs"></param> private void VideoCaptureDevice_NewFrame(object sender, NewFrameEventArgs eventArgs) { try { //eventArgs.Frame; 获取摄像头的每一帧图像 //pbxPicture.Image = eventArgs.Frame;//直接复制报错 //1、克隆 //this.Invoke(new MethodInvoker(delegate () //{ // Bitmap image = (Bitmap)eventArgs.Frame.Clone(); // pbxPicture.Image = image; // pbxPicture.Refresh(); //})); //2、根据句柄创建 Bitmap bitmap = eventArgs.Frame; //pbxPicture.Image = Bitmap.FromHbitmap(bitmap.GetHbitmap()); if (isStartRecordVideo) { //视频录像---向文件中写入摄像头的每一帧 videoFileWriter.WriteVideoFrame(bitmap); } } catch (Exception ex) { Log(ex.Message, MessageType.error); } #region 测试Bitmap和Marshal.Copy ////测试Bitmap和Marshal.Copy //Bitmap bitmap1 = new Bitmap("./123456.jpg"); //Rectangle rectangle = new Rectangle(0, 0, bitmap1.Width, bitmap1.Height); ////锁定bitmap到系统内存 //System.Drawing.Imaging.BitmapData bitmapData = bitmap1.LockBits(rectangle, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap1.PixelFormat); ////BitmapData 指定 Bitmap 的特性,如大小、像素格式、像素数据在内存中的起始地址以及每个扫描行的长度(步幅)。 //var pixel = bitmapData.PixelFormat; //Bitmap 的特性 宽度 //var Width = bitmapData.Width;//Bitmap 的特性 宽度 //var Height = bitmapData.Height; //Bitmap 的特性 高度 //var firstStartAddress = bitmapData.Scan0;//像素数据在内存中的起始地址 //var Stride = bitmapData.Stride;//像素数据在内存中的每个扫描行的长度(步幅) //var leength = Math.Abs(bitmapData.Stride) * bitmapData.Height; //byte[] bts = new byte[leength]; //// 将数据从非托管内存指针复制到托管 8 位无符号整数数组 //System.Runtime.InteropServices.Marshal.Copy(firstStartAddress, bts, 0, bts.Length); ////使rgb图片变红色 //for (int i = 2; i < bts.Length; i += 3) //{ // bts[i] = 255; //} ////将数据从一维托管 8 位无符号整数数组复制到非托管内存指针。 //System.Runtime.InteropServices.Marshal.Copy(bts, 0, firstStartAddress, bts.Length); //bitmap1.UnlockBits(bitmapData); //bitmap1.Save("./123456new.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); //bitmap1.Dispose(); ////测试托管内存到非托管内存 //string a = "123456"; //IntPtr dd = System.Runtime.InteropServices.Marshal.AllocHGlobal(10); //char[] chars = a.ToCharArray(); //// 将数据从一维托管字符数组复制到非托管内存指针。 //System.Runtime.InteropServices.Marshal.Copy(chars, 0, dd, chars.Length); ////修改 //// //char[] chars1 = new char[chars.Length]; ////将数据从非托管内存指针复制到托管字符数组。 //System.Runtime.InteropServices.Marshal.Copy(dd, chars1, 0, chars.Length); //System.Runtime.InteropServices.Marshal.FreeHGlobal(dd); #endregion } /// <summary> /// 选择不同的视频格式 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cbxSelectVideoSaveFormat_SelectedIndexChanged(object sender, EventArgs e) { //try //{ // //cbxSelectVideoSaveFormat.SelectedIndex = 0; //} //catch (Exception ex) //{ // Log(ex.Message, MessageType.error); //} } /// <summary> /// 开始录像 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStartVideo_Click(object sender, EventArgs e) { try { if (cbxSelectVideoSaveFormat.SelectedIndex < 0 || !Enum.TryParse(cbxSelectVideoSaveFormat.SelectedItem.ToString(), out VideoCodec videoCodec)) { MessageBox.Show("请选择视频格式", "提示:"); cbxSelectVideoSaveFormat.Focus(); return; } //创建具有指定名称和属性的视频文件。 //文件名:要创建的视频文件名称。 //宽度:视频文件的帧宽。 //高:视频文件的帧高。 //帧速率:视频文件的帧率。 //编码:视频编解码器用于压缩 VideoCapabilities capabilities = videoCapabilities[cbxSelectResolution.SelectedIndex]; int height = capabilities.FrameSize.Height;// 720;//高:视频文件的帧高。 int width = capabilities.FrameSize.Width;// 1280;//宽度:视频文件的帧宽。 //int frameRate = capabilities.FrameRate;// 30;//帧速率:视频文件的帧率。 int frameRate = capabilities.AverageFrameRate;// 30;//帧速率:视频文件的帧率。 switch (cbxSelectVideoSaveFormat.SelectedIndex) { case 0://MPEG-4 part 2. case 3:// MSMPEG4v2 = 3,MPEG-4 part 2 Microsoft variant version 2. case 4:// MSMPEG4v3 = 4,MPEG - 4 part 2 Microsoft variant version 3. case 7://MPEG2 = 7,MPEG-2 part 2. //创建具有指定名称和属性的视频文件,文件名:要创建的视频文件名称,宽度:视频文件的帧宽,高:视频文件的帧高,帧速率:视频文件的帧率,编码:视频编解码器用于压缩 videoFileWriter.Open("video.mp4", width, height, frameRate, videoCodec); break; case 1:// WMV1 = 1 Windows Media Video 7 case 2:// WMV2 = 2,Windows Media Video 8. videoFileWriter.Open("video.wmv", width, height, frameRate, videoCodec); break; case 5://H263P = 5, H.263+ / H.263-1998 / H.263 version 2. videoFileWriter.Open("video.mp4", width, height, frameRate, videoCodec); break; case 6://FLV1 = 6, Flash Video (FLV) / Sorenson Spark / Sorenson H.263. videoFileWriter.Open("video.flv", width, height, frameRate, videoCodec); break; case 8://Raw = 8,Raw (uncompressed) video. videoFileWriter.Open("video.mp4", width, height, frameRate, videoCodec); break; case -1: //摘要: Default = -1 Default video codec, which FFmpeg library selects for the specified file format. default: videoFileWriter.Open("video.mkv", width, height, frameRate, videoCodec); break; } isStartRecordVideo = true;//开始录像标记 lblRecord.ForeColor = Color.Red; lblRecord.Text = "录像中......"; } catch (Exception ex) { Log(ex.Message, MessageType.error); } } /// <summary> /// 停止录像 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStopVideo_Click(object sender, EventArgs e) { try { //关闭录像 isStartRecordVideo = false; videoFileWriter.Close(); lblRecord.ForeColor = DefaultForeColor; lblRecord.Text = ""; } catch (Exception ex) { Log(ex.Message, MessageType.error); } } /// <summary> /// 拍照 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnTakePhoto_Click(object sender, EventArgs e) { try { if (vspPlayer.IsRunning && videoCaptureDevice.IsRunning) { //拍照成功,照片保存路径 var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "takephoto.jpg"); //使用实时显示摄像头控件 //Bitmap image = vspPlayer.GetCurrentVideoFrame(); //AForge.Controls.VideoSourcePlayer Bitmap image = VideoSourcePlayerTest.GetCurrentVideoFrame(); image.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg); lblTakephotoSavePath.Text = $"拍照成功,照片保存路径:{path}"; pbxPicture.SizeMode = PictureBoxSizeMode.Zoom; pbxPicture.Image = Bitmap.FromHbitmap(image.GetHbitmap()); image.Dispose(); } } catch (Exception ex) { Log(ex.Message, MessageType.error); } } private void Frmmain_FormClosed(object sender, FormClosedEventArgs e) { try { videoCaptureDevice.SignalToStop(); videoCaptureDevice.WaitForStop(); vspPlayer.SignalToStop(); vspPlayer.WaitForStop(); VideoSourcePlayerTest.SignalToStop(); VideoSourcePlayerTest.WaitForStop(); //videoCaptureDevice.Stop(); //vspPlayer.Stop(); //VideoSourcePlayerTest.Stop(); } catch (Exception ex) { Log(ex.Message, MessageType.error); } } #endregion } /// <summary> /// 信息的类型 /// </summary> public enum MessageType { /// <summary> ///正常记录信息 /// </summary> info = 0, /// <summary> /// 错误信息 /// </summary> error, /// <summary> /// 失败信息 /// </summary> fail, } }
运行效果如下:
AForge.2.2.5.zip库连接地址:https://download.csdn.net/download/LongtengGensSupreme/21057551