c# - 如何使用 DirectX 捕获特定进程的视频输出快照?
问题描述
我目前正在使用SharpDX.Direct3D11
NuGet 包来捕获整个屏幕并将其转换为System.Drawing.Bitmap
对象,如下所示:
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using Device = SharpDX.Direct3D11.Device;
using MapFlags = SharpDX.Direct3D11.MapFlags;
using Resource = SharpDX.DXGI.Resource;
public class Direct3D11CaptureSource : SyncDisposable, ICaptureSource
{
public Direct3D11CaptureSource()
{
factory = new Factory1();
adapter = factory.GetAdapter1(0);
device = new Device(adapter);
output = adapter.GetOutput(0);
var desktopBounds = output.Description.DesktopBounds;
width = desktopBounds.Right - desktopBounds.Left;
height = desktopBounds.Bottom - desktopBounds.Top;
output1 = output.QueryInterface<Output1>();
copiedScreenTexture = new Texture2D(device, new Texture2DDescription
{
CpuAccessFlags = CpuAccessFlags.Read,
BindFlags = BindFlags.None,
Format = Format.B8G8R8A8_UNorm,
Width = width,
Height = height,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1,
SampleDescription = { Count = 1, Quality = 0 },
Usage = ResourceUsage.Staging
});
outputDuplication = output1.DuplicateOutput(device);
AcquireNextFrame();
ReleaseFrame();
}
readonly Adapter1 adapter;
readonly Texture2D copiedScreenTexture;
readonly Device device;
readonly Factory1 factory;
readonly int height;
readonly Output output;
readonly Output1 output1;
readonly OutputDuplication outputDuplication;
Resource screenResource;
readonly int width;
void AcquireNextFrame()
{
var result = outputDuplication.TryAcquireNextFrame(10000, out _, out screenResource);
if (result.Failure)
throw new Exception($"{nameof(outputDuplication.TryAcquireNextFrame)} failed");
if (!result.Success)
throw new Exception($"{nameof(outputDuplication.TryAcquireNextFrame)} did not succeed");
}
public Bitmap Capture()
{
try
{
AcquireNextFrame();
using (var screenTexture = screenResource.QueryInterface<Texture2D>())
device.ImmediateContext.CopyResource(screenTexture, copiedScreenTexture);
var map = device.ImmediateContext.MapSubresource(copiedScreenTexture, 0, MapMode.Read, MapFlags.None);
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var bitmapAccess = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
var source = map.DataPointer;
var target = bitmapAccess.Scan0;
for (var y = 0; y < height; ++y)
{
Utilities.CopyMemory(target, source, width * 4);
source = IntPtr.Add(source, map.RowPitch);
target = IntPtr.Add(target, bitmapAccess.Stride);
}
bitmap.UnlockBits(bitmapAccess);
device.ImmediateContext.UnmapSubresource(copiedScreenTexture, 0);
return bitmap;
}
finally
{
ReleaseFrame();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
ReleaseFrame();
outputDuplication.Dispose();
copiedScreenTexture.Dispose();
output1.Dispose();
output.Dispose();
device.Dispose();
adapter.Dispose();
factory.Dispose();
}
}
void ReleaseFrame()
{
screenResource?.Dispose();
screenResource = null;
}
}
我的目标更具体。我试图仅从特定进程(特别是 3D 视频游戏)中捕获快照。我可以用另一种方式使用这个 NuGet 来实现吗?我应该使用其他工具吗?
解决方案
推荐阅读
- php - 使用作曲家包
- reactjs - '(e: MediaQueryListEvent) => void' 类型的参数不可分配给'(e: Event) => void' 类型的参数
- stm32 - STM32 HSE VALUE 缺少二元运算符
- amazon-web-services - AWS CodePipeline 角色无权在阶段的“操作”块中对角色执行 AssumeRole
- r - ggforce geom_arc:如何计算 atan 并在预期的一侧绘制弧线
- go - Gorm如何按结果查找行?
- python - 使用Flask将带有另一个嵌套字典的字典插入mongoDB?
- java - 如果请求未使用 webClient 返回错误,我如何返回 Empty mono
- bash - 如何使用 pbrun 在 shell 脚本中运行命令
- c - 微分方程松弛技术的算法正确性