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下
如下就可以了
添加视频播放控件,操作如下:(拖动不行可以Ctrl+c Ctrl+v复制)
添加组件以后如下:
代码:
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,
}
}
运行效果如下:
-----------------------------------
©著作权归作者所有:来自51CTO博客作者龙腾一族至尊龙骑的原创作品,请联系作者获取转载授权,否则将追究法律责任
AForge处理视频和拍照(暂时没有音频)
https://blog.51cto.com/u_15693505/5422848