OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / win / C# / HandBrake.ApplicationServices / Services / Encode.cs
index 95cc576..4a6333d 100644 (file)
@@ -6,18 +6,19 @@
 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
@@ -27,11 +28,6 @@ namespace HandBrake.ApplicationServices.Services
         #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
@@ -49,52 +45,40 @@ namespace HandBrake.ApplicationServices.Services
         /// <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
@@ -102,7 +86,7 @@ namespace HandBrake.ApplicationServices.Services
         public event EncodeProgessStatus EncodeStatusChanged;\r
         #endregion\r
 \r
-        /* Properties */\r
+        #region Properties\r
 \r
         /// <summary>\r
         /// Gets or sets The HB Process\r
@@ -137,36 +121,49 @@ namespace HandBrake.ApplicationServices.Services
             }\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
@@ -174,7 +171,7 @@ namespace HandBrake.ApplicationServices.Services
                 }\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
@@ -182,7 +179,9 @@ namespace HandBrake.ApplicationServices.Services
                     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
@@ -190,14 +189,14 @@ namespace HandBrake.ApplicationServices.Services
                     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
@@ -229,28 +228,51 @@ namespace HandBrake.ApplicationServices.Services
             }\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
@@ -258,7 +280,7 @@ namespace HandBrake.ApplicationServices.Services
         /// 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
@@ -275,8 +297,6 @@ namespace HandBrake.ApplicationServices.Services
             //}*/\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
@@ -284,7 +304,7 @@ namespace HandBrake.ApplicationServices.Services
         /// <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
@@ -315,10 +335,14 @@ namespace HandBrake.ApplicationServices.Services
             }\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
@@ -328,12 +352,9 @@ namespace HandBrake.ApplicationServices.Services
         /// <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
@@ -346,16 +367,32 @@ namespace HandBrake.ApplicationServices.Services
 \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
@@ -401,7 +438,9 @@ namespace HandBrake.ApplicationServices.Services
                 }\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
@@ -409,10 +448,10 @@ namespace HandBrake.ApplicationServices.Services
         /// <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
@@ -428,18 +467,17 @@ namespace HandBrake.ApplicationServices.Services
 \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
@@ -461,20 +499,30 @@ namespace HandBrake.ApplicationServices.Services
                     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
@@ -484,14 +532,14 @@ namespace HandBrake.ApplicationServices.Services
         /// <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
@@ -521,14 +569,14 @@ namespace HandBrake.ApplicationServices.Services
         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