首页 > 其他分享 >Net中使用快速高性能的DX截图

Net中使用快速高性能的DX截图

时间:2024-12-04 11:44:27浏览次数:3  
标签:截图 return private DX using var new Net public

使用DX获取桌面图像主要有如下5步:

1 获取适配器;

2获取输出;

3创建设备;

4创建复制输出;

5创建图像纹理

使用的组件,Opencv使用mat 进行分辨率转换压缩

 using 指令集合

using System;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using OpenCvSharp;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using Device = SharpDX.Direct3D11.Device;
using MapFlags = SharpDX.Direct3D11.MapFlags;
using Size = System.Drawing.Size;
using ResultCode = SharpDX.DXGI.ResultCode;

详情(注意使用DXGI只能输出RGBA像素格式,以及注意创建适配和释放适配器,对性能的要求TimeOut很重要可根据具体情况调试设置)

1 创建

/// <summary>         /// 捕获图像大小,默认为捕获源大小,建议按原始比例设置         /// </summary>         public Size CaptureSize { get; set; }
        /// <summary>         /// 输出数据像素格式,默认为BGRA32         /// </summary>         public PixelFormat PixelFormat { get; set; } = PixelFormat.Bgra32;
        /// <summary>         /// 捕获超时时间         /// </summary>         public int TimeOut { get; set; } = 100;
        /// <summary>         /// 捕获源类型         /// </summary>         public SourceType SourceType => SourceType.Screen;
        /// <summary>         /// 捕获源大小         /// </summary>         public Size SourceSize { get; }
        // 设备接口表示一个虚拟适配器         private readonly Device _mDevice;
        // 复制输出设备         private readonly OutputDuplication _mDeskDupl;
        //图像纹理         private readonly Texture2D _desktopImageTexture;
        //屏幕大小         private Size _screenSize;
        private CancellationTokenSource _cancellationTokenSource;
        private bool _isManualCaptureStop;         /// <summary>         /// 复制指定监视器的输出         /// </summary>         /// <param name="whichMonitor">要复制的输出设备(即监视器)。以零开始,应于主监视器.</param>         public DxgiCapture(int whichMonitor = 0) : this(0, whichMonitor) { }
        /// <summary>         /// 在指定的显卡适配器上复制指定监视器的输出         /// </summary>         /// <remarks>1获取适配器;2获取输出;3创建设备;4创建复制输出; 5创建图像纹理</remarks>         /// <param name="whichGraphicsCardAdapter">显卡适配器</param>         /// <param name="whichOutputDevice">要复制的输出设备(即监视器)。以零开始,应于主监视器.</param>         public DxgiCapture(int whichGraphicsCardAdapter, int whichOutputDevice)         {             var primaryAdapter = GetPrimaryAdapter(whichGraphicsCardAdapter);             Output primaryOutput = GetOutput(primaryAdapter, whichOutputDevice);
            // 获取输出对象的描述信息             var mOutputDesc = primaryOutput.Description;             _screenSize = new Size             {                 Width = Math.Abs(mOutputDesc.DesktopBounds.Right - mOutputDesc.DesktopBounds.Left),                 Height = Math.Abs(mOutputDesc.DesktopBounds.Bottom - mOutputDesc.DesktopBounds.Top)             };             SourceSize = _screenSize;             CaptureSize = SourceSize;             //创建Direct3D设备             _mDevice = CreateDevice(primaryAdapter);             _mDeskDupl = CreateOutputDuplication(primaryOutput, _mDevice);
            // 创建共享资源             _desktopImageTexture = CreateTexture2D(_mDevice, _screenSize);         }         /// <summary>         /// 根据显卡编号获取适配器         /// </summary>         /// <remarks>获取输出设备(显卡、显示器),这里是主显卡和主显示器</remarks>         /// <param name="whichGraphicsCardAdapter"></param>         /// <returns></returns>         private Adapter1 GetPrimaryAdapter(int whichGraphicsCardAdapter)         {             try             {                 var adapter = new Factory1().GetAdapter1(whichGraphicsCardAdapter);                 return adapter;             }             catch (SharpDXException)             {                 throw new CaptureException("找不到指定的显卡适配器");             }         }
        /// <summary>         /// 根据显示适配器和输出设备获取输出         /// </summary>         /// <param name="adapter">显示适配器</param>         /// <param name="whichOutputDevice">输出设备(监视器)</param>         /// <returns></returns>         private Output GetOutput(Adapter1 adapter, int whichOutputDevice)         {             try             {                 return adapter.GetOutput(whichOutputDevice);             }             catch (SharpDXException)             {                 throw new CaptureException("找不到指定的输出设备");             }         }
        /// <summary>         /// 根据显卡适配器(视频卡)创建设备         /// </summary>         /// <param name="adapter"></param>         /// <returns></returns>         private Device CreateDevice(Adapter1 adapter)         {             return new Device(adapter);             //return new Device(DriverType.Hardware, DeviceCreationFlags.VideoSupport);         }
        /// <summary>         /// 根据输出和设备创建输出Duplication         /// </summary>         /// <param name="output">输出</param>         /// <param name="mDevice">设备</param>         /// <returns></returns>         private OutputDuplication CreateOutputDuplication(Output output, Device mDevice)         {             try             {                 var mDeskDupl = output.QueryInterface<Output1>().DuplicateOutput(mDevice);                 if (mDeskDupl == null)                 {                     throw new CaptureException(" Creates a desktop duplication interface Error");                 }
                return mDeskDupl;             }             catch (SharpDXException ex)             {                 if (ex.ResultCode.Code == ResultCode.NotCurrentlyAvailable.Result.Code)                 {                     throw new CaptureException("使用桌面复制API运行的应用程序已达到最大数量,请关闭其中一个应用程序,然后重试");                 }                 throw new CaptureException(ex.ToString());             }         }
        /// <summary>         /// 创建2D纹理         /// </summary>         /// <remarks>共享资源</remarks>         /// <param name="mDevice"></param>         /// <param name="screenSize"></param>         /// <returns></returns>         private Texture2D CreateTexture2D(Device mDevice, Size screenSize)         {             return new Texture2D(mDevice, new Texture2DDescription             {                 CpuAccessFlags = CpuAccessFlags.Read,                 BindFlags = BindFlags.None,                 Format = Format.B8G8R8A8_UNorm,                 Width = screenSize.Width,                 Height = screenSize.Height,                 OptionFlags = ResourceOptionFlags.None,                 MipLevels = 1,                 ArraySize = 1,                 SampleDescription = { Count = 1, Quality = 0 },                 Usage = ResourceUsage.Staging             });         }       

2 获取

 [HandleProcessCorruptedStateExceptions]
        private CaptureFrame CaptureFrames()
        {
            try
            {
                var width = _desktopImageTexture.Description.Width;
                var height = _desktopImageTexture.Description.Height;
                var data = PixelFormat switch
                {
                    PixelFormat.Bgra32 => new byte[CaptureSize.Width * CaptureSize.Height * 4],
                    PixelFormat.Bgr24 => new byte[CaptureSize.Width * CaptureSize.Height * 3],
                    _ => throw new ArgumentOutOfRangeException(nameof(PixelFormat), PixelFormat, null)
                };

                var result = _mDeskDupl.TryAcquireNextFrame(TimeOut, out _, out var desktopResource);
                if (result.Failure) return null;

                using var tempTexture = desktopResource?.QueryInterface<Texture2D>();
                _mDevice.ImmediateContext.CopyResource(tempTexture, _desktopImageTexture); //拷贝图像纹理:GPU硬件加速的纹理复制
                desktopResource?.Dispose();

                var desktopSource = _mDevice.ImmediateContext.MapSubresource(_desktopImageTexture, 0, MapMode.Read, MapFlags.None);
                using var inputRgbaMat = new Mat(_screenSize.Height, _screenSize.Width, MatType.CV_8UC4, desktopSource.DataPointer);
                if (CaptureSize.Width != _screenSize.Width || CaptureSize.Height != _screenSize.Height)
                {
                    var size = new OpenCvSharp.Size(CaptureSize.Width, CaptureSize.Height);
                    Cv2.Resize(inputRgbaMat, inputRgbaMat, size, interpolation: InterpolationFlags.Linear);
                }

                if (PixelFormat == PixelFormat.Bgr24)
                {
                    using var inputRgbMat = new Mat();
                    Cv2.CvtColor(inputRgbaMat, inputRgbMat, ColorConversionCodes.BGRA2BGR);
                    Marshal.Copy(inputRgbMat.Data, data, 0, data.Length);
                }
                else
                {
                    Marshal.Copy(inputRgbaMat.Data, data, 0, data.Length);
                }

                var captureFrame = new CaptureFrame(CaptureSize, PixelFormat, data);
                _mDevice.ImmediateContext.UnmapSubresource(_desktopImageTexture, 0);
                ReleaseFrame(_mDeskDupl);
                return captureFrame;
            }
            catch (AccessViolationException)
            {
                return null;
            }
            catch (Exception)
            {
                return null;
            }
        }

3 释放

   /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            _mDevice?.Dispose();
            _mDeskDupl?.Dispose();
            _desktopImageTexture?.Dispose();
        }

/// <summary>
        /// 释放帧
        /// </summary>
        /// <param name="mDeskDupl"></param>
        private void ReleaseFrame(OutputDuplication mDeskDupl)
        {
            try
            {
                mDeskDupl.ReleaseFrame();
            }
            catch (SharpDXException ex)
            {
                if (ex.ResultCode.Failure)
                    throw new CaptureException("释放帧失败");
                throw;
            }
        }

4 创建回调获取方式

        /// <summary>
        /// 开始捕获
        /// </summary>
        public void StartCapture(bool startMonitor = true)
        {
            _isManualCaptureStop = false;
            _cancellationTokenSource = new CancellationTokenSource();
            if (!startMonitor) return;
            Task.Run(() =>
            {
                try
                {
                    while (!_cancellationTokenSource.IsCancellationRequested)
                    {
                        var captureFrame = CaptureFrames();
                        if (captureFrame != null)
                        {
                            FrameArrived?.Invoke(this, captureFrame);
                        }
                    }
                }
                catch (Exception)
                {
                    //ignore
                }
                
            }, _cancellationTokenSource.Token);
        }

        /// <summary>
        /// 停止捕获
        /// </summary>
        public void StopCapture()
        {
            _cancellationTokenSource?.Cancel();
            Dispose();
            _isManualCaptureStop = true;
        }

        /// <summary>
        /// 获取下一帧图像
        /// </summary>
        /// <param name="captureFrame"></param>
        /// <returns></returns>
        public bool TryGetNextFrame(out CaptureFrame captureFrame)
        {
            captureFrame = null;

            if (_isManualCaptureStop) return false;
            _cancellationTokenSource?.Cancel();
            
            captureFrame = CaptureFrames();
            return captureFrame != null;
        }

         /// <summary>
        /// 新帧到达事件
        /// </summary>
        public event EventHandler<CaptureFrame> FrameArrived;

 

标签:截图,return,private,DX,using,var,new,Net,public
From: https://www.cnblogs.com/terryK/p/18585945

相关文章

  • B站朝夕教育 【.NET9.0+WPF实战三类流程化业务逻辑控制】学习记录 【四】
    播放地址:20241120-.NET9.0+WPF实战三类流程化业务逻辑控制-10_哔哩哔哩_bilibili第10节通过调整MainViewModel文件代码实现判断拖拽对象并生成对应组件publicpartialclassMainViewModel{publicObservableCollection<NodeModel>ProcessList{get;set;......
  • 使用ModelArts VS Code插件调试训练ResNet50图像分类模型
    应用场景Notebook等线上开发工具工程化开发体验不如IDE,但是本地开发服务器等资源有限,运行和调试环境大多使用团队公共搭建的CPU或GPU服务器,并且是多人共用,这带来一定的环境搭建和维护成本。因此使用本地IDE+远程Notebook结合的方式,可以同时享受IDE工程化开发和云上资源的即开......
  • 全面UI组件库Telerik 2024 Q4全新发布——官方宣布支持.NET 9
    TelerikDevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库,加快开发速度。TelerikDevCraft提供最完整的工具箱,用于构建现代和面向未来的业务应用程序,目前提供UIforASP.NETMVC、KendoUI、UIforASP.NETAJAX、UIforWPF......
  • 全面UI组件库Telerik 2024 Q4全新发布——官方宣布支持.NET 9
    TelerikDevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库,加快开发速度。TelerikDevCraft提供最完整的工具箱,用于构建现代和面向未来的业务应用程序,目前提供UIforASP.NETMVC、KendoUI、UIforASP.NETAJAX、UIforW......
  • DevExtreme JS & ASP.NET Core v24.2新功能预览 - 全新的聊天组件
    DevExtreme拥有高性能的HTML5/JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NETCore,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac,到ASP.NETCore或Vue,DevExtreme包含全面的高性能和响应式UI小部件集合,可在传统Web和下一代移动应用程......
  • 采集倍福PLC 转 profinet IO项目案例
    目录1 案例说明 12 VFBOX网关工作原理 13 准备工作 24 设置倍福PLC 25 配置网关参数采集倍福PLC数据 46 用PROFINETIO协议转发数据 77 案例总结 101 案例说明设置倍福PLC,开通ADS通信设置网关采集倍福PLC数据把采集的数据转成profinetIO从站协议转发给其他系统。2 ......
  • DevExtreme JS & ASP.NET Core v24.2新功能预览 - 全新的聊天组件
    DevExtreme拥有高性能的HTML5/JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NETCore,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac,到ASP.NETCore或Vue,DevExtreme包含全面的高性能和响应式UI小部件集合,可在传统Web和下一代移动应用程序中......
  • B站朝夕教育 【.NET9.0+WPF实战三类流程化业务逻辑控制】学习记录 【二】
    播放地址:20241120-.NET9.0+WPF实战三类流程化业务逻辑控制-10_哔哩哔哩_bilibili第6课使用ViewModel绑定的方式实现拖拽创建MainViewModel.cs文件1publicclassMainViewModel2{3publicObservableCollection<string>ProcessList{get;set;}=n......
  • 骑马与砍杀缺少d3dx9 42.dll怎么办?骑马与砍杀缺少d3dx9 42.dll问题的原因分析与解决策
    d3dx9_42.dll是DirectX9.0c库的一部分,主要用于支持图形处理功能。当您在运行《骑马与砍杀》(Mount&Blade)时遇到缺少d3dx9_42.dll的提示,这意味着您的系统中可能没有正确安装或存在该文件。以下是对这一问题的原因分析和解决策略汇总:原因分析1.DirectX安装不完整:如果......
  • C#(asp.net)研究生考试培训系统-毕业设计源码11751
    摘要近年来,随着研究生考试的竞争日益激烈,越来越多的学生倾向于参加培训课程以提高他们的考试成绩。然而,传统的面对面培训存在时间和地点限制,无法满足学生的灵活学习需求。因此,设计和开发一个基于C#(asp.net)的研究生考试培训系统具有重要意义。该系统旨在为管理员、学生用户......