Merge pull request #4 from DarthAffe/Igneom/master

Igneom/master
This commit is contained in:
DarthAffe 2022-05-03 21:18:28 +02:00 committed by GitHub
commit cdc03a9312
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1053 additions and 989 deletions

View File

@ -17,7 +17,7 @@ IEnumerable<Display> displays = screenCaptureService.GetDisplays(graphicsCards.F
// Create a screen-capture for all screens you want to capture
IScreenCapture screenCapture = screenCaptureService.GetScreenCapture(displays.First());
// Register the regions you want to capture om the screen
// Register the regions you want to capture on the screen
// Capture the whole screen
CaptureZone fullscreen = screenCapture.RegisterCaptureZone(0, 0, screenCapture.Display.Width, screenCapture.Display.Height);
// Capture a 100x100 region at the top left and scale it down to 50x50
@ -54,4 +54,13 @@ lock (fullscreen.Buffer)
}
}
}
// Move the top left zone more towards the center
// Using the Update-method allows to move the zone without having to allocate
// new buffers and textures which yields a good performance gain if done at high framerates.
screenCapture.UpdateCaptureZone(topLeft, x: 100, y: 200);
// Note that resizing the zone is also possible but currently reinitializes the zone
// -> no performance gain compared to removing and readding the zone.
screenCapture.UpdateCaptureZone(topLeft, width: 20, height: 20);
```

View File

@ -11,8 +11,8 @@ using Vortice.Mathematics;
using MapFlags = Vortice.Direct3D11.MapFlags;
using ResultCode = Vortice.DXGI.ResultCode;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
/// Represents a ScreenCapture using DirectX 11 desktop duplicaton.
/// https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api
@ -203,28 +203,13 @@ namespace ScreenCapture.NET
/// <inheritdoc />
public CaptureZone RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
{
if (_device == null) throw new ApplicationException("ScreenCapture isn't initialized.");
if (x < 0) throw new ArgumentException("x < 0");
if (y < 0) throw new ArgumentException("y < 0");
if (width <= 0) throw new ArgumentException("with <= 0");
if (height <= 0) throw new ArgumentException("height <= 0");
if ((x + width) > Display.Width) throw new ArgumentException("x + width > Display width");
if ((y + height) > Display.Height) throw new ArgumentException("y + height > Display height");
ValidateCaptureZoneAndThrow(x, y, width, height);
int unscaledWidth = width;
int unscaledHeight = height;
if (downscaleLevel > 0)
for (int i = 0; i < downscaleLevel; i++)
{
width /= 2;
height /= 2;
}
(width, height) = CalculateScaledSize(unscaledWidth, unscaledHeight, downscaleLevel);
if (width < 1) width = 1;
if (height < 1) height = 1;
byte[] buffer = new byte[width * height * 4];
byte[] buffer = new byte[width * height * BPP];
CaptureZone captureZone = new(_indexCounter++, x, y, width, height, BPP, downscaleLevel, unscaledWidth, unscaledHeight, buffer);
lock (_captureZones)
@ -252,6 +237,71 @@ namespace ScreenCapture.NET
}
}
/// <inheritdoc />
public void UpdateCaptureZone(CaptureZone captureZone, int? x = null, int? y = null, int? width = null, int? height = null, int? downscaleLevel = null)
{
lock (_captureZones)
if (!_captureZones.ContainsKey(captureZone))
throw new ArgumentException("The capture zone is not registered to this ScreenCapture", nameof(captureZone));
int newX = x ?? captureZone.X;
int newY = y ?? captureZone.Y;
int newUnscaledWidth = width ?? captureZone.UnscaledWidth;
int newUnscaledHeight = height ?? captureZone.UnscaledHeight;
int newDownscaleLevel = downscaleLevel ?? captureZone.DownscaleLevel;
ValidateCaptureZoneAndThrow(newX, newY, newUnscaledWidth, newUnscaledHeight);
captureZone.X = newX;
captureZone.Y = newY;
//TODO DarthAffe 01.05.2022: For now just reinitialize the zone in that case, but this could be optimized to only recreate the textures needed.
if ((width != null) || (height != null) || (downscaleLevel != null))
{
(int newWidth, int newHeight) = CalculateScaledSize(newUnscaledWidth, newUnscaledHeight, newDownscaleLevel);
lock (_captureZones)
{
UnregisterCaptureZone(captureZone);
captureZone.UnscaledWidth = newUnscaledWidth;
captureZone.UnscaledHeight = newUnscaledHeight;
captureZone.Width = newWidth;
captureZone.Height = newHeight;
captureZone.DownscaleLevel = newDownscaleLevel;
captureZone.Buffer = new byte[newWidth * newHeight * BPP];
InitializeCaptureZone(captureZone);
}
}
}
private (int width, int height) CalculateScaledSize(int width, int height, int downscaleLevel)
{
if (downscaleLevel > 0)
for (int i = 0; i < downscaleLevel; i++)
{
width /= 2;
height /= 2;
}
if (width < 1) width = 1;
if (height < 1) height = 1;
return (width, height);
}
private void ValidateCaptureZoneAndThrow(int x, int y, int width, int height)
{
if (_device == null) throw new ApplicationException("ScreenCapture isn't initialized.");
if (x < 0) throw new ArgumentException("x < 0");
if (y < 0) throw new ArgumentException("y < 0");
if (width <= 0) throw new ArgumentException("with <= 0");
if (height <= 0) throw new ArgumentException("height <= 0");
if ((x + width) > Display.Width) throw new ArgumentException("x + width > Display width");
if ((y + height) > Display.Height) throw new ArgumentException("y + height > Display height");
}
private void InitializeCaptureZone(in CaptureZone captureZone)
{
Texture2DDescription stagingTextureDesc = new()
@ -303,12 +353,12 @@ namespace ScreenCapture.NET
List<CaptureZone> captureZones = _captureZones.Keys.ToList();
Dispose();
using IDXGIAdapter1 adapter = _factory.GetAdapter1(Display.GraphicsCard.Index);
using IDXGIAdapter1 adapter = _factory.GetAdapter1(Display.GraphicsCard.Index) ?? throw new ApplicationException("Couldn't create DirectX-Adapter.");
D3D11.D3D11CreateDevice(adapter, DriverType.Unknown, DeviceCreationFlags.None, FEATURE_LEVELS, out _device).CheckError();
_context = _device.ImmediateContext;
_context = _device!.ImmediateContext;
_output = adapter.GetOutput(Display.Index);
_output = adapter.GetOutput(Display.Index) ?? throw new ApplicationException("Couldn't get DirectX-Output.");
using IDXGIOutput5 output = _output.QueryInterface<IDXGIOutput5>();
Texture2DDescription captureTextureDesc = new()
@ -377,4 +427,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -2,10 +2,10 @@
using System.Collections.Generic;
using Vortice.DXGI;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
///
/// Represents a <see cref="IScreenCaptureService"/> using the <see cref="DX11ScreenCapture"/>.
/// </summary>
public class DX11ScreenCaptureService : IScreenCaptureService
{
@ -20,11 +20,11 @@ namespace ScreenCapture.NET
#region Constructors
/// <summary>
///
/// Initializes a new instance of the <see cref="DX11ScreenCaptureService"/> class.
/// </summary>
public DX11ScreenCaptureService()
{
DXGI.CreateDXGIFactory1(out _factory).CheckError();
DXGI.CreateDXGIFactory1(out _factory!).CheckError();
}
#endregion
@ -81,4 +81,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -2,8 +2,8 @@
using System;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <inheritdoc />
/// <summary>
/// Represents the information supplied with an <see cref="E:ScreenCapture.IDX11ScreenCapture.Updated" />-event.
@ -32,4 +32,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -3,8 +3,8 @@
using System.Runtime.InteropServices;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
/// Helper-class for DPI-related WIN-API calls.
/// </summary>
@ -39,4 +39,3 @@ namespace ScreenCapture.NET
/// </summary>
public static void Initalize() => SetProcessDpiAwarenessContext((int)DPI_AWARENESS_CONTEXT.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
}

View File

@ -1,7 +1,7 @@
using System;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
/// Represents the duplication of a single display.
/// </summary>
@ -27,7 +27,7 @@ namespace ScreenCapture.NET
/// Creates a new <see cref="CaptureScreen"/> for this <see cref="IScreenCapture"/>.
/// </summary>
/// <param name="x">The x-location of the region to capture (must be &gt;= 0 and &lt; screen-width).</param>
/// <param name="y">The x-location of the region to capture (must be &gt;= 0 and &lt; screen-height).</param>
/// <param name="y">The y-location of the region to capture (must be &gt;= 0 and &lt; screen-height).</param>
/// <param name="width">The width of the region to capture (must be &gt;= 0 and this + x must be &lt;= screen-width).</param>
/// <param name="height">The height of the region to capture (must be &gt;= 0 and this + y must be &lt;= screen-height).</param>
/// <param name="downscaleLevel">The level of downscaling applied to the image of this region before copying to local memory. The calculation is (width and height)/2^downscaleLevel.</param>
@ -37,13 +37,26 @@ namespace ScreenCapture.NET
/// <summary>
/// Removes the given <see cref="CaptureScreen"/> from the <see cref="IScreenCapture"/>.
/// </summary>
/// <param name="captureZone">The previosly registered <see cref="CaptureScreen"/>.</param>
/// <param name="captureZone">The previously registered <see cref="CaptureScreen"/>.</param>
/// <returns><c>true</c> if the <see cref="CaptureScreen"/> was successfully removed; otherwise, <c>false</c>.</returns>
bool UnregisterCaptureZone(CaptureZone captureZone);
/// <summary>
/// Updates the the given <see cref="CaptureScreen"/>.
/// </summary>
/// <remarks>
/// <c>null</c>-parameters are ignored and not changed.
/// </remarks>
/// <param name="captureZone">The previously registered <see cref="CaptureScreen"/>.</param>
/// <param name="x">The new x-location of the region to capture (must be &gt;= 0 and &lt; screen-width).</param>
/// <param name="y">The new y-location of the region to capture (must be &gt;= 0 and &lt; screen-height).</param>
/// <param name="width">The width of the region to capture (must be &gt;= 0 and this + x must be &lt;= screen-width).</param>
/// <param name="height">The new height of the region to capture (must be &gt;= 0 and this + y must be &lt;= screen-height).</param>
/// <param name="downscaleLevel">The new level of downscaling applied to the image of this region before copying to local memory. The calculation is (width and height)/2^downscaleLevel.</param>
void UpdateCaptureZone(CaptureZone captureZone, int? x = null, int? y = null, int? width = null, int? height = null, int? downscaleLevel = null);
/// <summary>
/// Restarts the <see cref="IScreenCapture"/>.
/// </summary>
void Restart();
}
}

View File

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
///
/// </summary>
@ -28,4 +28,3 @@ namespace ScreenCapture.NET
/// <returns>The <see cref="IScreenCapture"/> for the give display.</returns>
IScreenCapture GetScreenCapture(Display display);
}
}

View File

@ -2,8 +2,8 @@
using System;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
/// Represents the configuration for the detection and removal of black bars around the screen image.
/// </summary>
@ -139,4 +139,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -2,8 +2,8 @@
using System;
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
/// Represents a duplicated region on the screen.
/// </summary>
@ -19,37 +19,37 @@ namespace ScreenCapture.NET
/// <summary>
/// Gets the x-location of the region on the screen.
/// </summary>
public int X { get; }
public int X { get; internal set; }
/// <summary>
/// Gets the y-location of the region on the screen.
/// </summary>
public int Y { get; }
public int Y { get; internal set; }
/// <summary>
/// Gets the width of the region on the screen.
/// Gets the width of the captured region.
/// </summary>
public int Width { get; }
public int Width { get; internal set; }
/// <summary>
/// Gets the height of the region on the screen.
/// Gets the height of the captured region.
/// </summary>
public int Height { get; }
public int Height { get; internal set; }
/// <summary>
/// Gets the level of downscaling applied to the image of this region before copying to local memory. The calculation is (width and height)/2^downscaleLevel.
/// </summary>
public int DownscaleLevel { get; }
public int DownscaleLevel { get; internal set; }
/// <summary>
/// Gets the original width of the region (this equals <see cref="Width"/> if <see cref="DownscaleLevel"/> is 0).
/// </summary>
public int UnscaledWidth { get; }
public int UnscaledWidth { get; internal set; }
/// <summary>
/// Gets the original height of the region (this equals <see cref="Height"/> if <see cref="DownscaleLevel"/> is 0).
/// </summary>
public int UnscaledHeight { get; }
public int UnscaledHeight { get; internal set; }
/// <summary>
/// Gets the amount of bytes per pixel in the image (most likely 3 [RGB] or 4 [ARGB]).
@ -64,7 +64,7 @@ namespace ScreenCapture.NET
/// <summary>
/// Gets the buffer containing the image data. Format depends on the specific capture but is most likely BGRA32.
/// </summary>
public byte[] Buffer { get; }
public byte[] Buffer { get; internal set; }
/// <summary>
/// Gets the config for black-bar detection.
@ -159,4 +159,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -1,7 +1,9 @@
// ReSharper disable MemberCanBePrivate.Global
namespace ScreenCapture.NET
{
using System;
namespace ScreenCapture.NET;
/// <summary>
/// Represents a display connected to graphics-card.
/// </summary>
@ -64,13 +66,13 @@ namespace ScreenCapture.NET
/// </summary>
/// <param name="other">The <see cref="Display"/> to compare.</param>
/// <returns><c>true</c> if the specified object is equal to the current object; otherwise, <c>false</c>.</returns>
public bool Equals(Display other) => Index == other.Index;
public bool Equals(Display other) => (Index == other.Index) && GraphicsCard.Equals(other.GraphicsCard);
/// <inheritdoc />
public override bool Equals(object? obj) => obj is Display other && Equals(other);
/// <inheritdoc />
public override int GetHashCode() => Index;
public override int GetHashCode() => HashCode.Combine(Index, GraphicsCard);
/// <summary>
/// Determines whether two <see cref="Display"/> are equal.
@ -90,4 +92,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -1,7 +1,7 @@
// ReSharper disable MemberCanBePrivate.Global
namespace ScreenCapture.NET
{
namespace ScreenCapture.NET;
/// <summary>
/// Represents a graphics-card.
/// </summary>
@ -83,4 +83,3 @@ namespace ScreenCapture.NET
#endregion
}
}

View File

@ -16,8 +16,8 @@
<RootNamespace>ScreenCapture.NET</RootNamespace>
<Description>Vortice based Screen-Capturing</Description>
<Summary>Vortice based Screen-Capturing using Desktop Duplication</Summary>
<Copyright>Copyright © Darth Affe 2021</Copyright>
<PackageCopyright>Copyright © Darth Affe 2021</PackageCopyright>
<Copyright>Copyright © Darth Affe 2022</Copyright>
<PackageCopyright>Copyright © Darth Affe 2022</PackageCopyright>
<PackageIcon>icon.png</PackageIcon>
<PackageProjectUrl>https://github.com/DarthAffe/ScreenCapture.NET</PackageProjectUrl>
<PackageLicenseExpression>LGPL-2.1-only</PackageLicenseExpression>
@ -26,15 +26,14 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageReleaseNotes>
- Fixed problems with capturing inside WPF-threads.
- Removed the need to call 'DPIAwareness.Initalize()' in default configuration
- Added .NET 6 support
- Updated Vortice to 1.9.143
- Added IScreenCapture.UpdateCaptureZone to modify existing CaptureZones without having to remove and add them again.
(This has performance benefits when only X and/or Y is changed, changes to width, height and downscale are internally still reinitializing the zone.)
- Fixed ambiguous equals in Display
</PackageReleaseNotes>
<Version>1.1.0</Version>
<AssemblyVersion>1.1.0</AssemblyVersion>
<FileVersion>1.1.0</FileVersion>
<Version>1.2.0</Version>
<AssemblyVersion>1.2.0</AssemblyVersion>
<FileVersion>1.2.0</FileVersion>
<OutputPath>..\bin\</OutputPath>
<GenerateDocumentationFile>true</GenerateDocumentationFile>