title author date CreateTime categories
win10 uwp 录制任意应用屏幕
lindexi
2019-10-31 09:10:38 +0800
2019-10-12 20:19:40 +0800
Win10 UWP

在 1803 可以使用 Windows.Graphics.Capture 捕获屏幕,可以用来录制应用的窗口

通过 CompositionAPI 和 win2d 可以作为 D3D 绘制,通过 Direct3D11CaptureFramePool 可以拿到其他应用的界面渲染图,这样就可以完成拿到其他窗口绘制在这个窗口内

用这个方法录屏的性能超级高,一个空的应用只做录屏占用内存只有 30M 左右,占用 CPU 几乎可以忽略,同时也不占用GPU资源,这是在底层做的优化。我猜是从显卡拿到渲染的图片的句柄,然后在win2d渲染只是复制句柄通过 DWM 渲染图层。这个方式的渲染速度基本就是跑满,同时占用资源如下图

下面请让我告诉大家如何使用

通过 GraphicsCapturePicker 可以让用户选取录制哪个应用,在开始之前需要申请权限。双击 Package.appxmanifest 文件,勾选图形捕获,请看下图

此时写一个简单的函数用来让用户选择捕获的应用

        public async Task StartCaptureAsync()
{
// 让用户选择哪个应用
var picker = new GraphicsCapturePicker();
GraphicsCaptureItem item = await picker.PickSingleItemAsync(); // 如果用户有选择一个应用那么这个属性不为空
if (item != null)
{
// 忽略代码
}
}

尝试在应用加载完成调用这个方法或在按钮调用这个方法,调用这个方法将会看到下面图片

当然在你的设备上应该看到的不是这个界面,因为你打开的应用应该和我不一样

现在需要初始化 CompositionAPI 和 win2d 的资源

请写一个方法 Setup 将会在这个方法里面写初始化

        private void Setup()
{
// 忽略代码
}

先定义两个字段,包括 CanvasDevice 和对应的图层,将会在创建资源的时候用到设备,在刷新界面的使用用到图层

        private CanvasDevice _canvasDevice;
private CompositionDrawingSurface _surface;

先从当前的窗口创建混合设备

            _canvasDevice = new CanvasDevice();

            var compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(
Window.Current.Compositor,
_canvasDevice); var compositor = Window.Current.Compositor;

创建图层,注意现在的图层能使用的参数如下

            _surface = compositionGraphicsDevice.CreateDrawingSurface(
new Size(1000, 600),
DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);

这里的 Size 可以任意修改,但是像素格式就不能修改

通过 CompositionAPI 创建精灵元素,将图层在精灵元素上显示,然后插入到当前控件作为最后一个图层也就是放在最上层元素

            var visual = compositor.CreateSpriteVisual();
visual.RelativeSizeAdjustment = Vector2.One;
var brush = compositor.CreateSurfaceBrush(_surface);
brush.Stretch = CompositionStretch.Uniform;
visual.Brush = brush;
ElementCompositionPreview.SetElementChildVisual(this, visual);

现在就初始化完成了

在刚才写的方法可以获取到 GraphicsCaptureItem 对象,接下面创建方法从拿到的 GraphicsCaptureItem 获取界面

在 Direct3D11CaptureFramePool.Create 静态方法可以创建 Direct3D11CaptureFramePool 属性,这个属性就是捕获窗口或屏幕的核心

在 Direct3D11CaptureFramePool 有一个事件是 FrameArrived 这个事件将会在捕获的界面刷新的时候触发,可以在这个事件触发的时候从参数拿到当前的界面图片,绘制在win2d图层

还有一个方法是 CreateCaptureSession 可以用来返回捕获会话,请看下面代码

            // 下面参数暂时不能修改
Direct3D11CaptureFramePool framePool = Direct3D11CaptureFramePool.Create(
_canvasDevice, // D3D device
DirectXPixelFormat.B8G8R8A8UIntNormalized, // Pixel format
// 要在其中存储捕获的框架的缓冲区数量
1,
// 每个缓冲区大小
item.Size); // Size of the buffers // 界面刷新的时候将会触发这个事件
framePool.FrameArrived += (s, a) =>
{
// 忽略代码
}; var captureSession = framePool.CreateCaptureSession(item);
captureSession.StartCapture();

captureSession.StartCapture 方法将会开始捕获传入的 item 界面,这里的 item 是 GraphicsCaptureItem 类,可以传入某个应用的窗口,也可以传入整个屏幕,也就是在上面代码让用户选的内容

framePool.FrameArrived 事件将会传入刷新的图片,此时的图片是 Direct3D11CaptureFrame 还不能在 win2d 渲染,需要使用 CanvasBitmap.CreateFromDirect3D11Surface 转换

           framePool.FrameArrived += (s, a) =>
{
using (var frame = framePool.TryGetNextFrame())
{
try
{
// 将获取到的 Direct3D11CaptureFrame 转 win2d 的
CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
_canvasDevice,
frame.Surface); // 忽略代码
}
catch
{ }
}
}

因为可能此时的窗口的大小修改了,所以需要执行修改当前的图层的大小

                        CanvasComposition.Resize(_surface, canvasBitmap.Size);

在获取到 CanvasBitmap 就可以使用 win2d 绘制到图层上,这样就完成了绘制其他窗口

                        using (var session = CanvasComposition.CreateDrawingSession(_surface))
{
session.Clear(Colors.Transparent);
session.DrawImage(canvasBitmap);
}

本文的代码放在 github 欢迎下载

相对于官方的源代码,我删了很多不是核心的细节代码,所以上面的代码只能在测试使用

如果你发现录到一半界面冻结了,也就是不刷新了,那么可能是你的 GraphicsCaptureSession 或 Direct3D11CaptureFramePool 类被回收了,在界面冻结的时候看调试工具是否有显示GC如果有,那么就是对象被回收了,解决方法是定义一些字段,将这些变量放在字段

如何调试内存请看 dotnet 代码调试方法

另外还有 robmikh 大神写的例子,请看 robmikh/SimpleRecorder: A simple screen recorder using both the Windows.Graphics.Capture and Windows.Media.Transcoding APIs.

在看到这个技术,我就想到了也许UWP是能做到很好的多进程渲染的,也就是用这个技术获取其他窗口的渲染界面,其他窗口可以在其他渲染架构的进程运行,然后转发用户输入消息,这样就能做到解决空域的多进程渲染

2019-10-31-win10-uwp-录制任意应用屏幕的更多相关文章

  1. win10 uwp 录制任意应用屏幕

    在 1803 可以使用 Windows.Graphics.Capture 捕获屏幕,可以用来录制应用的窗口 通过 CompositionAPI 和 win2d 可以作为 D3D 绘制,通过 Direc ...

  2. lyc——2019.10.31

    10:判决素数个数 总时间限制: 1000ms 内存限制: 65536kB 描述 输入两个整数X和Y,输出两者之间的素数个数(包括X和Y). 输入 两个整数X和Y(1 <= X,Y <= ...

  3. 牛客CSP-S提高组赛前集训营2 ———— 2019.10.31

    比赛链接 期望得分:100+20+20 实际得分:40+20+30 awa  cccc T1 :基于贪心的思路,然后开始爆搜(雾 那必然是会死的,好吧他就是死了 #include<iostrea ...

  4. win10 uwp 商业游戏 1.2.1

    上一个游戏已经告诉大家如何写多个游戏,现在继续写这个无聊的游戏 希望大家在看这篇文章之前先看win10 uwp 商业游戏,在这个文章告诉了大家如何创建游戏. 修改数值 可以从上一篇的博客的游戏看到升级 ...

  5. win10 uwp 毛玻璃

    毛玻璃在UWP很简单,不会和WPF那样伤性能. 本文告诉大家,如何在 UWP 使用 win2d 做毛玻璃. 毛玻璃可以使用 win2D 方法,也可以使用 Compositor . 使用 win2d 得 ...

  6. win10 uwp 读取保存WriteableBitmap 、BitmapImage

    我们在UWP,经常使用的图片,数据结构就是 BitmapImage 和 WriteableBitmap.关于 BitmapImage 和 WriteableBitmap 区别,我就不在这里说.主要说的 ...

  7. win10 uwp 手把手教你使用 asp dotnet core 做 cs 程序

    本文是一个非常简单的博客,让大家知道如何使用 asp dot net core 做后台,使用 UWP 或 WPF 等做前台. 本文因为没有什么业务,也不想做管理系统,所以看到起来是很简单. Visua ...

  8. Win10 UWP开发实现Bing翻译

    微软在WP上的发展从原来的Win7到Win8,Win8.1,到现在的Win10 UWP,什么是UWP,UWP即Windows 10 中的Universal Windows Platform简称.即Wi ...

  9. Win10/UWP开发—使用Cortana语音与App后台Service交互

    上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比 ...

  10. 【Win10 UWP】后台任务与动态磁贴

    动态磁贴(Live Tile)是WP系统的大亮点之一,一直以来受到广大用户的喜爱.这一讲主要研究如何在UWP应用里通过后台任务添加和使用动态磁贴功能. 从WP7到Win8,再到Win10 UWP,磁贴 ...

随机推荐

  1. HDU 2045:不容易系列之(3)—— LELE的RPG难题(动态规划)

    一.原题链接 Problem - 2045 (hdu.edu.cn) 二.题面 人称"AC女之杀手"的超级偶像LELE最近忽然玩起了深沉,这可急坏了众多"Cole&quo ...

  2. C# AES CBC模式 加密和解密

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.S ...

  3. KingbaseES V8R6集群运维案例之---sys_monitor.sh start启动动态库错误

    案例说明: 在KingbaseES V8R6集群部署了postgis后,执行sys_monitor.sh start启动集群时,出现动态库错误,如下图所示: 适用版本: KingbaseES V8R6 ...

  4. KingbaseES V8R3集群部署案例之---通用机无ssh环境脚本部署集群

    案例说明: 在一些通用机的生产环境,不允许主机之间通过ssh通讯,或者不允许root用户建立ssh互信或登录.默认KingbaseES V8R3集群通用机环境部署需要建立数据库用户及root用户,在集 ...

  5. (Nosql)列式存储是什么?

    首先nosql可以被理解为not only sql 泛指非关系型数据库,也就是说不仅仅是sql,所以它既包含了sql的一些东西,但是又和sql不同,并在其的基础上改变或者说扩展了一些东西. 提到nos ...

  6. 【Java基础知识】东软面试(一面)

    01 面向对象的特征 封装:隐藏部分对象的属性和实现细节,以不同的访问级别来保护对象内部的数据,防止外部程序的不当访问,对外提供公开的接口.[私有的属性,共有的方法] 继承:子类自动共享父类数据和方法 ...

  7. 数据库知识 DDL/DML/DCL

    DDL DDL的概述 DDL(Data Definition Language 数据定义语言)用于操作对象和对象的属性,这种对象包括数据库本身,以及数据库对象,像:表.视图等等,DDL对这些对象和属性 ...

  8. #扫描线,并查集,切比雪夫距离#洛谷 5193 [TJOI2012]炸弹

    题目 在平面上有 \(n\) 个炸弹 \([1 \ldots n]\) , 每个炸弹的爆炸范围是 \(|x-x_i|+|y-yi| \leq R\) 如果某个炸弹爆炸了,那么它将引燃它范围内的所有炸弹 ...

  9. #SG函数#HDU 1848 Fibonacci again and again

    题目 分析 可取状态只能是斐波那契数,求出SG函数 然后判断三个数sg函数异或和不为0先手必胜 代码 #include <cstdio> #include <cctype> # ...

  10. OpenHarmony Meetup 2023北京站圆满举办

      "OpenHarmony正当时"OpenHarmony Meetup 2023城市巡回活动,旨在通过meetup线下交流形式,解读OpenHarmony作为下一代智能终端操作系 ...