我遇到WinRT ScreenCapture阻止/冻结我的UI的问题。
我的应用程序在选定的窗口中循环,每隔几秒就对每个窗口进行一次截图。每次截图时,UI动画都会滞后,有时UI会完全冻结,直到我专注于另一个应用程序,该应用程序以某种方式释放UI块。
使用此ScreenCapture存储库作为参考-https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/tree/master/dotnet/WPF/ScreenCapture
为了增加截图功能,我相应地调整了BasicCapture.cs
-
public class BasicCapture : IDisposable
{
...
private Texture2D cpuTexture; // added this
private bool screenshotReady; // added this
public BasicCapture(IDirect3DDevice d, GraphicsCaptureItem i)
{
...
cpuTexture = CreateTexture2D(item.Size.Width, item.Size.Height); // added this
}
public void Dispose()
{
session?.Dispose();
framePool?.Dispose();
swapChain?.Dispose();
d3dDevice?.Dispose();
cpuTexture?.Dispose(); // added this
}
private Texture2D CreateTexture2D(int width, int height)
{
// create add texture2D 2D accessible by the CPU
var desc = new Texture2DDescription()
{
Width = width,
Height = height,
CpuAccessFlags = CpuAccessFlags.Read,
Usage = ResourceUsage.Staging,
Format = Format.B8G8R8A8_UNorm,
ArraySize = 1,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
};
return new Texture2D(d3dDevice, desc);
}
private void OnFrameArrived(Direct3D11CaptureFramePool sender, object args)
{
using (var frame = sender.TryGetNextFrame())
{
...
using (var backBuffer = swapChain.GetBackBuffer<SharpDX.Direct3D11.Texture2D>(0))
using (var bitmap = Direct3D11Helper.CreateSharpDXTexture2D(frame.Surface))
{
d3dDevice.ImmediateContext.CopyResource(bitmap, backBuffer);
if (screenshotReady == false)
{
// added this to copy the DirectX resource into the CPU-readable texture2D
d3dDevice.ImmediateContext.CopyResource(bitmap, cpuTexture);
screenshotReady = true;
}
}
}
}
public async Task<Image> ScreenshotWindow()
{
screenshotReady = false;
StartCapture();
//await for screenshot to be captured
while (screenshotReady == false) await Task.Delay(50);
// get IDirect3DSurface from texture
using var surf = Direct3D11Helper.CreateDirect3DSurfaceFromSharpDXTexture(cpuTexture);
// build a WinRT's SoftwareBitmap from this surface/texture
using var softwareBitmap = await SoftwareBitmap.CreateCopyFromSurfaceAsync(surf);
using var InMemoryStream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, InMemoryStream);
encoder.SetSoftwareBitmap(softwareBitmap);
await encoder.FlushAsync();
using var stream = InMemoryStream.AsStream();
return Image.Load(stream);
}
}
在BasicSampleApplication.cs
中,Iv 'e添加了这个-
public async Task<Image> ScreenshotWindow(GraphicsCaptureItem item)
{
capture = new BasicCapture(device, item);
var surface = capture.CreateSurface(compositor);
brush.Surface = surface;
var img = await capture.ScreenshotWindow();
StopCapture();
return img;
}
由于我实际上不需要在应用程序上可视化地显示捕获的屏幕,因此我示例化BasicSampleApplication
,而不使用任何可视化属性,并且在应用程序启动时执行一次-
// Create the compositor.
compositor = new Compositor();
_screenshotService = new BasicSampleApplication(compositor);
现在剩下的就是遍历选定的Windows并截图-
private async Task ScreenshotSelectedWindows()
{
while (ScreenshotsEnabled)
{
foreach (var wnd in _selectedWindows)
{
GraphicsCaptureItem item = CaptureHelper.CreateItemForWindow(wnd.WindowHandler);
using var img = await _screenshotService.ScreenshotWindow(item);
}
await Task.Delay(TimeSpan.FromSeconds(10));
}
}
现在,当我使用ScreenshotSelectedWindows()
时,它可以工作,但正如我最初所说的那样,它使UI动画滞后,有时UI只是完全冻结,直到我删除焦点。
我试过从后台任务调用这个方法-
Task.Run(()=>ScreenshotSelectedWindows());
由于某些原因,这样做不会起作用,OnFrameArrived
回调永远不会被触发。Iv 'e还尝试在后台线程上示例化BasicSampleApplication
,但在后台线程上创建合成器会抛出错误System.UnauthorizedAccessException: 'Access is denied. '
。
有什么建议可以帮助我在不阻塞/冻结UI的情况下实现截图目标吗?
谢谢!
编辑-我将添加一个指向GitHub问题的链接,因为它似乎特别引用了我的问题,我无法将其转换为我的代码:D
https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/69#issuecomment-1498188216
1条答案
按热度按时间jvidinwx1#
问题解决了
在后台线程上创建合成器需要创建调度器队列-https://github.com/microsoft/CsWinRT/issues/617#issuecomment-740757111
在我的用例中实际上并不需要,因为需要使用-
Direct3D11CaptureFramePool.CreateFreeThreaded
创建帧池,所以在后台线程上没有触发OnFrameArrived
一切都用比我在Github Issue评论中分享的更好的代码示例来解释-
https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/69#issuecomment-1498245106