better-genshin-impact/Fischless.GameCapture/Graphics/GraphicsCapture.cs

124 lines
3.3 KiB
C#
Raw Normal View History

using Fischless.GameCapture.Graphics.Helpers;
using SharpDX.Direct3D11;
using System.Diagnostics;
2023-10-02 18:00:14 +08:00
using Vanara.PInvoke;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
namespace Fischless.GameCapture.Graphics;
2023-10-02 18:00:14 +08:00
public class GraphicsCapture : IGameCapture
2023-10-02 18:00:14 +08:00
{
private nint _hWnd;
private Direct3D11CaptureFramePool _captureFramePool = null!;
private GraphicsCaptureItem _captureItem = null!;
private GraphicsCaptureSession _captureSession = null!;
public bool IsCapturing { get; private set; }
2023-10-08 00:22:01 +08:00
private ResourceRegion? _region;
2023-10-07 19:29:24 +08:00
public void Dispose() => Stop();
2023-10-02 18:00:14 +08:00
public void Start(nint hWnd)
{
_hWnd = hWnd;
2023-10-07 19:29:24 +08:00
_region = GetGameScreenRegion(hWnd);
2023-10-07 19:29:24 +08:00
2023-10-02 18:00:14 +08:00
IsCapturing = true;
_captureItem = CaptureHelper.CreateItemForWindow(_hWnd);
if (_captureItem == null)
{
throw new InvalidOperationException("Failed to create capture item.");
}
_captureItem.Closed += CaptureItemOnClosed;
var device = Direct3D11Helper.CreateDevice();
_captureFramePool = Direct3D11CaptureFramePool.Create(device, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2,
_captureItem.Size);
_captureSession = _captureFramePool.CreateCaptureSession(_captureItem);
_captureSession.IsCursorCaptureEnabled = false;
_captureSession.IsBorderRequired = false;
_captureSession.StartCapture();
IsCapturing = true;
}
/// <summary>
/// 从 DwmGetWindowAttribute 的矩形 截取出 GetClientRect的矩形游戏区域
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
2023-10-08 00:22:01 +08:00
private ResourceRegion? GetGameScreenRegion(nint hWnd)
2023-10-07 19:29:24 +08:00
{
2023-10-08 00:22:01 +08:00
var exStyle = User32.GetWindowLong(hWnd, User32.WindowLongFlags.GWL_EXSTYLE);
if ((exStyle & (int)User32.WindowStylesEx.WS_EX_TOPMOST) != 0)
{
return null;
}
2023-10-07 19:29:24 +08:00
ResourceRegion region = new();
DwmApi.DwmGetWindowAttribute<RECT>(hWnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out var windowRect);
User32.GetClientRect(_hWnd, out var clientRect);
//POINT point = default; // 这个点和 DwmGetWindowAttribute 结果差1
//User32.ClientToScreen(hWnd, ref point);
region.Left = 0;
region.Top = windowRect.Height - clientRect.Height;
region.Right = clientRect.Width;
region.Bottom = windowRect.Height;
region.Front = 0;
region.Back = 1;
return region;
}
2023-10-02 18:00:14 +08:00
public Bitmap? Capture()
{
if (_hWnd == IntPtr.Zero)
{
return null;
}
try
{
using var frame = _captureFramePool?.TryGetNextFrame();
if (frame == null)
{
return null;
}
2023-10-07 19:29:24 +08:00
return frame.ToBitmap(_region);
2023-10-02 18:00:14 +08:00
}
catch (Exception e)
{
Debug.WriteLine(e);
}
2023-10-07 19:29:24 +08:00
2023-10-02 18:00:14 +08:00
return null;
}
public void Stop()
{
_captureSession?.Dispose();
_captureFramePool?.Dispose();
_captureSession = null!;
_captureFramePool = null!;
_captureItem = null!;
_hWnd = IntPtr.Zero;
IsCapturing = false;
}
private void CaptureItemOnClosed(GraphicsCaptureItem sender, object args)
{
Stop();
}
2023-10-07 19:29:24 +08:00
}