OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / win / C# / HandBrake.ApplicationServices / Services / Encode.cs
1 /*  Encode.cs $\r
2     This file is part of the HandBrake source code.\r
3     Homepage: <http://handbrake.fr/>.\r
4     It may be used under the terms of the GNU General Public License. */\r
5 \r
6 namespace HandBrake.ApplicationServices.Services\r
7 {\r
8     using System;\r
9     using System.Diagnostics;\r
10     using System.IO;\r
11     using System.Text;\r
12     using System.Threading;\r
13     using System.Windows.Forms;\r
14 \r
15     using HandBrake.ApplicationServices.Functions;\r
16     using HandBrake.ApplicationServices.Model;\r
17     using HandBrake.ApplicationServices.Properties;\r
18 \r
19     using Timer = System.Threading.Timer;\r
20 \r
21     /// <summary>\r
22     /// Class which handles the CLI\r
23     /// </summary>\r
24     public class Encode\r
25     {\r
26         /* Private Variables */\r
27 \r
28         /// <summary>\r
29         /// An Encode Job\r
30         /// </summary>\r
31         private Job job;\r
32 \r
33         /// <summary>\r
34         /// The Log Buffer\r
35         /// </summary>\r
36         private StringBuilder logBuffer;\r
37 \r
38         /// <summary>\r
39         /// The line number thats been read to in the log file\r
40         /// </summary>\r
41         private int logFilePosition;\r
42 \r
43         /// <summary>\r
44         /// A Timer for this window\r
45         /// </summary>\r
46         private Timer windowTimer;\r
47 \r
48         /// <summary>\r
49         /// Gets The Process Handle\r
50         /// </summary>\r
51         private IntPtr processHandle;\r
52 \r
53         /// <summary>\r
54         /// Gets the Process ID\r
55         /// </summary>\r
56         private int processID;\r
57 \r
58         /* Event Handlers */\r
59 \r
60         /// <summary>\r
61         /// Fires when a new CLI Job starts\r
62         /// </summary>\r
63         public event EventHandler EncodeStarted;\r
64 \r
65         /// <summary>\r
66         /// Fires when a CLI job finishes.\r
67         /// </summary>\r
68         public event EventHandler EncodeEnded;\r
69 \r
70         /* Properties */\r
71 \r
72         /// <summary>\r
73         /// Gets or sets The HB Process\r
74         /// </summary>\r
75         public Process HbProcess { get; set; }\r
76 \r
77         /// <summary>\r
78         /// Gets a value indicating whether IsEncoding.\r
79         /// </summary>\r
80         public bool IsEncoding { get; private set; }\r
81 \r
82         /* Public Methods */\r
83 \r
84         /// <summary>\r
85         /// Gets ActivityLog.\r
86         /// </summary>\r
87         public string ActivityLog\r
88         {\r
89             get\r
90             {\r
91                 if (logBuffer == null)\r
92                 {\r
93                     ResetLogReader();\r
94                     ReadFile(null);\r
95                 }\r
96 \r
97                 return logBuffer != null ? logBuffer.ToString() : string.Empty;\r
98             }\r
99         }\r
100 \r
101         /// <summary>\r
102         /// Create a preview sample video\r
103         /// </summary>\r
104         /// <param name="query">\r
105         /// The CLI Query\r
106         /// </param>\r
107         public void CreatePreviewSample(string query)\r
108         {\r
109             this.Run(new Job { Query = query }, true);\r
110         }\r
111 \r
112         /// <summary>\r
113         /// Kill the CLI process\r
114         /// </summary>\r
115         public void Stop()\r
116         {\r
117             if (this.HbProcess != null)\r
118                 this.HbProcess.Kill();\r
119 \r
120             Process[] list = Process.GetProcessesByName("HandBrakeCLI");\r
121             foreach (Process process in list)\r
122                 process.Kill();\r
123 \r
124             if (this.EncodeEnded != null)\r
125                 this.EncodeEnded(this, new EventArgs());\r
126         }\r
127 \r
128         /// <summary>\r
129         /// Attempt to Safely kill a DirectRun() CLI\r
130         /// NOTE: This will not work with a MinGW CLI\r
131         /// Note: http://www.cygwin.com/ml/cygwin/2006-03/msg00330.html\r
132         /// </summary>\r
133         public void SafelyClose()\r
134         {\r
135             if ((int)this.processHandle == 0)\r
136                 return;\r
137 \r
138             // Allow the CLI to exit cleanly\r
139             Win32.SetForegroundWindow((int)this.processHandle);\r
140             SendKeys.Send("^C");\r
141             SendKeys.Flush();\r
142 \r
143             // HbProcess.StandardInput.AutoFlush = true;\r
144             // HbProcess.StandardInput.WriteLine("^C");\r
145         }\r
146 \r
147         /// <summary>\r
148         /// Execute a HandBrakeCLI process.\r
149         /// </summary>\r
150         /// <param name="encJob">\r
151         /// The enc Job.\r
152         /// </param>\r
153         /// <param name="RequireStandardOuput">\r
154         /// Set to True to show no window and force standard output redirect\r
155         /// </param>\r
156         protected void Run(Job encJob, bool RequireStandardOuput)\r
157         {\r
158             this.job = encJob;\r
159             try\r
160             {\r
161                 ResetLogReader();\r
162                 IsEncoding = true;\r
163 \r
164                 string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");\r
165                 string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs", "last_encode_log.txt");\r
166                 string strCmdLine = String.Format(@" /C """"{0}"" {1} 2>""{2}"" """, handbrakeCLIPath, encJob.Query, logPath);\r
167                 var cliStart = new ProcessStartInfo("CMD.exe", strCmdLine);\r
168 \r
169                 if (Settings.Default.enocdeStatusInGui || RequireStandardOuput)\r
170                 {\r
171                     cliStart.RedirectStandardOutput = true;\r
172                     cliStart.UseShellExecute = false;\r
173                     if (!Settings.Default.showCliForInGuiEncodeStatus || RequireStandardOuput)\r
174                         cliStart.CreateNoWindow = true;\r
175                 }\r
176                 if (Settings.Default.cli_minimized)\r
177                     cliStart.WindowStyle = ProcessWindowStyle.Minimized;\r
178 \r
179                 Process[] before = Process.GetProcesses(); // Get a list of running processes before starting.\r
180                 HbProcess = Process.Start(cliStart);\r
181                 this.processID = Main.GetCliProcess(before);\r
182 \r
183                 if (HbProcess != null)\r
184                     this.processHandle = HbProcess.MainWindowHandle; // Set the process Handle\r
185       \r
186                 // Start the Log Monitor\r
187                 windowTimer = new Timer(new TimerCallback(ReadFile), null, 1000, 1000);\r
188 \r
189                 // Set the process Priority\r
190                 Process hbCliProcess = null;\r
191                 if (this.processID != -1)\r
192                 {\r
193                     hbCliProcess = Process.GetProcessById(this.processID);\r
194                     hbCliProcess.EnableRaisingEvents = true;\r
195                     hbCliProcess.Exited += new EventHandler(HbProcess_Exited);\r
196                 }\r
197 \r
198                 if (hbCliProcess != null)\r
199                     switch (Settings.Default.processPriority)\r
200                     {\r
201                         case "Realtime":\r
202                             hbCliProcess.PriorityClass = ProcessPriorityClass.RealTime;\r
203                             break;\r
204                         case "High":\r
205                             hbCliProcess.PriorityClass = ProcessPriorityClass.High;\r
206                             break;\r
207                         case "Above Normal":\r
208                             hbCliProcess.PriorityClass = ProcessPriorityClass.AboveNormal;\r
209                             break;\r
210                         case "Normal":\r
211                             hbCliProcess.PriorityClass = ProcessPriorityClass.Normal;\r
212                             break;\r
213                         case "Low":\r
214                             hbCliProcess.PriorityClass = ProcessPriorityClass.Idle;\r
215                             break;\r
216                         default:\r
217                             hbCliProcess.PriorityClass = ProcessPriorityClass.BelowNormal;\r
218                             break;\r
219                     }\r
220 \r
221                 // Fire the Encode Started Event\r
222                 if (this.EncodeStarted != null)\r
223                     this.EncodeStarted(this, new EventArgs());\r
224             }\r
225             catch (Exception exc)\r
226             {\r
227                 Main.ShowExceptiowWindow("It would appear that HandBrakeCLI has not started correctly. You should take a look at the Activity log as it may indicate the reason why.\n\nDetailed Error Information: error occured in runCli()", exc.ToString());\r
228             }\r
229         }\r
230 \r
231         /// <summary>\r
232         /// The HandBrakeCLI process has exited.\r
233         /// </summary>\r
234         /// <param name="sender">\r
235         /// The sender.\r
236         /// </param>\r
237         /// <param name="e">\r
238         /// The EventArgs.\r
239         /// </param>\r
240         private void HbProcess_Exited(object sender, EventArgs e)\r
241         {\r
242             IsEncoding = false;\r
243         }\r
244 \r
245         /// <summary>\r
246         /// Function to run the CLI directly rather than via CMD\r
247         /// TODO: Code to handle the Log data has yet to be written.\r
248         /// TODO: Code to handle the % / ETA info has to be written.\r
249         /// </summary>\r
250         /// <param name="query">\r
251         /// The query.\r
252         /// </param>\r
253         protected void DirectRun(string query)\r
254         {\r
255             try\r
256             {\r
257                 if (this.EncodeStarted != null)\r
258                     this.EncodeStarted(this, new EventArgs());\r
259 \r
260                 IsEncoding = true;\r
261 \r
262                 ResetLogReader();\r
263 \r
264                 // Setup the job\r
265                 string handbrakeCLIPath = Path.Combine(Environment.CurrentDirectory, "HandBrakeCLI.exe");\r
266                 HbProcess = new Process\r
267                                 {\r
268                                     StartInfo =\r
269                                         {\r
270                                             FileName = handbrakeCLIPath,\r
271                                             Arguments = query,\r
272                                             UseShellExecute = false,\r
273                                             RedirectStandardOutput = true,\r
274                                             RedirectStandardError = true,\r
275                                             RedirectStandardInput = true,\r
276                                             CreateNoWindow = false,\r
277                                             WindowStyle = ProcessWindowStyle.Minimized\r
278                                         }\r
279                                 };\r
280 \r
281                 // Setup event handlers for rediected data\r
282                 HbProcess.ErrorDataReceived += new DataReceivedEventHandler(HbProcErrorDataReceived);\r
283                 HbProcess.OutputDataReceived += new DataReceivedEventHandler(HbProcOutputDataReceived);\r
284 \r
285                 // Start the process\r
286                 HbProcess.Start();\r
287 \r
288                 // Setup the asynchronous reading of stdin and stderr\r
289                 HbProcess.BeginErrorReadLine();\r
290                 HbProcess.BeginOutputReadLine();\r
291 \r
292                 // Set the Process Priority);\r
293                 switch (Settings.Default.processPriority)\r
294                 {\r
295                     case "Realtime":\r
296                         HbProcess.PriorityClass = ProcessPriorityClass.RealTime;\r
297                         break;\r
298                     case "High":\r
299                         HbProcess.PriorityClass = ProcessPriorityClass.High;\r
300                         break;\r
301                     case "Above Normal":\r
302                         HbProcess.PriorityClass = ProcessPriorityClass.AboveNormal;\r
303                         break;\r
304                     case "Normal":\r
305                         HbProcess.PriorityClass = ProcessPriorityClass.Normal;\r
306                         break;\r
307                     case "Low":\r
308                         HbProcess.PriorityClass = ProcessPriorityClass.Idle;\r
309                         break;\r
310                     default:\r
311                         HbProcess.PriorityClass = ProcessPriorityClass.BelowNormal;\r
312                         break;\r
313                 }\r
314 \r
315                 // Set the class items\r
316                 this.processID = HbProcess.Id;\r
317                 this.processHandle = HbProcess.Handle;\r
318             }\r
319             catch (Exception exc)\r
320             {\r
321                 Console.WriteLine(exc);\r
322             }\r
323         }\r
324 \r
325         /// <summary>\r
326         /// Perform an action after an encode. e.g a shutdown, standby, restart etc.\r
327         /// </summary>\r
328         protected void Finish()\r
329         {\r
330             if (!IsEncoding)\r
331             {\r
332                 windowTimer.Dispose();\r
333                 ReadFile(null);\r
334             }\r
335 \r
336             if (this.EncodeEnded != null)\r
337                 this.EncodeEnded(this, new EventArgs());\r
338 \r
339             // Growl\r
340         if (Settings.Default.growlQueue)\r
341                 GrowlCommunicator.Notify("Queue Completed", "Put down that cocktail...\nyour Handbrake queue is done.");\r
342 \r
343             // Do something whent he encode ends.\r
344             switch (Settings.Default.CompletionOption)\r
345             {\r
346                 case "Shutdown":\r
347                     Process.Start("Shutdown", "-s -t 60");\r
348                     break;\r
349                 case "Log Off":\r
350                     Win32.ExitWindowsEx(0, 0);\r
351                     break;\r
352                 case "Suspend":\r
353                     Application.SetSuspendState(PowerState.Suspend, true, true);\r
354                     break;\r
355                 case "Hibernate":\r
356                     Application.SetSuspendState(PowerState.Hibernate, true, true);\r
357                     break;\r
358                 case "Lock System":\r
359                     Win32.LockWorkStation();\r
360                     break;\r
361                 case "Quit HandBrake":\r
362                     Application.Exit();\r
363                     break;\r
364                 default:\r
365                     break;\r
366             }\r
367         }\r
368 \r
369         /// <summary>\r
370         /// Add the CLI Query to the Log File.\r
371         /// </summary>\r
372         /// <param name="encJob">\r
373         /// The Encode Job Object\r
374         /// </param>\r
375         protected void AddCLIQueryToLog(Job encJob)\r
376         {\r
377             try\r
378             {\r
379                 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +\r
380                                 "\\HandBrake\\logs";\r
381                 string logPath = Path.Combine(logDir, "last_encode_log.txt");\r
382 \r
383                 var reader = new StreamReader(File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.Read));\r
384                 string log = reader.ReadToEnd();\r
385                 reader.Close();\r
386 \r
387                 var writer = new StreamWriter(File.Create(logPath));\r
388 \r
389                 writer.WriteLine("### CLI Query: " + encJob.Query);\r
390                 writer.WriteLine("### User Query: " + encJob.CustomQuery);\r
391                 writer.WriteLine("#########################################");\r
392                 writer.WriteLine(log);\r
393                 writer.Flush();\r
394                 writer.Close();\r
395             }\r
396             catch (Exception)\r
397             {\r
398                 return;\r
399             }\r
400         }\r
401 \r
402         /// <summary>\r
403         /// Save a copy of the log to the users desired location or a default location\r
404         /// if this feature is enabled in options.\r
405         /// </summary>\r
406         /// <param name="destination">\r
407         /// The Destination File Path\r
408         /// </param>\r
409         protected void CopyLog(string destination)\r
410         {\r
411             try\r
412             {\r
413                 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +\r
414                                 "\\HandBrake\\logs";\r
415                 string tempLogFile = Path.Combine(logDir, "last_encode_log.txt");\r
416 \r
417                 string encodeDestinationPath = Path.GetDirectoryName(destination);\r
418                 string destinationFile = Path.GetFileName(destination);\r
419                 string encodeLogFile = destinationFile + " " +\r
420                                        DateTime.Now.ToString().Replace("/", "-").Replace(":", "-") + ".txt";\r
421 \r
422                 // Make sure the log directory exists.\r
423                 if (!Directory.Exists(logDir))\r
424                     Directory.CreateDirectory(logDir);\r
425 \r
426                 // Copy the Log to HandBrakes log folder in the users applciation data folder.\r
427                 File.Copy(tempLogFile, Path.Combine(logDir, encodeLogFile));\r
428 \r
429                 // Save a copy of the log file in the same location as the enocde.\r
430                 if (Settings.Default.saveLogWithVideo)\r
431                     File.Copy(tempLogFile, Path.Combine(encodeDestinationPath, encodeLogFile));\r
432 \r
433                 // Save a copy of the log file to a user specified location\r
434                 if (Directory.Exists(Settings.Default.saveLogPath))\r
435                     if (Settings.Default.saveLogPath != String.Empty && Settings.Default.saveLogToSpecifiedPath)\r
436                         File.Copy(tempLogFile, Path.Combine(Settings.Default.saveLogPath, encodeLogFile));\r
437             }\r
438             catch (Exception exc)\r
439             {\r
440                 Main.ShowExceptiowWindow("Unable to make a copy of the log file", exc.ToString());\r
441             }\r
442         }\r
443 \r
444         /// <summary>\r
445         /// Read the log file\r
446         /// </summary>\r
447         /// <param name="n">\r
448         /// The object.\r
449         /// </param>\r
450         private void ReadFile(object n)\r
451         {\r
452             lock (logBuffer)\r
453             {\r
454                 // last_encode_log.txt is the primary log file. Since .NET can't read this file whilst the CLI is outputing to it (Not even in read only mode),\r
455                 // we'll need to make a copy of it.\r
456                 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +\r
457                                 "\\HandBrake\\logs";\r
458                 string logFile = Path.Combine(logDir, "last_encode_log.txt");\r
459                 string logFile2 = Path.Combine(logDir, "tmp_appReadable_log.txt");\r
460 \r
461                 try\r
462                 {\r
463                     // Make sure the application readable log file does not already exist. FileCopy fill fail if it does.\r
464                     if (File.Exists(logFile2))\r
465                         File.Delete(logFile2);\r
466 \r
467                     // Copy the log file.\r
468                     if (File.Exists(logFile))\r
469                         File.Copy(logFile, logFile2, true);\r
470                     else\r
471                     {\r
472                         ResetLogReader();\r
473                         return;\r
474                     }\r
475 \r
476                     // Put the Query and User Generated Query Flag on the log.\r
477                     if (logFilePosition == 0 && job.Query != null)\r
478                     {\r
479                         logBuffer.AppendLine("### CLI Query: " + job.Query);\r
480                         logBuffer.AppendLine("### User Query: " + job.CustomQuery);\r
481                         logBuffer.AppendLine("#########################################");\r
482                     }\r
483 \r
484                     // Start the Reader\r
485                     // Only use text which continues on from the last read line\r
486                     StreamReader sr = new StreamReader(logFile2);\r
487                     string line;\r
488                     int i = 1;\r
489                     while ((line = sr.ReadLine()) != null)\r
490                     {\r
491                         if (i > logFilePosition)\r
492                         {\r
493                             logBuffer.AppendLine(line);\r
494                             logFilePosition++;\r
495                         }\r
496                         i++;\r
497                     }\r
498                     sr.Close();\r
499                     sr.Dispose();\r
500                 }\r
501                 catch (Exception)\r
502                 {\r
503                     ResetLogReader();\r
504                 }\r
505             }\r
506         }\r
507 \r
508         /// <summary>\r
509         /// Reset the Log Reader\r
510         /// </summary>\r
511         private void ResetLogReader()\r
512         {\r
513             logFilePosition = 0;\r
514             logBuffer = new StringBuilder();\r
515         }\r
516 \r
517         /// <summary>\r
518         /// Recieve the Standard Error information and process it\r
519         /// </summary>\r
520         /// <param name="sender">\r
521         /// The Sender Object\r
522         /// </param>\r
523         /// <param name="e">\r
524         /// DataReceived EventArgs\r
525         /// </param>\r
526         private void HbProcErrorDataReceived(object sender, DataReceivedEventArgs e)\r
527         {\r
528             if (!String.IsNullOrEmpty(e.Data))\r
529             {\r
530                 lock (logBuffer)\r
531                     logBuffer.AppendLine(e.Data);\r
532             }\r
533         }\r
534 \r
535         /// <summary>\r
536         /// Standard Input Data Recieved from the CLI\r
537         /// </summary>\r
538         /// <param name="sender">\r
539         /// The Sender Object\r
540         /// </param>\r
541         /// <param name="e">\r
542         /// DataReceived EventArgs\r
543         /// </param>\r
544         private void HbProcOutputDataReceived(object sender, DataReceivedEventArgs e)\r
545         {\r
546             if (!String.IsNullOrEmpty(e.Data))\r
547             {\r
548                 lock (logBuffer)\r
549                     logBuffer.AppendLine(e.Data);\r
550             }\r
551         }\r
552     }\r
553 }