如何使用DirectX捕获特定过程的视频输出的快照?

时间:2019-06-12 18:59:14

标签: 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来实现这一目标吗?我应该使用其他工具吗?

0 个答案:

没有答案