public void Close() { /* resetting common properties */ pausebutton.Visible = false; stopbutton.Visible = false; recbutton.Visible = true; captureStarted = false; capturing = false; OnTick(0); if (capturer == null) { return; } /* stopping and closing capturer */ try { capturer.Stop(); capturer.Close(); if (capturerType == CapturerType.Live) { /* release and dispose live capturer */ capturer.Error -= OnError; capturer.DeviceChange += OnDeviceChange; capturerhbox.Remove(capturer as Gtk.Widget); capturer.Dispose(); } } catch (Exception) {} capturer = null; }
public ctrlTextOverlay(TextOverlay textOverlay, int index, ICapturer capturer) { InitializeComponent(); _textOverlay = textOverlay; _index = index; _capturer = capturer; nmLeft.Value = _textOverlay.Left; nmTop.Value = _textOverlay.Top; txtText.Text = _textOverlay.Text; txtFont.Text = _textOverlay.Font.Name; txtFont.Font = _textOverlay.Font; pnlColor.BackColor = _textOverlay.Color; chkVisible.Checked = _textOverlay.Visible; btnUpdate.Visible = true; chkBackColor.Checked = _textOverlay.BackColor != Color.Transparent; btnBackColor.Enabled = _textOverlay.BackColor != Color.Transparent; pnlBackColor.BackColor = _textOverlay.BackColor; txtFont.Enabled = false; btnFont.Enabled = false; pnlColor.Enabled = false; btnColor.Enabled = false; chkBackColor.Enabled = false; btnBackColor.Enabled = false; pnlBackColor.Enabled = false; _isLoaded = true; }
private void timer1_Tick(object sender, EventArgs e) { if (!_isPaused) { lblStatus.Text = _capturer.IsRunning ? "Running" : "Stopped"; } else { lblStatus.Text = "Paused"; } if (_captureStarted && !_capturer.IsRunning && !_isPaused) { lblStatus.Text = "Restarting capturer..."; System.Runtime.InteropServices.Marshal.ReleaseComObject(_capturer); _capturer = null; InitCapturer(); lstOverlays.Items.Clear(); btnRecord.Text = "Record"; tabControl1.Enabled = true; lblStatus.Text = "Stopped"; timer1.Stop(); } }
public Tuple <double, double> GetAbsolutePointFromRelativePercent(double percentX, double percentY, ICapturer capturer) { var absoluteX = capturer.CurrentScreenBounds.Width * percentX + capturer.CurrentScreenBounds.Left; var absoluteY = capturer.CurrentScreenBounds.Height * percentY + capturer.CurrentScreenBounds.Top; return(new Tuple <double, double>(absoluteX, absoluteY)); }
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (_capturer.IsRunning) { _capturer.Stop(); } System.Runtime.InteropServices.Marshal.ReleaseComObject(_capturer); _capturer = null; }
public CaptureController(ICapturer <XDocument> xmlDocumentProcessor) { if (xmlDocumentProcessor == null) { throw new ArgumentNullException("xmlDocumentProcessor"); } _xmlDocumentProcessor = xmlDocumentProcessor; }
public EventsManager(IGUIToolkit guiToolkit) { this.guiToolkit = guiToolkit; mainWindow = guiToolkit.MainWindow; player = mainWindow.Player; capturer = mainWindow.Capturer; drawingManager = new VideoDrawingsManager(player); ConnectSignals(); }
public EventsManager(IGUIToolkit guiToolkit, IRenderingJobsManager renderer) { this.guiToolkit = guiToolkit; this.renderer = renderer; mainWindow = guiToolkit.MainWindow; player = mainWindow.Player; capturer = mainWindow.Capturer; drawingManager = new VideoDrawingsManager(player); ConnectSignals(); }
public Tuple <double, double> GetAbsolutePercentFromRelativePercent(double percentX, double percentY, ICapturer capturer) { var absoluteX = capturer.CurrentScreenBounds.Width * percentX + capturer.CurrentScreenBounds.Left - capturer.GetVirtualScreenBounds().Left; var absoluteY = capturer.CurrentScreenBounds.Height * percentY + capturer.CurrentScreenBounds.Top - capturer.GetVirtualScreenBounds().Top; return(new Tuple <double, double>(absoluteX / capturer.GetVirtualScreenBounds().Width, absoluteY / capturer.GetVirtualScreenBounds().Height)); }
public ctrlImageOverlay(ImageOverlay imageOverlay, int index, ICapturer capturer) { InitializeComponent(); _imageOverlay = imageOverlay; _index = index; _capturer = capturer; nmLeft.Value = _imageOverlay.Left; nmTop.Value = _imageOverlay.Top; txtFileName.Text = _imageOverlay.FileName; chkVisible.Checked = _imageOverlay.Visible; txtFileName.Enabled = false; btnBrowseFile.Enabled = false; _isLoaded = true; }
public void AddCapturer(ICapturer capturer) { object[] attributes = capturer.GetType().GetCustomAttributes(false); foreach (Object attribute in attributes) { if (attribute is Captures) { Captures cap = (Captures)attribute; CapturerInfo capturableInfo = new CapturerInfo(); capturableInfo.Capturer = capturer; capturableInfo.Capturable = cap.Name; capturableInfo.AddTo(_capturers); break; } } //TODO: Throw exception: [Captures] attribute is missing }
private void button1_Click(object sender, EventArgs e) { try { //根据选择创建对应的采集器 if (this.comboBox1.SelectedIndex == 0) { this.capturer = CapturerFactory.CreateCameraCapturer(0, new Size(int.Parse(this.textBox_width.Text), int.Parse(this.textBox_height.Text)), 20); ((ICameraCapturer)this.capturer).ImageCaptured += new ESBasic.CbGeneric <Bitmap>(Form1_ImageCaptured); } else if (this.comboBox1.SelectedIndex == 1) { this.capturer = CapturerFactory.CreateDesktopCapturer(60, false); ((IDesktopCapturer)this.capturer).ImageCaptured += new ESBasic.CbGeneric <Bitmap>(Form1_ImageCaptured); } else if (this.comboBox1.SelectedIndex == 2) { this.capturer = CapturerFactory.CreateMicrophoneCapturer(0); ((IMicrophoneCapturer)this.capturer).AudioCaptured += new ESBasic.CbGeneric <byte[]>(Form1_AudioCaptured); } else { this.capturer = CapturerFactory.CreateSoundcardCapturer(); ((ISoundcardCapturer)this.capturer).AudioCaptured += new ESBasic.CbGeneric <byte[]>(Form1_AudioCaptured); } this.button1.Enabled = false; this.button2.Enabled = true; this.comboBox1.Enabled = false; this.autioDataTotalLen = 0; this.label_audioDataTotal.Text = "0"; //开始采集 this.capturer.Start(); } catch (Exception ee) { MessageBox.Show(ee.Message); } }
private void Start() { _capturer = GetComponent <ICapturer> (); }
public static Tuple <double, double> GetAbsolutePercentFromRelativePercent(double percentX, double percentY, ICapturer capturer) { var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left; var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top; return(new Tuple <double, double>(absoluteX / capturer.GetVirtualScreenWidth(), absoluteY / capturer.GetVirtualScreenHeight())); }
private void InitCapturer() { _capturer = new CapturerClass(); _capturer.RegistrationName = "demo"; _capturer.RegistrationKey = "demo"; }
private void btnRecord_Click(object sender, EventArgs e) { try { if (_capturer.IsRunning) { _capturer.Stop(); System.Runtime.InteropServices.Marshal.ReleaseComObject(_capturer); _capturer = null; InitCapturer(); lstOverlays.Items.Clear(); btnRecord.Text = "Record"; grpProperties.Enabled = true; lblStatus.Text = "Stopped"; } else { _capturer.AudioEnabled = chkEnableAudio.Checked; if (chkEnableAudio.Checked) { _capturer.CurrentAudioDeviceName = cmbAudioDevices.SelectedItem.ToString(); //_capturer.CurrentAudioCodecName = cmbAudioCodecs.SelectedItem.ToString(); } _capturer.AddWebCamVideo = chkEnableWebcam.Checked; if (chkEnableWebcam.Checked) { _capturer.SetWebCamVideoRectangle((int)nmWebCamLeft.Value, (int)nmWebCamTop.Value, (int)nmWebCamWidth.Value, (int)nmWebCamHeight.Value); _capturer.CurrentWebCamName = cmbWebCam.SelectedItem.ToString(); } //_capturer.CurrentVideoCodecName = cmbVideoCodec.SelectedItem.ToString(); if (!string.IsNullOrEmpty(txtLogFile.Text)) { _capturer.SetLogFile(txtLogFile.Text); } _capturer.OutputFileName = txtOutputFile.Text; _capturer.CapturingType = (CaptureAreaType)cmbCaptureAreaType.SelectedItem; _previewGraphics = pnlPreview.CreateGraphics(); _previewHdc = _previewGraphics.GetHdc().ToInt32(); _capturer.SetFullPreviewContext(_previewHdc, 0, 0, pnlPreview.Width, pnlPreview.Height, 5); _capturer.CaptureRectLeft = (int)nmCaptureLeft.Value; _capturer.CaptureRectTop = (int)nmCaptureTop.Value; _capturer.CaptureRectWidth = (int)nmCaptureWidth.Value; _capturer.CaptureRectHeight = (int)nmCaptureHeight.Value; _capturer.OutputWidth = (int)nmOutputWidth.Value; _capturer.OutputHeight = (int)nmOutputHeight.Value; foreach (ListViewItem item in lstOverlays.Items) { Overlay overlay = item.Tag as Overlay; if (overlay is TextOverlay) { TextOverlay textOverlay = overlay as TextOverlay; int a = (int)textOverlay.BackColor.A; //_capturer.AddTextOverlay(textOverlay.Left, textOverlay.Top, textOverlay.Text, textOverlay.Font.Name, // (int)textOverlay.Font.Size,textOverlay.Font.Bold, textOverlay.Font.Italic, // textOverlay.Font.Underline, (uint)ColorTranslator.ToOle(textOverlay.Color)); _capturer.AddTextOverlayWithBackground2(textOverlay.Left, textOverlay.Top, textOverlay.Text, textOverlay.Font.Name, (int)textOverlay.Font.Size, textOverlay.Font.Bold, textOverlay.Font.Italic, textOverlay.Font.Underline, textOverlay.Color.R, textOverlay.Color.G, textOverlay.Color.B, textOverlay.Color.A, textOverlay.BackColor.R, textOverlay.BackColor.G, textOverlay.BackColor.B, textOverlay.BackColor.A); } else if (overlay is ImageOverlay) { ImageOverlay imageOverlay = overlay as ImageOverlay; _capturer.AddImageOverlay(imageOverlay.Left, imageOverlay.Top, imageOverlay.FileName); } } _capturer.Run(); //' IMPORTANT: if you want to check for some code if need to stop the recording then make sure you are //' using Thread.Sleep(1) inside the checking loop, so you have the loop like //' Do { //' Thread.Sleep(1) //' } //' While(StopButtonNotClicked); btnRecord.Text = "Stop"; grpProperties.Enabled = false; lblStatus.Text = "Running"; } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
public static async void BeginScreenCasting(string viewerID, string requesterName, ICapturer capturer, Conductor conductor) { Viewer viewer; byte[] encodedImageBytes; var success = false; Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {conductor.Mode} Desktop: {conductor.CurrentDesktopName}"); viewer = new Viewer() { Capturer = capturer, DisconnectRequested = false, Name = requesterName, ViewerConnectionID = viewerID, HasControl = true }; while (!success) { success = conductor.Viewers.TryAdd(viewerID, viewer); } if (conductor.Mode == Enums.AppMode.Normal) { conductor.InvokeViewerAdded(viewer); } await conductor.OutgoingMessages.SendScreenCount( capturer.SelectedScreen, capturer.GetScreenCount(), viewerID); await conductor.OutgoingMessages.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID); capturer.ScreenChanged += async(sender, bounds) => { await conductor.OutgoingMessages.SendScreenSize(bounds.Width, bounds.Height, viewerID); }; // TODO: SetThradDesktop causes issues with input after switching. //var desktopName = Win32Interop.GetCurrentDesktop(); while (!viewer.DisconnectRequested) { try { // TODO: SetThradDesktop causes issues with input after switching. //var currentDesktopName = Win32Interop.GetCurrentDesktop(); //if (desktopName.ToLower() != currentDesktopName.ToLower()) //{ // desktopName = currentDesktopName; // Logger.Write($"Switching to desktop {desktopName} in ScreenCaster."); // var inputDesktop = Win32Interop.OpenInputDesktop(); // User32.SetThreadDesktop(inputDesktop); // User32.CloseDesktop(inputDesktop); // continue; //} while (viewer.PendingFrames > 10) { await Task.Delay(1); } capturer.Capture(); var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen); if (diffArea.IsEmpty) { continue; } using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { if (capturer.CaptureFullscreen) { capturer.CaptureFullscreen = false; } //long newQuality; //if (viewer.PendingFrames < 8) //{ // newQuality = Math.Min(1, viewer.ImageQuality + 1); //} //else //{ // newQuality = Math.Max(0, viewer.ImageQuality - 1); //} //if (newQuality != viewer.ImageQuality) //{ // Logger.Write($"New quality: {newQuality}"); // viewer.ImageQuality = newQuality; // viewer.FullScreenRefreshNeeded = true; //} //else if (viewer.FullScreenRefreshNeeded) //{ // Logger.Write($"Quality stabilized."); // capturer.CaptureFullscreen = true; // viewer.FullScreenRefreshNeeded = false; //} encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams); if (encodedImageBytes?.Length > 0) { await conductor.OutgoingMessages.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow); viewer.PendingFrames++; } // TODO: Even after disposing of the bitmap, GC doesn't collect in time. Memory usage soars quickly. // Need to revisit this later. GC.Collect(); } } catch (Exception ex) { Logger.Write(ex); } } Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}."); success = false; while (!success) { success = conductor.Viewers.TryRemove(viewerID, out _); } capturer.Dispose(); // Close if no one is viewing. if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended) { Environment.Exit(0); } }
public void Close() { /* resetting common properties */ pausebutton.Visible = false; stopbutton.Visible = false; recbutton.Visible = true; captureStarted = false; capturing = false; OnTick(0); if (capturer == null) return; /* stopping and closing capturer */ try { capturer.Stop(); capturer.Close(); if (capturerType == CapturerType.Live){ /* release and dispose live capturer */ capturer.Error -= OnError; capturer.DeviceChange += OnDeviceChange; capturerhbox.Remove(capturer as Gtk.Widget); capturer.Dispose(); } } catch (Exception e) {} capturer = null; }
public ScreenSpy(ICapturer capturer) => _capturer = capturer;
public async Task BeginScreenCasting(string viewerID, string requesterName, ICapturer capturer) { var conductor = Conductor.Current; Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {conductor.Mode}"); byte[] encodedImageBytes; var fpsQueue = new Queue <DateTime>(); var viewer = new Viewer() { Capturer = capturer, DisconnectRequested = false, Name = requesterName, ViewerConnectionID = viewerID, HasControl = true }; conductor.Viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer); if (conductor.Mode == Enums.AppMode.Normal) { conductor.InvokeViewerAdded(viewer); } await conductor.CasterSocket.SendMachineName(Environment.MachineName, viewerID); await conductor.CasterSocket.SendScreenCount( capturer.SelectedScreen, capturer.GetScreenCount(), viewerID); await conductor.CasterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID); capturer.ScreenChanged += async(sender, bounds) => { await conductor.CasterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID); }; while (!viewer.DisconnectRequested) { try { if (viewer.Latency > 30000) { // Viewer isn't responding. Abort sending. break; } if (Conductor.Current.IsDebug) { while (fpsQueue.Any() && DateTime.Now - fpsQueue.Peek() > TimeSpan.FromSeconds(1)) { fpsQueue.Dequeue(); } fpsQueue.Enqueue(DateTime.Now); Debug.WriteLine($"Capture FPS: {fpsQueue.Count}"); } if (viewer.OutputBuffer > 150_000) { Debug.WriteLine($"Waiting for buffer to clear. Size: {viewer.OutputBuffer}"); await Task.Delay(50); continue; } capturer.GetNextFrame(); var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen); if (diffArea.IsEmpty) { continue; } using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { if (capturer.CaptureFullscreen) { capturer.CaptureFullscreen = false; } if (viewer.AutoAdjustQuality && viewer.Latency > 1000) { var quality = (int)(viewer.ImageQuality * 1000 / viewer.Latency); Debug.WriteLine($"Auto-adjusting image quality. Latency: {viewer.Latency}. Quality: {quality}"); encodedImageBytes = ImageUtils.EncodeBitmap(newImage, new EncoderParameters() { Param = new[] { new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality) } }); } else { encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams); } if (encodedImageBytes?.Length > 0) { await conductor.CasterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow); viewer.Latency += 300; viewer.OutputBuffer += encodedImageBytes.Length; } } } catch (Exception ex) { Logger.Write(ex); } finally { GC.Collect(); } } Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}."); conductor.Viewers.TryRemove(viewerID, out _); capturer.Dispose(); // Close if no one is viewing. if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended) { await conductor.CasterSocket.Disconnect(); Environment.Exit(0); } }
private void btnRecord_Click(object sender, EventArgs e) { try { if (_capturer.IsRunning) { _capturer.Stop(); System.Runtime.InteropServices.Marshal.ReleaseComObject(_capturer); _capturer = null; InitCapturer(); // lstOverlays.Items.Clear(); btnRecord.Text = "Record"; tabControl1.Enabled = true; lblStatus.Text = "Stopped"; timer1.Stop(); _captureStarted = false; btnPause.Enabled = false; _isPaused = false; } else { if (!_isPaused) { _capturer.AudioEnabled = chkEnableAudio.Checked; if (chkEnableAudio.Checked) { _capturer.CurrentAudioDeviceName = cmbAudioDevices.SelectedItem.ToString(); //_capturer.CurrentAudioCodecName = cmbAudioCodecs.SelectedItem.ToString(); } _capturer.AddWebCamVideo = chkEnableWebcam.Checked; if (chkEnableWebcam.Checked) { _capturer.SetWebCamVideoRectangle((int)nmWebCamLeft.Value, (int)nmWebCamTop.Value, (int)nmWebCamWidth.Value, (int)nmWebCamHeight.Value); _capturer.CurrentWebCamName = cmbWebCam.SelectedItem.ToString(); } //_capturer.CurrentVideoCodecName = cmbVideoCodec.SelectedItem.ToString(); if (!string.IsNullOrEmpty(txtLogFile.Text) && cbWriteLog.Checked) { _capturer.SetLogFile(txtLogFile.Text); } _capturer.OutputFileName = txtOutputFile.Text; _capturer.CapturingType = (CaptureAreaType)cmbCaptureAreaType.SelectedItem; _previewGraphics = pnlPreview.CreateGraphics(); _previewHdc = _previewGraphics.GetHdc().ToInt32(); _capturer.SetFullPreviewContext(_previewHdc, 0, 0, pnlPreview.Width, pnlPreview.Height, 5); _capturer.CaptureRectLeft = (int)nmCaptureLeft.Value; _capturer.CaptureRectTop = (int)nmCaptureTop.Value; _capturer.CaptureRectWidth = (int)nmCaptureWidth.Value; _capturer.CaptureRectHeight = (int)nmCaptureHeight.Value; _capturer.OutputWidth = (int)nmOutputWidth.Value; _capturer.OutputHeight = (int)nmOutputHeight.Value; foreach (ListViewItem item in lstOverlays.Items) { Overlay overlay = item.Tag as Overlay; if (overlay is TextOverlay) { TextOverlay textOverlay = overlay as TextOverlay; int a = (int)textOverlay.BackColor.A; //_capturer.AddTextOverlay(textOverlay.Left, textOverlay.Top, textOverlay.Text, textOverlay.Font.Name, // (int)textOverlay.Font.Size,textOverlay.Font.Bold, textOverlay.Font.Italic, // textOverlay.Font.Underline, (uint)ColorTranslator.ToOle(textOverlay.Color)); _capturer.AddTextOverlayWithBackground2(textOverlay.Left, textOverlay.Top, textOverlay.Text, textOverlay.Font.Name, (int)textOverlay.Font.Size, textOverlay.Font.Bold, textOverlay.Font.Italic, textOverlay.Font.Underline, textOverlay.Color.R, textOverlay.Color.G, textOverlay.Color.B, textOverlay.Color.A, textOverlay.BackColor.R, textOverlay.BackColor.G, textOverlay.BackColor.B, textOverlay.BackColor.A); } else if (overlay is ImageOverlay) { ImageOverlay imageOverlay = overlay as ImageOverlay; _capturer.AddImageOverlay(imageOverlay.Left, imageOverlay.Top, imageOverlay.FileName); } } _capturer.RecordingMode = (RecordingModeType)cmbMotionDetection.SelectedItem; _capturer.NoMotionDetectedActionInterval = (int)nmMotionInterval.Value; _capturer.NoMotionDetectedActionSensitivity = (double)nmMotionSensitivity.Value; _capturer.MonitorIndex = (int)cmbCurrentMonitor.SelectedItem; } _capturer.Run(); btnRecord.Text = "Stop"; tabControl1.Enabled = false; lblStatus.Text = "Running"; _captureStarted = true; timer1.Start(); _isPaused = false; btnPause.Enabled = true; } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
public static async void BeginScreenCasting(string viewerID, string requesterName, ICapturer capturer, Conductor conductor) { Viewer viewer; byte[] encodedImageBytes; Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {conductor.Mode} Desktop: {conductor.CurrentDesktopName}"); viewer = new Viewer() { Capturer = capturer, DisconnectRequested = false, Name = requesterName, ViewerConnectionID = viewerID, HasControl = true }; conductor.Viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer); if (conductor.Mode == Enums.AppMode.Normal) { conductor.InvokeViewerAdded(viewer); } await conductor.CasterSocket.SendMachineName(Environment.MachineName, viewerID); await conductor.CasterSocket.SendScreenCount( capturer.SelectedScreen, capturer.GetScreenCount(), viewerID); await conductor.CasterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID); capturer.ScreenChanged += async(sender, bounds) => { await conductor.CasterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID); }; var desktopName = string.Empty; if (OSUtils.IsWindows) { desktopName = Win32Interop.GetCurrentDesktop(); } while (!viewer.DisconnectRequested) { try { var currentDesktopName = Win32Interop.GetCurrentDesktop(); if (desktopName.ToLower() != currentDesktopName.ToLower()) { desktopName = currentDesktopName; Logger.Write($"Switching to desktop {desktopName} in ScreenCaster."); Win32Interop.SwitchToInputDesktop(); continue; } while (viewer.PendingFrames > 10) { await Task.Delay(1); } capturer.Capture(); var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen); if (diffArea.IsEmpty) { continue; } using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { if (capturer.CaptureFullscreen) { capturer.CaptureFullscreen = false; } encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams); if (encodedImageBytes?.Length > 0) { await conductor.CasterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow); viewer.PendingFrames++; } } } catch (Exception ex) { Logger.Write(ex); } finally { // TODO: Even after disposing of the bitmap, GC doesn't collect in time. Memory usage soars quickly. // Need to revisit this later. GC.Collect(); } } Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}."); conductor.Viewers.TryRemove(viewerID, out _); capturer.Dispose(); // Close if no one is viewing. if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended) { Environment.Exit(0); } }
public async Task BeginScreenCasting(string viewerID, string requesterName, ICapturer capturer) { var conductor = ServiceContainer.Instance.GetRequiredService <Conductor>(); var viewers = conductor.Viewers; var mode = conductor.Mode; var casterSocket = ServiceContainer.Instance.GetRequiredService <CasterSocket>(); Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {mode}"); byte[] encodedImageBytes; var fpsQueue = new Queue <DateTime>(); var viewer = new Viewer() { Capturer = capturer, DisconnectRequested = false, Name = requesterName, ViewerConnectionID = viewerID, HasControl = true }; viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer); if (mode == Enums.AppMode.Normal) { conductor.InvokeViewerAdded(viewer); } if (OSUtils.IsWindows) { await InitializeWebRtc(viewer, casterSocket); } await casterSocket.SendMachineName(Environment.MachineName, viewerID); await casterSocket.SendScreenCount( capturer.SelectedScreen, capturer.GetScreenCount(), viewerID); await casterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID); capturer.ScreenChanged += async(sender, bounds) => { await casterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID); }; while (!viewer.DisconnectRequested) { try { if (viewer.IsStalled()) { // Viewer isn't responding. Abort sending. break; } if (conductor.IsDebug) { while (fpsQueue.Any() && DateTime.Now - fpsQueue.Peek() > TimeSpan.FromSeconds(1)) { fpsQueue.Dequeue(); } fpsQueue.Enqueue(DateTime.Now); Debug.WriteLine($"Capture FPS: {fpsQueue.Count}"); } await viewer.ThrottleIfNeeded(); capturer.GetNextFrame(); var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen); if (diffArea.IsEmpty) { continue; } using (var newImage = capturer.CurrentFrame.Clone(diffArea, PixelFormat.Format32bppArgb)) { if (capturer.CaptureFullscreen) { capturer.CaptureFullscreen = false; } if (viewer.ShouldAdjustQuality()) { var quality = (int)(viewer.ImageQuality * 1000 / viewer.Latency); Logger.Debug($"Auto-adjusting image quality. Latency: {viewer.Latency}. Quality: {quality}"); encodedImageBytes = ImageUtils.EncodeBitmap(newImage, new EncoderParameters() { Param = new[] { new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality) } }); } else { encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams); } if (encodedImageBytes?.Length > 0) { if (viewer.IsUsingWebRtc()) { viewer.RtcSession.SendCaptureFrame(diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, encodedImageBytes); viewer.WebSocketBuffer = 0; viewer.Latency = 0; } else { await casterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow); viewer.Latency += 300; // Shave some off so it doesn't get deadlocked by dropped frames. viewer.WebSocketBuffer += (int)(encodedImageBytes.Length * .9); } } } } catch (Exception ex) { Logger.Write(ex); } finally { GC.Collect(); } } Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}."); viewers.TryRemove(viewerID, out _); var shouldExit = viewers.Count == 0 && mode == Enums.AppMode.Unattended; try { viewer.Dispose(); if (shouldExit) { capturer.Dispose(); await casterSocket.Disconnect(); } } catch (Exception ex) { Logger.Write(ex); } finally { // Close if no one is viewing. if (shouldExit) { Logger.Debug($"Exiting process ID {Process.GetCurrentProcess().Id}."); Environment.Exit(0); } } }