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是能做到很好的多进程渲染的,也就是用这个技术获取其他窗口的渲染界面,其他窗口可以在其他渲染架构的进程运行,然后转发用户输入消息,这样就能做到解决空域的多进程渲染
我搭建了自己的博客 https://blog.lindexi.com/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新
如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
win10 uwp 录制任意应用屏幕的更多相关文章
- win10怎么录制电脑屏幕 电脑播放视频录制
随着社会的发展,网络信息化时代已经来临,作为一个上班族,每天都离不开电脑,电脑仿佛就是我们的合作伙伴,也是陪伴我们的朋友,如今win10系统已经出来了,关于win10系统的问题相信大家有很多的问题,今 ...
- Win10 UWP开发系列:实现Master/Detail布局
在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档: ...
- win10 uwp DataContext
本文告诉大家DataContext的多种绑法. 适合于WPF的绑定和UWP的绑定. 我告诉大家很多个方法,所有的方法都有自己的优点和缺点,可以依靠自己喜欢的用法使用.当然,可以在新手面前秀下,一个页面 ...
- win10 uwp 读取保存WriteableBitmap 、BitmapImage
我们在UWP,经常使用的图片,数据结构就是 BitmapImage 和 WriteableBitmap.关于 BitmapImage 和 WriteableBitmap 区别,我就不在这里说.主要说的 ...
- win10 uwp 入门
UWP是什么我在这里就不说,本文主要是介绍如何入门UWP,也是合并我写的博客. 关于UWP介绍可以参见:http://lib.csdn.net/article/csharp/32451 首先需要申请一 ...
- win10 uwp 商业游戏 1.2.1
上一个游戏已经告诉大家如何写多个游戏,现在继续写这个无聊的游戏 希望大家在看这篇文章之前先看win10 uwp 商业游戏,在这个文章告诉了大家如何创建游戏. 修改数值 可以从上一篇的博客的游戏看到升级 ...
- win10 uwp ApplicationView
原文:win10 uwp ApplicationView 本文和大家介绍一个重要的类,他可以用来设置窗口,如设置启动大小,设置是否允许截图,是否进入全屏,所有和窗口有关的,都可以在他这里设置. 可以使 ...
- win10 uwp 使用 Border 布局
在 UWP 写一个界面需要将元素排列,在排列元素的时候有特殊的元素叫容器.容器的意思是元素里面包含元素,在 UWP 用到的容器有很多,也可以自己写一个.简单的容器是 Border 边框控件,如控件说的 ...
- Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App
安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...
随机推荐
- python已安装包的查看方法和requirements.text的使用
1.已经安装包的查看方法 命令pip freeze 2. 批量导出命令 pip freeze >requirements.txt 3. 批量导入命令 pip install -r requir ...
- Java排序需掌握算法 详解
package com.sxt.review; /*内部排序:(在内存) * 插入排序-->希尔排序 * 冒泡排序-->快速排序 * 选择排序-->堆排序 * 归并排序 * 基数排序 ...
- FinalShell for Mac
Mac一键安装脚本 curl -o finalshell_install.sh www.hostbuf.com/downloads/finalshell_install.sh;chmod +x fin ...
- CENTOS7安装R语言环境
CENTOS7安装R语言环境 yum install texinfo.x86_64 yum install texlive.x86_64 cd /opt wget https://mirrors.tu ...
- 5.0.1版本的react-router-dom路由传参以及路由表的配置和接收页面的接受
//第一种 通过问号传参 //发送 this.props.history.push("/detail?id="+item.downurl) //路由表配置 <Route pa ...
- D - Denouncing Mafia DFS
这道题其实很简单,求k个到根的链,使得链上的节点的个数尽可能多,如果节点被计算过了,就不能再被计算了,其实我们发现,只要k>=叶子节点,那么肯定是全部,所以我们考虑所有的叶子节点,DFS到根节点 ...
- 洛谷P1807 最长路_NOI导刊2010提高(07)
//拓扑排序求最长路 #include<bits/stdc++.h> #include<queue> using namespace std; const int INF=0x ...
- SpringBoot 获取properties配置文件的属性
自定义properties文件获取属性 使用 @ConfigurationProperties((prefix = "demo")) 和 @PropertySource(" ...
- iptables智能DNS
1. echo 1 > /proc/sys/net/ipv4/ip_forward 2. 在NAT服务器上添加以下规则: 在PREROUTING链中添加目的地址转换规则: iptables -t ...
- 割点(tarjan)
对于根来说,如果它有超过1棵子树,那么它是一个割点 对于非叶结点来说,如果它的某一个儿子没有回边能到达高于它的点,那么它是一个割点 叶节点不是割点 //洛谷3388 #include<algor ...