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>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CameraView));
this.ConnectingLabel = new System.Windows.Forms.Label();
this.StreamView = new System.Windows.Forms.PictureBox();
this.IssueLabel = new System.Windows.Forms.Label();
this.PausedOverlay = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.StreamView)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.PausedOverlay)).BeginInit();
this.SuspendLayout();
//
// ConnectingLabel
@ -71,17 +74,30 @@
this.IssueLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
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
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Gray;
this.Controls.Add(this.PausedOverlay);
this.Controls.Add(this.IssueLabel);
this.Controls.Add(this.StreamView);
this.Controls.Add(this.ConnectingLabel);
this.Margin = new System.Windows.Forms.Padding(0);
this.Name = "CameraView";
((System.ComponentModel.ISupportInitialize)(this.StreamView)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.PausedOverlay)).EndInit();
this.ResumeLayout(false);
}
@ -91,5 +107,6 @@
private System.Windows.Forms.Label ConnectingLabel;
private System.Windows.Forms.PictureBox StreamView;
private System.Windows.Forms.Label IssueLabel;
private System.Windows.Forms.PictureBox PausedOverlay;
}
}

View File

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

View File

@ -5,6 +5,7 @@ using System.Reflection;
using System.Windows.Forms;
using IPCamLib;
using IPCamLib.Concrete;
using Microsoft.Win32;
using Newtonsoft.Json;
namespace IPCamAppBar
@ -13,6 +14,7 @@ namespace IPCamAppBar
{
private readonly Config config;
private readonly AppBar appBar;
private bool paused = false;
public MainForm()
@ -39,6 +41,9 @@ namespace IPCamAppBar
: FlowDirection.LeftToRight;
config.Cameras?.ForEach(AddCamera);
SystemEvents.SessionSwitch += SystemEventsOnSessionSwitch;
}
@ -65,15 +70,14 @@ namespace IPCamAppBar
private static AppBarPosition GetAppBarPosition(ConfigSide side)
{
switch (side)
return side switch
{
case ConfigSide.Top: return AppBarPosition.Top;
case ConfigSide.Bottom: return AppBarPosition.Bottom;
case ConfigSide.Left: return AppBarPosition.Left;
case ConfigSide.Right: return AppBarPosition.Right;
default:
throw new ArgumentOutOfRangeException(nameof(side), side, @"Invalid side value");
}
ConfigSide.Top => AppBarPosition.Top,
ConfigSide.Bottom => AppBarPosition.Bottom,
ConfigSide.Left => AppBarPosition.Left,
ConfigSide.Right => AppBarPosition.Right,
_ => throw new ArgumentOutOfRangeException(nameof(side), side, @"Invalid side value")
};
}
@ -113,5 +117,31 @@ namespace IPCamAppBar
{
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