3 This file is part of the HandBrake source code.
\r
4 Homepage: <http://handbrake.fr/>.
\r
5 It may be used under the terms of the GNU General Public License. */
\r
8 using System.Collections.Generic;
\r
9 using System.Drawing;
\r
10 using System.Globalization;
\r
11 using System.Windows.Forms;
\r
13 using System.Diagnostics;
\r
14 using System.Threading;
\r
15 using Handbrake.EncodeQueue;
\r
16 using Handbrake.Functions;
\r
17 using Handbrake.Presets;
\r
18 using Handbrake.Parsing;
\r
22 public partial class frmMain : Form
\r
24 // Objects which may be used by one or more other objects *************
\r
25 Queue encodeQueue = new Queue();
\r
26 PresetsHandler presetHandler = new PresetsHandler();
\r
27 QueryGenerator queryGen = new QueryGenerator();
\r
29 // Globals: Mainly used for tracking. *********************************
\r
30 public Title selectedTitle;
\r
31 private frmQueue queueWindow;
\r
32 private frmPreview qtpreview;
\r
33 private frmActivityWindow ActivityWindow;
\r
34 private Form splash;
\r
35 public string sourcePath;
\r
36 private string lastAction;
\r
37 private SourceType selectedSourceType;
\r
38 private string dvdDrivePath;
\r
39 private string dvdDriveLabel;
\r
40 private Preset CurrentlySelectedPreset;
\r
41 private DVD currentSource;
\r
43 // Delegates **********************************************************
\r
44 private delegate void UpdateWindowHandler();
\r
46 // Applicaiton Startup ************************************************
\r
48 #region Application Startup
\r
51 // Load and setup the splash screen in this thread
\r
52 splash = new frmSplashScreen();
\r
54 Label lblStatus = new Label { Size = new Size(150, 20), Location = new Point(182, 102) };
\r
55 splash.Controls.Add(lblStatus);
\r
57 InitializeComponent();
\r
59 // Update the users config file with the CLI version data.
\r
60 lblStatus.Text = "Setting Version Data ...";
\r
61 Application.DoEvents();
\r
62 Main.SetCliVersionData();
\r
64 // Show the form, but leave disabled until preloading is complete then show the main form
\r
65 this.Enabled = false;
\r
67 Application.DoEvents(); // Forces frmMain to draw
\r
69 // Check for new versions, if update checking is enabled
\r
70 if (Properties.Settings.Default.updateStatus)
\r
72 DateTime now = DateTime.Now;
\r
73 DateTime lastCheck = Properties.Settings.Default.lastUpdateCheckDate;
\r
74 TimeSpan elapsed = now.Subtract(lastCheck);
\r
75 if (elapsed.TotalDays > Properties.Settings.Default.daysBetweenUpdateCheck)
\r
77 lblStatus.Text = "Checking for updates ...";
\r
78 Application.DoEvents();
\r
80 Main.BeginCheckForUpdates(new AsyncCallback(UpdateCheckDone), false);
\r
84 // Clear the log files in the background
\r
85 if (Properties.Settings.Default.clearOldLogs)
\r
87 lblStatus.Text = "Clearing Old Log Files ...";
\r
88 Application.DoEvents();
\r
89 Thread clearLog = new Thread(Main.ClearOldLogs);
\r
93 // Setup the GUI components
\r
94 lblStatus.Text = "Setting up the GUI ...";
\r
95 Application.DoEvents();
\r
96 loadPresetPanel(); // Load the Preset Panel
\r
97 treeView_presets.ExpandAll();
\r
98 lbl_encode.Text = "";
\r
99 drop_mode.SelectedIndex = 0;
\r
100 queueWindow = new frmQueue(encodeQueue, this); // Prepare the Queue
\r
101 if (!Properties.Settings.Default.QueryEditorTab)
\r
102 tabs_panel.TabPages.RemoveAt(7); // Remove the query editor tab if the user does not want it enabled.
\r
104 // Load the user's default settings or Normal Preset
\r
105 if (Properties.Settings.Default.defaultPreset != "")
\r
107 if (presetHandler.GetPreset(Properties.Settings.Default.defaultPreset) != null)
\r
109 string query = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).Query;
\r
110 Boolean loadPictureSettings = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).PictureSettings;
\r
114 x264Panel.reset2Defaults();
\r
116 QueryParser presetQuery = QueryParser.Parse(query);
\r
117 PresetLoader.presetLoader(this, presetQuery, Properties.Settings.Default.defaultPreset, loadPictureSettings);
\r
119 x264Panel.X264_StandardizeOptString();
\r
120 x264Panel.X264_SetCurrentSettingsInPanel();
\r
124 loadNormalPreset();
\r
127 loadNormalPreset();
\r
129 // Enabled GUI tooltip's if Required
\r
130 if (Properties.Settings.Default.tooltipEnable)
\r
131 ToolTip.Active = true;
\r
133 // Register with Growl (if not using Growl for the encoding completion action, this wont hurt anything)
\r
134 GrowlCommunicator.Register();
\r
137 lblStatus.Text = "Loading Complete!";
\r
138 Application.DoEvents();
\r
141 this.Enabled = true;
\r
143 // Event Handlers and Queue Recovery
\r
148 private void UpdateCheckDone(IAsyncResult result)
\r
150 if (InvokeRequired)
\r
152 Invoke(new MethodInvoker(() => UpdateCheckDone(result)));
\r
156 UpdateCheckInformation info;
\r
160 info = Main.EndCheckForUpdates(result);
\r
162 if (info.NewVersionAvailable)
\r
164 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
165 updateWindow.ShowDialog();
\r
168 catch (Exception ex)
\r
170 if ((bool)result.AsyncState)
\r
171 MessageBox.Show("Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
175 // Startup Functions
\r
176 private void queueRecovery()
\r
178 if (Main.CheckQueueRecovery())
\r
180 DialogResult result = MessageBox.Show("HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?", "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
182 if (result == DialogResult.Yes)
\r
183 encodeQueue.LoadQueueFromFile("hb_queue_recovery.xml"); // Start Recovery
\r
186 // Remove the Queue recovery file if the user doesn't want to recovery the last queue.
\r
187 string queuePath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
188 if (File.Exists(queuePath))
\r
189 File.Delete(queuePath);
\r
196 public string SourceName
\r
200 if (this.selectedSourceType == SourceType.DvdDrive)
\r
202 return this.dvdDriveLabel;
\r
205 if (Path.GetFileNameWithoutExtension(this.sourcePath) != "VIDEO_TS")
\r
206 return Path.GetFileNameWithoutExtension(this.sourcePath);
\r
208 return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.sourcePath));
\r
214 // Encoding Events for setting up the GUI
\r
215 private void events()
\r
217 // Handle Widget changes when preset is selected.
\r
218 RegisterPresetEventHandler();
\r
220 // Handle Window Resize
\r
221 if (Properties.Settings.Default.MainWindowMinimize)
\r
222 this.Resize += new EventHandler(frmMain_Resize);
\r
224 // Handle Encode Start / Finish / Pause
\r
225 encodeQueue.CurrentJobCompleted += new EventHandler(encodeEnded);
\r
226 encodeQueue.QueuePauseRequested += new EventHandler(encodePaused);
\r
227 encodeQueue.NewJobStarted += new EventHandler(encodeStarted);
\r
229 // Handle a file being draged onto the GUI.
\r
230 this.DragEnter += new DragEventHandler(frmMain_DragEnter);
\r
231 this.DragDrop += new DragEventHandler(frmMain_DragDrop);
\r
234 // Change the preset label to custom when a user changes a setting. Don't want to give the impression that users can change settings and still be using a preset
\r
235 private void RegisterPresetEventHandler()
\r
238 drop_format.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
239 check_largeFile.CheckedChanged += new EventHandler(changePresetLabel);
\r
240 check_iPodAtom.CheckedChanged += new EventHandler(changePresetLabel);
\r
241 check_optimiseMP4.CheckedChanged += new EventHandler(changePresetLabel);
\r
243 // Picture Settings
\r
244 //PictureSettings.PictureSettingsChanged += new EventHandler(changePresetLabel);
\r
247 Filters.FilterSettingsChanged += new EventHandler(changePresetLabel);
\r
250 drp_videoEncoder.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
251 check_2PassEncode.CheckedChanged += new EventHandler(changePresetLabel);
\r
252 check_turbo.CheckedChanged += new EventHandler(changePresetLabel);
\r
253 text_filesize.TextChanged += new EventHandler(changePresetLabel);
\r
254 text_bitrate.TextChanged += new EventHandler(changePresetLabel);
\r
255 slider_videoQuality.ValueChanged += new EventHandler(changePresetLabel);
\r
258 AudioSettings.AudioListChanged += new EventHandler(changePresetLabel);
\r
261 x264Panel.rtf_x264Query.TextChanged += new EventHandler(changePresetLabel);
\r
263 private void UnRegisterPresetEventHandler()
\r
265 // Output Settings
\r
266 drop_format.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
267 check_largeFile.CheckedChanged -= new EventHandler(changePresetLabel);
\r
268 check_iPodAtom.CheckedChanged -= new EventHandler(changePresetLabel);
\r
269 check_optimiseMP4.CheckedChanged -= new EventHandler(changePresetLabel);
\r
271 // Picture Settings
\r
272 //PictureSettings.PictureSettingsChanged -= new EventHandler(changePresetLabel);
\r
275 Filters.FilterSettingsChanged -= new EventHandler(changePresetLabel);
\r
278 drp_videoEncoder.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
279 check_2PassEncode.CheckedChanged -= new EventHandler(changePresetLabel);
\r
280 check_turbo.CheckedChanged -= new EventHandler(changePresetLabel);
\r
281 text_filesize.TextChanged -= new EventHandler(changePresetLabel);
\r
282 text_bitrate.TextChanged -= new EventHandler(changePresetLabel);
\r
283 slider_videoQuality.ValueChanged -= new EventHandler(changePresetLabel);
\r
286 AudioSettings.AudioListChanged -= new EventHandler(changePresetLabel);
\r
289 x264Panel.rtf_x264Query.TextChanged -= new EventHandler(changePresetLabel);
\r
291 private void changePresetLabel(object sender, EventArgs e)
\r
293 labelPreset.Text = "Output Settings (Preset: Custom)";
\r
294 CurrentlySelectedPreset = null;
\r
297 private static void frmMain_DragEnter(object sender, DragEventArgs e)
\r
299 if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
\r
300 e.Effect = DragDropEffects.All;
\r
302 private void frmMain_DragDrop(object sender, DragEventArgs e)
\r
304 string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
\r
305 sourcePath = string.Empty;
\r
307 if (fileList != null)
\r
309 if (fileList[0] != "")
\r
311 this.selectedSourceType = SourceType.VideoFile;
\r
312 StartScan(fileList[0], 0);
\r
315 UpdateSourceLabel();
\r
318 UpdateSourceLabel();
\r
320 private void encodeStarted(object sender, EventArgs e)
\r
322 lastAction = "encode";
\r
323 setEncodeStarted();
\r
325 // Experimental HBProc Process Monitoring.
\r
326 if (Properties.Settings.Default.enocdeStatusInGui)
\r
328 Thread encodeMon = new Thread(encodeMonitorThread);
\r
332 private void encodeEnded(object sender, EventArgs e)
\r
334 setEncodeFinished();
\r
336 private void encodePaused(object sender, EventArgs e)
\r
338 setEncodeFinished();
\r
342 // User Interface Menus / Tool Strips *********************************
\r
345 private void mnu_killCLI_Click(object sender, EventArgs e)
\r
349 private void mnu_exit_Click(object sender, EventArgs e)
\r
351 Application.Exit();
\r
356 private void mnu_encode_Click(object sender, EventArgs e)
\r
358 queueWindow.Show();
\r
360 private void mnu_encodeLog_Click(object sender, EventArgs e)
\r
362 frmActivityWindow dvdInfoWindow = new frmActivityWindow(lastAction);
\r
363 dvdInfoWindow.Show();
\r
365 private void mnu_options_Click(object sender, EventArgs e)
\r
367 Form options = new frmOptions(this);
\r
368 options.ShowDialog();
\r
372 #region Presets Menu
\r
373 private void mnu_presetReset_Click(object sender, EventArgs e)
\r
375 presetHandler.UpdateBuiltInPresets();
\r
377 if (treeView_presets.Nodes.Count == 0)
\r
378 MessageBox.Show("Unable to load the presets.xml file. Please select \"Update Built-in Presets\" from the Presets Menu. \nMake sure you are running the program in Admin mode if running on Vista. See Windows FAQ for details!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
380 MessageBox.Show("Presets have been updated!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
382 treeView_presets.ExpandAll();
\r
384 private void mnu_delete_preset_Click(object sender, EventArgs e)
\r
386 presetHandler.RemoveBuiltInPresets();
\r
387 loadPresetPanel(); // Reload the preset panel
\r
389 private void mnu_SelectDefault_Click(object sender, EventArgs e)
\r
391 loadNormalPreset();
\r
393 private void mnu_importMacPreset_Click(object sender, EventArgs e)
\r
397 private void btn_new_preset_Click(object sender, EventArgs e)
\r
399 Form preset = new frmAddPreset(this, queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null), presetHandler);
\r
400 preset.ShowDialog();
\r
405 private void mnu_user_guide_Click(object sender, EventArgs e)
\r
407 Process.Start("http://trac.handbrake.fr/wiki/HandBrakeGuide");
\r
409 private void mnu_handbrake_home_Click(object sender, EventArgs e)
\r
411 Process.Start("http://handbrake.fr");
\r
413 private void mnu_UpdateCheck_Click(object sender, EventArgs e)
\r
415 lbl_updateCheck.Visible = true;
\r
416 Main.BeginCheckForUpdates(new AsyncCallback(updateCheckDoneMenu), false);
\r
418 private void updateCheckDoneMenu(IAsyncResult result)
\r
420 // Make sure it's running on the calling thread
\r
421 if (InvokeRequired)
\r
423 Invoke(new MethodInvoker(() => updateCheckDoneMenu(result)));
\r
426 UpdateCheckInformation info;
\r
429 // Get the information about the new build, if any, and close the window
\r
430 info = Main.EndCheckForUpdates(result);
\r
432 if (info.NewVersionAvailable && info.BuildInformation != null)
\r
434 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
435 updateWindow.ShowDialog();
\r
438 MessageBox.Show("There are no new updates at this time.", "Update Check", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
439 lbl_updateCheck.Visible = false;
\r
442 catch (Exception ex)
\r
444 if ((bool)result.AsyncState)
\r
445 MessageBox.Show("Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
448 private void mnu_about_Click(object sender, EventArgs e)
\r
450 using (frmAbout About = new frmAbout())
\r
452 About.ShowDialog();
\r
458 // Right Click Menu Code
\r
459 private void pmnu_expandAll_Click(object sender, EventArgs e)
\r
461 treeView_presets.ExpandAll();
\r
463 private void pmnu_collapse_Click(object sender, EventArgs e)
\r
465 treeView_presets.CollapseAll();
\r
467 private void pmnu_import_Click(object sender, EventArgs e)
\r
471 private void pmnu_saveChanges_Click(object sender, EventArgs e)
\r
473 DialogResult result = MessageBox.Show("Do you wish to include picture settings when updating the preset: " + treeView_presets.SelectedNode.Text, "Update Preset", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
\r
474 if (result == DialogResult.Yes)
\r
475 presetHandler.Update(treeView_presets.SelectedNode.Text, QueryGenerator.GenerateTabbedComponentsQuery(this), true);
\r
476 else if (result == DialogResult.No)
\r
477 presetHandler.Update(treeView_presets.SelectedNode.Text, QueryGenerator.GenerateTabbedComponentsQuery(this), false);
\r
479 private void pmnu_delete_click(object sender, EventArgs e)
\r
481 if (treeView_presets.SelectedNode != null)
\r
483 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
484 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
486 treeView_presets.Select();
\r
488 private void presets_menu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
\r
490 // Make sure that the save menu is always disabled by default
\r
491 pmnu_saveChanges.Enabled = false;
\r
493 // Now enable the save menu if the selected preset is a user preset
\r
494 if (treeView_presets.SelectedNode != null)
\r
495 if (presetHandler.CheckIfUserPresetExists(treeView_presets.SelectedNode.Text))
\r
496 pmnu_saveChanges.Enabled = true;
\r
498 treeView_presets.Select();
\r
501 // Presets Management
\r
502 private void btn_addPreset_Click(object sender, EventArgs e)
\r
504 Form preset = new frmAddPreset(this, QueryGenerator.GenerateTabbedComponentsQuery(this), presetHandler);
\r
505 preset.ShowDialog();
\r
507 private void btn_removePreset_Click(object sender, EventArgs e)
\r
509 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
510 if (result == DialogResult.Yes)
\r
512 if (treeView_presets.SelectedNode != null)
\r
514 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
515 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
518 treeView_presets.Select();
\r
520 private void btn_setDefault_Click(object sender, EventArgs e)
\r
522 if (treeView_presets.SelectedNode != null)
\r
524 DialogResult result = MessageBox.Show("Are you sure you wish to set this preset as the default?", "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
525 if (result == DialogResult.Yes)
\r
527 Properties.Settings.Default.defaultPreset = treeView_presets.SelectedNode.Text;
\r
528 Properties.Settings.Default.Save();
\r
529 MessageBox.Show("New default preset set.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
533 MessageBox.Show("Please select a preset first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
535 private void treeview_presets_mouseUp(object sender, MouseEventArgs e)
\r
537 if (e.Button == MouseButtons.Right)
\r
538 treeView_presets.SelectedNode = treeView_presets.GetNodeAt(e.Location);
\r
539 else if (e.Button == MouseButtons.Left)
\r
541 if (treeView_presets.GetNodeAt(e.Location) != null)
\r
543 if (labelPreset.Text.Contains(treeView_presets.GetNodeAt(e.Location).Text))
\r
548 treeView_presets.Select();
\r
550 private void treeView_presets_AfterSelect(object sender, TreeViewEventArgs e)
\r
554 private void treeView_presets_deleteKey(object sender, KeyEventArgs e)
\r
556 if (e.KeyCode == Keys.Delete)
\r
558 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
559 if (result == DialogResult.Yes)
\r
561 if (treeView_presets.SelectedNode != null)
\r
562 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
564 // Remember each nodes expanded status so we can reload it
\r
565 List<Boolean> nodeStatus = new List<Boolean>();
\r
566 foreach (TreeNode node in treeView_presets.Nodes)
\r
567 nodeStatus.Add(node.IsExpanded);
\r
569 // Now reload the preset panel
\r
572 // And finally, re-expand any of the nodes if required
\r
574 foreach (TreeNode node in treeView_presets.Nodes)
\r
584 private void selectPreset()
\r
586 if (treeView_presets.SelectedNode != null)
\r
588 // Ok, so, we've selected a preset. Now we want to load it.
\r
589 string presetName = treeView_presets.SelectedNode.Text;
\r
590 Preset preset = presetHandler.GetPreset(presetName);
\r
591 if (preset != null)
\r
593 string query = presetHandler.GetPreset(presetName).Query;
\r
594 Boolean loadPictureSettings = presetHandler.GetPreset(presetName).PictureSettings;
\r
598 //Ok, Reset all the H264 widgets before changing the preset
\r
599 x264Panel.reset2Defaults();
\r
601 // Send the query from the file to the Query Parser class
\r
602 QueryParser presetQuery = QueryParser.Parse(query);
\r
604 // Now load the preset
\r
605 PresetLoader.presetLoader(this, presetQuery, presetName, loadPictureSettings);
\r
607 // The x264 widgets will need updated, so do this now:
\r
608 x264Panel.X264_StandardizeOptString();
\r
609 x264Panel.X264_SetCurrentSettingsInPanel();
\r
611 // Finally, let this window have a copy of the preset settings.
\r
612 CurrentlySelectedPreset = preset;
\r
613 PictureSettings.SetPresetCropWarningLabel(preset);
\r
618 private void loadNormalPreset()
\r
620 foreach (TreeNode treenode in treeView_presets.Nodes)
\r
622 foreach (TreeNode node in treenode.Nodes)
\r
624 if (node.Text.Equals("Normal"))
\r
625 treeView_presets.SelectedNode = treeView_presets.Nodes[treenode.Index].Nodes[0];
\r
629 private void importPreset()
\r
631 Import imp = new Import();
\r
632 if (openPreset.ShowDialog() == DialogResult.OK)
\r
634 QueryParser parsed = imp.importMacPreset(openPreset.FileName);
\r
635 if (presetHandler.CheckIfUserPresetExists(parsed.PresetName + " (Imported)"))
\r
637 DialogResult result = MessageBox.Show("This preset appears to already exist. Would you like to overwrite it?", "Overwrite preset?",
\r
638 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
639 if (result == DialogResult.Yes)
\r
641 PresetLoader.presetLoader(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
642 presetHandler.Update(parsed.PresetName + " (Imported)", queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null),
\r
643 parsed.UsesPictureSettings);
\r
648 PresetLoader.presetLoader(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
649 presetHandler.Add(parsed.PresetName, queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null), parsed.UsesPictureSettings);
\r
651 if (presetHandler.Add(parsed.PresetName + " (Imported)", queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null), parsed.UsesPictureSettings))
\r
653 TreeNode preset_treeview = new TreeNode(parsed.PresetName + " (Imported)") { ForeColor = Color.Black };
\r
654 treeView_presets.Nodes.Add(preset_treeview);
\r
662 private void btn_source_Click(object sender, EventArgs e)
\r
664 mnu_dvd_drive.Visible = true;
\r
665 Thread driveInfoThread = new Thread(getDriveInfoThread);
\r
666 driveInfoThread.Start();
\r
668 private void btn_start_Click(object sender, EventArgs e)
\r
670 if (btn_start.Text == "Stop")
\r
672 DialogResult result;
\r
673 if (Properties.Settings.Default.enocdeStatusInGui && !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
674 result = MessageBox.Show("Are you sure you wish to cancel the encode?\n\nPlease note, when 'Enable in-GUI encode status' is enabled, stopping this encode will render the file unplayable. ",
\r
675 "Cancel Encode?",MessageBoxButtons.YesNo,MessageBoxIcon.Question);
\r
677 result = MessageBox.Show("Are you sure you wish to cancel the encode?", "Cancel Encode?",
\r
678 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
680 if (result == DialogResult.Yes)
\r
683 encodeQueue.Pause();
\r
685 if (Properties.Settings.Default.enocdeStatusInGui && !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
687 encodeQueue.Stop();
\r
688 if (encodeQueue.HbProcess != null)
\r
689 encodeQueue.HbProcess.WaitForExit();
\r
693 // Allow the CLI to exit cleanly
\r
694 Win32.SetForegroundWindow((int) encodeQueue.ProcessHandle);
\r
695 SendKeys.Send("^C");
\r
699 setEncodeFinished();
\r
704 if (encodeQueue.Count != 0 || (!string.IsNullOrEmpty(sourcePath) && !string.IsNullOrEmpty(text_destination.Text)))
\r
706 string generatedQuery = queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null);
\r
707 string specifiedQuery = rtf_query.Text != "" ? rtf_query.Text : queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null);
\r
708 string query = string.Empty;
\r
710 // Check to make sure the generated query matches the GUI settings
\r
711 if (Properties.Settings.Default.PromptOnUnmatchingQueries && !string.IsNullOrEmpty(specifiedQuery) && generatedQuery != specifiedQuery)
\r
713 DialogResult result = MessageBox.Show("The query under the \"Query Editor\" tab " +
\r
714 "does not match the current GUI settings.\n\nBecause the manual query takes " +
\r
715 "priority over the GUI, your recently updated settings will not be taken " +
\r
716 "into account when encoding this job." + Environment.NewLine + Environment.NewLine +
\r
717 "Do you want to replace the manual query with the updated GUI-generated query?",
\r
718 "Manual Query does not Match GUI",
\r
719 MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk,
\r
720 MessageBoxDefaultButton.Button3);
\r
724 case DialogResult.Yes:
\r
725 // Replace the manual query with the generated one
\r
726 query = generatedQuery;
\r
727 rtf_query.Text = generatedQuery;
\r
729 case DialogResult.No:
\r
730 // Use the manual query
\r
731 query = specifiedQuery;
\r
733 case DialogResult.Cancel:
\r
734 // Don't start the encode
\r
740 query = specifiedQuery;
\r
743 DialogResult overwrite = DialogResult.Yes;
\r
744 if (text_destination.Text != "")
\r
745 if (File.Exists(text_destination.Text))
\r
746 overwrite = MessageBox.Show("The destination file already exists. Are you sure you want to overwrite it?", "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
748 if (overwrite == DialogResult.Yes)
\r
750 if (encodeQueue.Count == 0)
\r
751 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != ""));
\r
753 queueWindow.SetQueue();
\r
754 if (encodeQueue.Count > 1)
\r
755 queueWindow.Show(false);
\r
757 setEncodeStarted(); // Encode is running, so setup the GUI appropriately
\r
758 encodeQueue.Start(); // Start The Queue Encoding Process
\r
759 lastAction = "encode"; // Set the last action to encode - Used for activity window.
\r
761 if (ActivityWindow != null)
\r
762 ActivityWindow.SetEncodeMode();
\r
766 else if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
767 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
770 private void btn_add2Queue_Click(object sender, EventArgs e)
\r
772 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
773 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
776 String query = queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null);
\r
777 if (rtf_query.Text != "")
\r
778 query = rtf_query.Text;
\r
780 if (encodeQueue.CheckForDestinationDuplicate(text_destination.Text))
\r
782 DialogResult result = MessageBox.Show("There is already a queue item for this destination path. \n\n If you continue, the encode will be overwritten. Do you wish to continue?",
\r
783 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
784 if (result == DialogResult.Yes)
\r
785 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != ""));
\r
789 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != ""));
\r
791 lbl_encode.Text = encodeQueue.Count + " encode(s) pending in the queue";
\r
793 queueWindow.Show();
\r
796 private void btn_showQueue_Click(object sender, EventArgs e)
\r
798 queueWindow.Show();
\r
799 queueWindow.Activate();
\r
801 private void tb_preview_Click(object sender, EventArgs e)
\r
803 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
804 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
807 if (qtpreview == null)
\r
809 qtpreview = new frmPreview(this);
\r
812 else if (qtpreview.IsDisposed)
\r
814 qtpreview = new frmPreview(this);
\r
818 MessageBox.Show(qtpreview, "The preview window is already open!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
821 private void btn_ActivityWindow_Click(object sender, EventArgs e)
\r
823 if (ActivityWindow == null || !ActivityWindow.IsHandleCreated)
\r
824 ActivityWindow = new frmActivityWindow(lastAction);
\r
826 switch (lastAction)
\r
829 ActivityWindow.SetScanMode();
\r
832 ActivityWindow.SetEncodeMode();
\r
835 ActivityWindow.SetEncodeMode();
\r
839 ActivityWindow.Show();
\r
840 ActivityWindow.Activate();
\r
844 #region System Tray Icon
\r
845 private void frmMain_Resize(object sender, EventArgs e)
\r
847 if (FormWindowState.Minimized == this.WindowState)
\r
849 notifyIcon.Visible = true;
\r
852 else if (FormWindowState.Normal == this.WindowState)
\r
853 notifyIcon.Visible = false;
\r
855 private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
\r
857 this.Visible = true;
\r
859 this.WindowState = FormWindowState.Normal;
\r
860 notifyIcon.Visible = false;
\r
862 private void btn_restore_Click(object sender, EventArgs e)
\r
864 this.Visible = true;
\r
866 this.WindowState = FormWindowState.Normal;
\r
867 notifyIcon.Visible = false;
\r
871 #region Tab Control
\r
874 private void btn_dvd_source_Click(object sender, EventArgs e)
\r
876 if (DVD_Open.ShowDialog() == DialogResult.OK)
\r
878 this.selectedSourceType = SourceType.Folder;
\r
879 SelectSource(DVD_Open.SelectedPath);
\r
882 UpdateSourceLabel();
\r
884 private void btn_file_source_Click(object sender, EventArgs e)
\r
886 if (ISO_Open.ShowDialog() == DialogResult.OK)
\r
888 this.selectedSourceType = SourceType.VideoFile;
\r
889 SelectSource(ISO_Open.FileName);
\r
892 UpdateSourceLabel();
\r
894 private void mnu_dvd_drive_Click(object sender, EventArgs e)
\r
896 if (this.dvdDrivePath == null) return;
\r
897 this.selectedSourceType = SourceType.DvdDrive;
\r
898 SelectSource(this.dvdDrivePath);
\r
900 private void SelectSource(string file)
\r
902 Check_ChapterMarkers.Enabled = true;
\r
903 lastAction = "scan";
\r
904 sourcePath = string.Empty;
\r
906 if (file == string.Empty) // Must have a file or path
\r
908 UpdateSourceLabel();
\r
912 sourcePath = Path.GetFileName(file);
\r
913 StartScan(file, 0);
\r
915 private void drp_dvdtitle_Click(object sender, EventArgs e)
\r
917 if ((drp_dvdtitle.Items.Count == 1) && (drp_dvdtitle.Items[0].ToString() == "Automatic"))
\r
918 MessageBox.Show("There are no titles to select. Please load a source file by clicking the 'Source' button above before trying to select a title.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
920 private void drp_dvdtitle_SelectedIndexChanged(object sender, EventArgs e)
\r
922 UnRegisterPresetEventHandler();
\r
923 drop_mode.SelectedIndex = 0;
\r
925 PictureSettings.lbl_Aspect.Text = "Select a Title"; // Reset some values on the form
\r
926 drop_chapterStart.Items.Clear();
\r
927 drop_chapterFinish.Items.Clear();
\r
929 // If the dropdown is set to automatic nothing else needs to be done.
\r
930 // Otheriwse if its not, title data has to be loased from parsing.
\r
931 if (drp_dvdtitle.Text != "Automatic")
\r
933 selectedTitle = drp_dvdtitle.SelectedItem as Title;
\r
934 lbl_duration.Text = selectedTitle.Duration.ToString();
\r
935 PictureSettings.CurrentlySelectedPreset = CurrentlySelectedPreset;
\r
936 PictureSettings.Source = selectedTitle; // Setup Picture Settings Tab Control
\r
938 // Populate the Angles dropdown
\r
939 drop_angle.Items.Clear();
\r
940 if (!Properties.Settings.Default.noDvdNav)
\r
942 drop_angle.Visible = true;
\r
943 lbl_angle.Visible = true;
\r
944 drop_angle.Items.AddRange(selectedTitle.Angles.ToArray());
\r
945 if (drop_angle.Items.Count != 0)
\r
946 drop_angle.SelectedIndex = 0;
\r
950 drop_angle.Visible = false;
\r
951 lbl_angle.Visible = false;
\r
954 // Populate the Start chapter Dropdown
\r
955 drop_chapterStart.Items.Clear();
\r
956 drop_chapterStart.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
957 if (drop_chapterStart.Items.Count > 0)
\r
958 drop_chapterStart.Text = drop_chapterStart.Items[0].ToString();
\r
960 // Populate the Final Chapter Dropdown
\r
961 drop_chapterFinish.Items.Clear();
\r
962 drop_chapterFinish.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
963 if (drop_chapterFinish.Items.Count > 0)
\r
964 drop_chapterFinish.Text = drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString();
\r
966 // Populate the Audio Channels Dropdown
\r
967 AudioSettings.SetTrackList(selectedTitle);
\r
969 // Populate the Subtitles dropdown
\r
970 Subtitles.SetSubtitleTrackAuto(selectedTitle.Subtitles.ToArray());
\r
972 // Update the source label if we have multiple streams
\r
973 if (selectedTitle != null)
\r
974 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
975 labelSource.Text = labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
977 // Run the AutoName & ChapterNaming functions
\r
978 if (Properties.Settings.Default.autoNaming)
\r
980 string autoPath = Main.AutoName(this);
\r
981 if (autoPath != null)
\r
982 text_destination.Text = autoPath;
\r
984 MessageBox.Show("You currently have \"Automatically name output files\" enabled for the destination file box, but you do not have a default directory set.\n\nYou should set a \"Default Path\" in HandBrakes preferences. (See 'Tools' menu -> 'Options' -> 'General' Tab -> 'Default Path')", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
987 data_chpt.Rows.Clear();
\r
988 if (selectedTitle.Chapters.Count != 1)
\r
990 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
991 if (chapterGridView != null)
\r
992 data_chpt = chapterGridView;
\r
996 Check_ChapterMarkers.Checked = false;
\r
997 Check_ChapterMarkers.Enabled = false;
\r
1000 // Hack to force the redraw of the scrollbars which don't resize properly when the control is disabled.
\r
1001 data_chpt.Columns[0].Width = 166;
\r
1002 data_chpt.Columns[0].Width = 165;
\r
1004 RegisterPresetEventHandler();
\r
1006 private void chapersChanged(object sender, EventArgs e)
\r
1008 if (drop_mode.SelectedIndex != 0) // Function is not used if we are not in chapters mode.
\r
1011 Control ctl = (Control)sender;
\r
1012 int chapterStart, chapterEnd;
\r
1013 int.TryParse(drop_chapterStart.Text, out chapterStart);
\r
1014 int.TryParse(drop_chapterFinish.Text, out chapterEnd);
\r
1018 case "drop_chapterStart":
\r
1019 if (drop_chapterFinish.SelectedIndex == -1 && drop_chapterFinish.Items.Count != 0)
\r
1020 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1022 if (chapterEnd != 0)
\r
1023 if (chapterStart > chapterEnd)
\r
1024 drop_chapterFinish.Text = chapterStart.ToString();
\r
1026 case "drop_chapterFinish":
\r
1027 if (drop_chapterStart.Items.Count >= 1 && drop_chapterStart.SelectedIndex == -1)
\r
1028 drop_chapterStart.SelectedIndex = 0;
\r
1030 if (chapterStart != 0)
\r
1031 if (chapterEnd < chapterStart)
\r
1032 drop_chapterFinish.Text = chapterStart.ToString();
\r
1034 // Add more rows to the Chapter menu if needed.
\r
1035 if (Check_ChapterMarkers.Checked)
\r
1037 int i = data_chpt.Rows.Count, finish = 0;
\r
1038 int.TryParse(drop_chapterFinish.Text, out finish);
\r
1040 while (i < finish)
\r
1042 int n = data_chpt.Rows.Add();
\r
1043 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
1044 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
1045 data_chpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
1046 data_chpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
1053 // Update the Duration
\r
1054 lbl_duration.Text = Main.CalculateDuration(drop_chapterStart.SelectedIndex, drop_chapterFinish.SelectedIndex, selectedTitle).ToString();
\r
1056 // Run the Autonaming function
\r
1057 if (Properties.Settings.Default.autoNaming)
\r
1058 text_destination.Text = Main.AutoName(this);
\r
1060 // Disable chapter markers if only 1 chapter is selected.
\r
1061 if (chapterStart == chapterEnd)
\r
1063 Check_ChapterMarkers.Enabled = false;
\r
1064 btn_importChapters.Enabled = false;
\r
1065 data_chpt.Enabled = false;
\r
1069 Check_ChapterMarkers.Enabled = true;
\r
1070 if (Check_ChapterMarkers.Checked)
\r
1072 btn_importChapters.Enabled = true;
\r
1073 data_chpt.Enabled = true;
\r
1077 private void SecondsOrFramesChanged(object sender, EventArgs e)
\r
1080 int.TryParse(drop_chapterStart.Text, out start);
\r
1081 int.TryParse(drop_chapterFinish.Text, out end);
\r
1082 double duration = end - start;
\r
1084 switch (drop_mode.SelectedIndex)
\r
1087 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1090 if (selectedTitle != null)
\r
1092 duration = duration / selectedTitle.Fps;
\r
1093 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1096 lbl_duration.Text = "--:--:--";
\r
1101 private void drop_mode_SelectedIndexChanged(object sender, EventArgs e)
\r
1104 this.drop_chapterFinish.TextChanged -= new System.EventHandler(this.SecondsOrFramesChanged);
\r
1105 this.drop_chapterStart.TextChanged -= new System.EventHandler(this.SecondsOrFramesChanged);
\r
1108 switch (drop_mode.SelectedIndex)
\r
1111 drop_chapterStart.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1112 drop_chapterFinish.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1113 if (drop_chapterStart.Items.Count != 0)
\r
1115 drop_chapterStart.SelectedIndex = 0;
\r
1116 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1119 lbl_duration.Text = "--:--:--";
\r
1122 this.drop_chapterStart.TextChanged += new System.EventHandler(this.SecondsOrFramesChanged);
\r
1123 this.drop_chapterFinish.TextChanged += new System.EventHandler(this.SecondsOrFramesChanged);
\r
1124 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1125 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1126 if (selectedTitle != null)
\r
1128 drop_chapterStart.Text = "0";
\r
1129 drop_chapterFinish.Text = selectedTitle.Duration.TotalSeconds.ToString();
\r
1133 this.drop_chapterStart.TextChanged += new System.EventHandler(this.SecondsOrFramesChanged);
\r
1134 this.drop_chapterFinish.TextChanged += new System.EventHandler(this.SecondsOrFramesChanged);
\r
1135 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1136 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1137 if (selectedTitle != null)
\r
1139 drop_chapterStart.Text = "0";
\r
1140 drop_chapterFinish.Text = (selectedTitle.Fps * selectedTitle.Duration.TotalSeconds).ToString();
\r
1147 private void btn_destBrowse_Click(object sender, EventArgs e)
\r
1149 // This removes the file extension from the filename box on the save file dialog.
\r
1150 // It's daft but some users don't realise that typing an extension overrides the dropdown extension selected.
\r
1151 DVD_Save.FileName = Path.GetFileNameWithoutExtension(text_destination.Text);
\r
1153 if (Path.IsPathRooted(text_destination.Text))
\r
1154 DVD_Save.InitialDirectory = Path.GetDirectoryName(text_destination.Text);
\r
1156 // Show the dialog and set the main form file path
\r
1157 if (drop_format.SelectedIndex.Equals(0))
\r
1158 DVD_Save.FilterIndex = 1;
\r
1159 else if (drop_format.SelectedIndex.Equals(1))
\r
1160 DVD_Save.FilterIndex = 2;
\r
1162 if (DVD_Save.ShowDialog() == DialogResult.OK)
\r
1164 // Add a file extension manually, as FileDialog.AddExtension has issues with dots in filenames
\r
1165 switch (DVD_Save.FilterIndex)
\r
1168 if (!Path.GetExtension(DVD_Save.FileName).Equals(".mp4", StringComparison.InvariantCultureIgnoreCase))
\r
1169 if (Properties.Settings.Default.useM4v)
\r
1170 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".m4v").Replace(".mkv", ".m4v");
\r
1172 DVD_Save.FileName = DVD_Save.FileName.Replace(".m4v", ".mp4").Replace(".mkv", ".mp4");
\r
1175 if (!Path.GetExtension(DVD_Save.FileName).Equals(".mkv", StringComparison.InvariantCultureIgnoreCase))
\r
1176 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".mkv").Replace(".m4v", ".mkv");
\r
1182 text_destination.Text = DVD_Save.FileName;
\r
1184 // Quicktime requires .m4v file for chapter markers to work. If checked, change the extension to .m4v (mp4 and m4v are the same thing)
\r
1185 if (Check_ChapterMarkers.Checked && DVD_Save.FilterIndex != 2)
\r
1186 SetExtension(".m4v");
\r
1189 private void text_destination_TextChanged(object sender, EventArgs e)
\r
1191 string path = text_destination.Text;
\r
1192 if (path.EndsWith(".mp4") || path.EndsWith(".m4v"))
\r
1193 drop_format.SelectedIndex = 0;
\r
1194 else if (path.EndsWith(".mkv"))
\r
1195 drop_format.SelectedIndex = 1;
\r
1198 // Output Settings
\r
1199 private void drop_format_SelectedIndexChanged(object sender, EventArgs e)
\r
1201 switch (drop_format.SelectedIndex)
\r
1204 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked || AudioSettings.RequiresM4V() || Subtitles.RequiresM4V())
\r
1205 SetExtension(".m4v");
\r
1207 SetExtension(".mp4");
\r
1210 SetExtension(".mkv");
\r
1214 AudioSettings.SetContainer(drop_format.Text);
\r
1215 Subtitles.SetContainer(drop_format.SelectedIndex);
\r
1217 if (drop_format.Text.Contains("MP4"))
\r
1219 if (drp_videoEncoder.Items.Contains("VP3 (Theora)"))
\r
1221 drp_videoEncoder.Items.Remove("VP3 (Theora)");
\r
1222 drp_videoEncoder.SelectedIndex = 1;
\r
1225 else if (drop_format.Text.Contains("MKV"))
\r
1226 drp_videoEncoder.Items.Add("VP3 (Theora)");
\r
1228 public void SetExtension(string newExtension)
\r
1230 if (newExtension == ".mp4" || newExtension == ".m4v")
\r
1231 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked || AudioSettings.RequiresM4V() || Subtitles.RequiresM4V())
\r
1232 newExtension = ".m4v";
\r
1234 newExtension = ".mp4";
\r
1236 if (Path.HasExtension(newExtension))
\r
1237 text_destination.Text = Path.ChangeExtension(text_destination.Text, newExtension);
\r
1241 private void drp_videoEncoder_SelectedIndexChanged(object sender, EventArgs e)
\r
1243 setContainerOpts();
\r
1245 //Turn off some options which are H.264 only when the user selects a non h.264 encoder
\r
1246 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1248 if (check_2PassEncode.CheckState == CheckState.Checked)
\r
1249 check_turbo.Enabled = true;
\r
1251 tab_advanced.Enabled = true;
\r
1252 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1253 check_iPodAtom.Enabled = true;
\r
1255 check_iPodAtom.Enabled = false;
\r
1259 check_turbo.CheckState = CheckState.Unchecked;
\r
1260 check_turbo.Enabled = false;
\r
1261 tab_advanced.Enabled = false;
\r
1262 x264Panel.x264Query = "";
\r
1263 check_iPodAtom.Enabled = false;
\r
1264 check_iPodAtom.Checked = false;
\r
1267 // Setup the CQ Slider
\r
1268 switch (drp_videoEncoder.Text)
\r
1270 case "MPEG-4 (FFmpeg)":
\r
1271 if (slider_videoQuality.Value > 31)
\r
1272 slider_videoQuality.Value = 20; // Just reset to 70% QP 10 on encode change.
\r
1273 slider_videoQuality.Minimum = 1;
\r
1274 slider_videoQuality.Maximum = 31;
\r
1276 case "H.264 (x264)":
\r
1277 slider_videoQuality.Minimum = 0;
\r
1278 slider_videoQuality.TickFrequency = 1;
\r
1280 CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
\r
1281 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1282 double multiplier = 1.0 / cqStep;
\r
1283 double value = slider_videoQuality.Value * multiplier;
\r
1285 switch (Properties.Settings.Default.x264cqstep.ToString(culture))
\r
1288 slider_videoQuality.Maximum = 255;
\r
1291 slider_videoQuality.Maximum = 204;
\r
1294 slider_videoQuality.Maximum = 102;
\r
1297 slider_videoQuality.Maximum = 51;
\r
1300 slider_videoQuality.Maximum = 51;
\r
1303 if (value < slider_videoQuality.Maximum)
\r
1304 slider_videoQuality.Value = slider_videoQuality.Maximum - (int)value;
\r
1307 case "VP3 (Theora)":
\r
1308 if (slider_videoQuality.Value > 63)
\r
1309 slider_videoQuality.Value = 45; // Just reset to 70% QP 45 on encode change.
\r
1310 slider_videoQuality.Minimum = 0;
\r
1311 slider_videoQuality.Maximum = 63;
\r
1316 /// Set the container format options
\r
1318 public void setContainerOpts()
\r
1320 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1322 check_largeFile.Enabled = true;
\r
1323 check_optimiseMP4.Enabled = true;
\r
1324 check_iPodAtom.Enabled = true;
\r
1328 check_largeFile.Enabled = false;
\r
1329 check_optimiseMP4.Enabled = false;
\r
1330 check_iPodAtom.Enabled = false;
\r
1331 check_largeFile.Checked = false;
\r
1332 check_optimiseMP4.Checked = false;
\r
1333 check_iPodAtom.Checked = false;
\r
1336 private double _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1338 /// Update the CQ slider for x264 for a new CQ step. This is set from option
\r
1340 public void setQualityFromSlider()
\r
1342 // Work out the current RF value.
\r
1343 double cqStep = _cachedCqStep;
\r
1344 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1346 // Change the maximum value for the slider
\r
1347 switch (Properties.Settings.Default.x264cqstep.ToString(new CultureInfo("en-US")))
\r
1350 slider_videoQuality.Maximum = 255;
\r
1353 slider_videoQuality.Maximum = 204;
\r
1356 slider_videoQuality.Maximum = 102;
\r
1359 slider_videoQuality.Maximum = 51;
\r
1362 slider_videoQuality.Maximum = 51;
\r
1366 // Reset the CQ slider to RF0
\r
1367 slider_videoQuality.Value = slider_videoQuality.Maximum;
\r
1369 // Reset the CQ slider back to the previous value as close as possible
\r
1370 double cqStepNew = Properties.Settings.Default.x264cqstep;
\r
1371 double rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1372 while (rfValueCurrent < rfValue)
\r
1374 slider_videoQuality.Value--;
\r
1375 rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1378 // Cache the CQ step for the next calculation
\r
1379 _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1381 private void slider_videoQuality_Scroll(object sender, EventArgs e)
\r
1383 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1384 switch (drp_videoEncoder.Text)
\r
1386 case "MPEG-4 (FFmpeg)":
\r
1387 double rfValue = 31 - (slider_videoQuality.Value - 1);
\r
1388 double max = slider_videoQuality.Maximum;
\r
1389 double min = slider_videoQuality.Minimum;
\r
1390 double val = ((max - min) - (rfValue - min)) / (max - min);
\r
1391 lbl_SliderValue.Text = "QP:" + (32 - slider_videoQuality.Value);
\r
1392 lbl_qualityValue.Text = Math.Round((val * 100), 2).ToString(new CultureInfo("en-US")) + "%";
\r
1394 case "H.264 (x264)":
\r
1395 rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1396 max = slider_videoQuality.Maximum * cqStep;
\r
1397 min = slider_videoQuality.Minimum;
\r
1398 val = ((max - min) - (rfValue - min)) / (max - min);
\r
1399 rfValue = Math.Round(rfValue, 2);
\r
1400 lbl_SliderValue.Text = "RF:" + rfValue.ToString(new CultureInfo("en-US"));
\r
1401 lbl_qualityValue.Text = Math.Round((val * 100), 2).ToString(new CultureInfo("en-US")) + "%";
\r
1403 case "VP3 (Theora)":
\r
1404 rfValue = slider_videoQuality.Value;
\r
1405 double value = rfValue / 63;
\r
1406 lbl_SliderValue.Text = "QP:" + slider_videoQuality.Value;
\r
1407 lbl_qualityValue.Text = Math.Round((value * 100), 2).ToString(new CultureInfo("en-US")) + "%";
\r
1411 private void radio_targetFilesize_CheckedChanged(object sender, EventArgs e)
\r
1413 text_bitrate.Enabled = false;
\r
1414 text_filesize.Enabled = true;
\r
1415 slider_videoQuality.Enabled = false;
\r
1417 check_2PassEncode.Enabled = true;
\r
1419 private void radio_avgBitrate_CheckedChanged(object sender, EventArgs e)
\r
1421 text_bitrate.Enabled = true;
\r
1422 text_filesize.Enabled = false;
\r
1423 slider_videoQuality.Enabled = false;
\r
1425 check_2PassEncode.Enabled = true;
\r
1427 private void radio_cq_CheckedChanged(object sender, EventArgs e)
\r
1429 text_bitrate.Enabled = false;
\r
1430 text_filesize.Enabled = false;
\r
1431 slider_videoQuality.Enabled = true;
\r
1433 check_2PassEncode.Enabled = false;
\r
1434 check_2PassEncode.CheckState = CheckState.Unchecked;
\r
1436 private void check_2PassEncode_CheckedChanged(object sender, EventArgs e)
\r
1438 if (check_2PassEncode.CheckState.ToString() == "Checked")
\r
1440 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1441 check_turbo.Enabled = true;
\r
1445 check_turbo.Enabled = false;
\r
1446 check_turbo.CheckState = CheckState.Unchecked;
\r
1450 // Chapter Marker Tab
\r
1451 private void Check_ChapterMarkers_CheckedChanged(object sender, EventArgs e)
\r
1453 if (Check_ChapterMarkers.Checked)
\r
1455 if (drop_format.SelectedIndex != 1)
\r
1456 SetExtension(".m4v");
\r
1457 data_chpt.Enabled = true;
\r
1458 btn_importChapters.Enabled = true;
\r
1462 if (drop_format.SelectedIndex != 1 && !Properties.Settings.Default.useM4v)
\r
1463 SetExtension(".mp4");
\r
1464 data_chpt.Enabled = false;
\r
1465 btn_importChapters.Enabled = false;
\r
1468 private void btn_importChapters_Click(object sender, EventArgs e)
\r
1470 if (File_ChapterImport.ShowDialog() == DialogResult.OK)
\r
1472 String filename = File_ChapterImport.FileName;
\r
1473 DataGridView imported = Main.ImportChapterNames(data_chpt, filename);
\r
1474 if (imported != null)
\r
1475 data_chpt = imported;
\r
1478 private void mnu_resetChapters_Click(object sender, EventArgs e)
\r
1480 data_chpt.Rows.Clear();
\r
1481 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1482 if (chapterGridView != null)
\r
1484 data_chpt = chapterGridView;
\r
1488 // Query Editor Tab
\r
1489 private void btn_generate_Query_Click(object sender, EventArgs e)
\r
1491 rtf_query.Text = queryGen.GenerateCLIQuery(this, drop_mode.SelectedIndex, 0, null);
\r
1493 private void btn_clear_Click(object sender, EventArgs e)
\r
1495 rtf_query.Clear();
\r
1499 // MainWindow Components, Actions and Functions ***********************
\r
1501 #region Source Scan
\r
1502 public Boolean isScanning { get; set; }
\r
1503 private Scan SourceScan;
\r
1505 private void StartScan(String filename, int title)
\r
1507 // Setup the GUI components for the scan.
\r
1508 sourcePath = filename;
\r
1509 foreach (Control ctrl in Controls)
\r
1510 if (!(ctrl is StatusStrip || ctrl is MenuStrip || ctrl is ToolStrip))
\r
1511 ctrl.Enabled = false;
\r
1513 lbl_encode.Visible = true;
\r
1514 lbl_encode.Text = "Scanning ...";
\r
1515 btn_source.Enabled = false;
\r
1516 btn_start.Enabled = false;
\r
1517 btn_showQueue.Enabled = false;
\r
1518 btn_add2Queue.Enabled = false;
\r
1519 tb_preview.Enabled = false;
\r
1520 mnu_killCLI.Visible = true;
\r
1522 if (ActivityWindow != null)
\r
1523 ActivityWindow.SetScanMode();
\r
1528 isScanning = true;
\r
1529 SourceScan = new Scan();
\r
1530 SourceScan.ScanSource(sourcePath, title);
\r
1531 SourceScan.ScanStatusChanged += new EventHandler(SourceScan_ScanStatusChanged);
\r
1532 SourceScan.ScanCompleted += new EventHandler(SourceScan_ScanCompleted);
\r
1534 catch (Exception exc)
\r
1536 MessageBox.Show("frmMain.cs - StartScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1540 void SourceScan_ScanStatusChanged(object sender, EventArgs e)
\r
1542 UpdateScanStatusLabel();
\r
1544 void SourceScan_ScanCompleted(object sender, EventArgs e)
\r
1546 UpdateGuiAfterScan();
\r
1549 private void UpdateScanStatusLabel()
\r
1551 if (InvokeRequired)
\r
1553 BeginInvoke(new UpdateWindowHandler(UpdateScanStatusLabel));
\r
1556 lbl_encode.Text = SourceScan.ScanStatus();
\r
1558 private void UpdateGuiAfterScan()
\r
1560 if (InvokeRequired)
\r
1562 BeginInvoke(new UpdateWindowHandler(UpdateGuiAfterScan));
\r
1568 currentSource = SourceScan.SouceData();
\r
1570 // Setup some GUI components
\r
1571 drp_dvdtitle.Items.Clear();
\r
1572 if (currentSource.Titles.Count != 0)
\r
1573 drp_dvdtitle.Items.AddRange(currentSource.Titles.ToArray());
\r
1575 // Now select the longest title
\r
1576 if (currentSource.Titles.Count != 0)
\r
1577 drp_dvdtitle.SelectedItem = Main.SelectLongestTitle(currentSource);
\r
1579 // Enable the creation of chapter markers if the file is an image of a dvd.
\r
1580 if (sourcePath.ToLower().Contains(".iso") || sourcePath.Contains("VIDEO_TS") || Directory.Exists(Path.Combine(sourcePath, "VIDEO_TS")))
\r
1581 Check_ChapterMarkers.Enabled = true;
\r
1584 Check_ChapterMarkers.Enabled = false;
\r
1585 Check_ChapterMarkers.Checked = false;
\r
1586 data_chpt.Rows.Clear();
\r
1589 // If no titles were found, Display an error message
\r
1590 if (drp_dvdtitle.Items.Count == 0)
\r
1593 "No Title(s) found. \n\nYour Source may be copy protected, badly mastered or in a format which HandBrake does not support. \nPlease refer to the Documentation and FAQ (see Help Menu).",
\r
1594 "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
\r
1595 sourcePath = string.Empty;
\r
1597 UpdateSourceLabel();
\r
1599 // Enable the GUI components and enable any disabled components
\r
1602 catch (Exception exc)
\r
1604 MessageBox.Show("frmMain.cs - updateUIafterScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1609 private void EnableGUI()
\r
1613 if (InvokeRequired)
\r
1614 BeginInvoke(new UpdateWindowHandler(EnableGUI));
\r
1615 lbl_encode.Text = "Scan Completed";
\r
1616 foreach (Control ctrl in Controls)
\r
1617 ctrl.Enabled = true;
\r
1618 btn_start.Enabled = true;
\r
1619 btn_showQueue.Enabled = true;
\r
1620 btn_add2Queue.Enabled = true;
\r
1621 tb_preview.Enabled = true;
\r
1622 btn_source.Enabled = true;
\r
1623 mnu_killCLI.Visible = false;
\r
1625 catch (Exception exc)
\r
1627 MessageBox.Show("frmMain.cs - EnableGUI() " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1630 private void KillScan()
\r
1634 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
1638 if (SourceScan.ScanProcess() != null)
\r
1639 SourceScan.ScanProcess().Kill();
\r
1641 lbl_encode.Text = "Scan Cancelled!";
\r
1643 catch (Exception ex)
\r
1645 MessageBox.Show("Unable to kill HandBrakeCLI.exe \nYou may need to manually kill HandBrakeCLI.exe using the Windows Task Manager if it does not close automatically within the next few minutes. \n\nError Information: \n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1648 private void ResetGUI()
\r
1650 drp_dvdtitle.Items.Clear();
\r
1651 drop_chapterStart.Items.Clear();
\r
1652 drop_chapterFinish.Items.Clear();
\r
1653 lbl_duration.Text = "Select a Title";
\r
1654 PictureSettings.lbl_src_res.Text = "Select a Title";
\r
1655 PictureSettings.lbl_Aspect.Text = "Select a Title";
\r
1656 sourcePath = String.Empty;
\r
1657 text_destination.Text = String.Empty;
\r
1658 selectedTitle = null;
\r
1659 isScanning = false;
\r
1661 private void UpdateSourceLabel()
\r
1663 labelSource.Text = string.IsNullOrEmpty(sourcePath) ? "Select \"Source\" to continue." : this.SourceName;
\r
1665 if (selectedTitle != null)
\r
1666 if (!string.IsNullOrEmpty(selectedTitle.SourceName)) // If it's one of multiple source files, make sure we don't use the folder name
\r
1667 labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1673 /// Set the GUI to it's finished encoding state.
\r
1675 private void setEncodeFinished()
\r
1679 if (InvokeRequired)
\r
1681 BeginInvoke(new UpdateWindowHandler(setEncodeFinished));
\r
1685 lbl_encode.Text = "Encoding Finished";
\r
1686 btn_start.Text = "Start";
\r
1687 btn_start.ToolTipText = "Start the encoding process";
\r
1688 btn_start.Image = Properties.Resources.Play;
\r
1690 // If the window is minimized, display the notification in a popup.
\r
1691 if (Properties.Settings.Default.trayIconAlerts)
\r
1692 if (FormWindowState.Minimized == this.WindowState)
\r
1694 notifyIcon.BalloonTipText = lbl_encode.Text;
\r
1695 notifyIcon.ShowBalloonTip(500);
\r
1698 catch (Exception exc)
\r
1700 MessageBox.Show(exc.ToString());
\r
1705 /// Set the GUI to it's started encoding state.
\r
1707 private void setEncodeStarted()
\r
1711 if (InvokeRequired)
\r
1713 BeginInvoke(new UpdateWindowHandler(setEncodeStarted));
\r
1717 lbl_encode.Visible = true;
\r
1718 lbl_encode.Text = "Encoding with " + encodeQueue.Count + " encode(s) pending";
\r
1719 btn_start.Text = "Stop";
\r
1720 btn_start.ToolTipText = "Stop the encoding process.";
\r
1721 btn_start.Image = Properties.Resources.stop;
\r
1723 catch (Exception exc)
\r
1725 MessageBox.Show(exc.ToString());
\r
1730 #region DVD Drive Detection
\r
1731 private void getDriveInfoThread()
\r
1735 if (InvokeRequired)
\r
1737 BeginInvoke(new UpdateWindowHandler(getDriveInfoThread));
\r
1741 Boolean foundDrive = false;
\r
1742 DriveInfo[] theCollectionOfDrives = DriveInfo.GetDrives();
\r
1743 foreach (DriveInfo curDrive in theCollectionOfDrives)
\r
1745 if (curDrive.DriveType == DriveType.CDRom && curDrive.IsReady)
\r
1747 if (File.Exists(curDrive.RootDirectory + "VIDEO_TS\\VIDEO_TS.IFO"))
\r
1749 this.dvdDrivePath = curDrive.RootDirectory + "VIDEO_TS";
\r
1750 this.dvdDriveLabel = curDrive.VolumeLabel;
\r
1751 mnu_dvd_drive.Text = this.dvdDrivePath + " (" + this.dvdDriveLabel + ")";
\r
1752 foundDrive = true;
\r
1758 if (foundDrive == false)
\r
1759 mnu_dvd_drive.Text = "[No DVD Drive Ready]";
\r
1763 mnu_dvd_drive.Text = "[No DVD Drive Ready / Found]";
\r
1768 #region Public Methods
\r
1770 /// Access the preset Handler and setup the preset panel.
\r
1772 public void loadPresetPanel()
\r
1774 if (presetHandler.CheckIfPresetsAreOutOfDate())
\r
1775 if (!Properties.Settings.Default.presetNotification)
\r
1776 MessageBox.Show(splash,
\r
1777 "HandBrake has determined your built-in presets are out of date... These presets will now be updated.",
\r
1778 "Preset Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
1780 presetHandler.GetPresetPanel(ref treeView_presets);
\r
1781 treeView_presets.Update();
\r
1787 /// If the queue is being processed, prompt the user to confirm application close.
\r
1789 /// <param name="e"></param>
\r
1790 protected override void OnFormClosing(FormClosingEventArgs e)
\r
1792 // If currently encoding, the queue isn't paused, and there are queue items to process, prompt to confirm close.
\r
1793 if ((encodeQueue.IsEncoding) && (!encodeQueue.PauseRequested) && (encodeQueue.Count > 0))
\r
1795 DialogResult result = MessageBox.Show("HandBrake has queue items to process. Closing HandBrake will not stop the current encoding, but will stop processing the queue.\n\nDo you want to close HandBrake?",
\r
1796 "Close HandBrake?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
1797 if (result == DialogResult.No)
\r
1800 base.OnFormClosing(e);
\r
1804 #region In-GUI Encode Status (Experimental)
\r
1805 private void encodeMonitorThread()
\r
1809 Parser encode = new Parser(encodeQueue.HbProcess.StandardOutput.BaseStream);
\r
1810 encode.OnEncodeProgress += encodeOnEncodeProgress;
\r
1811 while (!encode.EndOfStream)
\r
1812 encode.readEncodeStatus();
\r
1814 catch (Exception exc)
\r
1816 MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1819 private void encodeOnEncodeProgress(object Sender, int CurrentTask, int TaskCount, float PercentComplete, float CurrentFps, float AverageFps, TimeSpan TimeRemaining)
\r
1821 if (this.InvokeRequired)
\r
1823 this.BeginInvoke(new EncodeProgressEventHandler(encodeOnEncodeProgress),
\r
1824 new object[] { Sender, CurrentTask, TaskCount, PercentComplete, CurrentFps, AverageFps, TimeRemaining });
\r
1827 lbl_encode.Text = string.Format("Encode Progress: {0}%, FPS: {1}, Avg FPS: {2}, Time Remaining: {3} ", PercentComplete, CurrentFps, AverageFps, TimeRemaining);
\r
1832 private enum SourceType
\r
1841 public void RecievingJob(Job job)
\r
1843 string query = job.Query;
\r
1844 StartScan(job.Source, 0);
\r
1847 if (query != null)
\r
1849 //Ok, Reset all the H264 widgets before changing the preset
\r
1850 x264Panel.reset2Defaults();
\r
1852 // Send the query from the file to the Query Parser class
\r
1853 QueryParser presetQuery = QueryParser.Parse(query);
\r
1855 // Now load the preset
\r
1856 PresetLoader.presetLoader(this, presetQuery, "Load Back From Queue", true);
\r
1858 // The x264 widgets will need updated, so do this now:
\r
1859 x264Panel.X264_StandardizeOptString();
\r
1860 x264Panel.X264_SetCurrentSettingsInPanel();
\r
1862 // Finally, let this window have a copy of the preset settings.
\r
1863 CurrentlySelectedPreset = null;
\r
1864 PictureSettings.SetPresetCropWarningLabel(null);
\r
1869 // This is the END of the road ****************************************
\r