aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-02 23:30:34 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-02 23:30:34 +0200
commit0dcd742a3c35527386a93e1b1ef761c2aeff8308 (patch)
treed5adb3fee35e73af95fa5d68b5316d25522471de /Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods
parent1a7fb274158f8a0e279aef26206a65fefac8c4c3 (diff)
downloadTango-0dcd742a3c35527386a93e1b1ef761c2aeff8308.tar.gz
Tango-0dcd742a3c35527386a93e1b1ef761c2aeff8308.zip
Implemented Tango.RemoteDesktop.
Implemented png 8 bit quantization. Implemented RasterFrame bounds clipping. Refactored VectorFrame to use indexed colors.
Diffstat (limited to 'Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods')
-rw-r--r--Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/BitBltScreenCapture.cs68
-rw-r--r--Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/DirectXScreenCapture.cs161
-rw-r--r--Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/GdiScreenCapture.cs41
3 files changed, 270 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/BitBltScreenCapture.cs b/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/BitBltScreenCapture.cs
new file mode 100644
index 000000000..d8f1e214c
--- /dev/null
+++ b/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/BitBltScreenCapture.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.RemoteDesktop.CaptureMethods
+{
+ /// <summary>
+ /// Represents a BitBlt screen capture method.
+ /// </summary>
+ /// <seealso cref="Tango.RemoteDesktop.ICaptureMethod" />
+ public class BitBltScreenCapture : ICaptureMethod
+ {
+ #region Win32 API Screen shot calls
+
+ // Win32 API calls necessary to support screen capture
+ [DllImport("gdi32", EntryPoint = "BitBlt", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
+ private static extern int BitBlt(int hDestDC, int x, int y, int nWidth, int nHeight, int hSrcDC, int xSrc,
+ int ySrc, int dwRop);
+
+ [DllImport("user32", EntryPoint = "GetDC", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
+ private static extern int GetDC(int hwnd);
+
+ [DllImport("user32", EntryPoint = "ReleaseDC", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
+ private static extern int ReleaseDC(int hwnd, int hdc);
+
+ #endregion
+
+ /// <summary>
+ /// Gets the desktop bitmap.
+ /// </summary>
+ /// <param name="region">The capture region.</param>
+ /// <returns></returns>
+ public Bitmap GetDesktopBitmap(CaptureRegion region)
+ {
+ const int SRCCOPY = 13369376;
+
+ Bitmap bitmap = new Bitmap(region.Width, region.Height);
+
+ using (Graphics g = Graphics.FromImage(bitmap))
+ {
+ // Get a device context to the windows desktop and our destination bitmaps
+ int hdcSrc = GetDC(0);
+ IntPtr hdcDest = g.GetHdc();
+
+ // Copy what is on the desktop to the bitmap
+ BitBlt(hdcDest.ToInt32(), 0, 0, region.Width, region.Height, hdcSrc, 0, 0, SRCCOPY);
+
+ // Release device contexts
+ g.ReleaseHdc(hdcDest);
+ ReleaseDC(0, hdcSrc);
+ }
+
+ return bitmap;
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ public void Dispose()
+ {
+ //Do nothing.
+ }
+ }
+}
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();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/GdiScreenCapture.cs b/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/GdiScreenCapture.cs
new file mode 100644
index 000000000..92f4403fd
--- /dev/null
+++ b/Software/Visual_Studio/Tango.RemoteDesktop/CaptureMethods/GdiScreenCapture.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.RemoteDesktop.CaptureMethods
+{
+ /// <summary>
+ /// Represents a standard GDI screen capture method.
+ /// </summary>
+ /// <seealso cref="Tango.RemoteDesktop.ICaptureMethod" />
+ public class GdiScreenCapture : ICaptureMethod
+ {
+ /// <summary>
+ /// Gets the desktop bitmap.
+ /// </summary>
+ /// <param name="region">The capture region.</param>
+ /// <returns></returns>
+ public Bitmap GetDesktopBitmap(CaptureRegion region)
+ {
+ var bitmap = new Bitmap(region.Width, region.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+ using (Graphics g = Graphics.FromImage(bitmap))
+ {
+ g.CopyFromScreen(region.Left, region.Top, 0, 0, bitmap.Size, System.Drawing.CopyPixelOperation.SourceCopy);
+ }
+
+ return bitmap;
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ public void Dispose()
+ {
+ //Do nothing
+ }
+ }
+}