summaryrefslogtreecommitdiffstats
path: root/win/CS/HandBrakeWPF
diff options
context:
space:
mode:
Diffstat (limited to 'win/CS/HandBrakeWPF')
-rw-r--r--win/CS/HandBrakeWPF/Factories/HBConfigurationFactory.cs4
-rw-r--r--win/CS/HandBrakeWPF/HandBrakeWPF.csproj7
-rw-r--r--win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs78
-rw-r--r--win/CS/HandBrakeWPF/Instance/Model/ServerResponse.cs24
-rw-r--r--win/CS/HandBrakeWPF/Instance/RemoteInstance.cs188
-rw-r--r--win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs13
-rw-r--r--win/CS/HandBrakeWPF/Services/Scan/LibScan.cs19
-rw-r--r--win/CS/HandBrakeWPF/UserSettingConstants.cs10
-rw-r--r--win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs1
-rw-r--r--win/CS/HandBrakeWPF/defaultsettings.xml16
10 files changed, 326 insertions, 34 deletions
diff --git a/win/CS/HandBrakeWPF/Factories/HBConfigurationFactory.cs b/win/CS/HandBrakeWPF/Factories/HBConfigurationFactory.cs
index 568f7e390..c4d199ef8 100644
--- a/win/CS/HandBrakeWPF/Factories/HBConfigurationFactory.cs
+++ b/win/CS/HandBrakeWPF/Factories/HBConfigurationFactory.cs
@@ -45,7 +45,9 @@ namespace HandBrakeWPF.Factories
SaveLogToCopyDirectory = UserSettingService.GetUserSetting<bool>(UserSettingConstants.SaveLogToCopyDirectory),
SaveLogWithVideo = UserSettingService.GetUserSetting<bool>(UserSettingConstants.SaveLogWithVideo),
SaveLogCopyDirectory = UserSettingService.GetUserSetting<string>(UserSettingConstants.SaveLogCopyDirectory),
- };
+ RemoteServiceEnabled = UserSettingService.GetUserSetting<bool>(UserSettingConstants.RemoteServiceEnabled),
+ RemoteServicePort = UserSettingService.GetUserSetting<int>(UserSettingConstants.RemoteServicePort)
+ };
return config;
}
diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj
index 1c1d4da42..bbd1fb88d 100644
--- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj
+++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj
@@ -90,6 +90,7 @@
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
+ <Reference Include="System.Net.Http" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@@ -153,6 +154,8 @@
<Compile Include="Helpers\MP4Helper.cs" />
<Compile Include="Helpers\TimeSpanHelper.cs" />
<Compile Include="Helpers\Validate.cs" />
+ <Compile Include="Instance\HandBrakeInstanceManager.cs" />
+ <Compile Include="Instance\Model\ServerResponse.cs" />
<Compile Include="Instance\RemoteInstance.cs" />
<Compile Include="Model\Audio\AudioBehaviourTrack.cs" />
<Compile Include="Model\Audio\AudioTrackDefaultsMode.cs" />
@@ -718,6 +721,10 @@
<Project>{087a2ba8-bac2-4577-a46f-07ff9d420016}</Project>
<Name>HandBrake.Interop</Name>
</ProjectReference>
+ <ProjectReference Include="..\HandBrake.Worker\HandBrake.Worker.csproj">
+ <Project>{f8370f37-b226-4830-aee7-6d7ae403e3d2}</Project>
+ <Name>HandBrake.Worker</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs b/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs
new file mode 100644
index 000000000..3fcf00e8f
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs
@@ -0,0 +1,78 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="HandBrakeInstanceManager.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>
+// The hand brake instance manager.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Instance
+{
+ using HandBrake.Interop.Interop;
+ using HandBrake.Interop.Interop.Interfaces;
+ using HandBrake.Interop.Model;
+
+ /// <summary>
+ /// The HandBrake Instance manager.
+ /// Only supports scanning right now.
+ /// </summary>
+ public static class HandBrakeInstanceManager
+ {
+ private static IEncodeInstance encodeInstance;
+
+ /// <summary>
+ /// Initializes static members of the <see cref="HandBrakeInstanceManager"/> class.
+ /// </summary>
+ static HandBrakeInstanceManager()
+ {
+ }
+
+ /// <summary>
+ /// The init.
+ /// </summary>
+ public static void Init()
+ {
+ // Nothing to do. Triggers static constructor.
+ }
+
+ /// <summary>
+ /// The get encode instance.
+ /// </summary>
+ /// <param name="verbosity">
+ /// The verbosity.
+ /// </param>
+ /// <param name="configuration">
+ /// The configuratio.
+ /// </param>
+ /// <returns>
+ /// The <see cref="IHandBrakeInstance"/>.
+ /// </returns>
+ public static IEncodeInstance GetEncodeInstance(int verbosity, HBConfiguration configuration)
+ {
+ if (encodeInstance != null)
+ {
+ encodeInstance.Dispose();
+ encodeInstance = null;
+ }
+
+ IEncodeInstance newInstance;
+
+ if (configuration.RemoteServiceEnabled)
+ {
+ newInstance = new RemoteInstance(configuration.RemoteServicePort);
+ }
+ else
+ {
+ newInstance = new HandBrakeInstance();
+ }
+
+ newInstance.Initialize(verbosity);
+ encodeInstance = newInstance;
+
+ HandBrakeUtils.SetDvdNav(!configuration.IsDvdNavDisabled);
+
+ return encodeInstance;
+ }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Instance/Model/ServerResponse.cs b/win/CS/HandBrakeWPF/Instance/Model/ServerResponse.cs
new file mode 100644
index 000000000..8b66a642c
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Instance/Model/ServerResponse.cs
@@ -0,0 +1,24 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ServerResponse.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>
+// A model of the response from the HandBrake Worker instance.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Instance.Model
+{
+ public class ServerResponse
+ {
+ public ServerResponse(bool wasSuccessful, string jsonResponse)
+ {
+ this.WasSuccessful = wasSuccessful;
+ this.JsonResponse = jsonResponse;
+ }
+
+ public bool WasSuccessful { get; private set; }
+
+ public string JsonResponse { get; private set; }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
index bfefb6caf..375dd2db1 100644
--- a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
+++ b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs
@@ -4,54 +4,111 @@
// </copyright>
// <summary>
// An Implementation of IEncodeInstance that works with a remote process rather than locally in-process.
+// This class is effectivly just a shim.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace HandBrakeWPF.Instance
{
using System;
+ using System.Collections.Generic;
using System.Diagnostics;
+ using System.Linq;
+ using System.Net.Http;
+ using System.Threading.Tasks;
+ using System.Timers;
using HandBrake.Interop.Interop.EventArgs;
using HandBrake.Interop.Interop.Interfaces;
using HandBrake.Interop.Interop.Json.Encode;
+ using HandBrake.Interop.Interop.Json.State;
- public class RemoteInstance : IEncodeInstance
+ using HandBrakeWPF.Instance.Model;
+
+ using Newtonsoft.Json;
+
+ /*
+ * TODO:
+ * 1. Add support for logging.
+ * 2. Code to detect what ports are in use / select one within range.
+ * 3. Add support for communciating via socket instead of HTTP.
+ */
+
+ public class RemoteInstance : IEncodeInstance, IDisposable
{
+ private const double EncodePollIntervalMs = 500;
+ private readonly HttpClient client = new HttpClient();
+ private readonly string serverUrl;
+ private readonly int port;
private Process workerProcess;
+ private Timer encodePollTimer;
+
+ public RemoteInstance(int port)
+ {
+ this.port = port;
+ this.serverUrl = "http://localhost/";
+ }
public event EventHandler<EncodeCompletedEventArgs> EncodeCompleted;
public event EventHandler<EncodeProgressEventArgs> EncodeProgress;
- public void PauseEncode()
+ public async void PauseEncode()
{
- throw new NotImplementedException();
+ this.StopPollingProgres();
+ await this.MakeHttpGetRequest("PauseEncode");
}
- public void ResumeEncode()
+ public async void ResumeEncode()
{
- throw new NotImplementedException();
+ await this.MakeHttpGetRequest("ResumeEncode");
+ this.MonitorEncodeProgress();
}
- public void StartEncode(JsonEncodeObject jobToStart)
+ public async void StartEncode(JsonEncodeObject jobToStart)
{
- throw new NotImplementedException();
+ JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
+ string job = JsonConvert.SerializeObject(jobToStart, Formatting.Indented, settings);
+
+ var values = new Dictionary<string, string> { { "jpb", job } };
+ await this.MakeHttpPostRequest("StartEncode", values);
+
+ this.MonitorEncodeProgress();
}
- public void StopEncode()
+ public async void StopEncode()
{
- throw new NotImplementedException();
+ this.StopPollingProgres();
+ await this.MakeHttpGetRequest("StopEncode");
}
- protected virtual void OnEncodeCompleted(EncodeCompletedEventArgs e)
+ public JsonState GetEncodeProgress()
{
- this.EncodeCompleted?.Invoke(this, e);
+ Task<ServerResponse> response = this.MakeHttpGetRequest("PollEncodeProgress");
+ response.Wait();
+
+ if (!response.Result.WasSuccessful)
+ {
+ return null;
+ }
+
+ string statusJson = response.Result?.JsonResponse;
+
+ JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);
+ return state;
}
- protected virtual void OnEncodeProgress(EncodeProgressEventArgs e)
+ public void Initialize(int verbosity)
{
- this.EncodeProgress?.Invoke(this, e);
+ this.StartServer();
+ }
+
+ public void Dispose()
+ {
+ this.client?.Dispose();
+ this.workerProcess?.Dispose();
+ this.StopEncode();
+ this.StopServer();
}
private void StartServer()
@@ -59,19 +116,42 @@ namespace HandBrakeWPF.Instance
if (this.workerProcess == null || this.workerProcess.HasExited)
{
this.workerProcess = new Process();
-
- // TODO Take default port from preferences, then find a usable port thereafter.
this.workerProcess.StartInfo =
- new ProcessStartInfo("HandBrake.Worker.exe", "--port=8080")
+ new ProcessStartInfo("HandBrake.Worker.exe", string.Format("--port={0}", this.port))
{
WindowStyle = ProcessWindowStyle.Normal
};
this.workerProcess.Start();
this.workerProcess.Exited += this.WorkerProcess_Exited;
+ Debug.WriteLine("Worker Process Started. PID = {0}", this.workerProcess.Id);
}
}
+ private void MonitorEncodeProgress()
+ {
+ this.encodePollTimer = new Timer();
+ this.encodePollTimer.Interval = EncodePollIntervalMs;
+
+ this.encodePollTimer.Elapsed += (o, e) =>
+ {
+ try
+ {
+ this.PollEncodeProgress();
+ }
+ catch (Exception exc)
+ {
+ Debug.WriteLine(exc);
+ }
+ };
+ this.encodePollTimer.Start();
+ }
+
+ private void StopPollingProgres()
+ {
+ this.encodePollTimer?.Stop();
+ }
+
private void WorkerProcess_Exited(object sender, EventArgs e)
{
Debug.WriteLine("Worker Process has exited");
@@ -84,5 +164,81 @@ namespace HandBrakeWPF.Instance
this.workerProcess.Kill();
}
}
+
+ private async void PollEncodeProgress()
+ {
+ ServerResponse response = await this.MakeHttpGetRequest("PollEncodeProgress");
+ if (!response.WasSuccessful)
+ {
+ return;
+ }
+
+ string statusJson = response.JsonResponse;
+
+ JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);
+
+ TaskState taskState = state != null ? TaskState.FromRepositoryValue(state.State) : null;
+
+ if (taskState != null && (taskState == TaskState.Working || taskState == TaskState.Muxing || taskState == TaskState.Searching))
+ {
+ if (this.EncodeProgress != null)
+ {
+ var progressEventArgs = new EncodeProgressEventArgs(
+ fractionComplete: state.Working.Progress,
+ currentFrameRate: state.Working.Rate,
+ averageFrameRate: state.Working.RateAvg,
+ estimatedTimeLeft: new TimeSpan(state.Working.Hours, state.Working.Minutes, state.Working.Seconds),
+ passId: state.Working.PassID,
+ pass: state.Working.Pass,
+ passCount: state.Working.PassCount,
+ stateCode: taskState.Code);
+
+ this.EncodeProgress(this, progressEventArgs);
+ }
+ }
+ else if (taskState != null && taskState == TaskState.WorkDone)
+ {
+ this.encodePollTimer.Stop();
+
+ this.EncodeCompleted?.Invoke(sender: this, e: new EncodeCompletedEventArgs(state.WorkDone.Error != 0));
+ }
+ }
+
+ private async Task<ServerResponse> MakeHttpPostRequest(string urlPath, Dictionary<string, string> postValues)
+ {
+ if (postValues == null || !postValues.Any())
+ {
+ throw new InvalidOperationException("No Post Values Found.");
+ }
+
+ if (postValues.Any())
+ {
+ FormUrlEncodedContent content = new FormUrlEncodedContent(postValues);
+ HttpResponseMessage response = await this.client.PostAsync(this.serverUrl + urlPath, content);
+ if (response != null)
+ {
+ string returnContent = await response.Content.ReadAsStringAsync();
+ ServerResponse serverResponse = new ServerResponse(response.IsSuccessStatusCode, returnContent);
+
+ return serverResponse;
+ }
+ }
+
+ return null;
+ }
+
+ private async Task<ServerResponse> MakeHttpGetRequest(string urlPath)
+ {
+ HttpResponseMessage response = await this.client.GetAsync(this.serverUrl + urlPath);
+ if (response != null)
+ {
+ string returnContent = await response.Content.ReadAsStringAsync();
+ ServerResponse serverResponse = new ServerResponse(response.IsSuccessStatusCode, returnContent);
+
+ return serverResponse;
+ }
+
+ return null;
+ }
}
}
diff --git a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
index 85c5a42b1..a00344836 100644
--- a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
+++ b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
@@ -13,7 +13,6 @@ namespace HandBrakeWPF.Services.Encode
using System.Diagnostics;
using System.IO;
- using HandBrake.Interop.Interop;
using HandBrake.Interop.Interop.EventArgs;
using HandBrake.Interop.Interop.Interfaces;
using HandBrake.Interop.Interop.Json.State;
@@ -24,11 +23,12 @@ namespace HandBrakeWPF.Services.Encode
using HandBrakeWPF.Services.Encode.Factories;
using EncodeTask = Model.EncodeTask;
+ using HandBrakeInstanceManager = Instance.HandBrakeInstanceManager;
using IEncode = Interfaces.IEncode;
- using ILog = HandBrakeWPF.Services.Logging.Interfaces.ILog;
- using LogLevel = HandBrakeWPF.Services.Logging.Model.LogLevel;
- using LogMessageType = HandBrakeWPF.Services.Logging.Model.LogMessageType;
- using LogService = HandBrakeWPF.Services.Logging.LogService;
+ using ILog = Logging.Interfaces.ILog;
+ using LogLevel = Logging.Model.LogLevel;
+ using LogMessageType = Logging.Model.LogMessageType;
+ using LogService = Logging.LogService;
/// <summary>
/// LibHB Implementation of IEncode
@@ -80,8 +80,7 @@ namespace HandBrakeWPF.Services.Encode
this.log.Reset(); // Reset so we have a clean log for the start of the encode.
this.ServiceLogMessage("Starting Encode ...");
- HandBrakeUtils.SetDvdNav(!configuration.IsDvdNavDisabled);
- this.instance = task.IsPreviewEncode ? HandBrakeInstanceManager.GetPreviewInstance(configuration.Verbosity) : HandBrakeInstanceManager.GetEncodeInstance(configuration.Verbosity);
+ this.instance = task.IsPreviewEncode ? HandBrake.Interop.Interop.HandBrakeInstanceManager.GetPreviewInstance(configuration.Verbosity, configuration) : HandBrakeInstanceManager.GetEncodeInstance(configuration.Verbosity, configuration);
this.instance.EncodeCompleted += this.InstanceEncodeCompleted;
this.instance.EncodeProgress += this.InstanceEncodeProgress;
diff --git a/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs b/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs
index 7bcc5531b..d17a5d3c9 100644
--- a/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs
+++ b/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs
@@ -30,14 +30,14 @@ namespace HandBrakeWPF.Services.Scan
using HandBrakeWPF.Services.Scan.Model;
using HandBrakeWPF.Utilities;
- using Chapter = HandBrakeWPF.Services.Scan.Model.Chapter;
- using ILog = HandBrakeWPF.Services.Logging.Interfaces.ILog;
- using LogLevel = HandBrakeWPF.Services.Logging.Model.LogLevel;
- using LogMessageType = HandBrakeWPF.Services.Logging.Model.LogMessageType;
- using LogService = HandBrakeWPF.Services.Logging.LogService;
+ using Chapter = Model.Chapter;
+ using ILog = Logging.Interfaces.ILog;
+ using LogLevel = Logging.Model.LogLevel;
+ using LogMessageType = Logging.Model.LogMessageType;
+ using LogService = Logging.LogService;
using ScanProgressEventArgs = HandBrake.Interop.Interop.EventArgs.ScanProgressEventArgs;
- using Subtitle = HandBrakeWPF.Services.Scan.Model.Subtitle;
- using Title = HandBrakeWPF.Services.Scan.Model.Title;
+ using Subtitle = Model.Subtitle;
+ using Title = Model.Title;
/// <summary>
/// Scan a Source
@@ -129,7 +129,7 @@ namespace HandBrakeWPF.Services.Scan
this.postScanOperation = postAction;
// Create a new HandBrake Instance.
- this.instance = HandBrakeInstanceManager.GetScanInstance(configuraiton.Verbosity);
+ this.instance = HandBrake.Interop.Interop.HandBrakeInstanceManager.GetScanInstance(configuraiton.Verbosity);
this.instance.ScanProgress += this.InstanceScanProgress;
this.instance.ScanCompleted += this.InstanceScanCompleted;
@@ -266,8 +266,7 @@ namespace HandBrakeWPF.Services.Scan
this.ServiceLogMessage("Starting Scan ...");
this.instance.StartScan(sourcePath.ToString(), previewCount, minDuration, title != 0 ? title : 0);
- if (this.ScanStarted != null)
- this.ScanStarted(this, System.EventArgs.Empty);
+ this.ScanStarted?.Invoke(this, System.EventArgs.Empty);
}
catch (Exception exc)
{
diff --git a/win/CS/HandBrakeWPF/UserSettingConstants.cs b/win/CS/HandBrakeWPF/UserSettingConstants.cs
index 34d24d25d..9e4d37a17 100644
--- a/win/CS/HandBrakeWPF/UserSettingConstants.cs
+++ b/win/CS/HandBrakeWPF/UserSettingConstants.cs
@@ -256,6 +256,16 @@ namespace HandBrakeWPF
/// </summary>
public static string WhenDoneAudioFile = "WhenDoneAudioFile";
+ /// <summary>
+ /// Setting to store whether we are using a Worker Process or in-process encoding.
+ /// </summary>
+ public static string RemoteServiceEnabled = "RemoteServiceEnabled";
+
+ /// <summary>
+ /// The port that the worker process is running on.
+ /// </summary>
+ public static string RemoteServicePort = "RemoteServicePort";
+
#endregion
}
} \ No newline at end of file
diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs
index 70fc5250e..9548fb573 100644
--- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs
+++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs
@@ -56,6 +56,7 @@ namespace HandBrakeWPF.ViewModels
using DataFormats = System.Windows.DataFormats;
using DragEventArgs = System.Windows.DragEventArgs;
using Execute = Caliburn.Micro.Execute;
+ using HandBrakeInstanceManager = HandBrakeWPF.Instance.HandBrakeInstanceManager;
using LogManager = HandBrakeWPF.Helpers.LogManager;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
diff --git a/win/CS/HandBrakeWPF/defaultsettings.xml b/win/CS/HandBrakeWPF/defaultsettings.xml
index c48921fff..853cf5396 100644
--- a/win/CS/HandBrakeWPF/defaultsettings.xml
+++ b/win/CS/HandBrakeWPF/defaultsettings.xml
@@ -520,4 +520,20 @@
<anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:string" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">Choose a File:</anyType>
</value>
</item>
+ <item>
+ <key>
+ <string>RemoteServiceEnabled</string>
+ </key>
+ <value>
+ <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:boolean" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">false</anyType>
+ </value>
+ </item>
+ <item>
+ <key>
+ <string>RemoteServicePort</string>
+ </key>
+ <value>
+ <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:int" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">8080</anyType>
+ </value>
+ </item>
</dictionary> \ No newline at end of file