// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The Video View Model // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.ViewModels { using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Globalization; using Caliburn.Micro; using HandBrake.ApplicationServices; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Model.Encoding; using HandBrake.ApplicationServices.Parsing; using HandBrake.ApplicationServices.Services.Interfaces; using HandBrake.ApplicationServices.Utilities; using HandBrake.Interop.Model.Encoding; using HandBrake.Interop.Model.Encoding.x264; using HandBrakeWPF.ViewModels.Interfaces; /// /// The Video View Model /// [Export(typeof(IVideoViewModel))] public class VideoViewModel : ViewModelBase, IVideoViewModel { #region Constants and Fields /// /// Backing field for the user setting service. /// private IUserSettingService userSettingService; /// /// Backing field used to display / hide the x264 options /// private bool displayX264Options; /// /// The quality max. /// private int qualityMax; /// /// The quality min. /// private int qualityMin; /// /// The show peak framerate. /// private bool showPeakFramerate; /// /// The show peak framerate. /// private int rf; #endregion #region Constructors and Destructors /// /// Initializes a new instance of the class. /// /// /// The window manager. /// /// /// The user Setting Service. /// public VideoViewModel(IWindowManager windowManager, IUserSettingService userSettingService) { this.Task = new EncodeTask { VideoEncoder = VideoEncoder.X264 }; this.userSettingService = userSettingService; this.QualityMin = 0; this.QualityMax = 51; this.IsConstantQuantity = true; this.VideoEncoders = EnumHelper.GetEnumList(); //X264Presets = EnumHelper.GetEnumList(); //X264Profiles = EnumHelper.GetEnumList(); //X264Tunes = EnumHelper.GetEnumList(); } #endregion #region Public Properties /// /// Gets or sets the current Encode Task. /// public EncodeTask Task { get; set; } /// /// Gets Framerates. /// public IEnumerable Framerates { get { return new List { "Same as source", "5", "10", "12", "15", "23.976", "24", "25", "29.97", "30", "50", "59.94", "60" }; } } /// /// Gets or sets a value indicating whether IsConstantFramerate. /// public bool IsConstantFramerate { get { return this.Task.FramerateMode == FramerateMode.CFR; } set { if (value) { this.Task.FramerateMode = FramerateMode.CFR; this.IsVariableFramerate = false; this.IsPeakFramerate = false; } this.NotifyOfPropertyChange(() => this.IsConstantFramerate); } } /// /// Gets or sets a value indicating whether IsConstantQuantity. /// public bool IsConstantQuantity { get { return this.Task.VideoEncodeRateType == VideoEncodeRateType.ConstantQuality; } set { if (value) { this.Task.VideoEncodeRateType = VideoEncodeRateType.ConstantQuality; this.Task.TwoPass = false; this.Task.TurboFirstPass = false; this.Task.VideoBitrate = null; this.NotifyOfPropertyChange(() => this.Task); } else { this.Task.VideoEncodeRateType = VideoEncodeRateType.AverageBitrate; } this.NotifyOfPropertyChange(() => this.IsConstantQuantity); } } /// /// Gets or sets a value indicating whether IsPeakFramerate. /// public bool IsPeakFramerate { get { return this.Task.FramerateMode == FramerateMode.PFR; } set { if (value) { this.Task.FramerateMode = FramerateMode.PFR; this.IsVariableFramerate = false; this.IsConstantFramerate = false; } this.NotifyOfPropertyChange(() => this.IsPeakFramerate); } } /// /// Gets or sets a value indicating whether IsVariableFramerate. /// public bool IsVariableFramerate { get { return this.Task.FramerateMode == FramerateMode.VFR; } set { if (value) { this.IsPeakFramerate = false; this.IsConstantFramerate = false; this.Task.FramerateMode = FramerateMode.VFR; } this.NotifyOfPropertyChange(() => this.IsVariableFramerate); } } /// /// Gets or sets QualityMax. /// public int QualityMax { get { return this.qualityMax; } set { if (!qualityMax.Equals(value)) { this.qualityMax = value; this.NotifyOfPropertyChange(() => this.QualityMax); } } } /// /// Gets or sets QualityMin. /// public int QualityMin { get { return this.qualityMin; } set { if (!qualityMin.Equals(value)) { this.qualityMin = value; this.NotifyOfPropertyChange(() => this.QualityMin); } } } /// /// Gets or sets RF. /// public int RF { get { return rf; } set { this.rf = value; double cqStep = userSettingService.GetUserSetting(ASUserSettingConstants.X264Step); this.SetQualitySliderBounds(); switch (this.SelectedVideoEncoder) { case VideoEncoder.FFMpeg: case VideoEncoder.FFMpeg2: this.Task.Quality = (32 - value); break; case VideoEncoder.X264: double rfValue = 51.0 - value * cqStep; rfValue = Math.Round(rfValue, 2); this.Task.Quality = rfValue; // TODO: Lossless warning. break; case VideoEncoder.Theora: Task.Quality = value; break; } this.NotifyOfPropertyChange(() => this.RF); this.NotifyOfPropertyChange(() => this.DisplayRF); } } /// /// Gets DisplayRF. /// public double DisplayRF { get { return Task.Quality.HasValue ? this.Task.Quality.Value : 0; } } /// /// Gets or sets SelectedFramerate. /// public string SelectedFramerate { get { if (this.Task.Framerate == null) { return "Same as source"; } return this.Task.Framerate.ToString(); } set { if (value == "Same as source") { this.Task.Framerate = null; this.ShowPeakFramerate = false; if (this.Task.FramerateMode == FramerateMode.PFR) { this.IsVariableFramerate = true; } } else if (!string.IsNullOrEmpty(value)) { this.ShowPeakFramerate = true; if (this.Task.FramerateMode == FramerateMode.VFR) { this.IsPeakFramerate = true; } this.Task.Framerate = double.Parse(value); } this.NotifyOfPropertyChange(() => this.SelectedFramerate); this.NotifyOfPropertyChange(() => this.Task); } } /// /// Gets or sets SelectedVideoEncoder. /// public VideoEncoder SelectedVideoEncoder { get { return this.Task.VideoEncoder; } set { this.Task.VideoEncoder = value; this.NotifyOfPropertyChange(() => this.SelectedVideoEncoder); // Tell the Advanced Panel off the change IAdvancedViewModel advancedViewModel = IoC.Get(); advancedViewModel.SetEncoder(this.Task.VideoEncoder); // Update the Quality Slider. Make sure the bounds are up to date with the users settings. this.SetQualitySliderBounds(); } } /// /// Gets or sets a value indicating whether ShowPeakFramerate. /// public bool ShowPeakFramerate { get { return this.showPeakFramerate; } set { this.showPeakFramerate = value; this.NotifyOfPropertyChange(() => this.ShowPeakFramerate); } } /// /// Gets or sets VideoEncoders. /// public IEnumerable VideoEncoders { get; set; } #endregion #region Public Methods /// /// Setup this window for a new source /// /// /// The title. /// /// /// The preset. /// /// /// The task. /// public void SetSource(Title title, Preset preset, EncodeTask task) { this.Task = task; } /// /// Setup this tab for the specified preset. /// /// /// The preset. /// /// /// The task. /// public void SetPreset(Preset preset, EncodeTask task) { this.Task = task; if (preset == null || preset.Task == null) { return; } this.SelectedVideoEncoder = preset.Task.VideoEncoder; if (preset.Task.Framerate.HasValue) { this.SelectedFramerate = preset.Task.Framerate.Value.ToString(CultureInfo.InvariantCulture); } this.IsConstantQuantity = preset.Task.VideoEncodeRateType == VideoEncodeRateType.ConstantQuality; switch (preset.Task.FramerateMode) { case FramerateMode.CFR: this.IsConstantFramerate = true; break; case FramerateMode.VFR: this.IsVariableFramerate = true; this.ShowPeakFramerate = false; break; case FramerateMode.PFR: this.IsPeakFramerate = true; this.ShowPeakFramerate = true; break; } double cqStep = userSettingService.GetUserSetting(ASUserSettingConstants.X264Step); double rfValue = 0; this.SetQualitySliderBounds(); switch (this.SelectedVideoEncoder) { case VideoEncoder.FFMpeg: case VideoEncoder.FFMpeg2: int cq; if (preset.Task.Quality.HasValue) { int.TryParse(preset.Task.Quality.Value.ToString(CultureInfo.InvariantCulture), out cq); this.RF = 32 - cq; } break; case VideoEncoder.X264: double multiplier = 1.0 / cqStep; if (preset.Task.Quality.HasValue) { rfValue = preset.Task.Quality.Value * multiplier; } this.RF = this.QualityMax - (int)Math.Round(rfValue, 0); break; case VideoEncoder.Theora: if (preset.Task.Quality.HasValue) { this.RF = (int)preset.Task.Quality.Value; } break; } this.Task.TwoPass = preset.Task.TwoPass; this.Task.TurboFirstPass = preset.Task.TurboFirstPass; this.Task.VideoBitrate = preset.Task.VideoBitrate; this.NotifyOfPropertyChange(() => this.Task); //if (preset != null && preset.Task != null) //{ // this.Query = preset.Task.AdvancedEncoderOptions; // this.SetEncoder(preset.Task.VideoEncoder); // this.X264Preset = preset.Task.x264Preset; // this.X264Profile = preset.Task.x264Profile; // this.X264Tune = preset.Task.X264Tune; //} } /// /// Update all the UI controls based on the encode task passed in. /// /// /// The task. /// public void UpdateTask(EncodeTask task) { this.Task = task; this.NotifyOfPropertyChange(() => this.IsConstantFramerate); this.NotifyOfPropertyChange(() => this.IsConstantQuantity); this.NotifyOfPropertyChange(() => this.IsPeakFramerate); this.NotifyOfPropertyChange(() => this.IsVariableFramerate); this.NotifyOfPropertyChange(() => this.SelectedVideoEncoder); this.NotifyOfPropertyChange(() => this.SelectedFramerate); this.NotifyOfPropertyChange(() => this.RF); this.NotifyOfPropertyChange(() => this.DisplayRF); this.NotifyOfPropertyChange(() => this.Task.VideoBitrate); this.NotifyOfPropertyChange(() => this.Task.TwoPass); this.NotifyOfPropertyChange(() => this.Task.TurboFirstPass); } /// /// Set the currently selected encoder. /// /// /// The Video Encoder. /// public void SetEncoder(VideoEncoder encoder) { //this.DisplayX264Options = encoder == VideoEncoder.X264; } /// /// Trigger a Notify Property Changed on the Task to force various UI elements to update. /// public void RefreshTask() { this.NotifyOfPropertyChange(() => this.Task); if (Task.OutputFormat == OutputFormat.Mp4 && this.SelectedVideoEncoder == VideoEncoder.Theora) { this.SelectedVideoEncoder = VideoEncoder.X264; } } #endregion /// /// Set the bounds of the Constant Quality Slider /// private void SetQualitySliderBounds() { // Note Updating bounds to the same values won't trigger an update. // The properties are smart enough to not take in equal values. switch (this.SelectedVideoEncoder) { case VideoEncoder.FFMpeg: case VideoEncoder.FFMpeg2: this.QualityMin = 1; this.QualityMax = 31; break; case VideoEncoder.X264: this.QualityMin = 0; this.QualityMax = (int)(51 / userSettingService.GetUserSetting(ASUserSettingConstants.X264Step)); break; case VideoEncoder.Theora: this.QualityMin = 0; this.QualityMax = 63; break; } } #region Advanced ///// ///// Gets or sets State. ///// //public string Query //{ // get // { // return this.Task.AdvancedEncoderOptions; // } // set // { // this.Task.AdvancedEncoderOptions = value; // this.NotifyOfPropertyChange(() => this.Query); // } //} ///// ///// Gets or sets X264Preset. ///// //public x264Preset X264Preset //{ // get // { // return this.Task.x264Preset; // } // set // { // this.Task.x264Preset = value; // this.NotifyOfPropertyChange(() => this.X264Preset); // } //} ///// ///// Gets or sets X264Profile. ///// //public x264Profile X264Profile //{ // get // { // return this.Task.x264Profile; // } // set // { // this.Task.x264Profile = value; // this.NotifyOfPropertyChange(() => this.X264Profile); // } //} ///// ///// Gets or sets X264Tune. ///// //public x264Tune X264Tune //{ // get // { // return this.Task.X264Tune; // } // set // { // this.Task.X264Tune = value; // this.NotifyOfPropertyChange(() => this.X264Tune); // } //} ///// ///// Gets or sets X264Presets. ///// //public IEnumerable X264Presets { get; set; } ///// ///// Gets or sets X264Profiles. ///// //public IEnumerable X264Profiles { get; set; } ///// ///// Gets or sets X264Tunes. ///// //public IEnumerable X264Tunes { get; set; } ///// ///// Gets or sets a value indicating whether DisplayX264Options. ///// //public bool DisplayX264Options //{ // get // { // return this.displayX264Options; // } // set // { // this.displayX264Options = value; // this.NotifyOfPropertyChange(() => this.DisplayX264Options); // } //} #endregion } }