using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Handbrake.Parsing;
namespace Handbrake.Controls
{
public partial class PictureSettings : UserControl
{
private bool _preventChangingWidth, _preventChangingHeight;
private int _maxWidth, _maxHeight, _lastEncodeWidth, _lastEncodeHeight;
private double _anamorphicRatio, _displayRatio;
private Title _title;
private double storageAspect;
public event EventHandler PictureSettingsChanged;
public PictureSettings()
{
InitializeComponent();
drp_anamorphic.SelectedIndex = 1;
drp_modulus.SelectedIndex = 0;
}
///
/// Gets or sets the source media used by this control.
///
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Title Source
{
get { return _title; }
set
{
_title = value;
_displayRatio = ((double)_title.Resolution.Width * _title.ParVal.Width / _title.ParVal.Height) / _title.Resolution.Height;
Enabled = _title != null;
MaximumWidth = _title.Resolution.Width;
MaximumHeight = _title.Resolution.Height;
updownParWidth.Value = _title.ParVal.Width;
updownParHeight.Value = _title.ParVal.Height;
// Set the source resolution
lbl_src_res.Text = Source.Resolution.Width + " x " + Source.Resolution.Height;
// Set ratios
_anamorphicRatio = (double)Source.Resolution.Width / Source.Resolution.Height;
// Set the encode width and height
EncodeWidth = _title.Resolution.Width;
EncodeHeight = _title.Resolution.Height;
_lastEncodeWidth = _title.Resolution.Width;
_lastEncodeHeight = _title.Resolution.Height;
// Set cropping
CroppingValues = _title.AutoCropDimensions;
lbl_Aspect.Text = _title.AspectRatio.ToString();
UpdateAnamorphicValue();
}
}
///
/// Gets or sets the resolution of the displayed video.
///
public Size DisplayResolution { get; set; }
public int EncodeWidth { get { return (int)text_width.Value; } set { text_width.Value = value; } }
public int EncodeHeight { get { return (int)text_height.Value; } set { text_height.Value = value; } }
public int[] CroppingValues
{
get
{
return new int[4]
{
(int)crop_top.Value,
(int)crop_bottom.Value,
(int)crop_left.Value,
(int)crop_right.Value
};
}
set
{
if (value.Length != 4)
{
throw new ArgumentException("The cropping values given must have a length of 4.");
}
crop_top.Value = value[0];
crop_bottom.Value = value[1];
crop_left.Value = value[2];
crop_right.Value = value[3];
}
}
///
/// Gets or sets the maximum allowable width of the encoded video.
///
public int MaximumWidth
{
get { return _maxWidth; }
set
{
_maxWidth = value > 0 ? value : (Source != null ? Source.Resolution.Width : 2560);
}
}
///
/// Gets or sets the maximum allowable height of the encoded video.
///
public int MaximumHeight
{
get { return _maxHeight; }
set
{
_maxHeight = value > 0 ? value : (Source != null ? Source.Resolution.Height : 2560);
}
}
public void setMax()
{
}
///
/// Updates the anamorphic value shown as the display width.
///
private void UpdateAnamorphicValue()
{
if (_title == null || _title.ParVal.IsEmpty)
return;
// Set globally useful values
double width;
double par;
switch (drp_anamorphic.SelectedIndex)
{
case 2:
int actualWidth = (int)text_width.Value - (int)crop_left.Value - (int)crop_right.Value;
int source_display_width = Source.Resolution.Width * Source.ParVal.Width / Source.ParVal.Height;
int source_cropped_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;
par = ((double) text_height.Value*source_display_width/source_cropped_height)/actualWidth;
width = (actualWidth * par);
width = Math.Truncate(width);
break;
default:
{
if (drp_anamorphic.SelectedIndex == 1) // Strict
par = (double)Source.ParVal.Width / Source.ParVal.Height;
else // Custom
par = (double)updownParWidth.Value / (double)updownParHeight.Value;
// Store the latest DAR
double rawWidth = (double)text_width.Value * par;
_displayRatio = rawWidth / (double)text_height.Value;
width = (int)Math.Round(rawWidth);
break;
}
}
labelDisplaySize.Text = width + " x " + text_height.Value;
updownDisplayWidth.Value = (decimal)width;
updownParWidth.Value = (decimal)width;
updownParHeight.Value = text_width.Value;
}
///
/// Sets the visibility of the advanced anamorphic options.
///
/// Whether or not the options should be visible.
private void SetCustomAnamorphicOptionsVisible(bool visible)
{
lbl_modulus.Visible = visible;
lbl_displayWidth.Visible = visible;
lbl_parWidth.Visible = visible;
lbl_parHeight.Visible = visible;
drp_modulus.Visible = visible;
updownDisplayWidth.Visible = visible;
updownParWidth.Visible = visible;
updownParHeight.Visible = visible;
}
///
/// Gets the normalized value from one given by the user that is divisible by the number
/// set in .
///
/// The value to normalize
/// A number that is divisible by .
///
/// The way that some video codecs, such as x264, compress video is by creating "macroblocks"
/// that are seperated into defined squares, often 16x16 pixels. Because of this, if the width
/// and height of the encoded video are not each divisible by the modulus defined, video quality
/// will suffer. This method takes the supplied value and normalizes it to the nearest mutliple
/// of .
///
private int GetModulusValue(int value)
{
int mod = int.Parse(drp_modulus.SelectedItem.ToString());
int remainder = value % mod;
if (remainder == 0)
return value;
return remainder >= mod / 2 ? value + (mod - remainder) : value - remainder;
}
private void ApplyStrictAnamorphic()
{
if (_anamorphicRatio == 0)
return;
_preventChangingWidth = true;
_preventChangingHeight = true;
text_width.Value = _title.Resolution.Width;
text_height.Value = _title.Resolution.Height;
_preventChangingWidth = false;
_preventChangingHeight = false;
}
///
/// Loosely anamorphs encode width and height values.
///
private void ApplyLooseAnamorphic()
{
// Prevents DivideByZeroExceptions
if (_anamorphicRatio == 0)
return;
int actualWidth = (int)text_width.Value - (int)crop_left.Value - (int)crop_right.Value;
int source_cropped_height = Source.Resolution.Height - (int)crop_top.Value - (int)crop_bottom.Value;
if (storageAspect == 0)
storageAspect = (double)actualWidth / source_cropped_height;
double hcalc = (actualWidth / storageAspect) + 0.5;
double newHeight = GetModulusValue((int)hcalc);
text_width.Value = GetModulusValue((int)text_width.Value);
text_height.Value = (decimal)newHeight;
UpdateAnamorphicValue();
}
///
/// Anamorphs encode width and height based on the custom options specified.
///
private void ApplyCustomAnamorphic(Control ctrlUpdated)
{
// Make sure the PAR values are set correctly
if (updownParWidth.Value == 0)
updownParWidth.Value = Source.ParVal.Width;
if (updownParHeight.Value == 0)
updownParHeight.Value = Source.ParVal.Height;
// Set various values
int parWidth = (int)updownParWidth.Value;
int parHeight = (int)updownParHeight.Value;
if (!check_KeepAR.Checked)
{
switch (ctrlUpdated.Name)
{
case "text_width":
case "updownParWidth":
case "updownParHeight":
updownDisplayWidth.Value = Math.Round(text_width.Value * parWidth / parHeight);
break;
case "updownDisplayWidth":
updownParWidth.Value = updownDisplayWidth.Value;
updownParHeight.Value = text_width.Value;
break;
}
}
else
{
switch (ctrlUpdated.Name)
{
case "updownDisplayWidth":
_preventChangingHeight = true;
text_height.Value = GetModulusValue((int)((double)updownDisplayWidth.Value / _displayRatio));
_preventChangingHeight = false;
goto case "text_width";
case "text_height":
updownDisplayWidth.Value = GetModulusValue((int)((double)text_width.Value * _anamorphicRatio * _displayRatio));
goto case "text_width";
case "text_width":
updownParWidth.Value = updownDisplayWidth.Value;
updownParHeight.Value = text_width.Value;
break;
}
}
}
private void text_width_ValueChanged(object sender, EventArgs e)
{
if (_preventChangingWidth)
return;
_preventChangingWidth = true;
if (text_width.Value > MaximumWidth)
{
text_width.Value = MaximumWidth;
}
switch (drp_anamorphic.SelectedIndex)
{
case 0:
if (check_KeepAR.Checked)
{
_preventChangingHeight = true;
decimal newHeight = text_width.Value / (decimal)_anamorphicRatio;
text_height.Value = newHeight > MaximumHeight ? MaximumHeight : newHeight;
_preventChangingHeight = false;
}
break;
case 1:
ApplyStrictAnamorphic();
break;
case 2:
ApplyLooseAnamorphic();
break;
case 3:
ApplyCustomAnamorphic((Control)sender);
break;
}
_preventChangingWidth = false;
}
private void text_height_ValueChanged(object sender, EventArgs e)
{
if (_preventChangingHeight)
return;
_preventChangingHeight = true;
if (text_height.Value > MaximumHeight)
{
text_height.Value = MaximumHeight;
}
switch (drp_anamorphic.SelectedIndex)
{
case 0:
if (check_KeepAR.Checked)
{
_preventChangingWidth = true;
decimal newWidth = text_height.Value * (decimal)_anamorphicRatio;
text_width.Value = newWidth > MaximumWidth ? MaximumWidth : newWidth;
_preventChangingWidth = false;
}
break;
case 3:
ApplyCustomAnamorphic((Control)sender);
break;
}
_preventChangingHeight = false;
}
private void drp_anamorphic_SelectedIndexChanged(object sender, EventArgs e)
{
switch (drp_anamorphic.SelectedIndex)
{
case 0:
text_width.Enabled = true;
text_height.Enabled = true;
check_KeepAR.Enabled = true;
SetCustomAnamorphicOptionsVisible(false);
labelStaticDisplaySize.Visible = false;
labelDisplaySize.Visible = false;
check_KeepAR.Checked = true;
break;
case 1:
text_width.Enabled = false;
text_height.Enabled = false;
check_KeepAR.Enabled = false;
SetCustomAnamorphicOptionsVisible(false);
labelStaticDisplaySize.Visible = true;
labelDisplaySize.Visible = true;
check_KeepAR.Checked = true;
break;
case 2:
text_width.Enabled = true;
text_height.Enabled = false;
check_KeepAR.Enabled = false;
SetCustomAnamorphicOptionsVisible(false);
labelStaticDisplaySize.Visible = true;
labelDisplaySize.Visible = true;
check_KeepAR.Checked = true;
break;
case 3:
text_width.Enabled = true;
text_height.Enabled = true;
check_KeepAR.Enabled = true;
SetCustomAnamorphicOptionsVisible(true);
labelStaticDisplaySize.Visible = true;
labelDisplaySize.Visible = true;
check_KeepAR.Checked = true;
break;
}
UpdateAnamorphicValue();
}
private void check_KeepAR_CheckedChanged(object sender, EventArgs e)
{
if (drp_anamorphic.SelectedIndex != 3)
{
if (check_KeepAR.Checked)
{
text_width_ValueChanged(this, new EventArgs());
}
}
else
{
updownParWidth.Enabled = !check_KeepAR.Checked;
updownParHeight.Enabled = !check_KeepAR.Checked;
}
}
private void crop_ValueChanged(object sender, EventArgs e)
{
text_width_ValueChanged(this, new EventArgs());
}
private void check_autoCrop_CheckedChanged(object sender, EventArgs e)
{
crop_top.Enabled = check_customCrop.Checked;
crop_bottom.Enabled = check_customCrop.Checked;
crop_left.Enabled = check_customCrop.Checked;
crop_right.Enabled = check_customCrop.Checked;
}
private void drp_modulus_SelectedIndexChanged(object sender, EventArgs e)
{
text_width.Increment = int.Parse(drp_modulus.SelectedItem.ToString());
text_height.Increment = int.Parse(drp_modulus.SelectedItem.ToString());
}
}
}