C# DXGI 截屏

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

Microsoft DirectX 图形基础结构 (DXGI) 处理枚举图形适配器、枚举显示模式、选择缓冲区格式、在进程之间共享资源 (,例如,应用程序与桌面窗口管理器 (DWM) ) 之间,以及向窗口或监视器显示呈现的帧。
本文章,主要是介绍C#使用封装好的 DXGI 采集桌面,比起传统的GDI方式,要强大很多。


一、DXGI

1.微软官方资源(都是C++语言)

点我穿越

2.github示例(都是C++语言)

点我穿越


二、基于github示例封装的dll文件

DesktopDuplication.dll下载
C++能力有限,封装的dll功能和性能都不及原github示例,测试截图正常,有能力的同学可以参考官网和github示例DIY。

三、C#调用DesktopDuplication.dll文件

1.使用流程:

将DesktopDuplication.dll下载到输出文件同级目录下,再把GXDI录屏相关代码复制到你的项目中,直接调用screenShotGXDI()方法即可。

2.封装屏幕采集大致流程:

C#通过线程初始化DesktopDuplication.dll进行屏幕采集再通过委托将DXGI采集的屏幕数据传给C#(多屏幕时通过屏幕号辨别数据是哪块屏幕)

3.C#调用示例:

		#region GXDI录屏相关代码

        public static int dxgifps = 0;
        public delegate void CallbackDelegate(IntPtr Image, int width, int height, int RowPitch, int ScreenNumber);//声明委托
        //接口定义
        [DllImport("DesktopDuplication.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern void SetRegisterFunctionCallback(CallbackDelegate callback);
        public CallbackDelegate callbackDelegate = new CallbackDelegate(CallBackFunction);

        [DllImport("DesktopDuplication.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int Initialize();
        [DllImport("DesktopDuplication.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        private static extern int SetSwitch(int type);
        [DllImport("DesktopDuplication.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool IsSessionLocked();

        [HandleProcessCorruptedStateExceptions]
        public static void CallBackFunction(IntPtr Image, int width, int height, int RowPitch, int ScreenNumber)
        {
#if DEBUG
            //DataView.PublicHandle.log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, ScreenNumber + "同屏数据");
#endif
#if false
            //if (Image == IntPtr.Zero && width == 0 && height == 0)
            //{
            //    SetSwitch(0);
            //    Thread.Sleep(10);
            //    Task task = new Task(() =>
            //    {
            //        Initialize();
            //    });
            //    task.Start();
            //    return;
            //}
#else
if (Image != IntPtr.Zero || width != 0 || height != 0)
            {
            GXGIMonitorTime = 5;//使用五秒检测是否需要重新初始化GXDI,回调判断可能出现睡眠循环调用
}
#endif
            try
            {
                Bitmap bitmap = new Bitmap(width, height, RowPitch, PixelFormat.Format32bppRgb, Image);//通过指针得到指定图片
                Bitmap thumbnailimage = ThumbnailImage(bitmap, 100, 100);//计算缩量图
                BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                #region 屏幕数据处理
                
                #endregion
                bitmap.UnlockBits(bitmapData);//不加此代码内存一直加
                bitmap.Dispose();
            }
            catch (Exception ex)
            {
#if DEBUG
                DataView.PublicHandle.log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, "DXGI CallBackFunction Error:" + ex.Message);
#endif
            }
            Thread.Sleep(20);
        }
        private static int GXGIMonitorTime = 5;//秒为单位
        public ManualResetEvent GXGIMonitorAre = new ManualResetEvent(true);
        private void GXDIMonitorThread()
        {
            while (true)
            {
                Thread.Sleep(1000);
                try
                {
                    GXGIMonitorAre.WaitOne();
                    GXGIMonitorTime--;
                    if (GXGIMonitorTime < 0)//规定时间内没有接受到屏幕数据
                    {
                        if (!IsSessionLocked())
                        {
                            ///系统非锁定状态下
                            SetIfon(0);//结束截屏
                            SetIfon(1);//开始截屏
                            GXGIMonitorTime = 5;
                        }
                        else
                        {
                            keyValuePairs.Clear();
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
        }
        private void screenShotGXDI()
        {
            try
            {
                SetRegisterFunctionCallback(callbackDelegate);

                Task task = new Task(() =>
                {
                    Initialize();
                });
                task.Start();
                Thread thread = new Thread(GXDIMonitorThread);
                thread.Start();
                /单独用一个线程发送队列数据
                //queue = new Queue<Buffer>();
                //Thread thread1 = new Thread(screenImageThreadHandler);
                //thread1.Start();
            }
            catch (Exception ex)
            {
                DataView.PublicHandle.log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, "DXGI Load Error:" + ex.Message);
            }
        }
        Task task;
        public void SetIfon(int type)
        {
            if (type == 0)
            {
                SetSwitch(type);
                if (task != null) task.Dispose();
            }
            else
            {
                task = new Task(() =>
                {
                    try
                    {
                        Initialize();
                    }
                    catch (Exception)
                    {
                    }
                });
                task.Start();
            }
        }
        #endregion

总结

从 Windows 8 开始,微软引入了一套新技术叫 Desktop Duplication API,应用程序可以通过这套 API 请求桌面的图形数据。
优点:由于 Desktop Duplication API 是通过 DirectX Graphics Infrastructure(简称 DXGI)来提供桌面图像的,竞争的是 GPU 流水线资源,所以 CPU 占用率很低,采集性能非常高。
缺点:不支持Windows8前的系统。
参考资料:
【技术分享】Windows桌面端录屏采集实现教程

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值