using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace butterflow_ui { /// A butterflow wrapper. Provides interaction with the butterflow executable. public class ButterflowWrapper : PropertyChangedAlerter { #region Members /// The RegEx string for matching probed resolution. private const string REGEX_RESOLUTION = @"Resolution\s*:\s(?\d+)x(?\d+)"; /// The RegEx string for matching the probed playback rate.. private const string REGEX_RATE = @"Rate\s*:\s(?\d+\.\d+) fps"; /// Full pathname of the butterflow executable file. private Lazy executablePath = new Lazy(() => Path.Combine(Directory.GetCurrentDirectory(), "ThirdPartyCompiled", "butterflow.exe")); /// The console output from butterflow. private string consoleOutput = string.Empty; /// True if butterflow is running, false if not. private bool isRunning; /// Event queue for all listeners interested in ParsedConsoleOutputRecieved events. public event EventHandler ParsedConsoleOutputRecieved; #endregion #region Properties /// Gets the console output from butterflow. /// The console output from butterflow. public string ConsoleOutput { get { return this.consoleOutput; } private set { this.consoleOutput = value; OnPropertyChanged(); } } /// Gets or sets a value indicating whether butterflow is currently running. /// True if butterflow is running, false if not. public bool IsRunning { get { return this.isRunning; } set { this.isRunning = value; OnPropertyChanged(); } } #endregion #region Methods /// Runs butterflow with the given . /// The options configuration. public void Run(OptionsConfiguration optionsConfiguration) { string arguments = optionsConfiguration.ToButterflowArguments(); Run(arguments); } /// Probes a video file. /// The video file to be probed. public void Probe(string videoFile) { string arguments = string.Format("-prb \"{0}\"", videoFile); Run(arguments); } /// Runs butterflow with the given . /// Options for controlling the operation. private void Run(string arguments) { if (!this.IsRunning) { var process = new Process(); process.StartInfo = new ProcessStartInfo(executablePath.Value, arguments); process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.EnableRaisingEvents = true; process.OutputDataReceived += Process_OutputDataReceived; process.ErrorDataReceived += Process_OutputDataReceived; process.Exited += Process_Exited; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); this.IsRunning = true; } } /// Event handler. Called by Process for exited events. /// Source of the event. /// Event information. private void Process_Exited(object sender, EventArgs e) { this.IsRunning = false; } /// /// Parses console output and attempts to find known values. If a known value is found, the /// event is triggered. /// /// The console output from butterflow. private void ParseConsoleOutput(string consoleOutput) { if (string.IsNullOrWhiteSpace(consoleOutput)) { //Ignore null content and just escape. return; } //Test for resolution var regex = new Regex(REGEX_RESOLUTION); foreach (Match match in regex.Matches(consoleOutput)) { var width = match.Groups["Width"].Value; var height = match.Groups["Height"].Value; OnParsedConsoleOutputRecieved(ButterflowOutputType.Width, width, consoleOutput); OnParsedConsoleOutputRecieved(ButterflowOutputType.Height, height, consoleOutput); } //Test for playback rate regex = new Regex(REGEX_RATE); foreach(Match match in regex.Matches(consoleOutput)) { var rate = match.Groups["Rate"].Value; OnParsedConsoleOutputRecieved(ButterflowOutputType.Rate, rate, consoleOutput); } } /// Executes the parsed console output recieved action. /// Type of the output. /// The value. /// The console output from butterflow. private void OnParsedConsoleOutputRecieved(ButterflowOutputType outputType, string value, string consoleOutput) { if (this.ParsedConsoleOutputRecieved != null) { this.ParsedConsoleOutputRecieved(this, new ButterflowOutputArgs(outputType, value, consoleOutput)); } } /// Event handler. Called by Process for output data received events. /// Source of the event. /// Data received event information. private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e) { this.ConsoleOutput += string.Format("{0}{1}", e.Data, Environment.NewLine); ParseConsoleOutput(e.Data); } #endregion #region Subclasses /// Arguments for butterflow output events where a known value of type can be parsed. public class ButterflowOutputArgs : ButterflowConsoleOutputArgs { #region Properties /// Gets or sets the type of the output detected from butterflow. /// The type of the output detected from butterflow. public ButterflowOutputType OutputType { get; private set; } /// Gets or sets the value detected from butterflow. /// The value detected from butterflow. public string Value { get; private set; } #endregion /// Constructor. /// The type of the output detected from butterflow. /// The value detected from butterflow. /// The console output. public ButterflowOutputArgs(ButterflowOutputType outputType, string value, string consoleOutput) : base(consoleOutput) { this.OutputType = outputType; this.Value = value; } } /// Arguments for butterflow console output events. public class ButterflowConsoleOutputArgs : EventArgs { #region Properties /// Gets the console output. /// The console output. public string ConsoleOutput { get; private set; } #endregion #region Constructors /// Constructor. /// The console output. public ButterflowConsoleOutputArgs(string consoleOutput) { this.ConsoleOutput = consoleOutput; } #endregion } /// Values that represent butterflow output types. public enum ButterflowOutputType { /// Video Width. Width, /// Video Height. Height, /// Video playback rate. Rate, /// Video processing progress. Progress } #endregion } }