aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs')
-rw-r--r--Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs161
1 files changed, 161 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs b/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs
new file mode 100644
index 000000000..1a661b27e
--- /dev/null
+++ b/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SharpDX;
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using Tango.RemoteDesktop.Utils;
+using Device = SharpDX.Direct3D11.Device;
+using MapFlags = SharpDX.Direct3D11.MapFlags;
+
+namespace Tango.RemoteDesktop.CaptureMethods
+{
+ /// <summary>
+ /// Represents a high performance DirectX screen capture method.
+ /// </summary>
+ /// <seealso cref="Tango.RemoteDesktop.ICaptureMethod" />
+ public class DirectXScreenCapture : ICaptureMethod
+ {
+ private static bool _hasInstance;
+ private Device device;
+ private Output1 output1;
+ private Texture2DDescription textureDesc;
+ private OutputDuplication duplicatedOutput;
+ private int monitorWidth;
+ private int monitorHeight;
+
+ /// <summary>
+ /// Gets or sets the index of the graphics adapter.
+ /// </summary>
+ public int AdapterIndex { get; set; }
+
+ /// <summary>
+ /// Gets or sets the index of the monitor within the graphics adapter.
+ /// </summary>
+ public int MonitorIndex { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DirectXScreenCapture"/> class.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">An instance of the DirectX screen capture method already exists. Please dispose it before attempting to create a new one.</exception>
+ public DirectXScreenCapture()
+ {
+ if (_hasInstance)
+ {
+ throw new InvalidOperationException("An instance of the DirectX screen capture method already exists. Please dispose it before attempting to create a new one.");
+ }
+
+ // Create DXGI Factory1
+ var factory = new Factory1();
+ var adapter = factory.GetAdapter1(AdapterIndex);
+
+ // Create device from Adapter
+ device = new Device(adapter);
+
+ // Get DXGI.Output
+ var output = adapter.GetOutput(MonitorIndex);
+ output1 = output.QueryInterface<Output1>();
+
+ // Width/Height of desktop to capture
+ monitorWidth = ((SharpDX.Rectangle)output.Description.DesktopBounds).Width;
+ monitorHeight = ((SharpDX.Rectangle)output.Description.DesktopBounds).Height;
+
+ // Create Staging texture CPU-accessible
+ textureDesc = new Texture2DDescription
+ {
+ CpuAccessFlags = CpuAccessFlags.Read,
+ BindFlags = BindFlags.None,
+ Format = Format.B8G8R8A8_UNorm,
+ Width = monitorWidth,
+ Height = monitorHeight,
+ OptionFlags = ResourceOptionFlags.None,
+ MipLevels = 1,
+ ArraySize = 1,
+ SampleDescription = { Count = 1, Quality = 0 },
+ Usage = ResourceUsage.Staging
+ };
+
+ // Duplicate the output
+ duplicatedOutput = output1.DuplicateOutput(device);
+
+ _hasInstance = true;
+ }
+
+ /// <summary>
+ /// Gets the desktop bitmap.
+ /// </summary>
+ /// <param name="region">The capture region.</param>
+ /// <returns></returns>
+ public virtual Bitmap GetDesktopBitmap(CaptureRegion region)
+ {
+ var screenTexture = new Texture2D(device, textureDesc);
+
+ SharpDX.DXGI.Resource screenResource;
+ OutputDuplicateFrameInformation duplicateFrameInformation;
+
+ // Try to get duplicated frame within given time
+ duplicatedOutput.AcquireNextFrame(10000, out duplicateFrameInformation, out screenResource);
+
+ // copy resource into memory that can be accessed by the CPU
+ using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
+ device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
+
+ // Get the desktop capture texture
+ var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, MapFlags.None);
+
+ // Create Drawing.Bitmap
+ var bitmap = new Bitmap(monitorWidth, monitorHeight, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
+ var boundsRect = new System.Drawing.Rectangle(0, 0, monitorWidth, monitorHeight);
+
+ // Copy pixels from screen capture Texture to GDI bitmap
+ var mapDest = bitmap.LockBits(boundsRect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
+ var sourcePtr = mapSource.DataPointer;
+ var destPtr = mapDest.Scan0;
+ for (int y = 0; y < region.Height; y++)
+ {
+ // Copy a single line
+ Utilities.CopyMemory(destPtr, sourcePtr, monitorWidth * 4);
+
+ // Advance pointers
+ sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
+ destPtr = IntPtr.Add(destPtr, mapDest.Stride);
+ }
+
+ // Release source and dest locks
+ bitmap.UnlockBits(mapDest);
+ device.ImmediateContext.UnmapSubresource(screenTexture, 0);
+
+ if (region.Left > 0 || region.Top > 0 || region.Width < monitorWidth || region.Height < monitorHeight)
+ {
+ var cropped = CropImage(bitmap, new System.Drawing.Rectangle(region.Left, region.Top, region.Width, region.Height));
+ bitmap.Dispose();
+ bitmap = cropped;
+ }
+
+ screenTexture.Dispose();
+ screenResource.Dispose();
+ duplicatedOutput.ReleaseFrame();
+
+ return bitmap;
+ }
+
+ private Bitmap CropImage(Bitmap img, System.Drawing.Rectangle cropArea)
+ {
+ Bitmap bmpImage = new Bitmap(img);
+ return bmpImage.Clone(cropArea, bmpImage.PixelFormat);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ public void Dispose()
+ {
+ _hasInstance = false;
+ duplicatedOutput.Dispose();
+ device.Dispose();
+ }
+ }
+}