mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
capture test
This commit is contained in:
@@ -13,13 +13,19 @@ using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.Graphics.Direct3D;
|
||||
using Snap.Hutao.Win32.Graphics.Direct3D11;
|
||||
using Snap.Hutao.Win32.Graphics.Dxgi;
|
||||
using Snap.Hutao.Win32.Graphics.Dxgi.Common;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using Snap.Hutao.Win32.System.WinRT;
|
||||
using Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
|
||||
using Windows.Graphics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics.Capture;
|
||||
using Windows.Graphics.DirectX;
|
||||
using Windows.Graphics.DirectX.Direct3D11;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Storage.Streams;
|
||||
using WinRT;
|
||||
using static Snap.Hutao.Win32.ConstValues;
|
||||
using static Snap.Hutao.Win32.D3D11;
|
||||
using static Snap.Hutao.Win32.Macros;
|
||||
@@ -42,8 +48,6 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly MainWindow mainWindow;
|
||||
|
||||
private long counter;
|
||||
|
||||
private UploadAnnouncement announcement = new();
|
||||
|
||||
public UploadAnnouncement Announcement { get => announcement; set => SetProperty(ref announcement, value); }
|
||||
@@ -159,10 +163,8 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
|
||||
[Command("TestWindowsGraphicsCaptureCommand")]
|
||||
private unsafe void TestWindowsGraphicsCapture()
|
||||
{
|
||||
counter = 0;
|
||||
|
||||
// https://github.com/obsproject/obs-studio/blob/master/libobs-winrt/winrt-capture.cpp
|
||||
if (!UniversalApiContract.IsPresent(WindowsVersion.Windows10Version1903))
|
||||
if (!Core.UniversalApiContract.IsPresent(WindowsVersion.Windows10Version1903))
|
||||
{
|
||||
logger.LogWarning("Windows 10 Version 1903 or later is required for Windows.Graphics.Capture API.");
|
||||
return;
|
||||
@@ -180,21 +182,100 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
|
||||
{
|
||||
if (SUCCEEDED(IUnknownMarshal.QueryInterface(pD3D11Device, in IDXGIDevice.IID, out IDXGIDevice* pDXGIDevice)))
|
||||
{
|
||||
if (SUCCEEDED(CreateDirect3D11DeviceFromDXGIDevice(pDXGIDevice, out IInspectable* inspectable)))
|
||||
if (SUCCEEDED(CreateDirect3D11DeviceFromDXGIDevice(pDXGIDevice, out Win32.System.WinRT.IInspectable* inspectable)))
|
||||
{
|
||||
IDirect3DDevice direct3DDevice = WinRT.CastExtensions.As<IDirect3DDevice>(WinRT.IInspectable.FromAbi((nint)inspectable));
|
||||
IDirect3DDevice direct3DDevice = WinRT.IInspectable.FromAbi((nint)inspectable).ObjRef.AsInterface<IDirect3DDevice>();
|
||||
|
||||
SizeInt32 size = new(1920, 1080);
|
||||
using (Direct3D11CaptureFramePool framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(direct3DDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, size))
|
||||
HWND hwnd = serviceProvider.GetRequiredService<ICurrentWindowReference>().GetWindowHandle();
|
||||
GraphicsCaptureItem.As<IGraphicsCaptureItemInterop>().CreateForWindow(hwnd, out GraphicsCaptureItem item);
|
||||
|
||||
using (Direct3D11CaptureFramePool framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(direct3DDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, item.Size))
|
||||
{
|
||||
framePool.FrameArrived += (pool, obj) =>
|
||||
framePool.FrameArrived += (pool, _) =>
|
||||
{
|
||||
Interlocked.Increment(ref counter);
|
||||
using (Direct3D11CaptureFrame frame = framePool.TryGetNextFrame())
|
||||
using (Direct3D11CaptureFrame frame = pool.TryGetNextFrame())
|
||||
{
|
||||
if (frame is not null)
|
||||
{
|
||||
logger.LogInformation("Content Size: {Width} x {Height} {Count}", frame.ContentSize.Width, frame.ContentSize.Height, Volatile.Read(ref counter));
|
||||
logger.LogInformation("Content Size: {Width} x {Height}", frame.ContentSize.Width, frame.ContentSize.Height);
|
||||
|
||||
IDirect3DDxgiInterfaceAccess access = frame.Surface.As<IDirect3DDxgiInterfaceAccess>();
|
||||
if (FAILED(access.GetInterface(in IDXGISurface.IID, out IDXGISurface* pDXGISurface)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FAILED(pDXGISurface->GetDesc(out DXGI_SURFACE_DESC surfaceDesc)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC texture2DDesc = default;
|
||||
texture2DDesc.Width = surfaceDesc.Width;
|
||||
texture2DDesc.Height = surfaceDesc.Height;
|
||||
texture2DDesc.ArraySize = 1;
|
||||
texture2DDesc.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ;
|
||||
texture2DDesc.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
texture2DDesc.MipLevels = 1;
|
||||
texture2DDesc.SampleDesc.Count = 1;
|
||||
texture2DDesc.Usage = D3D11_USAGE.D3D11_USAGE_STAGING;
|
||||
|
||||
if (FAILED(pDXGISurface->GetDevice(in ID3D11Device.IID, out ID3D11Device* pD3D11Device)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FAILED(pD3D11Device->CreateTexture2D(ref texture2DDesc, ref Unsafe.NullRef<D3D11_SUBRESOURCE_DATA>(), out ID3D11Texture2D* pTexture2D)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FAILED(access.GetInterface(in ID3D11Resource.IID, out ID3D11Resource* pD3D11Resource)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pD3D11Device->GetImmediateContext(out ID3D11DeviceContext* pDeviceContext);
|
||||
pDeviceContext->CopyResource((ID3D11Resource*)pTexture2D, pD3D11Resource);
|
||||
|
||||
if (FAILED(pDeviceContext->Map((ID3D11Resource*)pTexture2D, 0, D3D11_MAP.D3D11_MAP_READ, 0, out D3D11_MAPPED_SUBRESOURCE mappedSubresource)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int size = (int)(mappedSubresource.RowPitch * texture2DDesc.Height * 4);
|
||||
|
||||
SoftwareBitmap softwareBitmap = new(BitmapPixelFormat.Bgra8, (int)texture2DDesc.Width, (int)texture2DDesc.Height, BitmapAlphaMode.Premultiplied);
|
||||
using (BitmapBuffer bitmapBuffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Write))
|
||||
{
|
||||
using (IMemoryBufferReference reference = bitmapBuffer.CreateReference())
|
||||
{
|
||||
reference.As<IMemoryBufferByteAccess>().GetBuffer(out Span<byte> bufferSpan);
|
||||
fixed (byte* p = bufferSpan)
|
||||
{
|
||||
for (uint i = 0; i < texture2DDesc.Height; i++)
|
||||
{
|
||||
System.Buffer.MemoryCopy(((byte*)mappedSubresource.pData) + (i * mappedSubresource.RowPitch), p + (i * texture2DDesc.Width * 4), texture2DDesc.Width * 4, texture2DDesc.Width * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (InMemoryRandomAccessStream stream = new())
|
||||
{
|
||||
BitmapEncoder encoder = BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream).AsTask().Result;
|
||||
encoder.SetSoftwareBitmap(softwareBitmap);
|
||||
encoder.FlushAsync().AsTask().Wait();
|
||||
|
||||
using (FileStream fileStream = new("D:\\test.png", FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
stream.AsStream().CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
_ = 1;
|
||||
|
||||
pDeviceContext->Unmap((ID3D11Resource*)pTexture2D, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -203,9 +284,6 @@ internal sealed partial class TestViewModel : Abstraction.ViewModel
|
||||
}
|
||||
};
|
||||
|
||||
HWND hwnd = serviceProvider.GetRequiredService<ICurrentWindowReference>().GetWindowHandle();
|
||||
GraphicsCaptureItem.As<IGraphicsCaptureItemInterop>().CreateForWindow(hwnd, out GraphicsCaptureItem item);
|
||||
|
||||
using (GraphicsCaptureSession captureSession = framePool.CreateCaptureSession(item))
|
||||
{
|
||||
captureSession.IsCursorCaptureEnabled = false;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
|
||||
|
||||
[SuppressMessage("", "SA1307")]
|
||||
internal struct D3D11_MAPPED_SUBRESOURCE
|
||||
{
|
||||
public unsafe void* pData;
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Runtime.Versioning;
|
||||
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
|
||||
|
||||
[SupportedOSPlatform("windows6.1")]
|
||||
internal unsafe readonly struct ID3D11Device
|
||||
internal unsafe struct ID3D11Device
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
@@ -25,6 +25,28 @@ internal unsafe readonly struct ID3D11Device
|
||||
}
|
||||
}
|
||||
|
||||
public HRESULT CreateTexture2D(ref readonly D3D11_TEXTURE2D_DESC desc, [AllowNull] ref readonly D3D11_SUBRESOURCE_DATA initialData, [MaybeNull] out ID3D11Texture2D* pTexture2D)
|
||||
{
|
||||
fixed (D3D11_TEXTURE2D_DESC* pDesc = &desc)
|
||||
{
|
||||
fixed (D3D11_SUBRESOURCE_DATA* pInitialData = &initialData)
|
||||
{
|
||||
fixed (ID3D11Texture2D** ppTexture2D = &pTexture2D)
|
||||
{
|
||||
return ThisPtr->CreateTexture2D((ID3D11Device*)Unsafe.AsPointer(ref this), pDesc, pInitialData, ppTexture2D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GetImmediateContext(out ID3D11DeviceContext* pImmediateContext)
|
||||
{
|
||||
fixed (ID3D11DeviceContext** ppImmediateContext = &pImmediateContext)
|
||||
{
|
||||
ThisPtr->GetImmediateContext((ID3D11Device*)Unsafe.AsPointer(ref this), ppImmediateContext);
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IUnknown.Vftbl IUnknownVftbl;
|
||||
|
||||
@@ -11,7 +11,7 @@ using System.Runtime.Versioning;
|
||||
namespace Snap.Hutao.Win32.Graphics.Direct3D11;
|
||||
|
||||
[SupportedOSPlatform("windows6.1")]
|
||||
internal unsafe readonly struct ID3D11DeviceContext
|
||||
internal unsafe struct ID3D11DeviceContext
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
@@ -24,6 +24,26 @@ internal unsafe readonly struct ID3D11DeviceContext
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("", "SA1313")]
|
||||
public HRESULT Map(ID3D11Resource* pResource, uint Subresource, D3D11_MAP MapType, uint MapFlags, [MaybeNull] out D3D11_MAPPED_SUBRESOURCE mappedResource)
|
||||
{
|
||||
fixed (D3D11_MAPPED_SUBRESOURCE* pMappedResource = &mappedResource)
|
||||
{
|
||||
return ThisPtr->Map((ID3D11DeviceContext*)Unsafe.AsPointer(ref this), pResource, Subresource, MapType, MapFlags, pMappedResource);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("", "SA1313")]
|
||||
public void Unmap(ID3D11Resource* pResource, uint Subresource)
|
||||
{
|
||||
ThisPtr->Unmap((ID3D11DeviceContext*)Unsafe.AsPointer(ref this), pResource, Subresource);
|
||||
}
|
||||
|
||||
public void CopyResource(ID3D11Resource* pDstResource, ID3D11Resource* pSrcResource)
|
||||
{
|
||||
ThisPtr->CopyResource((ID3D11DeviceContext*)Unsafe.AsPointer(ref this), pDstResource, pSrcResource);
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly ID3D11DeviceChild.Vftbl ID3D11DeviceChildVftbl;
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Win32.Graphics.Dxgi;
|
||||
|
||||
internal unsafe readonly struct IDXGISurface
|
||||
internal unsafe struct IDXGISurface
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
@@ -20,6 +20,26 @@ internal unsafe readonly struct IDXGISurface
|
||||
}
|
||||
}
|
||||
|
||||
public HRESULT GetDevice<T>(ref readonly Guid iid, out T* pDevice)
|
||||
where T : unmanaged
|
||||
{
|
||||
fixed (Guid* riid = &iid)
|
||||
{
|
||||
fixed (T** ppDevice = &pDevice)
|
||||
{
|
||||
return ThisPtr->IDXGIDeviceSubObjectVftbl.GetDevice((IDXGIDeviceSubObject*)Unsafe.AsPointer(ref this), riid, (void**)ppDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HRESULT GetDesc(out DXGI_SURFACE_DESC desc)
|
||||
{
|
||||
fixed (DXGI_SURFACE_DESC* pDesc = &desc)
|
||||
{
|
||||
return ThisPtr->GetDesc((IDXGISurface*)Unsafe.AsPointer(ref this), pDesc);
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IDXGIDeviceSubObject.Vftbl IDXGIDeviceSubObjectVftbl;
|
||||
|
||||
@@ -7,14 +7,14 @@ namespace Snap.Hutao.Win32.System.Com;
|
||||
|
||||
internal static class IUnknownMarshal
|
||||
{
|
||||
public static unsafe HRESULT QueryInterface<TInterface>(void* pIUnknown, ref readonly Guid riid, out TInterface* pvObject)
|
||||
public static unsafe HRESULT QueryInterface<TInterface>(void* pIUnknown, ref readonly Guid iid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
fixed (Guid* riid = &iid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ((IUnknown*)pIUnknown)->ThisPtr->QueryInterface((IUnknown*)pIUnknown, riid2, (void**)ppvObject);
|
||||
return ((IUnknown*)pIUnknown)->ThisPtr->QueryInterface((IUnknown*)pIUnknown, riid, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
|
||||
|
||||
[ComImport]
|
||||
[Guid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IDirect3DDxgiInterfaceAccess
|
||||
{
|
||||
[PreserveSig]
|
||||
unsafe HRESULT GetInterface(Guid* iid, void** p);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
|
||||
namespace Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
|
||||
|
||||
internal static class IDirect3DDxgiInterfaceAccessExtension
|
||||
{
|
||||
public static unsafe HRESULT GetInterface<T>(this IDirect3DDxgiInterfaceAccess access, ref readonly Guid iid, out T* p)
|
||||
where T : unmanaged
|
||||
{
|
||||
fixed (Guid* riid = &iid)
|
||||
{
|
||||
fixed (T** pp = &p)
|
||||
{
|
||||
return access.GetInterface(riid, (void**)pp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Composition;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.Graphics.Gdi;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
|
||||
|
||||
@@ -8,7 +8,7 @@ using Windows.Graphics.Capture;
|
||||
|
||||
namespace Snap.Hutao.Win32.System.WinRT.Graphics.Capture;
|
||||
|
||||
internal static class GraphicsCaptureItemInteropExtension
|
||||
internal static class IGraphicsCaptureItemInteropExtension
|
||||
{
|
||||
public static unsafe HRESULT CreateForWindow(this IGraphicsCaptureItemInterop interop, HWND window, out GraphicsCaptureItem result)
|
||||
{
|
||||
Reference in New Issue
Block a user