OSDN Git Service

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