using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using csmic; namespace butterflow_ui { /// The butterflow options configuration. Contians all the options necessary to run butterflow and process a video. [Serializable] public class OptionsConfiguration : PropertyChangedAlerter { #region Members /// An interpreter used to ensure numeric input is correctly calculated. private InputInterpreter interpreter = new InputInterpreter(); /// The aspect ratio used for calculating heights when the aspect ratio is locked. private decimal aspectRatio = 0; private string playbackRate; private bool keepAudio; private int width; private int height; private bool keepAspectRatio; private bool losslessQuality; private bool smoothMotion; private bool lockAspectRatio; private string videoInput; private string videoOutput; private bool fastPyramid; private decimal pyramidScale; private int levels; private int windowSize; private int iterations; private int pixelNeighborhood; private decimal smoothDerivativeStandardDeviation; private ObservableCollection subregions = new ObservableCollection(); #endregion #region Properties /// Gets the command line output given the current configuration. /// The command line output. public string CommandLineOutput { get { return ToButterflowArguments(); } } /// Gets or sets the playback rate. /// The playback rate. public string PlaybackRate { get { return this.playbackRate; } set { this.playbackRate = value; OnPropertyChanged(); } } /// Gets or sets a value indicating whether the keep audio. /// True if keep audio, false if not. public bool KeepAudio { get { return this.keepAudio; } set { this.keepAudio = value; OnPropertyChanged(); } } /// Gets or sets a value indicating whether the butterflow should be turned toward smooth motion. /// True if tuned toward smooth motion, false if not. public bool SmoothMotion { get { return this.smoothMotion; } set { this.smoothMotion = value; OnPropertyChanged(); } } /// Gets or sets a value indicating whether to lock aspect ratio of the video. /// True if locking aspect ratio of the video, false if not. public bool LockAspectRatio { get { return this.lockAspectRatio; } set { if (value) { this.aspectRatio = Convert.ToDecimal(this.height) / Convert.ToDecimal(this.width); } this.lockAspectRatio = value; OnPropertyChanged(); } } /// Gets or sets the width of the video output. /// The width of the video output. public string Width { get { return this.width.ToString(); } set { var oldWidth = this.width; interpreter.Interpret(value); this.width = interpreter.Int; OnPropertyChanged(); if (this.lockAspectRatio) { interpreter.Interpret(string.Format("{0} * {1}", this.aspectRatio, this.width)); this.height = interpreter.Int; OnPropertyChanged("Height"); } } } /// Gets or sets the height of the video output. /// The height of the video output. public string Height { get { return this.height.ToString(); } set { interpreter.Interpret(value); this.height = interpreter.Int; OnPropertyChanged(); } } /// Gets or sets a value indicating whether the keep aspect ratio of the input video file for the output video file. /// True if keep aspect ratio, false if not. public bool KeepAspectRatio { get { return this.keepAspectRatio; } set { this.keepAspectRatio = value; OnPropertyChanged(); } } /// Gets or sets a value indicating whether the result is rendered in lossless quality. /// True if lossless quality is selected, false if not. public bool LosslessQuality { get { return this.losslessQuality; } set { this.losslessQuality = value; OnPropertyChanged(); } } /// Gets or sets the video input file path. /// The video input file path. public string VideoInput { get { return this.videoInput; } set { this.videoInput = value; OnPropertyChanged(); } } /// Gets or sets the video output file path. /// The video output file path. public string VideoOutput { get { return this.videoOutput; } set { this.videoOutput = value; OnPropertyChanged(); } } /// Gets or sets a value indicating whether to use fast pyramids. /// True if using fast pyramids, false if not. public bool FastPyramid { get { return this.fastPyramid; } set { this.fastPyramid = value; OnPropertyChanged(); } } /// Gets or sets the pyramid scale factor. /// The pyramid scale factor. public string PyramidScale { get { return this.pyramidScale.ToString(); } set { interpreter.Interpret(value); this.pyramidScale = interpreter.Decimal; OnPropertyChanged(); } } /// Gets or sets the number of pyramid layers. /// The number of pyramid layers. public string Levels { get { return this.levels.ToString(); } set { interpreter.Interpret(value); this.levels = interpreter.Int; OnPropertyChanged(); } } /// Gets or sets the size of the windowing average. /// The size of the windowing average. public string WindowSize { get { return this.windowSize.ToString(); } set { interpreter.Interpret(value); this.windowSize = interpreter.Int; OnPropertyChanged(); } } /// Gets or sets the number of iterations at each pyramid level. /// The number of iterations at each pyramid level. public string Iterations { get { return this.iterations.ToString(); } set { interpreter.Interpret(value); this.iterations = interpreter.Int; OnPropertyChanged(); } } /// Gets or sets the size of the pixel neighborhood. /// The size of the pixel neighborhood. public string PixelNeighborhood { get { return this.pixelNeighborhood.ToString(); } set { interpreter.Interpret(value); this.pixelNeighborhood = interpreter.Int; OnPropertyChanged(); } } /// Gets or sets the standard deviation of smooth derivatives. /// The standard deviation of smooth derivatives. public string SmoothDerivativeStandardDeviation { get { return this.smoothDerivativeStandardDeviation.ToString(); } set { interpreter.Interpret(value); this.smoothDerivativeStandardDeviation = interpreter.Decimal; OnPropertyChanged(); } } /// Gets or sets the subregions of the video on which to work. /// The subregions of the video. public ObservableCollection Subregions { get { return this.subregions; } set { this.subregions = value; OnPropertyChanged(); } } #endregion #region Contructors /// Default constructor. public OptionsConfiguration() { AddConstantCallProperty("CommandLineOutput"); this.subregions.CollectionChanged += SubregionsCollectionChanged; } private void SubregionsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (ButterflowSubregion newItem in e.NewItems) { newItem.PropertyChanged += SubregionPropertyChanged; } } if (e.OldItems != null) { foreach (ButterflowSubregion oldItem in e.OldItems) { oldItem.PropertyChanged -= SubregionPropertyChanged; } } OnPropertyChanged("CommandLineOutput"); } #endregion #region Methods private void SubregionPropertyChanged(object sender, PropertyChangedEventArgs e) { OnPropertyChanged("CommandLineOutput"); } /// Converts this object to a butterflow options. /// This object as a string. public string ToButterflowArguments() { var stringBuilder = new StringBuilder("-v "); //Verbose if (this.KeepAspectRatio) { stringBuilder.AppendFormat("-vs {0}:-1 ", this.Width); } else { stringBuilder.AppendFormat("-vs {0}:{1} ", this.Width, this.Height); } if (!string.IsNullOrWhiteSpace(this.PlaybackRate)) stringBuilder.AppendFormat("-r {0} ", this.PlaybackRate); if (this.KeepAudio) stringBuilder.Append("-audio "); if (this.LosslessQuality) stringBuilder.Append("-l "); stringBuilder.AppendFormat("\"{0}\"", this.VideoInput); if (this.Subregions.Any()) { foreach (var anon in this.Subregions.Select((sr, index) => new { Index = index, Subregion = sr })) { string format = "ss\\.fff"; if (anon.Index > 0) { stringBuilder.Append(":"); } if (anon.Subregion.Start.TotalHours > 1) { format = "h\\:m\\:s\\.fff"; } else if (anon.Subregion.Start.TotalMinutes > 1) { format = "m\\:s\\.fff"; } stringBuilder.AppendFormat("a={0},b={1},{2}={3}", anon.Subregion.Start.ToString(format), anon.Subregion.ToEnd ? "end" : anon.Subregion.End.ToString(format), anon.Subregion.SubregionType, anon.Subregion.Value); } stringBuilder.Append(" "); } return stringBuilder.ToString(); } /// Returns a string that represents the current object. /// A string that represents the current object. public override string ToString() { return ToButterflowArguments(); } #endregion } }