Pause video feed while the computer is locked

This commit is contained in:
Mark van Renswoude 2021-07-13 21:57:06 +02:00
parent 6284bd0609
commit 3995ab92a2
5 changed files with 114 additions and 17 deletions

View File

@ -28,10 +28,13 @@
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CameraView));
this.ConnectingLabel = new System.Windows.Forms.Label(); this.ConnectingLabel = new System.Windows.Forms.Label();
this.StreamView = new System.Windows.Forms.PictureBox(); this.StreamView = new System.Windows.Forms.PictureBox();
this.IssueLabel = new System.Windows.Forms.Label(); this.IssueLabel = new System.Windows.Forms.Label();
this.PausedOverlay = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.StreamView)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.StreamView)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.PausedOverlay)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// ConnectingLabel // ConnectingLabel
@ -71,17 +74,30 @@
this.IssueLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.IssueLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.IssueLabel.Visible = false; this.IssueLabel.Visible = false;
// //
// PausedOverlay
//
this.PausedOverlay.BackColor = System.Drawing.Color.Transparent;
this.PausedOverlay.Image = ((System.Drawing.Image)(resources.GetObject("PausedOverlay.Image")));
this.PausedOverlay.Location = new System.Drawing.Point(19, 40);
this.PausedOverlay.Name = "PausedOverlay";
this.PausedOverlay.Size = new System.Drawing.Size(64, 64);
this.PausedOverlay.TabIndex = 3;
this.PausedOverlay.TabStop = false;
this.PausedOverlay.Visible = false;
//
// CameraView // CameraView
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Gray; this.BackColor = System.Drawing.Color.Gray;
this.Controls.Add(this.PausedOverlay);
this.Controls.Add(this.IssueLabel); this.Controls.Add(this.IssueLabel);
this.Controls.Add(this.StreamView); this.Controls.Add(this.StreamView);
this.Controls.Add(this.ConnectingLabel); this.Controls.Add(this.ConnectingLabel);
this.Margin = new System.Windows.Forms.Padding(0); this.Margin = new System.Windows.Forms.Padding(0);
this.Name = "CameraView"; this.Name = "CameraView";
((System.ComponentModel.ISupportInitialize)(this.StreamView)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.StreamView)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.PausedOverlay)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
} }
@ -91,5 +107,6 @@
private System.Windows.Forms.Label ConnectingLabel; private System.Windows.Forms.Label ConnectingLabel;
private System.Windows.Forms.PictureBox StreamView; private System.Windows.Forms.PictureBox StreamView;
private System.Windows.Forms.Label IssueLabel; private System.Windows.Forms.Label IssueLabel;
private System.Windows.Forms.PictureBox PausedOverlay;
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -11,32 +12,50 @@ namespace IPCamAppBar
{ {
public partial class CameraView : UserControl, IRetryableCameraObserver public partial class CameraView : UserControl, IRetryableCameraObserver
{ {
private readonly ICamera camera;
private readonly bool overlayDateTime; private readonly bool overlayDateTime;
private Bitmap viewBitmap; private Bitmap viewBitmap;
private CancellationTokenSource streamCancellationTokenSource;
public CameraView(ICamera camera, bool overlayDateTime) public CameraView(ICamera camera, bool overlayDateTime)
{ {
this.camera = camera;
this.overlayDateTime = overlayDateTime; this.overlayDateTime = overlayDateTime;
InitializeComponent(); InitializeComponent();
var streamCancellationTokenSource = new CancellationTokenSource(); StartCamera();
Disposed += (_, _) =>
{
StopCamera();
};
}
private void StartCamera()
{
streamCancellationTokenSource = new CancellationTokenSource();
Task.Run(async () => Task.Run(async () =>
{ {
var retryableCamera = new RetryableCamera(camera); var retryableCamera = new RetryableCamera(camera);
await retryableCamera.Fetch(this, streamCancellationTokenSource.Token); await retryableCamera.Fetch(this, streamCancellationTokenSource.Token);
}); });
}
Disposed += (_, _) =>
{
streamCancellationTokenSource.Cancel(); private void StopCamera()
}; {
streamCancellationTokenSource.Cancel();
} }
private Bitmap resizedBitmap; private Bitmap resizedBitmap;
public Task OnFrame(Image image) public Task OnFrame(Image image)
{ {
if (streamCancellationTokenSource.IsCancellationRequested)
return Task.CompletedTask;
if (overlayDateTime || image is not Bitmap bitmap || image.Width != Width || image.Height != Height) if (overlayDateTime || image is not Bitmap bitmap || image.Width != Width || image.Height != Height)
{ {
resizedBitmap ??= new Bitmap(Width, Height); resizedBitmap ??= new Bitmap(Width, Height);
@ -100,6 +119,7 @@ namespace IPCamAppBar
ConnectingLabel.Visible = false; ConnectingLabel.Visible = false;
StreamView.Visible = true; StreamView.Visible = true;
IssueLabel.Visible = false; IssueLabel.Visible = false;
PausedOverlay.Visible = false;
if (viewBitmap == null) if (viewBitmap == null)
@ -130,12 +150,28 @@ namespace IPCamAppBar
private void InvokeDisconnected(Exception exception, TimeSpan retryDelay) private void InvokeDisconnected(Exception exception, TimeSpan retryDelay)
{ {
if (IsDisposed) if (IsDisposed || streamCancellationTokenSource.IsCancellationRequested)
return; return;
IssueLabel.Text = (exception?.Message ?? "Camera disconnected") + $", retrying in {retryDelay.TotalSeconds} seconds"; IssueLabel.Text = (exception?.Message ?? "Camera disconnected") + $", retrying in {retryDelay.TotalSeconds} seconds";
IssueLabel.Visible = true; IssueLabel.Visible = true;
IssueLabel.BringToFront(); IssueLabel.BringToFront();
} }
public void SetPaused(bool pause)
{
if (pause)
{
StopCamera();
PausedOverlay.Left = (Width - PausedOverlay.Width) / 2;
PausedOverlay.Top = (Height - PausedOverlay.Height) / 2;
PausedOverlay.Visible = true;
PausedOverlay.BringToFront();
}
else
StartCamera();
}
} }
} }

View File

@ -117,4 +117,18 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="PausedOverlay.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAF8SURBVHhetc8xCsAAEALB/P/TF9PaSZiBrcXnvG/j
TxQfiD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+
tEbxgehDaxQfiD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+IPrRG8YHo
Q2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+I
PrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB
6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQf
iD60RvGB6ENrFB+IPrRG8YHoQ2sUH4g+tEbxgehDaxQfiD60RvGB6ENrFB+IPrQG3b1Awcd2Z2RJDQAA
AABJRU5ErkJggg==
</value>
</data>
</root> </root>

View File

@ -5,6 +5,7 @@ using System.Reflection;
using System.Windows.Forms; using System.Windows.Forms;
using IPCamLib; using IPCamLib;
using IPCamLib.Concrete; using IPCamLib.Concrete;
using Microsoft.Win32;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace IPCamAppBar namespace IPCamAppBar
@ -13,6 +14,7 @@ namespace IPCamAppBar
{ {
private readonly Config config; private readonly Config config;
private readonly AppBar appBar; private readonly AppBar appBar;
private bool paused = false;
public MainForm() public MainForm()
@ -39,6 +41,9 @@ namespace IPCamAppBar
: FlowDirection.LeftToRight; : FlowDirection.LeftToRight;
config.Cameras?.ForEach(AddCamera); config.Cameras?.ForEach(AddCamera);
SystemEvents.SessionSwitch += SystemEventsOnSessionSwitch;
} }
@ -65,15 +70,14 @@ namespace IPCamAppBar
private static AppBarPosition GetAppBarPosition(ConfigSide side) private static AppBarPosition GetAppBarPosition(ConfigSide side)
{ {
switch (side) return side switch
{ {
case ConfigSide.Top: return AppBarPosition.Top; ConfigSide.Top => AppBarPosition.Top,
case ConfigSide.Bottom: return AppBarPosition.Bottom; ConfigSide.Bottom => AppBarPosition.Bottom,
case ConfigSide.Left: return AppBarPosition.Left; ConfigSide.Left => AppBarPosition.Left,
case ConfigSide.Right: return AppBarPosition.Right; ConfigSide.Right => AppBarPosition.Right,
default: _ => throw new ArgumentOutOfRangeException(nameof(side), side, @"Invalid side value")
throw new ArgumentOutOfRangeException(nameof(side), side, @"Invalid side value"); };
}
} }
@ -113,5 +117,31 @@ namespace IPCamAppBar
{ {
Close(); Close();
} }
private void SystemEventsOnSessionSwitch(object sender, SessionSwitchEventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action(() => SystemEventsOnSessionSwitch(sender, e)));
return;
}
var pause = e.Reason == SessionSwitchReason.ConsoleDisconnect ||
e.Reason == SessionSwitchReason.RemoteDisconnect ||
e.Reason == SessionSwitchReason.SessionLock ||
e.Reason == SessionSwitchReason.SessionLogoff;
if (pause == paused)
return;
foreach (var control in CameraViewContainer.Controls)
{
if (control is CameraView cameraView)
cameraView.SetPaused(pause);
}
paused = pause;
}
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B