namespace HandBrake.ApplicationServices.Services\r
{\r
using System;\r
+ using System.ComponentModel;\r
using System.Diagnostics;\r
using System.IO;\r
using System.Text;\r
using System.Threading;\r
using System.Windows.Forms;\r
\r
- using HandBrake.Framework.Services;\r
- using HandBrake.Framework.Services.Interfaces;\r
+ using HandBrake.ApplicationServices.EventArgs;\r
using HandBrake.ApplicationServices.Functions;\r
using HandBrake.ApplicationServices.Model;\r
using HandBrake.ApplicationServices.Parsing;\r
using HandBrake.ApplicationServices.Services.Interfaces;\r
+ using HandBrake.ApplicationServices.Utilities;\r
\r
/// <summary>\r
/// Class which handles the CLI\r
#region Private Variables\r
\r
/// <summary>\r
- /// The Error Service\r
- /// </summary>\r
- protected IErrorService errorService;\r
-\r
- /// <summary>\r
/// The Log Buffer\r
/// </summary>\r
private StringBuilder logBuffer;\r
/// <summary>\r
/// Gets the Process ID\r
/// </summary>\r
- private int processID;\r
+ private int processId;\r
\r
/// <summary>\r
/// Windows 7 API Pack wrapper\r
/// </summary>\r
private Win7 windowsSeven = new Win7();\r
\r
- #endregion\r
+ /// <summary>\r
+ /// A Lock for the filewriter\r
+ /// </summary>\r
+ static readonly object fileWriterLock = new object();\r
\r
- /* Constructor */\r
+ #endregion\r
\r
/// <summary>\r
/// Initializes a new instance of the <see cref="Encode"/> class.\r
/// </summary>\r
public Encode()\r
{\r
- this.EncodeStarted += Encode_EncodeStarted;\r
+ this.EncodeStarted += this.EncodeEncodeStarted;\r
GrowlCommunicator.Register();\r
-\r
- this.errorService = new ErrorService();\r
}\r
\r
#region Delegates and Event Handlers\r
\r
/// <summary>\r
- /// Encode Progess Status\r
- /// </summary>\r
- /// <param name="sender">\r
- /// The sender.\r
- /// </param>\r
- /// <param name="e">\r
- /// The EncodeProgressEventArgs.\r
- /// </param>\r
- public delegate void EncodeProgessStatus(object sender, EncodeProgressEventArgs e);\r
-\r
- /* Event Handlers */\r
-\r
- /// <summary>\r
- /// Fires when a new CLI Job starts\r
+ /// Fires when a new CLI QueueTask starts\r
/// </summary>\r
public event EventHandler EncodeStarted;\r
\r
/// <summary>\r
- /// Fires when a CLI job finishes.\r
+ /// Fires when a CLI QueueTask finishes.\r
/// </summary>\r
- public event EventHandler EncodeEnded;\r
+ public event EncodeCompletedStatus EncodeCompleted;\r
\r
/// <summary>\r
/// Encode process has progressed\r
public event EncodeProgessStatus EncodeStatusChanged;\r
#endregion\r
\r
- /* Properties */\r
+ #region Properties\r
\r
/// <summary>\r
/// Gets or sets The HB Process\r
}\r
}\r
\r
- /* Public Methods */\r
+ #endregion\r
\r
- /// <summary>\r
- /// Create a preview sample video\r
- /// </summary>\r
- /// <param name="query">\r
- /// The CLI Query\r
- /// </param>\r
- public void CreatePreviewSample(string query)\r
- {\r
- this.Run(new Job { Query = query }, false);\r
- }\r
+ #region Public Methods\r
\r
/// <summary>\r
/// Execute a HandBrakeCLI process.\r
/// </summary>\r
- /// <param name="encJob">\r
- /// The enc Job.\r
+ /// <param name="encodeQueueTask">\r
+ /// The encodeQueueTask.\r
/// </param>\r
/// <param name="enableLogging">\r
/// Enable Logging. When Disabled we onlt parse Standard Ouput for progress info. Standard Error log data is ignored.\r
/// </param>\r
- protected void Run(Job encJob, bool enableLogging)\r
+ public void Start(QueueTask encodeQueueTask, bool enableLogging)\r
{\r
try\r
{\r
+ QueueTask queueTask = encodeQueueTask;\r
+\r
+ if (queueTask == null)\r
+ {\r
+ throw new ArgumentNullException("QueueTask was null");\r
+ }\r
+\r
+ if (IsEncoding)\r
+ {\r
+ throw new Exception("HandBrake is already encodeing.");\r
+ }\r
+\r
IsEncoding = true;\r
\r
if (enableLogging)\r
- SetupLogging(encJob);\r
+ {\r
+ try\r
+ {\r
+ SetupLogging(queueTask);\r
+ }\r
+ catch (Exception)\r
+ {\r
+ IsEncoding = false;\r
+ throw;\r
+ }\r
+ }\r
\r
if (Init.PreventSleep)\r
{\r
}\r
\r
string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");\r
- ProcessStartInfo cliStart = new ProcessStartInfo(handbrakeCLIPath, encJob.Query)\r
+ ProcessStartInfo cliStart = new ProcessStartInfo(handbrakeCLIPath, queueTask.Query)\r
{\r
RedirectStandardOutput = true,\r
RedirectStandardError = enableLogging ? true : false,\r
CreateNoWindow = !Init.ShowCliForInGuiEncodeStatus ? true : false\r
};\r
\r
- this.HbProcess = Process.Start(cliStart);\r
+ this.HbProcess = new Process { StartInfo = cliStart };\r
+\r
+ this.HbProcess.Start();\r
\r
if (enableLogging)\r
{\r
this.HbProcess.BeginErrorReadLine();\r
}\r
\r
- this.processID = HbProcess.Id;\r
+ this.processId = HbProcess.Id;\r
this.processHandle = HbProcess.Handle;\r
\r
// Set the process Priority\r
- if (this.processID != -1)\r
+ if (this.processId != -1)\r
{\r
this.HbProcess.EnableRaisingEvents = true;\r
- this.HbProcess.Exited += HbProcess_Exited;\r
+ this.HbProcess.Exited += this.HbProcessExited;\r
}\r
\r
// Set the Process Priority\r
}\r
catch (Exception exc)\r
{\r
- errorService.ShowError("It would appear that HandBrakeCLI has not started correctly." +\r
- "You should take a look at the Activity log as it may indicate the reason why.\n\nDetailed Error Information: error occured in runCli()",\r
- exc.ToString());\r
+ if (this.EncodeCompleted != null)\r
+ this.EncodeCompleted(this, new EncodeCompletedEventArgs(false, exc, "An Error has occured in EncodeService.Run()"));\r
}\r
}\r
\r
/// <summary>\r
- /// Kill the CLI process\r
+ /// Stop the Encode\r
/// </summary>\r
public void Stop()\r
{\r
+ this.Stop(null);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Kill the CLI process\r
+ /// </summary>\r
+ /// <param name="exc">\r
+ /// The Exception that has occured.\r
+ /// This will get bubbled up through the EncodeCompletedEventArgs\r
+ /// </param>\r
+ public void Stop(Exception exc)\r
+ {\r
try\r
{\r
- if (this.HbProcess != null) this.HbProcess.Kill();\r
+ if (this.HbProcess != null && !this.HbProcess.HasExited)\r
+ {\r
+ this.HbProcess.Kill();\r
+ }\r
}\r
- catch (Exception exc)\r
+ catch (Exception)\r
{\r
- errorService.ShowError("Unable to stop HandBrakeCLI. It may not be running.", exc.ToString());\r
+ // No need to report anything to the user. If it fails, it's probably already stopped.\r
}\r
\r
- if (this.EncodeEnded != null)\r
- this.EncodeEnded(this, new EventArgs());\r
+\r
+ if (exc == null)\r
+ {\r
+ if (this.EncodeCompleted != null)\r
+ this.EncodeCompleted(this, new EncodeCompletedEventArgs(true, null, string.Empty));\r
+ }\r
+ else\r
+ {\r
+ if (this.EncodeCompleted != null)\r
+ this.EncodeCompleted(this, new EncodeCompletedEventArgs(false, exc, "An Error has occured."));\r
+ }\r
}\r
\r
/// <summary>\r
/// NOTE: This will not work with a MinGW CLI\r
/// Note: http://www.cygwin.com/ml/cygwin/2006-03/msg00330.html\r
/// </summary>\r
- public void SafelyClose()\r
+ public void SafelyStop()\r
{\r
if ((int)this.processHandle == 0)\r
return;\r
//}*/\r
}\r
\r
- /* Helpers */\r
-\r
/// <summary>\r
/// Save a copy of the log to the users desired location or a default location\r
/// if this feature is enabled in options.\r
/// <param name="destination">\r
/// The Destination File Path\r
/// </param>\r
- protected void CopyLog(string destination)\r
+ public void ProcessLogs(string destination)\r
{\r
try\r
{\r
}\r
catch (Exception exc)\r
{\r
- errorService.ShowError("Unable to make a copy of the log file", exc.ToString());\r
+ // This exception doesn't warrent user interaction, but it should be logged (TODO)\r
}\r
}\r
\r
+ #endregion\r
+\r
+ #region Private Helper Methods\r
+\r
/// <summary>\r
/// The HandBrakeCLI process has exited.\r
/// </summary>\r
/// <param name="e">\r
/// The EventArgs.\r
/// </param>\r
- private void HbProcess_Exited(object sender, EventArgs e)\r
+ private void HbProcessExited(object sender, EventArgs e)\r
{\r
IsEncoding = false;\r
- if (this.EncodeEnded != null)\r
- this.EncodeEnded(this, new EventArgs());\r
-\r
if (windowsSeven.IsWindowsSeven)\r
{\r
windowsSeven.SetTaskBarProgressToNoProgress();\r
\r
try\r
{\r
- if (fileWriter != null)\r
+ lock (fileWriterLock)\r
{\r
- fileWriter.Close();\r
- fileWriter.Dispose();\r
+ // This is just a quick hack to ensure that we are done processing the logging data.\r
+ // Logging data comes in after the exit event has processed sometimes. We should really impliment ISyncronizingInvoke\r
+ // and set the SyncObject on the process. I think this may resolve this properly.\r
+ // For now, just wait 2.5 seconds to let any trailing log messages come in and be processed.\r
+ Thread.Sleep(2500);\r
+\r
+ this.HbProcess.CancelErrorRead();\r
+\r
+ if (fileWriter != null)\r
+ {\r
+ fileWriter.Close();\r
+ fileWriter.Dispose();\r
+ }\r
+\r
+ fileWriter = null;\r
}\r
}\r
catch (Exception exc)\r
{\r
- errorService.ShowError("Unable to close the log file wrtier", exc.ToString());\r
+ // This exception doesn't warrent user interaction, but it should be logged (TODO)\r
}\r
+\r
+ if (this.EncodeCompleted != null)\r
+ this.EncodeCompleted(this, new EncodeCompletedEventArgs(true, null, string.Empty));\r
}\r
\r
/// <summary>\r
}\r
catch (Exception exc)\r
{\r
- throw new Exception("Unable to read log file" + Environment.NewLine + exc);\r
+ logBuffer.Append(\r
+ Environment.NewLine + "Unable to read Log file..." + Environment.NewLine + exc +\r
+ Environment.NewLine);\r
}\r
}\r
}\r
/// <summary>\r
/// Setup the logging.\r
/// </summary>\r
- /// <param name="encodeJob">\r
- /// The encode Job.\r
+ /// <param name="encodeQueueTask">\r
+ /// The encode QueueTask.\r
/// </param>\r
- private void SetupLogging(Job encodeJob)\r
+ private void SetupLogging(QueueTask encodeQueueTask)\r
{\r
string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";\r
string logFile = Path.Combine(logDir, string.Format("last_encode_log{0}.txt", Init.InstanceId));\r
\r
fileWriter = new StreamWriter(logFile) { AutoFlush = true };\r
\r
- fileWriter.WriteLine(Logging.CreateCliLogHeader(encodeJob));\r
- logBuffer.AppendLine(Logging.CreateCliLogHeader(encodeJob));\r
+ fileWriter.WriteLine(UtilityService.CreateCliLogHeader(encodeQueueTask));\r
+ logBuffer.AppendLine(UtilityService.CreateCliLogHeader(encodeQueueTask));\r
}\r
- catch (Exception exc)\r
+ catch (Exception)\r
{\r
if (fileWriter != null)\r
{\r
fileWriter.Close();\r
fileWriter.Dispose();\r
}\r
-\r
- errorService.ShowError("Error", exc.ToString());\r
+ throw;\r
}\r
}\r
\r
lock (logBuffer)\r
logBuffer.AppendLine(e.Data);\r
\r
- if (fileWriter != null && fileWriter.BaseStream.CanWrite)\r
+ lock (fileWriterLock)\r
{\r
- fileWriter.WriteLine(e.Data);\r
- } \r
+ if (fileWriter != null && fileWriter.BaseStream.CanWrite)\r
+ {\r
+ fileWriter.WriteLine(e.Data);\r
+\r
+ // If the logging grows past 100MB, kill the encode and stop.\r
+ if (fileWriter.BaseStream.Length > 100000000)\r
+ {\r
+ this.Stop(\r
+ new Exception(\r
+ "The encode has been stopped. The log file has grown to over 100MB which indicates a serious problem has occured with the encode." +\r
+ "Please check the encode log for an indication of what the problem is."));\r
+ }\r
+ }\r
+ }\r
}\r
catch (Exception exc)\r
{\r
- // errorService.ShowError("Unable to write log data...", exc.ToString());\r
+ // Do Nothing.\r
}\r
}\r
}\r
\r
- #region Encode Status from Standard Output\r
-\r
/// <summary>\r
/// Encode Started\r
/// </summary>\r
/// <param name="e">\r
/// The EventArgs.\r
/// </param>\r
- private void Encode_EncodeStarted(object sender, EventArgs e)\r
+ private void EncodeEncodeStarted(object sender, EventArgs e)\r
{\r
Thread monitor = new Thread(EncodeMonitor);\r
monitor.Start();\r
}\r
\r
/// <summary>\r
- /// Monitor the Job\r
+ /// Monitor the QueueTask\r
/// </summary>\r
private void EncodeMonitor()\r
{\r
private void EncodeOnEncodeProgress(object sender, int currentTask, int taskCount, float percentComplete, float currentFps, float avg, string timeRemaining)\r
{\r
EncodeProgressEventArgs eventArgs = new EncodeProgressEventArgs\r
- {\r
- AverageFrameRate = avg,\r
- CurrentFrameRate = currentFps,\r
- EstimatedTimeLeft = timeRemaining,\r
- PercentComplete = percentComplete,\r
- Task = currentTask,\r
- TaskCount = taskCount\r
- };\r
+ {\r
+ AverageFrameRate = avg,\r
+ CurrentFrameRate = currentFps,\r
+ EstimatedTimeLeft = Converters.EncodeToTimespan(timeRemaining),\r
+ PercentComplete = percentComplete,\r
+ Task = currentTask,\r
+ TaskCount = taskCount\r
+ };\r
\r
if (this.EncodeStatusChanged != null)\r
this.EncodeStatusChanged(this, eventArgs);\r