// --------------------------------------------------------------------------------------------------------------------
//
// 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;
using System.Globalization;
using System.Linq;
using System.Windows;
using Caliburn.Micro;
using HandBrake.Interop.Interop;
using HandBrake.Interop.Interop.Interfaces.Model.Encoders;
using HandBrakeWPF.EventArgs;
using HandBrakeWPF.Properties;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Services.Presets.Model;
using HandBrakeWPF.Services.Scan.Model;
using HandBrakeWPF.Utilities;
using HandBrakeWPF.ViewModels.Interfaces;
using Clipboard = System.Windows.Clipboard;
using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask;
using FramerateMode = HandBrakeWPF.Services.Encode.Model.Models.FramerateMode;
using OutputFormat = HandBrakeWPF.Services.Encode.Model.Models.OutputFormat;
using SettingChangedEventArgs = HandBrakeWPF.EventArgs.SettingChangedEventArgs;
using VideoEncoder = HandBrakeWPF.Model.Video.VideoEncoder;
using VideoEncodeRateType = HandBrakeWPF.Model.Video.VideoEncodeRateType;
using VideoLevel = HandBrakeWPF.Services.Encode.Model.Models.Video.VideoLevel;
using VideoPreset = HandBrakeWPF.Services.Encode.Model.Models.Video.VideoPreset;
using VideoProfile = HandBrakeWPF.Services.Encode.Model.Models.Video.VideoProfile;
using VideoTune = HandBrakeWPF.Services.Encode.Model.Models.Video.VideoTune;
///
/// The Video View Model
///
public class VideoViewModel : ViewModelBase, IVideoViewModel
{
/*
* Hard Code "None" in the Models for Tune.
* Test Everything */
#region Constants and Fields
private const string SameAsSource = "Same as source";
private readonly IUserSettingService userSettingService;
private readonly IErrorService errorService;
private bool displayOptimiseOptions;
private int qualityMax;
private int qualityMin;
private bool showPeakFramerate;
private int rf;
private bool displayTurboFirstPass;
private int videoPresetMaxValue;
private int videoPresetValue;
private VideoTune videoTune;
private bool fastDecode;
private bool displayTuneControls;
private bool displayLevelControl;
private bool displayProfileControl;
private Dictionary encoderOptions = new Dictionary();
#endregion
#region Constructors and Destructors
///
/// Initializes a new instance of the class.
///
///
/// The user Setting Service.
///
public VideoViewModel(IUserSettingService userSettingService, IErrorService errorService)
{
this.Task = new EncodeTask { VideoEncoder = VideoEncoder.X264 };
this.userSettingService = userSettingService;
this.errorService = errorService;
this.QualityMin = 0;
this.QualityMax = 51;
this.IsConstantQuantity = true;
this.VideoEncoders = EnumHelper.GetEnumList();
this.VideoProfiles = new BindingList();
this.VideoTunes = new BindingList();
this.VideoPresets = new BindingList();
this.VideoLevels = new BindingList();
this.userSettingService.SettingChanged += this.UserSettingServiceSettingChanged;
}
#endregion
public event EventHandler TabStatusChanged;
#region Public Properties
public IUserSettingService UserSettingService => this.userSettingService;
///
/// Gets or sets the current Encode Task.
///
public EncodeTask Task { get; set; }
///
/// Gets Framerates.
///
public IEnumerable Framerates
{
get
{
List framerates = new List { "Same as source" };
framerates.AddRange(HandBrakeEncoderHelpers.VideoFramerates.Select(item => item.Name));
return framerates;
}
}
///
/// 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);
this.OnTabStatusChanged(null);
}
}
///
/// 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.TwoPass = false;
this.TurboFirstPass = false;
this.VideoBitrate = null;
this.NotifyOfPropertyChange(() => this.Task);
}
else
{
this.Task.VideoEncodeRateType = VideoEncodeRateType.AverageBitrate;
}
this.NotifyOfPropertyChange(() => this.IsConstantQuantity);
this.NotifyOfPropertyChange(() => this.IsTwoPassEnabled);
this.OnTabStatusChanged(null);
}
}
public bool IsTwoPassEnabled
{
get
{
if (this.IsConstantQuantity)
{
return false;
}
if (this.SelectedVideoEncoder == VideoEncoder.NvencH264
|| this.SelectedVideoEncoder == VideoEncoder.NvencH265
|| this.SelectedVideoEncoder == VideoEncoder.VceH264
|| this.SelectedVideoEncoder == VideoEncoder.VceH265
|| this.SelectedVideoEncoder == VideoEncoder.QuickSync
|| this.SelectedVideoEncoder == VideoEncoder.QuickSyncH265
|| this.SelectedVideoEncoder == VideoEncoder.QuickSyncH26510b)
{
return false;
}
return true;
}
}
///
/// 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);
this.OnTabStatusChanged(null);
}
}
///
/// 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);
this.OnTabStatusChanged(null);
}
}
///
/// Gets a value indicating whether is lossless.
///
public bool IsLossless
{
get
{
return 0.0.Equals(this.DisplayRF) && (this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10);
}
}
///
/// 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;
this.SetQualitySliderBounds();
switch (this.SelectedVideoEncoder)
{
case VideoEncoder.FFMpeg:
case VideoEncoder.FFMpeg2:
this.Task.Quality = (32 - value);
break;
case VideoEncoder.VP8:
case VideoEncoder.VP9:
this.Task.Quality = (63 - value);
break;
case VideoEncoder.X264:
case VideoEncoder.X264_10:
case VideoEncoder.X265:
case VideoEncoder.X265_10:
case VideoEncoder.X265_12:
double cqStep = userSettingService.GetUserSetting(UserSettingConstants.X264Step);
double rfValue = 51.0 - (value * cqStep);
rfValue = Math.Round(rfValue, 2);
this.Task.Quality = rfValue;
break;
case VideoEncoder.QuickSync:
case VideoEncoder.QuickSyncH265:
case VideoEncoder.VceH264:
case VideoEncoder.VceH265:
case VideoEncoder.NvencH264:
case VideoEncoder.NvencH265:
rfValue = 51.0 - value;
rfValue = Math.Round(rfValue, 0);
this.Task.Quality = rfValue;
break;
case VideoEncoder.QuickSyncH26510b:
rfValue = 63.0 - (value - 0);
rfValue = Math.Round(rfValue, 0);
this.Task.Quality = rfValue;
break;
case VideoEncoder.Theora:
Task.Quality = value;
break;
}
this.NotifyOfPropertyChange(() => this.RF);
this.NotifyOfPropertyChange(() => this.DisplayRF);
this.NotifyOfPropertyChange(() => this.IsLossless);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets the Video Bitrate.
///
public int? VideoBitrate
{
get
{
return this.Task.VideoBitrate;
}
set
{
if (value == this.Task.VideoBitrate)
{
return;
}
this.Task.VideoBitrate = value;
this.NotifyOfPropertyChange(() => this.VideoBitrate);
this.OnTabStatusChanged(null);
}
}
///
/// Gets DisplayRF.
///
public double DisplayRF
{
get
{
return Task.Quality.HasValue ? this.Task.Quality.Value : 0;
}
}
///
/// Gets or sets a value indicating whether two pass.
///
public bool TwoPass
{
get
{
return this.Task.TwoPass;
}
set
{
this.Task.TwoPass = value;
this.NotifyOfPropertyChange(() => this.TwoPass);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets a value indicating whether turbo first pass.
///
public bool TurboFirstPass
{
get
{
return this.Task.TurboFirstPass;
}
set
{
this.Task.TurboFirstPass = value;
this.NotifyOfPropertyChange(() => this.TurboFirstPass);
this.OnTabStatusChanged(null);
}
}
///
/// Gets the rfqp.
///
public string Rfqp
{
get
{
if (this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10
|| this.SelectedVideoEncoder == VideoEncoder.X265
|| this.SelectedVideoEncoder == VideoEncoder.X265_10
|| this.SelectedVideoEncoder == VideoEncoder.X265_12)
{
return "RF";
}
if (this.SelectedVideoEncoder == VideoEncoder.NvencH264
|| this.SelectedVideoEncoder == VideoEncoder.NvencH265)
{
return string.Empty;
}
return "QP";
}
}
///
/// Gets the high quality label.
///
public string HighQualityLabel
{
get
{
return this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10 ? Resources.Video_PlaceboQuality : Resources.Video_HigherQuality;
}
}
///
/// Gets or sets SelectedFramerate.
///
public string SelectedFramerate
{
get
{
if (this.Task.Framerate == null)
{
return "Same as source";
}
return this.Task.Framerate.Value.ToString(CultureInfo.InvariantCulture);
}
set
{
if (value == "Same as source" || value == null)
{
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, CultureInfo.InvariantCulture);
}
this.NotifyOfPropertyChange(() => this.SelectedFramerate);
this.NotifyOfPropertyChange(() => this.Task);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets SelectedVideoEncoder.
///
public VideoEncoder SelectedVideoEncoder
{
get
{
return this.Task.VideoEncoder;
}
set
{
if (!object.Equals(value, this.Task.VideoEncoder))
{
// Cache the current extra args. We can set them back later if the user switches back
this.encoderOptions[EnumHelper.GetShortName(this.Task.VideoEncoder)] = this.ExtraArguments;
this.Task.VideoEncoder = value;
this.NotifyOfPropertyChange(() => this.SelectedVideoEncoder);
this.HandleEncoderChange(this.Task.VideoEncoder);
this.HandleRFChange();
this.OnTabStatusChanged(null);
}
}
}
///
/// 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; }
///
/// Gets or sets the extra arguments.
///
public string ExtraArguments
{
get
{
return this.Task.ExtraAdvancedArguments;
}
set
{
if (!Equals(this.Task.ExtraAdvancedArguments, value))
{
this.Task.ExtraAdvancedArguments = value;
this.NotifyOfPropertyChange(() => this.ExtraArguments);
this.NotifyOfPropertyChange(() => FullOptionsTooltip);
this.OnTabStatusChanged(null);
}
}
}
///
/// Gets or sets a value indicating whether to display H264
///
public bool DisplayOptimiseOptions
{
get
{
return this.displayOptimiseOptions;
}
set
{
this.displayOptimiseOptions = value;
this.NotifyOfPropertyChange(() => this.DisplayOptimiseOptions);
this.NotifyOfPropertyChange(() => FullOptionsTooltip);
}
}
///
/// Gets or sets a value indicating whether display non qsv controls.
///
public bool DisplayTwoPass
{
get
{
return this.SelectedVideoEncoder != VideoEncoder.QuickSync
&& this.SelectedVideoEncoder != VideoEncoder.QuickSyncH265
&& this.SelectedVideoEncoder != VideoEncoder.QuickSyncH26510b
&& this.SelectedVideoEncoder != VideoEncoder.NvencH264
&& this.SelectedVideoEncoder != VideoEncoder.NvencH265;
}
}
///
/// Gets or sets a value indicating whether display tune controls.
///
public bool DisplayTuneControls
{
get
{
return this.displayTuneControls;
}
set
{
if (value.Equals(this.displayTuneControls))
{
return;
}
this.displayTuneControls = value;
this.NotifyOfPropertyChange(() => this.DisplayTuneControls);
}
}
public bool DisplayFastDecode { get; set; }
///
/// Gets or sets a value indicating whether display level control.
///
public bool DisplayLevelControl
{
get
{
return this.displayLevelControl;
}
set
{
if (value.Equals(this.displayLevelControl))
{
return;
}
this.displayLevelControl = value;
this.NotifyOfPropertyChange(() => this.DisplayLevelControl);
}
}
///
/// Gets or sets a value indicating whether the profile control is displayed.
///
public bool DisplayProfileControl
{
get
{
return this.displayProfileControl;
}
set
{
if (value.Equals(this.displayProfileControl))
{
return;
}
this.displayProfileControl = value;
this.NotifyOfPropertyChange(() => this.DisplayProfileControl);
}
}
///
/// Gets or sets a value indicating whether fast decode.
///
public bool FastDecode
{
get
{
return this.Task.VideoTunes.Contains(VideoTune.FastDecode);
}
set
{
this.fastDecode = value;
// Update the encode task
if (value && !this.Task.VideoTunes.Contains(VideoTune.FastDecode))
{
this.Task.VideoTunes.Add(VideoTune.FastDecode);
}
else
{
this.Task.VideoTunes.Remove(VideoTune.FastDecode);
}
this.NotifyOfPropertyChange(() => this.FastDecode);
this.NotifyOfPropertyChange(() => this.FullOptionsTooltip);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets the video preset.
///
public VideoPreset VideoPreset
{
get
{
return this.Task.VideoPreset;
}
set
{
this.Task.VideoPreset = value;
this.NotifyOfPropertyChange(() => this.VideoPreset);
this.NotifyOfPropertyChange(() => this.FullOptionsTooltip);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets the video preset value.
///
public int VideoPresetValue
{
get
{
return this.videoPresetValue;
}
set
{
this.videoPresetValue = value;
HBVideoEncoder encoder = HandBrakeEncoderHelpers.VideoEncoders.FirstOrDefault(s => s.ShortName == EnumHelper.GetShortName(this.SelectedVideoEncoder));
if (encoder != null)
{
string preset = value >= 0 ? encoder.Presets[value] : null;
this.VideoPreset = preset != null ? new VideoPreset(preset, preset) : this.VideoPresets.FirstOrDefault();
}
this.NotifyOfPropertyChange(() => this.VideoPresetValue);
}
}
///
/// Gets or sets the video preset max value.
///
public int VideoPresetMaxValue
{
get
{
return this.videoPresetMaxValue;
}
set
{
if (value == this.videoPresetMaxValue)
{
return;
}
this.videoPresetMaxValue = value;
this.NotifyOfPropertyChange(() => this.VideoPresetMaxValue);
}
}
///
/// Gets or sets the video tune.
///
public VideoTune VideoTune
{
get
{
return this.videoTune;
}
set
{
if (Equals(value, this.videoTune))
{
return;
}
this.videoTune = value;
// Update the encode task.
bool hasFastDecode = this.Task.VideoTunes.Contains(VideoTune.FastDecode);
this.Task.VideoTunes.Clear();
if (value != null && !Equals(value, VideoTune.None))
{
this.Task.VideoTunes.Add(value);
}
if ((this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10) && hasFastDecode)
{
this.Task.VideoTunes.Add(VideoTune.FastDecode);
}
this.NotifyOfPropertyChange(() => this.VideoTune);
this.NotifyOfPropertyChange(() => this.FullOptionsTooltip);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets the video profile.
///
public VideoProfile VideoProfile
{
get
{
return this.Task.VideoProfile;
}
set
{
this.Task.VideoProfile = value;
this.NotifyOfPropertyChange(() => this.VideoProfile);
this.NotifyOfPropertyChange(() => this.FullOptionsTooltip);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets the video level.
///
public VideoLevel VideoLevel
{
get
{
return this.Task.VideoLevel;
}
set
{
this.Task.VideoLevel = value;
this.NotifyOfPropertyChange(() => this.VideoLevel);
this.NotifyOfPropertyChange(() => this.FullOptionsTooltip);
this.OnTabStatusChanged(null);
}
}
///
/// Gets or sets the video presets.
///
public BindingList VideoPresets { get; set; }
///
/// Gets or sets the video tunes.
///
public BindingList VideoTunes { get; set; }
///
/// Gets or sets the video profiles.
///
public BindingList VideoProfiles { get; set; }
///
/// Gets or sets the video levels.
///
public BindingList VideoLevels { get; set; }
///
/// Gets the full options tooltip.
///
public string FullOptionsTooltip
{
get
{
return this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10 ? string.Format(Resources.Video_EncoderExtraArgs, this.GetActualx264Query()) : Resources.Video_EncoderExtraArgsTooltip;
}
}
///
/// Gets or sets a value indicating whether display turbo first pass.
///
public bool DisplayTurboFirstPass
{
get
{
return this.displayTurboFirstPass;
}
set
{
if (value.Equals(this.displayTurboFirstPass))
{
return;
}
this.displayTurboFirstPass = value;
this.NotifyOfPropertyChange(() => this.DisplayTurboFirstPass);
}
}
#endregion
#region Public Methods
///
/// Setup this window for a new source
///
///
/// The source.
///
///
/// The title.
///
///
/// The preset.
///
///
/// The task.
///
public void SetSource(Source source, 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;
this.SelectedFramerate = preset.Task.Framerate.HasValue ? preset.Task.Framerate.Value.ToString(CultureInfo.InvariantCulture) : SameAsSource;
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;
}
this.TwoPass = preset.Task.TwoPass;
this.TurboFirstPass = preset.Task.TurboFirstPass;
this.VideoBitrate = preset.Task.VideoEncodeRateType == VideoEncodeRateType.AverageBitrate ? preset.Task.VideoBitrate : null;
this.NotifyOfPropertyChange(() => this.Task);
this.HandleEncoderChange(preset.Task.VideoEncoder);
this.SetQualitySliderBounds();
this.SetRF(preset.Task.Quality);
HBVideoEncoder encoder = HandBrakeEncoderHelpers.VideoEncoders.FirstOrDefault(s => s.ShortName == EnumHelper.GetShortName(preset.Task.VideoEncoder));
if (encoder != null)
{
if (preset.Task.VideoEncoder == VideoEncoder.X264 || preset.Task.VideoEncoder == VideoEncoder.X264_10
|| preset.Task.VideoEncoder == VideoEncoder.X265 || preset.Task.VideoEncoder == VideoEncoder.X265_10 || preset.Task.VideoEncoder == VideoEncoder.X265_12
|| preset.Task.VideoEncoder == VideoEncoder.QuickSync || preset.Task.VideoEncoder == VideoEncoder.QuickSyncH265 || preset.Task.VideoEncoder == VideoEncoder.QuickSyncH26510b
|| preset.Task.VideoEncoder == VideoEncoder.VceH264 || preset.Task.VideoEncoder == VideoEncoder.VceH265
|| preset.Task.VideoEncoder == VideoEncoder.NvencH264 || preset.Task.VideoEncoder == VideoEncoder.NvencH265)
{
this.VideoLevel = preset.Task.VideoLevel != null ? preset.Task.VideoLevel.Clone() : this.VideoLevels.FirstOrDefault();
this.VideoProfile = preset.Task.VideoProfile != null ? preset.Task.VideoProfile.Clone() : this.VideoProfiles.FirstOrDefault();
this.VideoPresetValue = preset.Task.VideoPreset != null ? this.VideoPresets.IndexOf(preset.Task.VideoPreset) : 0;
if (preset.Task.VideoEncoder == VideoEncoder.X265 || preset.Task.VideoEncoder == VideoEncoder.X265_10 || preset.Task.VideoEncoder == VideoEncoder.X265_12)
{
this.FastDecode = false;
this.VideoTune = (preset.Task.VideoTunes != null && preset.Task.VideoTunes.Any() ? preset.Task.VideoTunes.FirstOrDefault() : this.VideoTunes.FirstOrDefault()) ?? VideoTune.None;
}
else
{
this.FastDecode = preset.Task.VideoTunes != null && preset.Task.VideoTunes.Contains(VideoTune.FastDecode);
this.VideoTune = (preset.Task.VideoTunes != null && preset.Task.VideoTunes.Any() ? preset.Task.VideoTunes.FirstOrDefault(t => !Equals(t, VideoTune.FastDecode)) : this.VideoTunes.FirstOrDefault())
?? VideoTune.None;
}
}
}
this.ExtraArguments = preset.Task.ExtraAdvancedArguments;
}
///
/// Update all the UI controls based on the encode task passed in.
///
///
/// The task.
///
public void UpdateTask(EncodeTask task)
{
this.Task = task;
this.SetQualitySliderBounds();
this.SetRF(task.Quality);
this.ShowPeakFramerate = this.IsPeakFramerate;
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.QualityMax);
this.NotifyOfPropertyChange(() => this.QualityMin);
this.NotifyOfPropertyChange(() => this.RF);
this.NotifyOfPropertyChange(() => this.DisplayRF);
this.NotifyOfPropertyChange(() => this.IsLossless);
this.NotifyOfPropertyChange(() => this.VideoBitrate);
this.NotifyOfPropertyChange(() => this.Task.Quality);
this.NotifyOfPropertyChange(() => this.Task.TwoPass);
this.NotifyOfPropertyChange(() => this.Task.TurboFirstPass);
this.NotifyOfPropertyChange(() => this.VideoTune);
this.NotifyOfPropertyChange(() => this.VideoProfile);
this.NotifyOfPropertyChange(() => this.VideoPreset);
this.NotifyOfPropertyChange(() => this.VideoLevel);
this.NotifyOfPropertyChange(() => this.FastDecode);
this.NotifyOfPropertyChange(() => this.ExtraArguments);
this.VideoTune = (task.VideoTunes != null && task.VideoTunes.Any() ? task.VideoTunes.FirstOrDefault(t => !Equals(t, VideoTune.FastDecode)) : this.VideoTunes.FirstOrDefault())
?? VideoTune.None;
HBVideoEncoder encoder = HandBrakeEncoderHelpers.VideoEncoders.FirstOrDefault(s => s.ShortName == EnumHelper.GetShortName(this.SelectedVideoEncoder));
if (encoder != null && this.VideoPreset != null)
{
int index = encoder.Presets.IndexOf(this.VideoPreset.ShortName);
this.VideoPresetValue = index;
}
}
public bool MatchesPreset(Preset preset)
{
if (preset.Task.VideoEncoder != this.Task.VideoEncoder)
{
return false;
}
if (preset.Task.Framerate != this.Task.Framerate)
{
return false;
}
if (preset.Task.FramerateMode != this.Task.FramerateMode)
{
return false;
}
if (preset.Task.VideoEncodeRateType != this.Task.VideoEncodeRateType)
{
return false;
}
if (preset.Task.VideoEncodeRateType == VideoEncodeRateType.AverageBitrate)
{
if (preset.Task.VideoBitrate != this.Task.VideoBitrate)
{
return false;
}
if (preset.Task.TwoPass != this.Task.TwoPass)
{
return false;
}
if (preset.Task.TurboFirstPass != this.Task.TurboFirstPass)
{
return false;
}
}
else
{
if (preset.Task.Quality != this.Task.Quality)
{
return false;
}
}
if (this.Task.VideoEncoder == VideoEncoder.X264 || this.Task.VideoEncoder == VideoEncoder.X264_10
|| this.Task.VideoEncoder == VideoEncoder.X265 || this.Task.VideoEncoder == VideoEncoder.X265_10
|| this.Task.VideoEncoder == VideoEncoder.X265_12 || this.Task.VideoEncoder == VideoEncoder.QuickSync
|| this.Task.VideoEncoder == VideoEncoder.QuickSyncH265 || this.Task.VideoEncoder == VideoEncoder.QuickSyncH26510b
|| this.Task.VideoEncoder == VideoEncoder.VceH264 || this.Task.VideoEncoder == VideoEncoder.VceH265
|| this.Task.VideoEncoder == VideoEncoder.NvencH264 || this.Task.VideoEncoder == VideoEncoder.NvencH265)
{
if (!Equals(preset.Task.VideoPreset, this.Task.VideoPreset))
{
return false;
}
foreach (VideoTune taskVideoTune in preset.Task.VideoTunes)
{
if (!this.Task.VideoTunes.Contains(taskVideoTune))
{
return false;
}
}
foreach (VideoTune tune in preset.Task.VideoTunes)
{
if (!this.Task.VideoTunes.Contains(tune))
{
return false;
}
}
if (preset.Task.VideoTunes.Count != this.Task.VideoTunes.Count)
{
return false;
}
if (!Equals(preset.Task.VideoProfile, this.Task.VideoProfile))
{
return false;
}
if (!Equals(preset.Task.VideoLevel, this.Task.VideoLevel))
{
return false;
}
}
if (!Equals(preset.Task.ExtraAdvancedArguments, this.Task.ExtraAdvancedArguments))
{
return false;
}
return true;
}
///
/// Trigger a Notify Property Changed on the Task to force various UI elements to update.
///
public void RefreshTask()
{
this.NotifyOfPropertyChange(() => this.Task);
VideoEncoder[] allowableWebmEncoders = { VideoEncoder.VP8, VideoEncoder.VP9 };
if ((Task.OutputFormat == OutputFormat.Mp4) && (this.SelectedVideoEncoder == VideoEncoder.Theora || allowableWebmEncoders.Contains(this.SelectedVideoEncoder)))
{
this.SelectedVideoEncoder = VideoEncoder.X264;
}
if ((Task.OutputFormat == OutputFormat.WebM) && !allowableWebmEncoders.Contains(this.SelectedVideoEncoder))
{
this.SelectedVideoEncoder = VideoEncoder.VP8;
}
}
///
/// The copy query.
///
public void CopyQuery()
{
Clipboard.SetDataObject(this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10 ? this.GetActualx264Query() : this.ExtraArguments);
}
#endregion
protected virtual void OnTabStatusChanged(TabStatusEventArgs e)
{
this.TabStatusChanged?.Invoke(this, e);
}
///
/// 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.QuickSync:
case VideoEncoder.QuickSyncH265:
case VideoEncoder.VceH264:
case VideoEncoder.VceH265:
case VideoEncoder.NvencH264:
case VideoEncoder.NvencH265:
this.QualityMin = 0;
this.QualityMax = 51;
break;
case VideoEncoder.QuickSyncH26510b:
this.QualityMin = 0;
this.QualityMax = 63;
break;
case VideoEncoder.X264:
case VideoEncoder.X264_10:
case VideoEncoder.X265:
case VideoEncoder.X265_10:
case VideoEncoder.X265_12:
this.QualityMin = 0;
this.QualityMax = (int)(51 / userSettingService.GetUserSetting(UserSettingConstants.X264Step));
break;
case VideoEncoder.Theora:
case VideoEncoder.VP8:
case VideoEncoder.VP9:
this.QualityMin = 0;
this.QualityMax = 63;
break;
}
}
///
/// The get actualx 264 query.
///
///
/// The .
///
private string GetActualx264Query()
{
VideoEncoder encoder = this.SelectedVideoEncoder;
if (encoder != VideoEncoder.X264 && encoder != VideoEncoder.X264_10)
{
return string.Empty;
}
HBVideoEncoder hbEncoder = HandBrakeEncoderHelpers.VideoEncoders.FirstOrDefault(s => s.ShortName == EnumHelper.GetShortName(encoder));
if (hbEncoder == null || !hbEncoder.Presets.Contains(this.VideoPreset?.ShortName))
{
return string.Empty;
}
string preset = this.VideoPreset != null ? this.VideoPreset.ShortName : string.Empty;
string profile = this.VideoProfile != null ? this.VideoProfile.ShortName : string.Empty;
List tunes = new List();
if (this.VideoTune != null && this.VideoTune.ShortName != "none")
{
tunes.Add(this.VideoTune.ShortName);
}
if (this.FastDecode)
{
tunes.Add("fastdecode");
}
// Get the width or height, default if we don't have it yet so we don't crash.
int width = this.Task.Width.HasValue ? this.Task.Width.Value : 720;
int height = this.Task.Height.HasValue ? this.Task.Height.Value : 576;
if (height == 0)
{
height = 576;
}
if (width == 0)
{
width = 720;
}
try
{
return HandBrakeUtils.CreateX264OptionsString(
preset,
tunes,
this.ExtraArguments,
profile,
this.VideoLevel != null ? this.VideoLevel.ShortName : string.Empty,
width,
height);
}
catch (Exception)
{
return "Error: Libhb not loaded.";
}
}
///
/// The user setting service_ setting changed.
///
///
/// The sender.
///
///
/// The e.
///
private void UserSettingServiceSettingChanged(object sender, SettingChangedEventArgs e)
{
if (e.Key == UserSettingConstants.EnableVceEncoder || e.Key == UserSettingConstants.EnableNvencEncoder || e.Key == UserSettingConstants.EnableQuickSyncEncoding)
{
this.NotifyOfPropertyChange(() => this.VideoEncoders);
}
}
///
/// The set rf.
///
///
/// The quality.
///
private void SetRF(double? quality)
{
double cqStep = this.userSettingService.GetUserSetting(UserSettingConstants.X264Step);
double rfValue = 0;
switch (this.SelectedVideoEncoder)
{
case VideoEncoder.FFMpeg:
case VideoEncoder.FFMpeg2:
if (quality.HasValue)
{
int cq;
int.TryParse(quality.Value.ToString(CultureInfo.InvariantCulture), out cq);
this.RF = 32 - cq;
}
break;
case VideoEncoder.VP8:
case VideoEncoder.VP9:
if (quality.HasValue)
{
int cq;
int.TryParse(quality.Value.ToString(CultureInfo.InvariantCulture), out cq);
this.RF = 63 - cq;
}
break;
case VideoEncoder.X265:
case VideoEncoder.X265_10:
case VideoEncoder.X265_12:
case VideoEncoder.X264:
case VideoEncoder.X264_10:
case VideoEncoder.QuickSync:
case VideoEncoder.QuickSyncH265:
case VideoEncoder.QuickSyncH26510b:
case VideoEncoder.VceH264:
case VideoEncoder.VceH265:
case VideoEncoder.NvencH264:
case VideoEncoder.NvencH265:
if (this.SelectedVideoEncoder == VideoEncoder.QuickSync || this.SelectedVideoEncoder == VideoEncoder.QuickSyncH265 || this.SelectedVideoEncoder == VideoEncoder.QuickSyncH26510b
|| this.SelectedVideoEncoder == VideoEncoder.VceH264 || this.SelectedVideoEncoder == VideoEncoder.VceH265
|| this.SelectedVideoEncoder == VideoEncoder.NvencH264 || this.SelectedVideoEncoder == VideoEncoder.NvencH265)
{
cqStep = 1;
}
double multiplier = 1.0 / cqStep;
if (quality.HasValue)
{
rfValue = quality.Value * multiplier;
}
this.RF = this.QualityMax - (int)Math.Round(rfValue, 0);
break;
case VideoEncoder.Theora:
if (quality.HasValue)
{
this.RF = (int)quality.Value;
}
break;
}
}
///
/// The handle encoder change.
///
///
/// The selected encoder.
///
private void HandleEncoderChange(VideoEncoder selectedEncoder)
{
HBVideoEncoder encoder = HandBrakeEncoderHelpers.VideoEncoders.FirstOrDefault(s => s.ShortName == EnumHelper.GetShortName(selectedEncoder));
if (encoder != null)
{
// Setup Profile
this.VideoProfiles.Clear();
if (encoder.Profiles != null)
{
foreach (var item in encoder.Profiles)
{
this.VideoProfiles.Add(new VideoProfile(item, item));
}
this.VideoProfile = this.VideoProfiles.FirstOrDefault();
}
else
{
this.VideoProfile = null;
}
// Setup Tune
this.VideoTunes.Clear();
if (encoder.Tunes != null)
{
this.VideoTunes.Add(VideoTune.None);
foreach (var item in encoder.Tunes)
{
if (item == VideoTune.FastDecode.ShortName && (selectedEncoder == VideoEncoder.X264 || selectedEncoder == VideoEncoder.X264_10))
{
continue;
}
this.VideoTunes.Add(new VideoTune(item, item));
}
this.FastDecode = false;
this.VideoTune = VideoTune.None;
}
else
{
this.FastDecode = false;
this.VideoTune = VideoTune.None;
}
// Setup Levels
this.VideoLevels.Clear();
if (encoder.Levels != null)
{
foreach (var item in encoder.Levels)
{
this.VideoLevels.Add(new VideoLevel(item, item));
}
this.VideoLevel = this.VideoLevels.FirstOrDefault();
}
else
{
this.VideoLevel = VideoLevel.Auto;
}
// Setup Presets.
this.VideoPresets.Clear();
if (encoder.Presets != null)
{
foreach (var item in encoder.Presets)
{
this.VideoPresets.Add(new VideoPreset(item, item));
}
this.VideoPresetMaxValue = encoder.Presets.Count - 1;
this.VideoPresetValue = GetDefaultEncoderPreset(selectedEncoder);
}
else
{
this.VideoPreset = null;
}
}
// Update the Quality Slider. Make sure the bounds are up to date with the users settings.
this.SetQualitySliderBounds();
// Update control display
this.DisplayOptimiseOptions = this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10 ||
this.SelectedVideoEncoder == VideoEncoder.X265 || this.SelectedVideoEncoder == VideoEncoder.X265_10 || this.SelectedVideoEncoder == VideoEncoder.X265_12 ||
this.SelectedVideoEncoder == VideoEncoder.QuickSync || this.SelectedVideoEncoder == VideoEncoder.QuickSyncH265 || this.SelectedVideoEncoder == VideoEncoder.QuickSyncH26510b ||
this.SelectedVideoEncoder == VideoEncoder.VceH264 || this.SelectedVideoEncoder == VideoEncoder.VceH265 ||
this.SelectedVideoEncoder == VideoEncoder.NvencH264 || this.SelectedVideoEncoder == VideoEncoder.NvencH265 ||
this.SelectedVideoEncoder == VideoEncoder.VP8 || this.SelectedVideoEncoder == VideoEncoder.VP9;
this.DisplayTurboFirstPass = selectedEncoder == VideoEncoder.X264 || selectedEncoder == VideoEncoder.X264_10 ||
selectedEncoder == VideoEncoder.X265 || selectedEncoder == VideoEncoder.X265_10 || selectedEncoder == VideoEncoder.X265_12;
this.DisplayTuneControls = this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10 ||
this.SelectedVideoEncoder == VideoEncoder.X265 || this.SelectedVideoEncoder == VideoEncoder.X265_10 || this.SelectedVideoEncoder == VideoEncoder.X265_12;
this.DisplayLevelControl = this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10 ||
this.SelectedVideoEncoder == VideoEncoder.X265 || this.SelectedVideoEncoder == VideoEncoder.X265_10 || this.SelectedVideoEncoder == VideoEncoder.X265_12 ||
this.SelectedVideoEncoder == VideoEncoder.QuickSync || this.SelectedVideoEncoder == VideoEncoder.QuickSyncH265 || this.SelectedVideoEncoder == VideoEncoder.QuickSyncH26510b ||
this.SelectedVideoEncoder == VideoEncoder.VceH264 || this.SelectedVideoEncoder == VideoEncoder.VceH265 ||
this.SelectedVideoEncoder == VideoEncoder.NvencH264 || this.SelectedVideoEncoder == VideoEncoder.NvencH265;
this.DisplayFastDecode = this.SelectedVideoEncoder == VideoEncoder.X264 || this.SelectedVideoEncoder == VideoEncoder.X264_10;
this.NotifyOfPropertyChange(() => this.DisplayFastDecode);
if (!this.DisplayFastDecode)
{
this.FastDecode = false;
}
this.DisplayProfileControl = this.SelectedVideoEncoder == VideoEncoder.X264
|| this.SelectedVideoEncoder == VideoEncoder.X264_10
|| this.SelectedVideoEncoder == VideoEncoder.X265
|| this.SelectedVideoEncoder == VideoEncoder.X265_10
|| this.SelectedVideoEncoder == VideoEncoder.X265_12
|| this.SelectedVideoEncoder == VideoEncoder.QuickSync
|| this.SelectedVideoEncoder == VideoEncoder.QuickSyncH265
|| this.SelectedVideoEncoder == VideoEncoder.QuickSyncH26510b
|| this.SelectedVideoEncoder == VideoEncoder.VceH264
|| this.SelectedVideoEncoder == VideoEncoder.VceH265
|| this.SelectedVideoEncoder == VideoEncoder.NvencH264
|| this.SelectedVideoEncoder == VideoEncoder.NvencH265;
// Refresh Display
this.NotifyOfPropertyChange(() => this.Rfqp);
this.NotifyOfPropertyChange(() => this.HighQualityLabel);
this.NotifyOfPropertyChange(() => this.IsTwoPassEnabled);
this.NotifyOfPropertyChange(() => this.DisplayTwoPass);
// Handle some quicksync specific options.
if (selectedEncoder == VideoEncoder.QuickSync || selectedEncoder == VideoEncoder.QuickSyncH265 || selectedEncoder == VideoEncoder.QuickSyncH26510b)
{
this.TwoPass = false;
this.TurboFirstPass = false;
this.SelectedFramerate = null;
}
if (selectedEncoder == VideoEncoder.NvencH264 || selectedEncoder == VideoEncoder.NvencH265
|| selectedEncoder == VideoEncoder.VceH264
|| selectedEncoder == VideoEncoder.VceH265)
{
this.TwoPass = false;
this.TurboFirstPass = false;
}
// Cleanup Extra Arguments
// Load the cached arguments. Saves the user from resetting when switching encoders.
string result;
this.ExtraArguments = this.encoderOptions.TryGetValue(EnumHelper.GetShortName(selectedEncoder), out result) ? result : string.Empty;
}
private void HandleRFChange()
{
double displayRF = this.DisplayRF;
if (displayRF > this.QualityMax || displayRF < this.QualityMin)
{
displayRF = this.qualityMax / 2;
}
this.SetRF(displayRF);
}
private int GetDefaultEncoderPreset(VideoEncoder selectedEncoder)
{
int defaultPreset = (int)Math.Round((decimal)(this.VideoPresetMaxValue / 2), 0);
// Override for NVEnc
if (selectedEncoder == VideoEncoder.NvencH264 || selectedEncoder == VideoEncoder.NvencH265)
{
// TODO -> is the RTX good enough to default to a more balanced preset?
defaultPreset = this.VideoPresets.IndexOf(this.VideoPresets.FirstOrDefault(s => s.ShortName == "slow"));
}
// Override for QuickSync
if (selectedEncoder == VideoEncoder.QuickSyncH265 || selectedEncoder == VideoEncoder.QuickSyncH26510b)
{
if (HandBrake.Interop.Utilities.SystemInfo.QsvHardwareGeneration > 6)
{
defaultPreset = this.VideoPresets.IndexOf(this.VideoPresets.FirstOrDefault(s => s.ShortName == "speed")); // TGL
}
else
{
defaultPreset = this.VideoPresets.IndexOf(this.VideoPresets.FirstOrDefault(s => s.ShortName == "balanced")); // ICL and Earlier.
}
}
if (selectedEncoder == VideoEncoder.QuickSync)
{
// h264 encoder hasn't changed much in recent years, so stick to balanced.
defaultPreset = this.VideoPresets.IndexOf(this.VideoPresets.FirstOrDefault(s => s.ShortName == "balanced"));
}
// Override for VCE
if (selectedEncoder == VideoEncoder.VceH264 || selectedEncoder == VideoEncoder.VceH265)
{
// TODO Would be good to have VCE version detection.
defaultPreset = this.VideoPresets.IndexOf(this.VideoPresets.FirstOrDefault(s => s.ShortName == "balanced"));
}
return defaultPreset;
}
}
}