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摄像头视频显示及存储

posted @   Hey,Coder!  阅读(155)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2018-11-26 使用.net core efcore根据数据库结构自动生成实体类
点击右上角即可分享
微信分享提示