diff options
| author | ferferga <ferferga.fer@gmail.com> | 2020-10-19 17:28:07 +0200 |
|---|---|---|
| committer | ferferga <ferferga.fer@gmail.com> | 2020-10-19 17:28:07 +0200 |
| commit | 9fd01fade6ac971ba72a2e7dd54e2295f23839bc (patch) | |
| tree | 20a5ff4a1621e765fc93c0e53b149edb61ff3654 /MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | |
| parent | ba03ed65fe64b724b3e8b5b94b9cbe1075c61da2 (diff) | |
| parent | 49ac4c4044b1777dc3a25544aead7b0b15b953e8 (diff) | |
Remove "download images in advance" option
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs')
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 214 |
1 files changed, 145 insertions, 69 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 6e036d24c..3287f9814 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -1,8 +1,10 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; @@ -12,28 +14,50 @@ namespace MediaBrowser.MediaEncoding.Encoder { private const string DefaultEncoderPath = "ffmpeg"; - private static readonly string[] requiredDecoders = new[] + private static readonly string[] _requiredDecoders = new[] { + "h264", + "hevc", "mpeg2video", + "mpeg4", + "msmpeg4", + "dts", + "ac3", + "aac", + "mp3", "h264_qsv", "hevc_qsv", "mpeg2_qsv", - "mpeg2_mmal", - "mpeg4_mmal", "vc1_qsv", - "vc1_mmal", + "vp8_qsv", + "vp9_qsv", "h264_cuvid", "hevc_cuvid", - "dts", - "ac3", - "aac", - "mp3", - "h264", + "mpeg2_cuvid", + "vc1_cuvid", + "mpeg4_cuvid", + "vp8_cuvid", + "vp9_cuvid", "h264_mmal", - "hevc" + "mpeg2_mmal", + "mpeg4_mmal", + "vc1_mmal", + "h264_mediacodec", + "hevc_mediacodec", + "mpeg2_mediacodec", + "mpeg4_mediacodec", + "vp8_mediacodec", + "vp9_mediacodec", + "h264_opencl", + "hevc_opencl", + "mpeg2_opencl", + "mpeg4_opencl", + "vp8_opencl", + "vp9_opencl", + "vc1_opencl" }; - private static readonly string[] requiredEncoders = new[] + private static readonly string[] _requiredEncoders = new[] { "libx264", "libx265", @@ -43,36 +67,37 @@ namespace MediaBrowser.MediaEncoding.Encoder "libvpx-vp9", "aac", "libfdk_aac", + "ac3", "libmp3lame", "libopus", "libvorbis", "srt", - "h264_nvenc", - "hevc_nvenc", + "h264_amf", + "hevc_amf", "h264_qsv", "hevc_qsv", - "h264_omx", - "hevc_omx", + "h264_nvenc", + "hevc_nvenc", "h264_vaapi", "hevc_vaapi", + "h264_omx", + "hevc_omx", "h264_v4l2m2m", - "ac3", - "h264_amf", - "hevc_amf" + "h264_videotoolbox", + "hevc_videotoolbox" }; - // Try and use the individual library versions to determine a FFmpeg version - // This lookup table is to be maintained with the following command line: - // $ ffmpeg -version | perl -ne ' print "$1=$2.$3," if /^(lib\w+)\s+(\d+)\.\s*(\d+)/' - private static readonly IReadOnlyDictionary<string, Version> _ffmpegVersionMap = new Dictionary<string, Version> + // These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below + private static readonly IReadOnlyDictionary<string, Version> _ffmpegMinimumLibraryVersions = new Dictionary<string, Version> { - { "libavutil=56.31,libavcodec=58.54,libavformat=58.29,libavdevice=58.8,libavfilter=7.57,libswscale=5.5,libswresample=3.5,libpostproc=55.5,", new Version(4, 2) }, - { "libavutil=56.22,libavcodec=58.35,libavformat=58.20,libavdevice=58.5,libavfilter=7.40,libswscale=5.3,libswresample=3.3,libpostproc=55.3,", new Version(4, 1) }, - { "libavutil=56.14,libavcodec=58.18,libavformat=58.12,libavdevice=58.3,libavfilter=7.16,libswscale=5.1,libswresample=3.1,libpostproc=55.1,", new Version(4, 0) }, - { "libavutil=55.78,libavcodec=57.107,libavformat=57.83,libavdevice=57.10,libavfilter=6.107,libswscale=4.8,libswresample=2.9,libpostproc=54.7,", new Version(3, 4) }, - { "libavutil=55.58,libavcodec=57.89,libavformat=57.71,libavdevice=57.6,libavfilter=6.82,libswscale=4.6,libswresample=2.7,libpostproc=54.5,", new Version(3, 3) }, - { "libavutil=55.34,libavcodec=57.64,libavformat=57.56,libavdevice=57.1,libavfilter=6.65,libswscale=4.2,libswresample=2.3,libpostproc=54.1,", new Version(3, 2) }, - { "libavutil=54.31,libavcodec=56.60,libavformat=56.40,libavdevice=56.4,libavfilter=5.40,libswscale=3.1,libswresample=1.2,libpostproc=53.3,", new Version(2, 8) } + { "libavutil", new Version(56, 14) }, + { "libavcodec", new Version(58, 18) }, + { "libavformat", new Version(58, 12) }, + { "libavdevice", new Version(58, 3) }, + { "libavfilter", new Version(7, 16) }, + { "libswscale", new Version(5, 1) }, + { "libswresample", new Version(3, 1) }, + { "libpostproc", new Version(55, 1) } }; private readonly ILogger _logger; @@ -85,6 +110,13 @@ namespace MediaBrowser.MediaEncoding.Encoder _encoderPath = encoderPath; } + private enum Codec + { + Encoder, + Decoder + } + + // When changing this, also change the minimum library versions in _ffmpegMinimumLibraryVersions public static Version MinVersion { get; } = new Version(4, 0); public static Version MaxVersion { get; } = null; @@ -123,32 +155,36 @@ namespace MediaBrowser.MediaEncoding.Encoder // Work out what the version under test is var version = GetFFmpegVersion(versionOutput); - _logger.LogInformation("Found ffmpeg version {0}", version != null ? version.ToString() : "unknown"); + _logger.LogInformation("Found ffmpeg version {Version}", version != null ? version.ToString() : "unknown"); if (version == null) { - if (MinVersion != null && MaxVersion != null) // Version is unknown + if (MaxVersion != null) // Version is unknown { if (MinVersion == MaxVersion) { - _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", MinVersion); + _logger.LogWarning("FFmpeg validation: We recommend version {MinVersion}", MinVersion); } else { - _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", MinVersion, MaxVersion); + _logger.LogWarning("FFmpeg validation: We recommend a minimum of {MinVersion} and maximum of {MaxVersion}", MinVersion, MaxVersion); } } + else + { + _logger.LogWarning("FFmpeg validation: We recommend minimum version {MinVersion}", MinVersion); + } return false; } - else if (MinVersion != null && version < MinVersion) // Version is below what we recommend + else if (version < MinVersion) // Version is below what we recommend { - _logger.LogWarning("FFmpeg validation: The minimum recommended ffmpeg version is {0}", MinVersion); + _logger.LogWarning("FFmpeg validation: The minimum recommended version is {MinVersion}", MinVersion); return false; } else if (MaxVersion != null && version > MaxVersion) // Version is above what we recommend { - _logger.LogWarning("FFmpeg validation: The maximum recommended ffmpeg version is {0}", MaxVersion); + _logger.LogWarning("FFmpeg validation: The maximum recommended version is {MaxVersion}", MaxVersion); return false; } @@ -159,63 +195,103 @@ namespace MediaBrowser.MediaEncoding.Encoder public IEnumerable<string> GetEncoders() => GetCodecs(Codec.Encoder); + public IEnumerable<string> GetHwaccels() => GetHwaccelTypes(); + /// <summary> /// Using the output from "ffmpeg -version" work out the FFmpeg version. /// For pre-built binaries the first line should contain a string like "ffmpeg version x.y", which is easy - /// to parse. If this is not available, then we try to match known library versions to FFmpeg versions. - /// If that fails then we use one of the main libraries to determine if it's new/older than the latest - /// we have stored. + /// to parse. If this is not available, then we try to match known library versions to FFmpeg versions. + /// If that fails then we test the libraries to determine if they're newer than our minimum versions. /// </summary> - /// <param name="output"></param> - /// <returns></returns> - internal static Version GetFFmpegVersion(string output) + /// <param name="output">The output from "ffmpeg -version".</param> + /// <returns>The FFmpeg version.</returns> + internal Version GetFFmpegVersion(string output) { // For pre-built binaries the FFmpeg version should be mentioned at the very start of the output - var match = Regex.Match(output, @"^ffmpeg version n?((?:\d+\.?)+)"); + var match = Regex.Match(output, @"^ffmpeg version n?((?:[0-9]+\.?)+)"); if (match.Success) { - return new Version(match.Groups[1].Value); + if (Version.TryParse(match.Groups[1].Value, out var result)) + { + return result; + } } - else - { - // Create a reduced version string and lookup key from dictionary - var reducedVersion = GetLibrariesVersionString(output); - // Try to lookup the string and return Key, otherwise if not found returns null - return _ffmpegVersionMap.TryGetValue(reducedVersion, out Version version) ? version : null; + var versionMap = GetFFmpegLibraryVersions(output); + + var allVersionsValidated = true; + + foreach (var minimumVersion in _ffmpegMinimumLibraryVersions) + { + if (versionMap.TryGetValue(minimumVersion.Key, out var foundVersion)) + { + if (foundVersion >= minimumVersion.Value) + { + _logger.LogInformation("Found {Library} version {FoundVersion} ({MinimumVersion})", minimumVersion.Key, foundVersion, minimumVersion.Value); + } + else + { + _logger.LogWarning("Found {Library} version {FoundVersion} lower than recommended version {MinimumVersion}", minimumVersion.Key, foundVersion, minimumVersion.Value); + allVersionsValidated = false; + } + } + else + { + _logger.LogError("{Library} version not found", minimumVersion.Key); + allVersionsValidated = false; + } } + + return allVersionsValidated ? MinVersion : null; } /// <summary> /// Grabs the library names and major.minor version numbers from the 'ffmpeg -version' output - /// and condenses them on to one line. Output format is "name1=major.minor,name2=major.minor,etc." + /// and condenses them on to one line. Output format is "name1=major.minor,name2=major.minor,etc.". /// </summary> - /// <param name="output"></param> - /// <returns></returns> - private static string GetLibrariesVersionString(string output) + /// <param name="output">The 'ffmpeg -version' output.</param> + /// <returns>The library names and major.minor version numbers.</returns> + private static IReadOnlyDictionary<string, Version> GetFFmpegLibraryVersions(string output) { - var rc = new StringBuilder(144); - foreach (Match m in Regex.Matches( + var map = new Dictionary<string, Version>(); + + foreach (Match match in Regex.Matches( output, - @"((?<name>lib\w+)\s+(?<major>\d+)\.\s*(?<minor>\d+))", + @"((?<name>lib\w+)\s+(?<major>[0-9]+)\.\s*(?<minor>[0-9]+))", RegexOptions.Multiline)) { - rc.Append(m.Groups["name"]) - .Append('=') - .Append(m.Groups["major"]) - .Append('.') - .Append(m.Groups["minor"]) - .Append(','); + var version = new Version( + int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture), + int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture)); + + map.Add(match.Groups["name"].Value, version); } - return rc.Length == 0 ? null : rc.ToString(); + return map; } - private enum Codec + private IEnumerable<string> GetHwaccelTypes() { - Encoder, - Decoder + string output = null; + try + { + output = GetProcessOutput(_encoderPath, "-hwaccels"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error detecting available hwaccel types"); + } + + if (string.IsNullOrWhiteSpace(output)) + { + return Enumerable.Empty<string>(); + } + + var found = output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); + _logger.LogInformation("Available hwaccel types: {Types}", found); + + return found; } private IEnumerable<string> GetCodecs(Codec codec) @@ -236,7 +312,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return Enumerable.Empty<string>(); } - var required = codec == Codec.Encoder ? requiredEncoders : requiredDecoders; + var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders; var found = Regex .Matches(output, @"^\s\S{6}\s(?<codec>[\w|-]+)\s+.+$", RegexOptions.Multiline) |
