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.ApplicationServices.EventArgs;\r
using HandBrake.ApplicationServices.Functions;\r
using HandBrake.ApplicationServices.Model;\r
using HandBrake.ApplicationServices.Parsing;\r
- using HandBrake.ApplicationServices.Properties;\r
using HandBrake.ApplicationServices.Services.Interfaces;\r
+ using HandBrake.ApplicationServices.Utilities;\r
\r
/// <summary>\r
/// Class which handles the CLI\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
\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
if (this.IsEncoding == false)\r
{\r
- ReadFile(); // Read the last log file back in if it exists\r
+ try\r
+ {\r
+ ReadFile(); // Read the last log file back in if it exists\r
+ }\r
+ catch (Exception exc)\r
+ {\r
+ return exc.ToString();\r
+ }\r
}\r
\r
return string.IsNullOrEmpty(this.logBuffer.ToString()) ? "No log data available..." : this.logBuffer.ToString();\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
- Main.ShowExceptiowWindow("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
- Main.ShowExceptiowWindow("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
SendKeys.Send("^C");\r
SendKeys.Flush();\r
\r
- //if (HbProcess != null)\r
+ /*/if (HbProcess != null)\r
//{\r
// HbProcess.StandardInput.AutoFlush = true;\r
// HbProcess.StandardInput.WriteLine("^c^z");\r
- //}\r
+ //}*/\r
}\r
\r
- /* Helpers */\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
- Main.ShowExceptiowWindow("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
-\r
- // ReadFile(null);\r
-\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
- fileWriter.Close();\r
+ lock (fileWriterLock)\r
+ {\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
- Main.ShowExceptiowWindow("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
/// Read the log file\r
/// </summary>\r
- /// <param name="n">\r
- /// The object.\r
- /// </param>\r
private void ReadFile()\r
{\r
logBuffer = new StringBuilder();\r
\r
try\r
{\r
- // Make sure the application readable log file does not already exist. FileCopy fill fail if it does.\r
- if (File.Exists(logFile2))\r
- File.Delete(logFile2);\r
-\r
// Copy the log file.\r
if (File.Exists(logFile))\r
File.Copy(logFile, logFile2, true);\r
\r
// Start the Reader\r
// Only use text which continues on from the last read line\r
- StreamReader sr = new StreamReader(logFile2);\r
- string line;\r
- int i = 1;\r
- while ((line = sr.ReadLine()) != null)\r
+ using (StreamReader sr = new StreamReader(logFile2))\r
{\r
- if (i > logFilePosition)\r
+ string line;\r
+ int i = 1;\r
+ while ((line = sr.ReadLine()) != null)\r
{\r
- logBuffer.AppendLine(line);\r
- logFilePosition++;\r
+ if (i > logFilePosition)\r
+ {\r
+ logBuffer.AppendLine(line);\r
+ logFilePosition++;\r
+ }\r
+ i++;\r
}\r
- i++;\r
+ sr.Close();\r
}\r
- sr.Close();\r
- sr.Dispose();\r
}\r
catch (Exception exc)\r
{\r
- Main.ShowExceptiowWindow("Unable to read log file", exc.ToString());\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
- private void SetupLogging(Job encodeJob)\r
+ /// <param name="encodeQueueTask">\r
+ /// The encode QueueTask.\r
+ /// </param>\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
- Main.ShowExceptiowWindow("Error", exc.ToString());\r
+ fileWriter.Dispose();\r
+ }\r
+ throw;\r
}\r
}\r
\r
{\r
if (!String.IsNullOrEmpty(e.Data))\r
{\r
- lock (logBuffer)\r
- logBuffer.AppendLine(e.Data);\r
-\r
try\r
{\r
- if (fileWriter != null)\r
- fileWriter.WriteLine(e.Data);\r
+ lock (logBuffer)\r
+ logBuffer.AppendLine(e.Data);\r
+\r
+ lock (fileWriterLock)\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
- Main.ShowExceptiowWindow("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
}\r
catch (Exception exc)\r
{\r
- Main.ShowExceptiowWindow("An Unknown Error has occured", exc.ToString());\r
+ EncodeOnEncodeProgress(null, 0, 0, 0, 0, 0, "Unknown, status not available..");\r
}\r
}\r
\r
/// <param name="currentFps">Current encode speed in fps</param>\r
/// <param name="avg">Avg encode speed</param>\r
/// <param name="timeRemaining">Time Left</param>\r
- private void EncodeOnEncodeProgress(object sender, int currentTask, int taskCount, float percentComplete, float currentFps, float avg, TimeSpan timeRemaining)\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