用 .NET / C# 开发一个录屏小程序
实现思路:
不断的获取桌面屏幕的图像,每一张图像我们称为 一帧 。
这里介绍一下 帧率 (FPS , Frame per Second) 的概念:每秒显示的帧数。
人类视觉系统每秒可处理10到12张图像并单独感知它们,也就是说,假如,每秒有超过12张连续的图像经过人的眼睛,人眼就会认为这是连贯的。
例如:12 帧率的 2D 动画,24 帧率的电影,25 帧率的高清电视,30 帧率的 3D 动漫,60 帧率的游戏 等…
最后把获取桌面屏幕的一张张图像再合成视频,就可以完成一个简单的录屏小程序了。
话不多说,直接上干货:
这里我的开发环境是在 Windows 系统下 VS2019 和 .NET Framework 4.6.1
获取桌面屏幕图像
/// <summary>
/// 声明一个 Rectangle 对象,用来指定矩形的位置和大小
/// </summary>
private readonly Rectangle _bounds = Screen.PrimaryScreen.Bounds;
/// <summary>
/// 获取鼠标位置的 Rectangle 对象值
/// </summary>
/// <returns></returns>
private static Rectangle GetMousePositionRectangle()
{
return new Rectangle(MousePosition.X + -5, MousePosition.Y + -5, 32, 32);
}
/// <summary>
/// 获取 桌面屏幕图片
/// </summary>
/// <returns></returns>
private Bitmap GetScreenImgByteArray()
{
Bitmap bitmap = new Bitmap(_bounds.Width, _bounds.Height, PixelFormat.Format24bppRgb);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(Point.Empty, Point.Empty, _bounds.Size, CopyPixelOperation.SourceCopy);
switch (MouseButtons)
{
default:
// 插入鼠标指针的图标
graphics.DrawIcon(Resources.MousePointerImg, GetMousePositionRectangle());
break;
case MouseButtons.Left:
// 插入鼠标左键的图标
graphics.DrawIcon(Resources.MouseLeftImg, GetMousePositionRectangle());
break;
case MouseButtons.Right:
// 插入鼠标右键的图标
graphics.DrawIcon(Resources.MouseRightImg, GetMousePositionRectangle());
break;
case MouseButtons.Middle:
// 插入鼠标滚轮键的图标
graphics.DrawIcon(Resources.MouseWheelImg, GetMousePositionRectangle());
break;
}
return bitmap;
}
}
桌面屏幕的图像我们已经可以获取到了,接下来就是把一张张的图像合成一个视频文件。
这里我用到了适合 C# 的 OpenCV 开源库:OpenCvSharp4。
注意:因为我是在 Windows 系统下开发的,所以也需要安装 OpenCvSharp4.runtime.win;
还有一个问题,如果写入视频报错,需要卸载这个 NuGet 包,重新安装。
如下图,使用 NuGet 即可安装使用。
图像写入视频
/// <summary>
/// 声明一个 VideoWriter 对象,用来写入视频文件
/// </summary>
private VideoWriter _videoWriter = null;
/// <summary>
/// 用来存放 桌面屏幕图片的线程安全队列
/// </summary>
private readonly ConcurrentQueue<Bitmap> _screenImgByteArray = new ConcurrentQueue<Bitmap>();
/// <summary>
/// 视频写入中锁对象
/// </summary>
private readonly object _videoWriteingLock = new object();
/// <summary>
/// 生成视频所需的 fps 参数值,来自界面上的选择;默认 15
/// </summary>
private double _fps = 15;
// 初始化
{
// path 写入的视频文件绝对路径 "...\...\xxx.mp4"
_videoWriter = new VideoWriter(path, new FourCC(FourCC.XVID), _fps, new OcvSize(_bounds.Width, _bounds.Height));
}
// 循环体
{
Bitmap img = null;
try
{
if (_screenImgByteArray.TryDequeue(out img))
{
using (Mat mat = BitmapConverter.ToMat(img))
{
using (InputArray input = InputArray.Create(mat))
{
lock (_videoWriteingLock)
{
// 写入视频
_videoWriter?.Write(input);
}
}
}
}
}
catch (Exception)
{
continue;
}
finally
{
img?.Dispose();
img = null;
}
}
// 结束时
{
lock (_videoWriteingLock)
{
_videoWriter?.Dispose(); // 结束后一定要调用 Dispose()
_videoWriter = null;
}
}
上面代码只是部分核心代码,仅供参考。
具体的代码示例我已经放在 GitHub 上,如下链接:
程序源码
运行效果:
因为具体的示例代码还是稍微复杂一些,这里只是粘出来部分的核心代码,详细的示例请到 GitHub 下载源码后详细研究!示例仅供参考!