using System; using System.Collections.Generic; using System.Diagnostics; using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Logging; namespace MediaBrowser.MediaEncoding.Encoder { public class EncoderValidator { private readonly ILogger _logger; private readonly IProcessFactory _processFactory; public EncoderValidator(ILogger logger, IProcessFactory processFactory) { _logger = logger; _processFactory = processFactory; } public Tuple, List> Validate(string encoderPath) { _logger.Info("Validating media encoder at {0}", encoderPath); var decoders = GetDecoders(encoderPath); var encoders = GetEncoders(encoderPath); _logger.Info("Encoder validation complete"); return new Tuple, List>(decoders, encoders); } public bool ValidateVersion(string encoderAppPath, bool logOutput) { string output = string.Empty; try { output = GetProcessOutput(encoderAppPath, "-version"); } catch { } if (logOutput) { _logger.Info("ffmpeg info: {0}", output ?? string.Empty); } if (string.IsNullOrWhiteSpace(output)) { return false; } if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1) { return false; } return true; } private List GetDecoders(string encoderAppPath) { string output = string.Empty; try { output = GetProcessOutput(encoderAppPath, "-decoders"); } catch { } var found = new List(); var required = new[] { "h264_qsv", "mpeg2_qsv", "vc1_qsv" }; foreach (var codec in required) { var srch = " " + codec + " "; if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) != -1) { _logger.Info("Decoder available: " + codec); found.Add(codec); } } return found; } private List GetEncoders(string encoderAppPath) { string output = null; try { output = GetProcessOutput(encoderAppPath, "-encoders"); } catch { } var found = new List(); var required = new[] { "libx264", "libx265", "mpeg4", "msmpeg4", "libvpx", "libvpx-vp9", "aac", "libmp3lame", "libopus", "libvorbis", "srt", "h264_nvenc", "h264_qsv", "h264_omx", "h264_vaapi", "ac3" }; output = output ?? string.Empty; var index = 0; foreach (var codec in required) { var srch = " " + codec + " "; if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) != -1) { if (index < required.Length - 1) { _logger.Info("Encoder available: " + codec); } found.Add(codec); } index++; } return found; } private string GetProcessOutput(string path, string arguments) { var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, UseShellExecute = false, FileName = path, Arguments = arguments, IsHidden = true, ErrorDialog = false, RedirectStandardOutput = true }); _logger.Info("Running {0} {1}", path, arguments); using (process) { process.Start(); try { return process.StandardOutput.ReadToEnd(); } catch { _logger.Info("Killing process {0} {1}", path, arguments); // Hate having to do this try { process.Kill(); } catch (Exception ex1) { _logger.ErrorException("Error killing process", ex1); } throw; } } } } }