/* x264Panel.cs $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ namespace Handbrake.Controls { using System; using System.Globalization; using System.Windows.Forms; using HandBrake.ApplicationServices; using HandBrake.ApplicationServices.Services.Interfaces; /// /// The x264 Panel /// public partial class x264Panel : UserControl { /* * TODO This code was ported from the obj-c MacGUI code. It's really messy and could really do with being cleaned up * at some point. */ /// /// The User Setting Service. /// private readonly IUserSettingService UserSettingService = ServiceManager.UserSettingService; /// /// Initializes a new instance of the class. /// Initializes a new instance of the x264 panel user control /// public x264Panel() { InitializeComponent(); if (this.UserSettingService.GetUserSetting(UserSettingConstants.TooltipEnable)) ToolTip.Active = true; Reset2Defaults(); } /// /// Gets or sets the X264 query string /// public string X264Query { get { return rtf_x264Query.Text; } set { rtf_x264Query.Text = value; } } /// /// Reset all components to defaults and clears the x264 rtf box /// public void Reset2Defaults() { check_8x8DCT.CheckState = CheckState.Checked; check_Cabac.CheckState = CheckState.Checked; check_weightp.CheckState = CheckState.Checked; check_noDCTDecimate.CheckState = CheckState.Unchecked; combo_pyrmidalBFrames.SelectedIndex = 0; drop_analysis.SelectedIndex = 0; drop_bFrames.SelectedIndex = 0; drop_deblockAlpha.SelectedIndex = 0; drop_deblockBeta.SelectedIndex = 0; drop_directPrediction.SelectedIndex = 0; drop_MotionEstimationMethod.SelectedIndex = 0; drop_MotionEstimationRange.SelectedIndex = 0; drop_refFrames.SelectedIndex = 0; drop_subpixelMotionEstimation.SelectedIndex = 0; drop_trellis.SelectedIndex = 0; slider_psyrd.Value = 10; slider_psytrellis.Value = 0; drop_adaptBFrames.SelectedIndex = 0; slider_adaptiveQuantStrength.Value = slider_adaptiveQuantStrength.Maximum / 2; rtf_x264Query.Text = string.Empty; } #region Standardize Option String /// /// Iterate over every x264 option, standardize it, write the full string to the x264 rtf box /// public void StandardizeOptString() { /* Set widgets depending on the opt string in field */ string thisOpt; // The separated option such as "bframes=3" string optName; // The option name such as "bframes" string optValue; // The option value such as "3" string changedOptString = string.Empty; string[] currentOptsArray; /*First, we get an opt string to process */ string currentOptString = rtf_x264Query.Text; /*verify there is an opt string to process */ if (currentOptString.Contains("=")) { /*Put individual options into an array based on the ":" separator for processing, result is "="*/ currentOptsArray = currentOptString.Split(':'); /*iterate through the array and get and /// Take a single option and standardize it. Returns as a String /// Input: String. - Single X264 Option. Name only /// Output: String - Single X264 Option. Name only. Changed to standard format /// /// a string of x264 options to clean /// A string containing standardized x264 option names private static string StandardizeOptName(string cleanOptNameString) { string input = cleanOptNameString; /* Reference Frames */ if (input.Equals("ref") || input.Equals("frameref")) cleanOptNameString = "ref"; /*No Dict Decimate*/ if (input.Equals("no-dct-decimate") || input.Equals("no_dct_decimate") || input.Equals("nodct_decimate")) cleanOptNameString = "no-dct-decimate"; /*Subme*/ if (input.Equals("subme")) cleanOptNameString = "subq"; /*ME Range*/ if (input.Equals("me-range") || input.Equals("me_range")) cleanOptNameString = "merange"; /*B Pyramid*/ if (input.Equals("b_pyramid")) cleanOptNameString = "b-pyramid"; /*Direct Prediction*/ if (input.Equals("direct-pred") || input.Equals("direct_pred")) cleanOptNameString = "direct"; /*Deblocking*/ if (input.Equals("filter")) cleanOptNameString = "deblock"; /*Analysis*/ if (input.Equals("partitions")) cleanOptNameString = "analyse"; return cleanOptNameString; } #endregion /// /// Resets the GUI widgets to the contents of the option string. /// public void SetCurrentSettingsInPanel() { /* Set widgets depending on the opt string in field */ string thisOpt; // The separated option such as "bframes=3" string optName; // The option name such as "bframes" string optValue; // The option value such as "3" string[] currentOptsArray; // Set currentOptString to the contents of the text box. string currentOptString = rtf_x264Query.Text.Replace("\n", string.Empty); /*verify there is an opt string to process */ if (currentOptString.Contains("=")) { /*Put individual options into an array based on the ":" separator for processing, result is "="*/ currentOptsArray = currentOptString.Split(':'); /*iterate through the array and get and and /// This function will update the X264 Query when one of the GUI widgets changes. /// /// /// The sender. /// private void OnX264WidgetChange(string sender) { Animate(sender); string optNameToChange = sender; string currentOptString = rtf_x264Query.Text; /*First, we create a pattern to check for ":"optNameToChange"=" to modify the option if the name falls after the first character of the opt string (hence the ":") */ string checkOptNameToChange = ":" + optNameToChange + "="; string checkOptNameToChangeBegin = optNameToChange + "="; // IF the current H264 Option String Contains Multiple Items or Just 1 Item if ((currentOptString.Contains(checkOptNameToChange)) || (currentOptString.StartsWith(checkOptNameToChangeBegin))) HasOptions(currentOptString, optNameToChange); else // IF there is no options in the rich text box! HasNoOptions(optNameToChange); } /// /// Called when the current x264 option string contains multiple (or a single) item(s) in it seperated by : /// it updates the current option that the widget corrosponds to, if it is already in thes string. /// /// The Current Option String /// Name of the option to change private void HasOptions(string currentOptString, string optNameToChange) { string thisOpt; // The separated option such as "bframes=3" string optName; // The option name such as "bframes" string[] currentOptsArray; /* Create new empty opt string*/ string changedOptString = string.Empty; /*Put individual options into an array based on the ":" separator for processing, result is "="*/ currentOptsArray = currentOptString.Split(':'); /*iterate through the array and get and /// Add's an option to the x264 query string. /// Handles 2 cases. 1 Where rtf_x264Query.Text is empty, and one where there is an option with no value, /// e.g no-fast-pskip /// /// The Option Name to Change private void HasNoOptions(IEquatable optNameToChange) { string colon = string.Empty; if (rtf_x264Query.Text != string.Empty) colon = ":"; string query = rtf_x264Query.Text; if (optNameToChange.Equals("me")) { switch (drop_MotionEstimationMethod.SelectedIndex) { case 1: query = query + colon + "me=dia"; break; case 2: query = query + colon + "me=hex"; break; case 3: query = query + colon + "me=umh"; break; case 4: query = query + colon + "me=esa"; break; case 5: query = query + colon + "me=tesa"; break; default: break; } } else if (optNameToChange.Equals("direct")) { switch (drop_directPrediction.SelectedIndex) { case 1: query = query + colon + "direct=none"; break; case 2: query = query + colon + "direct=spatial"; break; case 3: query = query + colon + "direct=temporal"; break; case 4: query = query + colon + "direct=auto"; break; default: break; } } else if (optNameToChange.Equals("analyse")) { switch (drop_analysis.SelectedIndex) { case 1: query = query + colon + "analyse=none"; break; case 2: query = query + colon + "analyse=i4x4,i8x8"; break; case 3: query = query + colon + "analyse=all"; break; default: break; } } else if (optNameToChange.Equals("merange")) { int value = drop_MotionEstimationRange.SelectedIndex + 3; query = query + colon + "merange=" + value; } else if (optNameToChange.Equals("b-adapt")) { int value = drop_adaptBFrames.SelectedIndex - 1; query = query + colon + "b-adapt=" + value; } else if (optNameToChange.Equals("deblock")) { string da = drop_deblockAlpha.SelectedItem.ToString(); string db = drop_deblockBeta.Text; if (((da.Contains("Default")) && (db.Contains("Default"))) || ((da.Contains("0")) && (db.Contains("0")))) { drop_deblockBeta.SelectedItem = "Default (0)"; drop_deblockAlpha.SelectedItem = "Default (0)"; } else { if (db.Contains("Default")) db = "0"; if (da.Contains("Default")) da = "0"; query = query + colon + "deblock=" + da + "," + db; } } else if (optNameToChange.Equals("aq-strength")) { if (slider_adaptiveQuantStrength.Value == 10) query = string.Empty; else { double value = slider_adaptiveQuantStrength.Value * 0.1; string aqs = value.ToString("f1", CultureInfo.InvariantCulture); query += colon + "aq-strength=" + aqs; } } else if (optNameToChange.Equals("psy-rd")) { if (slider_psyrd.Value == 10 && slider_psytrellis.Value == 0) query += string.Empty; else { double psyrd = slider_psyrd.Value * 0.1; double psytre = slider_psytrellis.Value * 0.05; string rd = psyrd.ToString("f1", CultureInfo.InvariantCulture); string rt = psytre.ToString("f2", CultureInfo.InvariantCulture); query += colon + "psy-rd=" + rd + "," + rt; } } else if (optNameToChange.Equals("b-pyramid")) { switch (combo_pyrmidalBFrames.SelectedIndex) { case 0: break; case 1: query = query + colon + "b-pyramid=none"; break; case 2: query = query + colon + "b-pyramid=strict"; break; } } else if (optNameToChange.Equals("no-dct-decimate")) { if (check_noDCTDecimate.CheckState == CheckState.Checked) query = query + colon + "no-dct-decimate=1"; } else if (optNameToChange.Equals("8x8dct")) { if (check_8x8DCT.CheckState == CheckState.Unchecked) query = query + colon + "8x8dct=0"; } else if (optNameToChange.Equals("cabac")) { if (check_Cabac.CheckState != CheckState.Checked) query = query + colon + "cabac=0"; } else if (optNameToChange.Equals("weightp")) { if (check_weightp.CheckState == CheckState.Unchecked) query = query + colon + "weightp=0"; } else if (optNameToChange.Equals("ref")) { if (!drop_refFrames.SelectedItem.ToString().Contains("Default")) query = query + colon + "ref=" + drop_refFrames.SelectedItem; } else if (optNameToChange.Equals("bframes")) { string value = drop_bFrames.SelectedItem.ToString(); if (!drop_bFrames.SelectedItem.ToString().Contains("Default")) query = query + colon + "bframes=" + value; } else if (optNameToChange.Equals("subq")) { string value = drop_subpixelMotionEstimation.SelectedItem.ToString(); if (!drop_subpixelMotionEstimation.SelectedItem.ToString().Contains("Default")) { string[] val = value.Split(':'); query = query + colon + "subq=" + val[0]; } } else if (optNameToChange.Equals("trellis")) { switch (drop_trellis.SelectedIndex) { case 1: // Off query = query + colon + "trellis=0"; break; case 2: // Encode Only query = query + colon + "trellis=1"; break; case 3: // Always query = query + colon + "trellis=2"; break; default: break; } } rtf_x264Query.Text = query; } /// /// Shows and hides controls based on the values of other controls. /// /// The Sender private void Animate(string sender) { /* Lots of situations to cover. - B-frames (when 0 turn of b-frame specific stuff, when < 2 disable b-pyramid) - CABAC (when 0 turn off trellis and psy-trel - subme (if under 6, turn off psy-rd and psy-trel) - trellis (if 0, turn off psy-trel) */ switch (sender) { case "bframes": if (drop_bFrames.SelectedIndex == 1) { /* If the b-frame widget is at 1, the user has chosen not to use b-frames at all. So disable the options that can only be used when b-frames are enabled. */ combo_pyrmidalBFrames.Visible = false; lbl_prymidalBframes.Visible = false; drop_directPrediction.Visible = false; lbl_direct_prediction.Visible = false; combo_pyrmidalBFrames.SelectedIndex = 0; drop_directPrediction.SelectedIndex = 0; drop_adaptBFrames.Visible = false; lbl_adaptBFrames.Visible = false; drop_adaptBFrames.SelectedIndex = 0; } else if (drop_bFrames.SelectedIndex == 2) { /* Only 1 b-frame? Disable b-pyramid. */ combo_pyrmidalBFrames.Visible = false; lbl_prymidalBframes.Visible = false; combo_pyrmidalBFrames.SelectedIndex = 0; drop_directPrediction.Visible = true; lbl_direct_prediction.Visible = true; drop_adaptBFrames.Visible = true; lbl_adaptBFrames.Visible = true; } else { combo_pyrmidalBFrames.Visible = true; lbl_prymidalBframes.Visible = true; drop_directPrediction.Visible = true; lbl_direct_prediction.Visible = true; drop_adaptBFrames.Visible = true; lbl_adaptBFrames.Visible = true; } break; case "me": // Motion Estimation if (drop_MotionEstimationMethod.SelectedIndex < 3) { drop_MotionEstimationRange.Visible = false; lbl_merange.Visible = false; drop_MotionEstimationRange.SelectedIndex = 0; } else { drop_MotionEstimationRange.Visible = true; lbl_merange.Visible = true; } break; case "subq": // subme if (drop_subpixelMotionEstimation.SelectedIndex != 0 && drop_subpixelMotionEstimation.SelectedIndex < 7) { slider_psyrd.Visible = false; slider_psyrd.Value = 10; lbl_psyrd.Visible = false; slider_psytrellis.Visible = false; slider_psytrellis.Value = 0; lbl_psytrellis.Visible = false; } else { slider_psyrd.Visible = true; lbl_psyrd.Visible = true; if (drop_trellis.SelectedIndex >= 2 && slider_psytrellis.Visible == false) { slider_psytrellis.Visible = true; lbl_psytrellis.Visible = true; } } break; case "trellis": // subme if (drop_trellis.SelectedIndex > 0 && drop_trellis.SelectedIndex < 2) { slider_psytrellis.Visible = false; slider_psytrellis.Value = 0; lbl_psytrellis.Visible = false; } else { if ((drop_subpixelMotionEstimation.SelectedIndex == 0 || drop_subpixelMotionEstimation.SelectedIndex >= 7) && slider_psytrellis.Visible == false) { slider_psytrellis.Visible = true; lbl_psytrellis.Visible = true; } } break; } } /* UI Events */ private void widgetControlChanged(object sender, EventArgs e) { Control changedControlName = (Control) sender; string controlName = string.Empty; switch (changedControlName.Name.Trim()) { case "drop_refFrames": controlName = "ref"; break; case "drop_bFrames": controlName = "bframes"; break; case "drop_directPrediction": controlName = "direct"; break; case "check_weightp": controlName = "weightp"; break; case "combo_pyrmidalBFrames": controlName = "b-pyramid"; break; case "drop_MotionEstimationMethod": controlName = "me"; break; case "drop_MotionEstimationRange": controlName = "merange"; break; case "drop_subpixelMotionEstimation": controlName = "subq"; break; case "drop_analysis": controlName = "analyse"; break; case "check_8x8DCT": controlName = "8x8dct"; break; case "drop_deblockAlpha": controlName = "deblock"; break; case "drop_deblockBeta": controlName = "deblock"; break; case "drop_trellis": controlName = "trellis"; break; case "check_noDCTDecimate": controlName = "no-dct-decimate"; break; case "check_Cabac": controlName = "cabac"; break; case "slider_psyrd": controlName = "psy-rd"; break; case "slider_psytrellis": controlName = "psy-rd"; break; case "slider_adaptiveQuantStrength": controlName = "aq-strength"; break; case "drop_adaptBFrames": controlName = "b-adapt"; break; } OnX264WidgetChange(controlName); } private void rtf_x264Query_TextChanged(object sender, EventArgs e) { if (rtf_x264Query.Text.EndsWith("\n")) { string query = rtf_x264Query.Text.Replace("\n", string.Empty); Reset2Defaults(); rtf_x264Query.Text = query; this.StandardizeOptString(); this.SetCurrentSettingsInPanel(); if (rtf_x264Query.Text == string.Empty) Reset2Defaults(); } } private void btn_reset_Click(object sender, EventArgs e) { rtf_x264Query.Text = string.Empty; Reset2Defaults(); } } }