diff options
Diffstat (limited to 'Software/Visual_Studio/Tango.RemoteDesktop/ScreenCaptureEngine.cs')
| -rw-r--r-- | Software/Visual_Studio/Tango.RemoteDesktop/ScreenCaptureEngine.cs | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/ScreenCaptureEngine.cs b/Software/Visual_Studio/Tango.RemoteDesktop/ScreenCaptureEngine.cs new file mode 100644 index 000000000..915147d2a --- /dev/null +++ b/Software/Visual_Studio/Tango.RemoteDesktop/ScreenCaptureEngine.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.RemoteDesktop.Utils; + +namespace Tango.RemoteDesktop +{ + /// <summary> + /// Represents a generic screen capture engine. + /// The <see cref="TFrame"/> type will be the type of difference object delivered by the engine. + /// </summary> + /// <typeparam name="TFrame">The type of the frame.</typeparam> + /// <seealso cref="Tango.RemoteDesktop.IScreenCaptureEngine{TFrame}" /> + public class ScreenCaptureEngine<TFrame> : IScreenCaptureEngine<TFrame> where TFrame : class, IFrame + { + private Thread _captureThread; + private Bitmap _previousBitmap; + private bool _isDisposed; + + /// <summary> + /// Occurs when a new screen frame is available. + /// </summary> + public event EventHandler<ScreenCaptureFrameReceivedEventArgs<TFrame>> FrameReceived; + + /// <summary> + /// Gets or sets the screen capture method. + /// </summary> + public ICaptureMethod CaptureMethod { get; set; } + + /// <summary> + /// Gets or sets the screen capture region. + /// </summary> + public CaptureRegion CaptureRegion { get; set; } + + /// <summary> + /// Gets a value indicating whether this instance is currently capturing. + /// </summary> + public bool IsStarted { get; private set; } + + /// <summary> + /// Gets or sets the frame rate per second. + /// Default is 10. + /// </summary> + public int FrameRate { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether to include the cursor when capturing. + /// </summary> + public bool CaptureCursor { get; set; } + + /// <summary> + /// Gets or sets the bitmap comparer. + /// </summary> + public IBitmapComparer<TFrame> Comparer { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether to enable image comparison. + /// </summary> + public bool EnableComparer { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="ScreenCaptureEngine{TFrame}"/> class using the specified <see cref="IBitmapComparer{TFrame}"/>. + /// </summary> + /// <param name="comparer">The comparer.</param> + public ScreenCaptureEngine(IBitmapComparer<TFrame> comparer) + { + FrameRate = 10; + CaptureMethod = new CaptureMethods.DirectXScreenCapture(); + CaptureRegion = new CaptureRegion(System.Windows.Forms.Screen.PrimaryScreen.Bounds); + Comparer = comparer; + CaptureCursor = true; + + if (Comparer != null) + { + EnableComparer = true; + } + } + + /// <summary> + /// Start capturing. + /// </summary> + /// <exception cref="ObjectDisposedException">Screen capture engine cannot be started after disposed.</exception> + public void Start() + { + if (_isDisposed) + { + throw new ObjectDisposedException("Screen capture engine cannot be started after disposed."); + } + + if (!IsStarted) + { + IsStarted = true; + + _captureThread = new Thread(CaptureThreadMethod); + _captureThread.IsBackground = true; + _captureThread.Name = "Screen Capture Thread"; + _captureThread.Start(); + } + } + + /// <summary> + /// Stop capturing. + /// </summary> + public void Stop() + { + if (IsStarted) + { + IsStarted = false; + _previousBitmap?.Dispose(); + } + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + public void Dispose() + { + if (!_isDisposed) + { + _isDisposed = true; + Stop(); + CaptureMethod?.Dispose(); + } + } + + private void CaptureThreadMethod() + { + Stopwatch watch = new Stopwatch(); + + while (IsStarted) + { + watch.Restart(); + + var bitmap = CaptureMethod.GetDesktopBitmap(CaptureRegion); + + if (CaptureCursor) + { + using (Graphics g = Graphics.FromImage(bitmap)) + { + CursorUtils.ApplyCursor(g, bitmap, CaptureRegion.Left, CaptureRegion.Top); + } + } + + if (EnableComparer && Comparer != null) + { + if (_previousBitmap == null) + { + _previousBitmap = bitmap.Clone() as Bitmap; + OnFrameReceived(bitmap, null, false); + } + else + { + var result = Comparer.CreateDifference(_previousBitmap, bitmap); + _previousBitmap.Dispose(); + _previousBitmap = bitmap.Clone() as Bitmap; + OnFrameReceived(bitmap, result.Frame, result.ContainsDifference); + } + } + else + { + OnFrameReceived(bitmap, null, false); + } + + int delay = Math.Max(5, (FrameRate * 10) - (int)watch.ElapsedMilliseconds); + Thread.Sleep(delay); + } + } + + private void OnFrameReceived(Bitmap currentBitmap, TFrame diffFrame, bool hasDifference) + { + FrameReceived?.Invoke(this, new ScreenCaptureFrameReceivedEventArgs<TFrame>() + { + Frame = new ScreenCaptureFrame<TFrame>(currentBitmap, diffFrame) + { + HasDifference = hasDifference + } + }); + } + } +} |
