summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorsr55 <[email protected]>2020-06-05 14:08:15 +0100
committersr55 <[email protected]>2020-06-05 14:08:28 +0100
commitafc7e2a2c94bc81b425063361e87e9351c16dd73 (patch)
tree92c3f343d2e23068d929a42c879fc82b0c7bf94e /win
parentf61c986d9a5a706b7bbc96c79f5eba209dd18ca5 (diff)
WinGui: UI performance improvement when starting multiple jobs. #2912
Diffstat (limited to 'win')
-rw-r--r--win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs4
-rw-r--r--win/CS/HandBrakeWPF/Instance/RemoteInstance.cs72
-rw-r--r--win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs16
-rw-r--r--win/CS/HandBrakeWPF/Services/Interfaces/IPortService.cs18
-rw-r--r--win/CS/HandBrakeWPF/Services/PortService.cs76
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs6
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/QueueService.cs7
-rw-r--r--win/CS/HandBrakeWPF/Startup/AppBootstrapper.cs1
-rw-r--r--win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs4
9 files changed, 144 insertions, 60 deletions
diff --git a/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs b/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs
index 51ac11458..1017ba1e1 100644
--- a/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs
+++ b/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs
@@ -37,7 +37,7 @@ namespace HandBrakeWPF.Instance
HandBrakeUtils.EnsureGlobalInit(noHardwareMode);
}
- public static IEncodeInstance GetEncodeInstance(int verbosity, HBConfiguration configuration, ILog logService, IUserSettingService userSettingService)
+ public static IEncodeInstance GetEncodeInstance(int verbosity, HBConfiguration configuration, ILog logService, IUserSettingService userSettingService, IPortService portService)
{
if (!HandBrakeUtils.IsInitialised())
{
@@ -48,7 +48,7 @@ namespace HandBrakeWPF.Instance
if (userSettingService.GetUserSetting<bool>(UserSettingConstants.ProcessIsolationEnabled) && Portable.IsProcessIsolationEnabled())
{
- newInstance = new RemoteInstance(configuration, logService, userSettingService);
+ newInstance = new RemoteInstance(logService, userSettingService, portService);
}
else
{
diff --git a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
index 97abf671b..757878a66 100644
--- a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
+++ b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
@@ -11,39 +11,33 @@
namespace HandBrakeWPF.Instance
{
using System;
- using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.NetworkInformation;
using System.Text;
+ using System.Threading;
using System.Threading.Tasks;
- using System.Timers;
- using System.Windows.Media.Animation;
-
using HandBrake.Interop.Interop.EventArgs;
using HandBrake.Interop.Interop.Interfaces;
using HandBrake.Interop.Interop.Json.Encode;
using HandBrake.Interop.Interop.Json.State;
- using HandBrake.Interop.Model;
using HandBrake.Worker.Routing.Commands;
using HandBrakeWPF.Instance.Model;
using HandBrakeWPF.Model.Options;
- using HandBrakeWPF.Services;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Services.Logging.Interfaces;
using HandBrakeWPF.Utilities;
using Newtonsoft.Json;
+ using Timer = System.Timers.Timer;
+
public class RemoteInstance : HttpRequestBase, IEncodeInstance, IDisposable
{
- private readonly HBConfiguration configuration;
private readonly ILog logService;
private readonly IUserSettingService userSettingService;
+ private readonly IPortService portService;
private const double EncodePollIntervalMs = 500;
@@ -51,13 +45,11 @@ namespace HandBrakeWPF.Instance
private Timer encodePollTimer;
private int retryCount = 0;
- public RemoteInstance(HBConfiguration configuration, ILog logService, IUserSettingService userSettingService)
+ public RemoteInstance(ILog logService, IUserSettingService userSettingService, IPortService portService)
{
- this.configuration = configuration;
this.logService = logService;
this.userSettingService = userSettingService;
- this.port = this.GetOpenPort(userSettingService.GetUserSetting<int>(UserSettingConstants.ProcessIsolationPort));
- this.serverUrl = string.Format("http://127.0.0.1:{0}/", this.port);
+ this.portService = portService;
}
public event EventHandler<EncodeCompletedEventArgs> EncodeCompleted;
@@ -80,24 +72,30 @@ namespace HandBrakeWPF.Instance
public void StartEncode(JsonEncodeObject jobToStart)
{
+ Thread thread1 = new Thread(() => RunEncodeInitProcess(jobToStart));
+ thread1.Start();
+ }
+
+ private void RunEncodeInitProcess(JsonEncodeObject jobToStart)
+ {
InitCommand initCommand = new InitCommand
- {
- EnableDiskLogging = false,
- AllowDisconnectedWorker = false,
- DisableLibDvdNav = !this.userSettingService.GetUserSetting<bool>(UserSettingConstants.DisableLibDvdNav),
- EnableHardwareAcceleration = true,
- LogDirectory = DirectoryUtilities.GetLogDirectory(),
- LogVerbosity = this.userSettingService.GetUserSetting<int>(UserSettingConstants.Verbosity)
- };
+ {
+ EnableDiskLogging = false,
+ AllowDisconnectedWorker = false,
+ DisableLibDvdNav = !this.userSettingService.GetUserSetting<bool>(UserSettingConstants.DisableLibDvdNav),
+ EnableHardwareAcceleration = true,
+ LogDirectory = DirectoryUtilities.GetLogDirectory(),
+ LogVerbosity = this.userSettingService.GetUserSetting<int>(UserSettingConstants.Verbosity)
+ };
initCommand.LogFile = Path.Combine(initCommand.LogDirectory, string.Format("activity_log.worker.{0}.txt", GeneralUtilities.ProcessId));
JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
+
string job = JsonConvert.SerializeObject(new EncodeCommand { InitialiseCommand = initCommand, EncodeJob = jobToStart }, Formatting.None, settings);
var task = Task.Run(async () => await this.MakeHttpJsonPostRequest("StartEncode", job));
task.Wait();
-
this.MonitorEncodeProgress();
}
@@ -128,6 +126,8 @@ namespace HandBrakeWPF.Instance
{
var plainTextBytes = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString());
this.base64Token = Convert.ToBase64String(plainTextBytes);
+ this.port = this.portService.GetOpenPort(userSettingService.GetUserSetting<int>(UserSettingConstants.ProcessIsolationPort));
+ this.serverUrl = string.Format("http://127.0.0.1:{0}/", this.port);
workerProcess = new Process
{
@@ -287,32 +287,8 @@ namespace HandBrakeWPF.Instance
}
this.EncodeCompleted?.Invoke(sender: this, e: new EncodeCompletedEventArgs(state.WorkDone.Error));
+ this.portService.FreePort(this.port);
}
}
-
- private int GetOpenPort(int startPort)
- {
- if (startPort == 0)
- {
- startPort = 8037;
- }
-
- int portStartIndex = startPort;
-
- IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
- IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners();
-
- List<int> usedPorts = tcpEndPoints.Select(p => p.Port).ToList<int>();
- int unusedPort = 0;
-
- unusedPort = Enumerable.Range(portStartIndex, 99).FirstOrDefault(p => !usedPorts.Contains(p));
-
- if (startPort != unusedPort)
- {
- this.logService.LogMessage(string.Format("Port {0} in use. Using {1} instead", startPort, unusedPort));
- }
-
- return unusedPort;
- }
}
}
diff --git a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
index 78cfd54c9..f30300f9d 100644
--- a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
+++ b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
@@ -12,10 +12,10 @@ namespace HandBrakeWPF.Services.Encode
using System;
using System.Diagnostics;
using System.IO;
- using System.Windows.Forms.VisualStyles;
using HandBrake.Interop.Interop.EventArgs;
using HandBrake.Interop.Interop.Interfaces;
+ using HandBrake.Interop.Interop.Json.Encode;
using HandBrake.Interop.Interop.Json.State;
using HandBrake.Interop.Interop.Providers.Interfaces;
using HandBrake.Interop.Model;
@@ -49,12 +49,15 @@ namespace HandBrakeWPF.Services.Encode
private bool isLoggingInitialised;
private int encodeCounter;
- public LibEncode(IHbFunctionsProvider hbFunctionsProvider, IUserSettingService userSettingService, ILogInstanceManager logInstanceManager, int encodeCounter) : base(userSettingService)
+ private readonly IPortService portService;
+
+ public LibEncode(IHbFunctionsProvider hbFunctionsProvider, IUserSettingService userSettingService, ILogInstanceManager logInstanceManager, int encodeCounter, IPortService portService) : base(userSettingService)
{
this.userSettingService = userSettingService;
this.logInstanceManager = logInstanceManager;
this.hbFunctionsProvider = hbFunctionsProvider;
this.encodeCounter = encodeCounter;
+ this.portService = portService;
}
public bool IsPasued { get; private set; }
@@ -112,7 +115,7 @@ namespace HandBrakeWPF.Services.Encode
// Prevent port stealing if multiple jobs start at the same time.
lock (portLock)
{
- this.instance = task.IsPreviewEncode ? HandBrakeInstanceManager.GetPreviewInstance(verbosity, this.userSettingService) : HandBrakeInstanceManager.GetEncodeInstance(verbosity, configuration, this.encodeLogService, userSettingService);
+ this.instance = task.IsPreviewEncode ? HandBrakeInstanceManager.GetPreviewInstance(verbosity, this.userSettingService) : HandBrakeInstanceManager.GetEncodeInstance(verbosity, configuration, this.encodeLogService, userSettingService, this.portService);
this.instance.EncodeCompleted += this.InstanceEncodeCompleted;
this.instance.EncodeProgress += this.InstanceEncodeProgress;
@@ -124,7 +127,12 @@ namespace HandBrakeWPF.Services.Encode
this.VerifyEncodeDestinationPath(task);
// Get an EncodeJob object for the Interop Library
- this.instance.StartEncode(EncodeTaskFactory.Create(task, configuration, hbFunctionsProvider.GetHbFunctionsWrapper()));
+ JsonEncodeObject work = EncodeTaskFactory.Create(
+ task,
+ configuration,
+ hbFunctionsProvider.GetHbFunctionsWrapper());
+
+ this.instance.StartEncode(work);
}
// Fire the Encode Started Event
diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/IPortService.cs b/win/CS/HandBrakeWPF/Services/Interfaces/IPortService.cs
new file mode 100644
index 000000000..f9234f775
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/Interfaces/IPortService.cs
@@ -0,0 +1,18 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="IPortService.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Defines the IPortService type.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Interfaces
+{
+ public interface IPortService
+ {
+ int GetOpenPort(int startPort);
+
+ void FreePort(int port);
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/PortService.cs b/win/CS/HandBrakeWPF/Services/PortService.cs
new file mode 100644
index 000000000..1a10db298
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/PortService.cs
@@ -0,0 +1,76 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="PortService.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Defines the PortService type.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.Net.NetworkInformation;
+
+ using HandBrakeWPF.Services.Interfaces;
+
+ public class PortService : IPortService
+ {
+ private readonly object lockObject = new object();
+ private List<int> usedPorts = new List<int>();
+
+ public PortService()
+ {
+ }
+
+ public void FreePort(int port)
+ {
+ lock (this.lockObject)
+ {
+ this.usedPorts.Remove(port);
+ }
+ }
+
+ public int GetOpenPort(int startPort)
+ {
+ lock (this.lockObject)
+ {
+ int foundPort = FindUnusedPort(startPort);
+
+ // If we find a port that's free on the system, but we've already allocated, try find another.
+ while (this.usedPorts.Contains(foundPort))
+ {
+ int nextPort = foundPort + 1;
+ foundPort = FindUnusedPort(nextPort);
+ }
+
+ // Record we've used this port.
+ this.usedPorts.Add(foundPort);
+
+ return foundPort;
+ }
+ }
+
+ private int FindUnusedPort(int startPort)
+ {
+ if (startPort == 0)
+ {
+ startPort = 8037;
+ }
+
+ int portStartIndex = startPort;
+
+ IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
+ IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners();
+
+ List<int> usedPorts = tcpEndPoints.Select(p => p.Port).ToList<int>();
+ int unusedPort = 0;
+
+ unusedPort = Enumerable.Range(portStartIndex, 99).FirstOrDefault(p => !usedPorts.Contains(p));
+
+ return unusedPort;
+ }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs b/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs
index 10fffcbf0..8daa6064d 100644
--- a/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs
+++ b/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs
@@ -10,6 +10,7 @@
namespace HandBrakeWPF.Services.Queue
{
using System;
+ using System.Diagnostics;
using HandBrake.Interop.Interop.Providers.Interfaces;
@@ -26,10 +27,10 @@ namespace HandBrakeWPF.Services.Queue
private readonly QueueTask job;
private readonly IEncode encodeService;
- public ActiveJob(QueueTask task, IHbFunctionsProvider hbFunctionsProvider, IUserSettingService userSettingService, ILogInstanceManager logInstanceManager, int jobId)
+ public ActiveJob(QueueTask task, IHbFunctionsProvider hbFunctionsProvider, IUserSettingService userSettingService, ILogInstanceManager logInstanceManager, int jobId, IPortService portService)
{
this.job = task;
- this.encodeService = new LibEncode(hbFunctionsProvider, userSettingService, logInstanceManager, jobId);
+ this.encodeService = new LibEncode(hbFunctionsProvider, userSettingService, logInstanceManager, jobId, portService);
}
public event EventHandler<ActiveJobCompletedEventArgs> JobFinished;
@@ -60,6 +61,7 @@ namespace HandBrakeWPF.Services.Queue
this.encodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted;
this.encodeService.EncodeStatusChanged += this.EncodeStatusChanged;
+
this.encodeService.Start(this.job.Task, this.job.Configuration, this.job.SelectedPresetKey);
}
}
diff --git a/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs b/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
index f3228db7a..2eb7cd7ce 100644
--- a/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
+++ b/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
@@ -57,6 +57,8 @@ namespace HandBrakeWPF.Services.Queue
private readonly ILogInstanceManager logInstanceManager;
private readonly IHbFunctionsProvider hbFunctionsProvider;
+ private readonly IPortService portService;
+
private readonly ObservableCollection<QueueTask> queue = new ObservableCollection<QueueTask>();
private readonly string queueFile;
private readonly object queueFileLock = new object();
@@ -65,13 +67,14 @@ namespace HandBrakeWPF.Services.Queue
private int jobIdCounter = 0;
private bool processIsolationEnabled;
- public QueueService(IUserSettingService userSettingService, ILog logService, IErrorService errorService, ILogInstanceManager logInstanceManager, IHbFunctionsProvider hbFunctionsProvider)
+ public QueueService(IUserSettingService userSettingService, ILog logService, IErrorService errorService, ILogInstanceManager logInstanceManager, IHbFunctionsProvider hbFunctionsProvider, IPortService portService)
{
this.userSettingService = userSettingService;
this.logService = logService;
this.errorService = errorService;
this.logInstanceManager = logInstanceManager;
this.hbFunctionsProvider = hbFunctionsProvider;
+ this.portService = portService;
// If this is the first instance, just use the main queue file, otherwise add the instance id to the filename.
this.queueFile = string.Format("{0}{1}.json", QueueRecoveryHelper.QueueFileName, GeneralUtilities.ProcessId);
@@ -567,7 +570,7 @@ namespace HandBrakeWPF.Services.Queue
}
this.jobIdCounter = this.jobIdCounter + 1;
- ActiveJob activeJob = new ActiveJob(job, this.hbFunctionsProvider, this.userSettingService, this.logInstanceManager, this.jobIdCounter);
+ ActiveJob activeJob = new ActiveJob(job, this.hbFunctionsProvider, this.userSettingService, this.logInstanceManager, this.jobIdCounter, this.portService);
activeJob.JobFinished += this.ActiveJob_JobFinished;
activeJob.JobStatusUpdated += this.ActiveJob_JobStatusUpdated;
this.activeJobs.Add(activeJob);
diff --git a/win/CS/HandBrakeWPF/Startup/AppBootstrapper.cs b/win/CS/HandBrakeWPF/Startup/AppBootstrapper.cs
index 16e5cad60..e2280ee80 100644
--- a/win/CS/HandBrakeWPF/Startup/AppBootstrapper.cs
+++ b/win/CS/HandBrakeWPF/Startup/AppBootstrapper.cs
@@ -87,6 +87,7 @@ namespace HandBrakeWPF.Startup
this.container.Singleton<ISystemService, SystemService>();
this.container.Singleton<IHbFunctionsProvider, HbFunctionsProvider>();
this.container.Singleton<ILogInstanceManager, LogInstanceManager>();
+ this.container.Singleton<IPortService, PortService>();
// Tab Components
this.container.Singleton<IAudioViewModel, AudioViewModel>();
diff --git a/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs
index 52d4bb4b3..1908c964f 100644
--- a/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs
+++ b/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs
@@ -58,7 +58,7 @@ namespace HandBrakeWPF.ViewModels
private bool useSystemDefaultPlayer;
private bool previewRotateFlip;
- public StaticPreviewViewModel(IScan scanService, IUserSettingService userSettingService, IErrorService errorService, IHbFunctionsProvider hbFunctionsProvider, ILog logService, ILogInstanceManager logInstanceManager)
+ public StaticPreviewViewModel(IScan scanService, IUserSettingService userSettingService, IErrorService errorService, IHbFunctionsProvider hbFunctionsProvider, ILog logService, ILogInstanceManager logInstanceManager, IPortService portService)
{
this.scanService = scanService;
this.selectedPreviewImage = 1;
@@ -68,7 +68,7 @@ namespace HandBrakeWPF.ViewModels
// Live Preview
this.userSettingService = userSettingService;
this.errorService = errorService;
- this.encodeService = new LibEncode(hbFunctionsProvider, userSettingService, logInstanceManager, 0); // Preview needs a separate instance rather than the shared singleton. This could maybe do with being refactored at some point
+ this.encodeService = new LibEncode(hbFunctionsProvider, userSettingService, logInstanceManager, 0, portService); // Preview needs a separate instance rather than the shared singleton. This could maybe do with being refactored at some point
this.Title = "Preview";
this.Percentage = "0.00%";