From 0f1e3811cce92fa2becc6dcf9c5ccf76bc4fb118 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Wed, 15 May 2019 17:22:53 -0700 Subject: [PATCH] Remote control session recorder now pipes directly into MP4 file. XAML fix for Avalonia project. --- Remotely_Desktop.Unix/App.xaml | 2 +- .../Controls/HostNamePrompt.xaml | 2 +- .../Controls/MessageBox.xaml | 2 +- .../Remotely_Desktop.Unix.csproj | 20 +++--- .../ViewModels/MainWindowViewModel.cs | 5 ++ Remotely_Desktop.Unix/Views/MainWindow.xaml | 2 +- Remotely_Desktop.Win/App.config | 4 ++ .../Remotely_Desktop.Win.csproj | 12 ++-- Remotely_Desktop.Win/packages.config | 4 +- .../Remotely_ScreenCast.Core.csproj | 2 +- Remotely_ScreenCast.Win/App.config | 4 ++ .../Remotely_ScreenCast.Win.csproj | 16 ++--- Remotely_ScreenCast.Win/packages.config | 8 +-- Remotely_Server/CurrentVersion.txt | 2 +- .../Models/RecordingSessionState.cs | 15 ++++ Remotely_Server/Remotely_Server.csproj | 2 +- .../Services/RCBrowserSocketHub.cs | 2 +- .../Services/RemoteControlSessionRecorder.cs | 69 ++++++++----------- 18 files changed, 93 insertions(+), 80 deletions(-) create mode 100644 Remotely_Server/Models/RecordingSessionState.cs diff --git a/Remotely_Desktop.Unix/App.xaml b/Remotely_Desktop.Unix/App.xaml index 850e44d6..71d35736 100644 --- a/Remotely_Desktop.Unix/App.xaml +++ b/Remotely_Desktop.Unix/App.xaml @@ -1,6 +1,6 @@  diff --git a/Remotely_Desktop.Unix/Controls/HostNamePrompt.xaml b/Remotely_Desktop.Unix/Controls/HostNamePrompt.xaml index b9f6f37a..6998a78e 100644 --- a/Remotely_Desktop.Unix/Controls/HostNamePrompt.xaml +++ b/Remotely_Desktop.Unix/Controls/HostNamePrompt.xaml @@ -4,7 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Remotely_Desktop.Unix.Controls.HostNamePrompt" - xmlns:ViewModels="clr-namespace:Remotely_Desktop.Unix.ViewModels" + xmlns:ViewModels="clr-namespace:Remotely_Desktop.Unix.ViewModels;assembly=Remotely_Desktop" Title="Remotely Host Name" Height="150" Width="350" WindowStartupLocation="CenterOwner"> diff --git a/Remotely_Desktop.Unix/Controls/MessageBox.xaml b/Remotely_Desktop.Unix/Controls/MessageBox.xaml index 5f8d877b..93ccdb04 100644 --- a/Remotely_Desktop.Unix/Controls/MessageBox.xaml +++ b/Remotely_Desktop.Unix/Controls/MessageBox.xaml @@ -3,7 +3,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:vm="clr-namespace:Remotely_Desktop.Unix.ViewModels;assembly=Remotely_Desktop.Unix" + xmlns:vm="clr-namespace:Remotely_Desktop.Unix.ViewModels;assembly=Remotely_Desktop" x:Class="Remotely_Desktop.Unix.Controls.MessageBox" Title="{Binding Caption}" SizeToContent="WidthAndHeight" MinWidth="200" MinHeight="100" WindowStartupLocation="CenterOwner"> diff --git a/Remotely_Desktop.Unix/Remotely_Desktop.Unix.csproj b/Remotely_Desktop.Unix/Remotely_Desktop.Unix.csproj index 9698237c..a648a15f 100644 --- a/Remotely_Desktop.Unix/Remotely_Desktop.Unix.csproj +++ b/Remotely_Desktop.Unix/Remotely_Desktop.Unix.csproj @@ -17,24 +17,24 @@ + + + + + MSBuild:Compile + + + MSBuild:Compile + + - - - MSBuild:Compile - - - - - MSBuild:Compile - - diff --git a/Remotely_Desktop.Unix/ViewModels/MainWindowViewModel.cs b/Remotely_Desktop.Unix/ViewModels/MainWindowViewModel.cs index d20f5665..ced42d60 100644 --- a/Remotely_Desktop.Unix/ViewModels/MainWindowViewModel.cs +++ b/Remotely_Desktop.Unix/ViewModels/MainWindowViewModel.cs @@ -155,6 +155,11 @@ namespace Remotely_Desktop.Unix.ViewModels { Conductor.SetMessageHandlers(new X11Input()); } + + if (OSUtils.IsWindows) + { + return; + } await Conductor.CasterSocket.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName); await Conductor.CasterSocket.GetSessionID(); diff --git a/Remotely_Desktop.Unix/Views/MainWindow.xaml b/Remotely_Desktop.Unix/Views/MainWindow.xaml index 6852e72d..2a8ae6c6 100644 --- a/Remotely_Desktop.Unix/Views/MainWindow.xaml +++ b/Remotely_Desktop.Unix/Views/MainWindow.xaml @@ -1,6 +1,6 @@  + + + + \ No newline at end of file diff --git a/Remotely_Desktop.Win/Remotely_Desktop.Win.csproj b/Remotely_Desktop.Win/Remotely_Desktop.Win.csproj index 749315f4..c864b330 100644 --- a/Remotely_Desktop.Win/Remotely_Desktop.Win.csproj +++ b/Remotely_Desktop.Win/Remotely_Desktop.Win.csproj @@ -1,6 +1,6 @@  - + @@ -51,8 +51,8 @@ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll - - ..\packages\PropertyChanged.Fody.3.0.0\lib\net452\PropertyChanged.dll + + ..\packages\PropertyChanged.Fody.3.0.1\lib\net452\PropertyChanged.dll @@ -148,13 +148,13 @@ - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + + + \ No newline at end of file diff --git a/Remotely_Desktop.Win/packages.config b/Remotely_Desktop.Win/packages.config index 39524c0f..5f0c7813 100644 --- a/Remotely_Desktop.Win/packages.config +++ b/Remotely_Desktop.Win/packages.config @@ -1,7 +1,7 @@  - + - + \ No newline at end of file diff --git a/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj b/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj index 8f3e1748..30fa02af 100644 --- a/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj +++ b/Remotely_ScreenCast.Core/Remotely_ScreenCast.Core.csproj @@ -15,7 +15,7 @@ - + diff --git a/Remotely_ScreenCast.Win/App.config b/Remotely_ScreenCast.Win/App.config index 63d075b4..1e150b0e 100644 --- a/Remotely_ScreenCast.Win/App.config +++ b/Remotely_ScreenCast.Win/App.config @@ -25,6 +25,10 @@ + + + + \ No newline at end of file diff --git a/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj b/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj index cea4268a..5e424d58 100644 --- a/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj +++ b/Remotely_ScreenCast.Win/Remotely_ScreenCast.Win.csproj @@ -41,8 +41,8 @@ ..\packages\Costura.Fody.4.0.0\lib\net40\Costura.dll - - ..\packages\MessagePack.1.7.3.4\lib\net47\MessagePack.dll + + ..\packages\MessagePack.1.7.3.7\lib\net47\MessagePack.dll ..\packages\Microsoft.AspNetCore.Connections.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll @@ -68,8 +68,8 @@ ..\packages\Microsoft.AspNetCore.SignalR.Protocols.Json.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll - - ..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll + + ..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.1.1.5\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll ..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll @@ -126,8 +126,8 @@ ..\packages\System.IO.Pipelines.4.5.3\lib\netstandard2.0\System.IO.Pipelines.dll - - ..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll @@ -186,12 +186,12 @@ copy /y "$(TargetPath)" "$(SolutionDir)Remotely_Agent\bin\Debug\netcoreapp2.2\ScreenCast\" ) - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + + \ No newline at end of file diff --git a/Remotely_ScreenCast.Win/packages.config b/Remotely_ScreenCast.Win/packages.config index 1f1ce765..14249384 100644 --- a/Remotely_ScreenCast.Win/packages.config +++ b/Remotely_ScreenCast.Win/packages.config @@ -1,8 +1,8 @@  - - + + @@ -11,7 +11,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/Remotely_Server/CurrentVersion.txt b/Remotely_Server/CurrentVersion.txt index a3050ac0..c205aedd 100644 --- a/Remotely_Server/CurrentVersion.txt +++ b/Remotely_Server/CurrentVersion.txt @@ -1 +1 @@ -2019.05.09.2205 +2019.05.15.1708 diff --git a/Remotely_Server/Models/RecordingSessionState.cs b/Remotely_Server/Models/RecordingSessionState.cs new file mode 100644 index 00000000..76b49233 --- /dev/null +++ b/Remotely_Server/Models/RecordingSessionState.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Threading.Tasks; + +namespace Remotely_Server.Models +{ + public class RecordingSessionState + { + public Bitmap CumulativeFrame { get; set; } + public Process FfmpegProcess { get; set; } + } +} diff --git a/Remotely_Server/Remotely_Server.csproj b/Remotely_Server/Remotely_Server.csproj index 85ad91b7..dd8694ce 100644 --- a/Remotely_Server/Remotely_Server.csproj +++ b/Remotely_Server/Remotely_Server.csproj @@ -56,7 +56,7 @@ - + diff --git a/Remotely_Server/Services/RCBrowserSocketHub.cs b/Remotely_Server/Services/RCBrowserSocketHub.cs index e3d6d2e5..a3bf6b30 100644 --- a/Remotely_Server/Services/RCBrowserSocketHub.cs +++ b/Remotely_Server/Services/RCBrowserSocketHub.cs @@ -134,7 +134,7 @@ namespace Remotely_Server.Services if (AppConfig.RecordRemoteControlSessions) { - RCSessionRecorder.EncodeFrames(Context.ConnectionId); + RCSessionRecorder.StopProcessing(Context.ConnectionId); } } diff --git a/Remotely_Server/Services/RemoteControlSessionRecorder.cs b/Remotely_Server/Services/RemoteControlSessionRecorder.cs index c3dbb72e..2b36adb2 100644 --- a/Remotely_Server/Services/RemoteControlSessionRecorder.cs +++ b/Remotely_Server/Services/RemoteControlSessionRecorder.cs @@ -4,6 +4,7 @@ using Remotely_Server.Models; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; @@ -16,7 +17,7 @@ namespace Remotely_Server.Services { private static bool IsProcessing { get; set; } private static ConcurrentQueue FrameQueue { get; } = new ConcurrentQueue(); - private static ConcurrentDictionary CumulativeFrames { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary SessionStates { get; } = new ConcurrentDictionary(); private static object LockObject { get; } = new object(); private IHostingEnvironment HostingEnv { get; } @@ -52,18 +53,28 @@ namespace Remotely_Server.Services { if (FrameQueue.TryDequeue(out var frame)) { - if (!CumulativeFrames.ContainsKey(frame.ViewerID)) - { - CumulativeFrames[frame.ViewerID] = new Bitmap(frame.Width, frame.Height); - } - var saveDir = Directory.CreateDirectory(GetSaveFolder(frame)); - var saveFile = Path.Combine( - saveDir.FullName, - $"frame-{(Directory.GetFiles(saveDir.FullName).Length + 1).ToString()}.jpg"); + var saveFile = Path.Combine(saveDir.FullName, $"Recording.mp4"); - var bitmap = CumulativeFrames[frame.ViewerID] as Bitmap; + if (!SessionStates.ContainsKey(frame.ViewerID)) + { + SessionStates[frame.ViewerID] = new RecordingSessionState() + { + CumulativeFrame = new Bitmap(frame.Width, frame.Height) + }; + var ffmpegProc = new Process(); + SessionStates[frame.ViewerID].FfmpegProcess = ffmpegProc; + + ffmpegProc.StartInfo.FileName = "ffmpeg.exe"; + ffmpegProc.StartInfo.Arguments = $"-y -f image2pipe -i pipe:.jpg -r 5 \"{saveFile}\""; + ffmpegProc.StartInfo.UseShellExecute = false; + ffmpegProc.StartInfo.RedirectStandardInput = true; + + ffmpegProc.Start(); + } + + var bitmap = SessionStates[frame.ViewerID].CumulativeFrame; using (var graphics = Graphics.FromImage(bitmap)) { using (var ms = new MemoryStream(frame.FrameBytes)) @@ -74,14 +85,10 @@ namespace Remotely_Server.Services } } } - bitmap.Save(saveFile, ImageFormat.Jpeg); + bitmap.Save(SessionStates[frame.ViewerID].FfmpegProcess.StandardInput.BaseStream, ImageFormat.Jpeg); } } } - catch (Exception ex) - { - DataService.WriteEvent(ex); - } finally { IsProcessing = false; @@ -102,34 +109,12 @@ namespace Remotely_Server.Services frame.StartTime.ToString("HH.mm.ss.fff")); } - internal void EncodeFrames(string viewerID) + internal void StopProcessing(string viewerID) { - var recordingDirs = Directory.GetDirectories(Path.Combine( - HostingEnv.ContentRootPath, - "Recordings", - DateTime.Now.Year.ToString().PadLeft(4, '0'), - DateTime.Now.Month.ToString().PadLeft(2, '0')), - viewerID, - SearchOption.AllDirectories); - - foreach (var dir in recordingDirs) - { - foreach (var subDir in Directory.GetDirectories(dir)) - { - try - { - System.Diagnostics.Process.Start("ffmpeg", $"-y -i \"{Path.Combine(subDir, "frame-%d.jpg")}\" \"{Path.Combine(subDir, "Recording.mp4")}\"").WaitForExit(); - foreach (var file in Directory.GetFiles(subDir, "*.jpg")) - { - File.Delete(file); - } - } - catch (Exception ex) - { - DataService.WriteEvent(ex); - } - } - } + SessionStates[viewerID].FfmpegProcess.StandardInput.Flush(); + SessionStates[viewerID].FfmpegProcess.StandardInput.Close(); + SessionStates[viewerID].FfmpegProcess.Close(); + SessionStates.TryRemove(viewerID, out _); } } }