Skip to content

Commit

Permalink
重构 WGC截图,截图模型 注意:Dx11兼容性未知
Browse files Browse the repository at this point in the history
  • Loading branch information
MakesYT committed Jan 2, 2025
1 parent fc81a40 commit 918c73e
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 126 deletions.
50 changes: 45 additions & 5 deletions Core.Window/ScreenCapture/CaptureTool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using PluginCore;
using Windows.Graphics;
using PluginCore;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;

Expand All @@ -9,13 +10,13 @@ public static class CaptureTool
public static unsafe byte[] GetBytesSpan(MappedSubresource mappedSubresource, OutputDesc1 outputDesc,ref ScreenCaptureInfo screenCaptureInfo)
{
var sizeX = outputDesc.DesktopCoordinates.Size.X;
int startX = Math.Clamp(screenCaptureInfo.X, 0, sizeX - 1);
int startX = Math.Clamp(screenCaptureInfo.X, 0, outputDesc.DesktopCoordinates.Size.X - 1);
int startY = Math.Clamp(screenCaptureInfo.Y, 0, outputDesc.DesktopCoordinates.Size.Y - 1);
int endX = Math.Clamp(screenCaptureInfo.X + screenCaptureInfo.Width, 0, sizeX);
int endY = Math.Clamp(screenCaptureInfo.Y + screenCaptureInfo.Height, 0, outputDesc.DesktopCoordinates.Size.Y);
int endX = Math.Clamp(screenCaptureInfo.Width, 0, outputDesc.DesktopCoordinates.Size.X);
int endY = Math.Clamp(screenCaptureInfo.Height, 0, outputDesc.DesktopCoordinates.Size.Y);
screenCaptureInfo.Height = endY - startY;
screenCaptureInfo.Width = endX - startX;
screenCaptureInfo.X = startX;
screenCaptureInfo.X = startX;
screenCaptureInfo.Y = startY;
// 结果数组:区域宽 * 区域高 * 4(RGBA)
int regionWidth = endX - startX;
Expand Down Expand Up @@ -97,4 +98,43 @@ public static unsafe byte[] GetBytesSpan(MappedSubresource mappedSubresource, Ou

return result;
}
public static unsafe byte[] GetBytesSpan(MappedSubresource mappedSubresource,SizeInt32 size,ref ScreenCaptureInfo screenCaptureInfo)
{
var sizeX = size.Width;
int startX = Math.Clamp(screenCaptureInfo.X, 0, size.Width - 1);
int startY = Math.Clamp(screenCaptureInfo.Y, 0, size.Height - 1);
int endX = Math.Clamp(screenCaptureInfo.X+screenCaptureInfo.Width, 0,size.Width);
int endY = Math.Clamp(screenCaptureInfo.Y+screenCaptureInfo.Height, 0,size.Height);
screenCaptureInfo.Height = endY - startY;
screenCaptureInfo.Width = endX - startX;
screenCaptureInfo.X = startX;
screenCaptureInfo.Y = startY;
// 结果数组:区域宽 * 区域高 * 4(RGBA)
int regionWidth = endX - startX;
int regionHeight = endY - startY;
byte[] result = new byte[regionWidth * regionHeight * 4];
{
var span = new ReadOnlySpan<uint>(mappedSubresource.PData,
(int)mappedSubresource.DepthPitch / 4);

for (int y = startY; y < endY; y++)
{
for (int x = startX; x < endX; x++)
{
int sourceIndex = (y * sizeX + x) * 4;
int targetIndex = ((y - startY) * regionWidth + (x - startX)) * 4;

// 读取原始像素并复制到结果
uint value = span[sourceIndex / 4];
result[targetIndex+ 2] = (byte)(value & 0xFF); // R
result[targetIndex + 1] = (byte)((value >> 8) & 0xFF); // G
result[targetIndex ] = (byte)((value >> 16) & 0xFF); // B
result[targetIndex + 3] = (byte)((value >> 24) & 0xFF); // A
}
}

span = null;
}
return result;
}
}
1 change: 0 additions & 1 deletion Core.Window/ScreenCapture/ScreenCaptureByDx11.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ public List<ScreenCaptureInfo> GetAllScreenInfo()
if (output->GetDesc(ref desc) != 0) throw new Exception("Failed to get output description");
screenCaptureInfos.Add(new ScreenCaptureInfo()
{
Index = i,
Height = desc.DesktopCoordinates.Size.Y,
Width = desc.DesktopCoordinates.Size.X,
X = desc.DesktopCoordinates.Min.X,
Expand Down
78 changes: 31 additions & 47 deletions Core.Window/ScreenCapture/ScreenCaptureByWGC.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Graphics;
using Windows.Graphics.Capture;
using Avalonia;
using Avalonia.Media.Imaging;
Expand Down Expand Up @@ -28,17 +29,26 @@ public List<ScreenCaptureInfo> GetAllScreenInfo()
{
screenCaptureInfos.Add(new ScreenCaptureInfo()
{
Index = i,
X = arg3.left,
Y = arg3.top,

X = 0,
Y = 0,
Width = arg3.right - arg3.left,
Height = arg3.bottom - arg3.top,
hMonitor = arg2,
hdcMonitor = arg4
ScreenInfo = new ScreenInfo()
{
X = arg3.left,
Y = arg3.top,
Width = arg3.right - arg3.left,
Height = arg3.bottom - arg3.top,
hMonitor = arg1,
hdcMonitor = arg2
}

});
i++;
return true;
}, IntPtr.Zero);

return screenCaptureInfos;
}

Expand Down Expand Up @@ -140,14 +150,14 @@ public ScreenCaptureResult CaptureScreenBitmap(ScreenCaptureResult captureAllScr

captureAllScreenInfo.Bytes = null;
captureAllScreenInfo.Source = writeableBitmap;
return (captureAllScreenInfo);
return captureAllScreenInfo;
}

public unsafe ScreenCaptureResult CaptureScreenBytes(ScreenCaptureInfo screenCaptureInfo)
{
var factory2 = ActivationFactory.Get(typeof(GraphicsCaptureItem).FullName);
var interop = factory2.AsInterface<IGraphicsCaptureItemInterop>();
var itemPointer = interop.CreateForMonitor(screenCaptureInfo.hMonitor, GraphicsCaptureItemGuid);
var itemPointer = interop.CreateForMonitor(screenCaptureInfo.ScreenInfo.hMonitor, GraphicsCaptureItemGuid);
var item = MarshalInterface<GraphicsCaptureItem>.FromAbi(itemPointer);
var dxgi = new DXGI(new DefaultNativeContext("dxgi"));

Expand All @@ -156,18 +166,14 @@ public unsafe ScreenCaptureResult CaptureScreenBytes(ScreenCaptureInfo screenCap
ID3D11DeviceContext* immediateContext = null;
ID3D11Device* d3dDevice = null;
ComPtr<ID3D11Resource> stagingResource = null;
IDXGIOutput* output = null;
ComPtr<IDXGIOutput6> output6 = null;
Direct3D11CaptureFrame direct3D11CaptureFrame = null;
ID3D11Texture2D* stagingTexture = null;
GraphicsCaptureSession session = null;
Direct3D11CaptureFramePool framePool = null;
var d3D11 = new D3D11(new DefaultNativeContext("d3d11"));
using var d3D11 = new D3D11(new DefaultNativeContext("d3d11"));
try
{
using var factory = dxgi.CreateDXGIFactory1<IDXGIFactory1>();


if (factory.EnumAdapters1(0, ref adapter1) != 0) throw new Exception("Failed to create DXGI adapter");
var featureLevel = D3DFeatureLevel.Level110;
D3DFeatureLevel[] featureLevels =
Expand Down Expand Up @@ -206,43 +212,32 @@ IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(ID3D11Device* d3dDevice)
}

var direct3DDeviceFromSharpDxDevice = CreateDirect3DDeviceFromSharpDXDevice(d3dDevice);


adapter1->EnumOutputs(screenCaptureInfo.Index, ref output);
if (output->QueryInterface<IDXGIOutput6>(out output6) != 0)
throw new Exception("Failed to get IDXGIOutput6");
var outputDesc = new OutputDesc1();
if (output6.GetDesc1(ref outputDesc) != 0) throw new Exception("Failed to get Desc1");

framePool = Direct3D11CaptureFramePool.Create(
direct3DDeviceFromSharpDxDevice,
outputDesc.ColorSpace.ToString().EndsWith("2020")
? DirectXPixelFormat.R16G16B16A16Float
: DirectXPixelFormat.R8G8B8A8UIntNormalized,
DirectXPixelFormat.R8G8B8A8UIntNormalized,
2,
item.Size);
item.Size);

session = framePool.CreateCaptureSession(item);

session.IsCursorCaptureEnabled = false;
session.StartCapture( );


while ((direct3D11CaptureFrame = framePool.TryGetNextFrame()) == null)
{
}

using var bitmap = CreateSharpDXTexture2D(direct3D11CaptureFrame.Surface);

var mappedSubresource = new MappedSubresource();

Texture2DDesc stagingTextureDesc = new()
{
CPUAccessFlags = (uint)CpuAccessFlag.Read,
BindFlags = (uint)BindFlag.None,
Format = outputDesc.ColorSpace.ToString().EndsWith("2020")
? Format.FormatR16G16B16A16Float
: Format.FormatR8G8B8A8Unorm,
Width = (uint)direct3D11CaptureFrame.ContentSize.Width,
Height = (uint)direct3D11CaptureFrame.ContentSize.Height,
Format = Format.FormatR8G8B8A8Unorm,
Width = (uint)item.Size.Width,
Height = (uint)item.Size.Height,
MiscFlags = (uint)ResourceMiscFlag.None,
MipLevels = 1,
ArraySize = 1,
Expand All @@ -257,9 +252,8 @@ IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(ID3D11Device* d3dDevice)
immediateContext->CopyResource(stagingResource, bitmap);
if (immediateContext->Map(stagingResource, 0, Map.Read, 0, &mappedSubresource) != 0)
throw new Exception("Failed to map staging texture");


var bytesSpan = CaptureTool.GetBytesSpan(mappedSubresource, outputDesc,ref screenCaptureInfo);
var bytesSpan = CaptureTool.GetBytesSpan(mappedSubresource, item.Size,ref screenCaptureInfo);

return new ScreenCaptureResult()
{
Info = screenCaptureInfo,
Expand All @@ -268,6 +262,7 @@ IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(ID3D11Device* d3dDevice)
}
finally
{

if (adapter1 != null)
{
adapter1->Release();
Expand Down Expand Up @@ -295,19 +290,7 @@ IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(ID3D11Device* d3dDevice)

stagingResource.Release();
stagingResource = null;


if (output != null)
{
output->Release();
output = null;
}


output6.Release();
output6 = null;



if (direct3D11CaptureFrame != null)
{
direct3D11CaptureFrame.Dispose();
Expand All @@ -328,6 +311,7 @@ IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(ID3D11Device* d3dDevice)

if (session != null)
{

session.Dispose();
session = null;
}
Expand Down
17 changes: 8 additions & 9 deletions KitopiaAvalonia/Windows/ScreenCaptureWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public ScreenCaptureWindow(ScreenCaptureInfo screenCaptureInfo)
{
InitializeComponent();
_screenCaptureInfo = screenCaptureInfo;
Position = new PixelPoint(screenCaptureInfo.X, screenCaptureInfo.Y);
Position = new PixelPoint(screenCaptureInfo.ScreenInfo.X, screenCaptureInfo.ScreenInfo.Y);
WindowState = WindowState.FullScreen;
SystemDecorations = SystemDecorations.None;
Background = new SolidColorBrush(Colors.Black);
Expand Down Expand Up @@ -81,6 +81,7 @@ public ScreenCaptureWindow(ScreenCaptureInfo screenCaptureInfo)

Close();
WeakReferenceMessenger.Default.Unregister<string>(this);
GC.Collect(2,GCCollectionMode.Aggressive,true);
break;
}
case "Selected":
Expand Down Expand Up @@ -812,13 +813,12 @@ private void FinnishCapture()
{
selectModeAction.Invoke(new ScreenCaptureInfo()
{
Index = _screenCaptureInfo.Index,
hdcMonitor = _screenCaptureInfo.hdcMonitor,
hMonitor = _screenCaptureInfo.hMonitor,

X = Math.Max((int)dragTransformX, 0),
Y = Math.Max((int)dragTransformY, 0),
Width = cropW,
Height = cropH
Height = cropH,
ScreenInfo = _screenCaptureInfo.ScreenInfo
});
} else{
foreach (var canvasChild in Canvas.Children)
Expand Down Expand Up @@ -865,13 +865,12 @@ private void FinnishCapture()
{
Info = new ScreenCaptureInfo()
{
Index = _screenCaptureInfo.Index,
hdcMonitor = _screenCaptureInfo.hdcMonitor,
hMonitor = _screenCaptureInfo.hMonitor,

X = Math.Max((int)dragTransformX, 0),
Y = Math.Max((int)dragTransformY, 0),
Width = cropW,
Height = cropH
Height = cropH,
ScreenInfo = _screenCaptureInfo.ScreenInfo
},
Bytes = d
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ public string Serialize<T>(T value)
{
return "";
}
return $"{nameof(screenCaptureInfo.Index)}={screenCaptureInfo.Index},{nameof(screenCaptureInfo.hMonitor)}={(uint)screenCaptureInfo.hMonitor},{nameof(screenCaptureInfo.hdcMonitor)}={(uint)screenCaptureInfo.hdcMonitor},{nameof(screenCaptureInfo.X)}={screenCaptureInfo.X},{nameof(screenCaptureInfo.Y)}={screenCaptureInfo.Y},{nameof(screenCaptureInfo.Width)}={screenCaptureInfo.Width},{nameof(screenCaptureInfo.Height)}={screenCaptureInfo.Height}";
return $"ScreenInfo.X={screenCaptureInfo.ScreenInfo.X},ScreenInfo.Y={screenCaptureInfo.ScreenInfo.Y},ScreenInfo.Height={screenCaptureInfo.ScreenInfo.Height},ScreenInfo.Width={screenCaptureInfo.ScreenInfo.Width},ScreenInfo.hdcMonitor={screenCaptureInfo.ScreenInfo.hdcMonitor},ScreenInfo.hMonitor={screenCaptureInfo.ScreenInfo.hMonitor},{nameof(screenCaptureInfo.X)}={screenCaptureInfo.X},{nameof(screenCaptureInfo.Y)}={screenCaptureInfo.Y},{nameof(screenCaptureInfo.Width)}={screenCaptureInfo.Width},{nameof(screenCaptureInfo.Height)}={screenCaptureInfo.Height}";
}

public object Deserialize(ReadOnlySpan<byte> value)
{
var str = Encoding.UTF8.GetString(value);

var split = str.Split(',');
if (split.Length != 7)
if (split.Length != 10)
{
return null;
}
Expand All @@ -35,9 +35,15 @@ public object Deserialize(ReadOnlySpan<byte> value)
}
var screenCaptureInfo = new ScreenCaptureInfo
{
Index = uint.Parse(dic[nameof(ScreenCaptureInfo.Index)]),
hMonitor = (IntPtr)uint.Parse(dic[nameof(ScreenCaptureInfo.hMonitor)]),
hdcMonitor = (IntPtr)uint.Parse(dic[nameof(ScreenCaptureInfo.hdcMonitor)]),
ScreenInfo = new ScreenInfo
{
hdcMonitor = new IntPtr(int.Parse(dic["ScreenInfo.hdcMonitor"])),
hMonitor = new IntPtr(int.Parse(dic["ScreenInfo.hMonitor"])),
Height = int.Parse(dic["ScreenInfo.Height"]),
Width = int.Parse(dic["ScreenInfo.Width"]),
X = int.Parse(dic["ScreenInfo.X"]),
Y = int.Parse(dic["ScreenInfo.Y"]),
},
X = int.Parse(dic[nameof(ScreenCaptureInfo.X)]),
Y = int.Parse(dic[nameof(ScreenCaptureInfo.Y)]),
Width = int.Parse(dic[nameof(ScreenCaptureInfo.Width)]),
Expand Down

This file was deleted.

Loading

0 comments on commit 918c73e

Please sign in to comment.