c# 获取本地摄像头列表 录制视频 拍照 OpenCvSharp4 NAudio
视频录制
安装nuget 【System.Runtime.InteropServices】
public class EnumDevices
{
/// <summary>
/// 枚举视频设备
/// </summary>
public static IEnumerable<string> Devices
{
get
{
IMoniker[] monikers = new IMoniker[5];
var devEnum = Activator.CreateInstance(Type.GetTypeFromCLSID(SystemDeviceEnum)) as ICreateDevEnum;
IEnumMoniker moniker;
if (devEnum.CreateClassEnumerator(VideoInputDevice, out moniker, 0) == 0)
{
while (true)
{
int hr = moniker.Next(1, monikers, IntPtr.Zero);
if (hr != 0 || monikers[0] == null)
break;
yield return GetName(monikers[0]);
foreach (var i in monikers)
{
if (i != null)
Marshal.ReleaseComObject(i);
}
}
Marshal.ReleaseComObject(moniker);
}
Marshal.ReleaseComObject(devEnum);
}
}
/// <summary>
/// 获取设备名称
/// </summary>
/// <param name="moniker"></param>
/// <returns></returns>
static string GetName(IMoniker moniker)
{
IPropertyBag property;
object value;
object temp = null;
try
{
Guid guid = typeof(IPropertyBag).GUID;
moniker.BindToStorage(null, null, ref guid, out temp);
property = temp as IPropertyBag;
int hr = property.Read("FriendlyName", out value, null);
Marshal.ThrowExceptionForHR(hr);
return value as string;
}
catch (Exception)
{
return null;
}
finally
{
if (temp != null)
{
Marshal.ReleaseComObject(temp);
}
}
}
static readonly Guid SystemDeviceEnum = new Guid(0x62BE5D10, 0x60EB, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
static readonly Guid VideoInputDevice = new Guid(0x860BB310, 0x5D01, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
[Flags]
enum CDef
{
None = 0x0,
ClassDefault = 0x1,
BypassClassManager = 0x2,
ClassLegacy = 0x4,
MeritAboveDoNotUse = 0x8,
DevmonCMGRDevice = 0x10,
DevmonDMO = 0x20,
DevmonPNPDevice = 0x40,
DevmonFilter = 0x80,
DevmonSelectiveMask = 0xF0
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("3127CA40-446E-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IErrorLog
{
[PreserveSig]
int AddError([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In] System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo);
}
[ComImport]
[Localizable(false)]
[SuppressUnmanagedCodeSecurity]
[Guid("55272A00-42CB-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyBag
{
[PreserveSig]
int Read([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [MarshalAs(UnmanagedType.Struct)] out object pVar, [In] IErrorLog pErrorLog);
[PreserveSig]
int Write([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In][MarshalAs(UnmanagedType.Struct)] ref object pVar);
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("29840822-5B84-11D0-BD3B-00A0C911CE86")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICreateDevEnum
{
[PreserveSig]
int CreateClassEnumerator([In][MarshalAs(UnmanagedType.LPStruct)] Guid pType, out IEnumMoniker ppEnumMoniker, [In] CDef dwFlags);
}
}
相关nuget
安装操作视频、图片的nuget ,注意版本号
OpenCvSharp4 4.7.0.20230115
OpenCvSharp4.Extensions 4.7.0.20230115
OpenCvSharp4.runtime.win 4.7.0.20230115
操作
临时变量
private VideoCapture Capture;
VideoWriter videoWriter;
打开摄像头
//0为第一个摄像头设备
Capture = new VideoCapture(0, VideoCaptureAPIs.DSHOW);
Capture.FrameWidth = Convert.ToInt32(1024);
Capture.FrameHeight = Convert.ToInt32(768);
Capture.FourCC = @"MJPG";
捕获图片 - 转换为BitmapSource可以直接显示在界面上
Mat frameTemp = new Mat();
Capture.Read(frameTemp);
//if (frameTemp.Empty())
// continue;
var bitmapInfo = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frameTemp);
//录制视频保存到输出
videoWriter?.Write(frameTemp);
var hBitmap = bitmapInfo.GetHbitmap();
var imgData = Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
保存视频
videoWriter = new VideoWriter(
"D:\\test.mp4",
VideoWriter.FourCC(@"X264"),
30, new OpenCvSharp.Size(Capture.FrameWidth, Capture.FrameHeight));
停止录制
videoWriter.Dispose();
关闭摄像头
Capture.Dispose();
音频录制
安装nuget
NAudio 2.2.1
WaveIn cap = new WaveIn(); // cap, capture
WaveFileWriter writer = new WaveFileWriter("filename", new WaveFormat(16000, 16, 1));
cap.DataAvailable += (s, args) => writer.Write(args.Buffer, 0, args.BytesRecorded); // 订阅事件
cap.StartRecording(); // 开始录制
// 结束录制时:
cap.StopRecording(); // 停止录制
writer.Close(); // 关闭 FileWriter, 保存数据
OpenCVSharp录屏
public class ScreenRecordHelper
{
/// <summary>
/// 录屏线程
/// </summary>
private static CancellationTokenSource cts;
/// <summary>
/// 录屏保存er
/// </summary>
private static VideoWriter _videoWriter;
/// <summary>
/// 录屏-开始
/// </summary>
/// <param name="index">屏幕序号;0=第一个屏幕</param>
/// <param name="parameter">录制参数</param>
/// <param name="videoParameter">录制文件保存参数</param>
/// <param name="doCaptureScreen">处理方法</param>
/// <exception cref="Exception"></exception>
public static void CaptureScreen_Start(int index, ScreenParameter parameter, VideoParameter videoParameter)
{
// 获取屏幕
Screen[] screens = Screen.AllScreens;
if (screens == null || screens.Length < 1)
{
throw new Exception("未检测到任何屏幕!");
}
if (index > screens.Length - 1)
{
throw new Exception($"未检测到屏幕【{index}】!");
}
Screen screen = screens[index];
// 设置录制参数
if (parameter == null || (parameter.SourceX == 0 && parameter.SourceY == 0 && parameter.DestinationX == 0 && parameter.DestinationY == 0 && parameter.BlockRegionSize == default))
{
parameter = new ScreenParameter();
parameter.SourceX = screen.Bounds.X;
parameter.SourceY = screen.Bounds.Y;
parameter.DestinationX = 0;
parameter.DestinationY = 0;
parameter.BlockRegionSize = screen.Bounds.Size;
}
else
{
parameter.SourceX = parameter.SourceX < screen.Bounds.X ? screen.Bounds.X : parameter.SourceX;
parameter.SourceY = parameter.SourceY < screen.Bounds.Y ? screen.Bounds.Y : parameter.SourceY;
parameter.DestinationX = parameter.DestinationX < screen.Bounds.X ? screen.Bounds.X : parameter.DestinationX;
parameter.DestinationX = parameter.DestinationX > screen.Bounds.Width ? screen.Bounds.Width : parameter.DestinationX;
parameter.DestinationY = parameter.DestinationY < screen.Bounds.Y ? screen.Bounds.Y : parameter.DestinationY;
parameter.DestinationY = parameter.DestinationY > screen.Bounds.Height ? screen.Bounds.Height : parameter.DestinationY;
int width = screen.Bounds.Width;
int height = screen.Bounds.Height;
width = parameter.BlockRegionSize.Width > width ? width : parameter.BlockRegionSize.Width;
height = parameter.BlockRegionSize.Height > height ? height : parameter.BlockRegionSize.Height;
parameter.BlockRegionSize = new System.Drawing.Size(width, height);
}
// 设置录屏文件参数
if (videoParameter == null)
{
throw new Exception("请先设置好‘录制文件保存参数’【videoParameter】!");
}
if (string.IsNullOrEmpty(videoParameter.FileName))
{
throw new Exception("请先设置好‘录制文件的保存路径’!");
}
if (videoParameter.FrameSize == default)
{
videoParameter.FrameSize = new OpenCvSharp.Size(parameter.BlockRegionSize.Width, parameter.BlockRegionSize.Height);
}
_videoWriter = new VideoWriter(videoParameter.FileName, videoParameter.ApiPreference, videoParameter.Fourcc,
videoParameter.Fps, videoParameter.FrameSize, videoParameter.IsColor);
// 录制
Bitmap bitmap = new Bitmap(parameter.BlockRegionSize.Width, parameter.BlockRegionSize.Height);
Graphics g = Graphics.FromImage(bitmap);
cts = new CancellationTokenSource();
Task.Run(() =>
{
while (!cts.Token.IsCancellationRequested)
{
g.CopyFromScreen(parameter.SourceX, parameter.SourceY, parameter.DestinationX, parameter.DestinationY, screen.Bounds.Size);
Mat mat = bitmap.ToMat();
// 托管方法
//TODO
// 保存
_videoWriter.Write(mat);
}
});
}
/// <summary>
/// 录屏-结束
/// </summary>
public static void CaptureScreen_Stop()
{
if (cts != null)
{
cts.Cancel();
Thread.Sleep(1000);
_videoWriter?.Release(); // 关闭写入
_videoWriter?.Dispose();
// 托管方法
//TODO 回调
}
}
/// <summary>
/// 录屏参数
/// </summary>
public class ScreenParameter
{
/// <summary>
/// 截屏位置X
/// </summary>
public int SourceX { get; set; } = 0;
/// <summary>
/// 截屏位置Y
/// </summary>
public int SourceY { get; set; } = 0;
/// <summary>
/// 截屏目标位置X
/// </summary>
public int DestinationX { get; set; } = 0;
/// <summary>
/// 截屏目标位置Y
/// </summary>
public int DestinationY { get; set; } = 0;
/// <summary>
/// 截屏大小
/// </summary>
public System.Drawing.Size BlockRegionSize { get; set; } = default;
}
}
/// <summary>
/// 录屏保存文件参数
/// </summary>
public class VideoParameter
{
/// <summary>
/// 视频文件保存路径
/// </summary>
public string FileName { set; get; } = string.Empty;
/// <summary>
/// API后端
/// </summary>
public VideoCaptureAPIs ApiPreference { set; get; } = VideoCaptureAPIs.ANY;
/// <summary>
/// 编码格式
/// </summary>
public FourCC Fourcc { set; get; } = FourCC.H264;
/// <summary>
/// 帧数
/// </summary>
public double Fps { set; get; } = 30;
/// <summary>
/// 视频分辨率
/// 默认不需要指定
/// </summary>
public OpenCvSharp.Size FrameSize { set; get; } = default;
/// <summary>
/// 是否是彩色图
/// </summary>
public bool IsColor { set; get; } = true;
}
[参考]
C#环境下通过OpenCvSharp实现USB摄像头视频显示及存储
C#环境下通过VLC实现USB摄像头视频显示及存储
留待后查,同时方便他人
联系我:renhanlinbsl@163.com
联系我:renhanlinbsl@163.com
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2018-11-26 使用.net core efcore根据数据库结构自动生成实体类