aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding/Encoder
diff options
context:
space:
mode:
authorNyanmisaka <nst799610810@gmail.com>2020-09-04 02:55:57 +0800
committerGitHub <noreply@github.com>2020-09-04 02:55:57 +0800
commit4cb0a57e4645aba8e5e65c7d086091b9161c6c09 (patch)
tree25e77817485d70cac8ec3e11a785b08b69d0c60b /MediaBrowser.MediaEncoding/Encoder
parent54349fc94597824714f623b8c31583fc044274aa (diff)
parent53703566b5e1239bbab308031d94df34a4d168aa (diff)
Merge branch 'master' into tonemap
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs133
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs16
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs104
3 files changed, 150 insertions, 103 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index 5c43fdcfa..c8bf5557b 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,7 +14,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
private const string DefaultEncoderPath = "ffmpeg";
- private static readonly string[] requiredDecoders = new[]
+ private static readonly string[] _requiredDecoders = new[]
{
"h264",
"hevc",
@@ -55,7 +57,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
"vc1_opencl"
};
- private static readonly string[] requiredEncoders = new[]
+ private static readonly string[] _requiredEncoders = new[]
{
"libx264",
"libx265",
@@ -85,19 +87,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
"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.51,libavcodec=58.91,libavformat=58.45,libavdevice=58.10,libavfilter=7.85,libswscale=5.7,libswresample=3.7,libpostproc=55.7,", new Version(4, 3) },
- { "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;
@@ -110,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;
@@ -148,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;
}
@@ -189,13 +200,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <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?((?:[0-9]+\.?)+)");
@@ -204,45 +214,58 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
return new Version(match.Groups[1].Value);
}
- 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>[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));
- return rc.Length == 0 ? null : rc.ToString();
- }
+ map.Add(match.Groups["name"].Value, version);
+ }
- private enum Codec
- {
- Encoder,
- Decoder
+ return map;
}
private IEnumerable<string> GetHwaccelTypes()
@@ -262,7 +285,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return Enumerable.Empty<string>();
}
- var found = output.Split(new char[] {'\r','\n'}, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList();
+ var found = output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList();
_logger.LogInformation("Available hwaccel types: {Types}", found);
return found;
@@ -286,7 +309,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)
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
index d4aede572..63310fdf6 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
@@ -1,4 +1,8 @@
+#pragma warning disable CS1591
+
+using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Model.MediaInfo;
@@ -12,7 +16,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var url = inputFiles[0];
- return string.Format("\"{0}\"", url);
+ return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", url);
}
return GetConcatInputArgument(inputFiles);
@@ -31,7 +35,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var files = string.Join("|", inputFiles.Select(NormalizePath));
- return string.Format("concat:\"{0}\"", files);
+ return string.Format(CultureInfo.InvariantCulture, "concat:\"{0}\"", files);
}
// Determine the input path for video files
@@ -45,15 +49,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns>System.String.</returns>
private static string GetFileInputArgument(string path)
{
- if (path.IndexOf("://") != -1)
+ if (path.IndexOf("://", StringComparison.Ordinal) != -1)
{
- return string.Format("\"{0}\"", path);
+ return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", path);
}
// Quotes are valid path characters in linux and they need to be escaped here with a leading \
path = NormalizePath(path);
- return string.Format("file:\"{0}\"", path);
+ return string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", path);
}
/// <summary>
@@ -64,7 +68,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private static string NormalizePath(string path)
{
// Quotes are valid path characters in linux and they need to be escaped here with a leading \
- return path.Replace("\"", "\\\"");
+ return path.Replace("\"", "\\\"", StringComparison.Ordinal);
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 62fdbc618..5a3a9185d 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -1,5 +1,8 @@
+#pragma warning disable CS1591
+
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -9,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Json;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing;
@@ -19,9 +23,8 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
-using Microsoft.Extensions.Logging;
-using System.Diagnostics;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -35,6 +38,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
internal const int DefaultImageExtractionTimeout = 5000;
+ /// <summary>
+ /// The us culture.
+ /// </summary>
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
private readonly ILogger<MediaEncoder> _logger;
private readonly IServerConfigurationManager _configurationManager;
private readonly IFileSystem _fileSystem;
@@ -47,6 +55,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly object _runningProcessesLock = new object();
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
+ // MediaEncoder is registered as a Singleton
+ private readonly JsonSerializerOptions _jsonSerializerOptions;
+
+ private List<string> _encoders = new List<string>();
+ private List<string> _decoders = new List<string>();
+ private List<string> _hwaccels = new List<string>();
+
private string _ffmpegPath = string.Empty;
private string _ffprobePath;
@@ -64,6 +79,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_localization = localization;
_encodingHelperFactory = encodingHelperFactory;
_startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty;
+ _jsonSerializerOptions = JsonDefaults.GetOptions();
}
private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
@@ -77,7 +93,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <summary>
/// Run at startup or if the user removes a Custom path from transcode page.
/// Sets global variables FFmpegPath.
- /// Precedence is: Config > CLI > $PATH
+ /// Precedence is: Config > CLI > $PATH.
/// </summary>
public void SetFFmpegPath()
{
@@ -122,8 +138,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Triggered from the Settings > Transcoding UI page when users submits Custom FFmpeg path to use.
/// Only write the new path to xml if it exists. Do not perform validation checks on ffmpeg here.
/// </summary>
- /// <param name="path"></param>
- /// <param name="pathType"></param>
+ /// <param name="path">The path.</param>
+ /// <param name="pathType">The path type.</param>
public void UpdateEncoderPath(string path, string pathType)
{
string newPath;
@@ -168,8 +184,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// If checks pass, global variable FFmpegPath and EncoderLocation are updated.
/// </summary>
/// <param name="path">FQPN to test.</param>
- /// <param name="location">Location (External, Custom, System) of tool</param>
- /// <returns></returns>
+ /// <param name="location">Location (External, Custom, System) of tool.</param>
+ /// <returns><c>true</c> if the version validation succeeded; otherwise, <c>false</c>.</returns>
private bool ValidatePath(string path, FFmpegLocation location)
{
bool rc = false;
@@ -185,9 +201,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.LogWarning("FFmpeg: {Location}: Failed version check: {Path}", location, path);
}
- // ToDo - Enable the ffmpeg validator. At the moment any version can be used.
- rc = true;
-
_ffmpegPath = path;
EncoderLocation = location;
}
@@ -221,8 +234,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <summary>
/// Search the system $PATH environment variable looking for given filename.
/// </summary>
- /// <param name="fileName"></param>
- /// <returns></returns>
+ /// <param name="fileName">The filename.</param>
+ /// <returns>The full path to the file.</returns>
private string ExistsOnSystemPath(string fileName)
{
var inJellyfinPath = GetEncoderPathFromDirectory(AppContext.BaseDirectory, fileName, recursive: true);
@@ -246,25 +259,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
return null;
}
- private List<string> _encoders = new List<string>();
public void SetAvailableEncoders(IEnumerable<string> list)
{
_encoders = list.ToList();
- // _logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray()));
}
- private List<string> _decoders = new List<string>();
public void SetAvailableDecoders(IEnumerable<string> list)
{
_decoders = list.ToList();
- // _logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray()));
}
- private List<string> _hwaccels = new List<string>();
public void SetAvailableHwaccels(IEnumerable<string> list)
{
_hwaccels = list.ToList();
- //_logger.Info("Supported hwaccels: {0}", string.Join(",", list.ToArray()));
}
public bool SupportsEncoder(string encoder)
@@ -332,8 +339,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
var forceEnableLogging = request.MediaSource.Protocol != MediaProtocol.File;
- return GetMediaInfoInternal(GetInputArgument(inputFiles, request.MediaSource.Protocol), request.MediaSource.Path, request.MediaSource.Protocol, extractChapters,
- probeSize, request.MediaType == DlnaProfileType.Audio, request.MediaSource.VideoType, forceEnableLogging, cancellationToken);
+ return GetMediaInfoInternal(
+ GetInputArgument(inputFiles, request.MediaSource.Protocol),
+ request.MediaSource.Path,
+ request.MediaSource.Protocol,
+ extractChapters,
+ probeSize,
+ request.MediaType == DlnaProfileType.Audio,
+ request.MediaSource.VideoType,
+ forceEnableLogging,
+ cancellationToken);
}
/// <summary>
@@ -342,7 +357,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <param name="inputFiles">The input files.</param>
/// <param name="protocol">The protocol.</param>
/// <returns>System.String.</returns>
- /// <exception cref="ArgumentException">Unrecognized InputType</exception>
+ /// <exception cref="ArgumentException">Unrecognized InputType.</exception>
public string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol)
=> EncodingUtils.GetInputArgument(inputFiles, protocol);
@@ -350,7 +365,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets the media info internal.
/// </summary>
/// <returns>Task{MediaInfoResult}.</returns>
- private async Task<MediaInfo> GetMediaInfoInternal(string inputPath,
+ private async Task<MediaInfo> GetMediaInfoInternal(
+ string inputPath,
string primaryPath,
MediaProtocol protocol,
bool extractChapters,
@@ -363,7 +379,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var args = extractChapters
? "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_chapters -show_format"
: "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_format";
- args = string.Format(args, probeSizeArgument, inputPath).Trim();
+ args = string.Format(CultureInfo.InvariantCulture, args, probeSizeArgument, inputPath).Trim();
var process = new Process
{
@@ -378,7 +394,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
FileName = _ffprobePath,
Arguments = args,
-
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false,
},
@@ -404,6 +419,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
result = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(
process.StandardOutput.BaseStream,
+ _jsonSerializerOptions,
cancellationToken: cancellationToken).ConfigureAwait(false);
}
catch
@@ -439,11 +455,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- /// <summary>
- /// The us culture.
- /// </summary>
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
public Task<string> ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken)
{
return ExtractImage(new[] { path }, null, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken);
@@ -459,8 +470,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, protocol, false, null, null, cancellationToken);
}
- private async Task<string> ExtractImage(string[] inputFiles, string container, MediaStream videoStream, int? imageStreamIndex, MediaProtocol protocol, bool isAudio,
- Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
+ private async Task<string> ExtractImage(
+ string[] inputFiles,
+ string container,
+ MediaStream videoStream,
+ int? imageStreamIndex,
+ MediaProtocol protocol,
+ bool isAudio,
+ Video3DFormat? threedFormat,
+ TimeSpan? offset,
+ CancellationToken cancellationToken)
{
var inputArgument = GetInputArgument(inputFiles, protocol);
@@ -536,8 +555,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
var thumbnail = enableThumbnail ? ",thumbnail=24" : string.Empty;
- var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
- string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
+ var args = useIFrame ? string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
+ string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
@@ -554,7 +573,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (offset.HasValue)
{
- args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args;
+ args = string.Format(CultureInfo.InvariantCulture, "-ss {0} ", GetTimeParameter(offset.Value)) + args;
}
if (videoStream != null)
@@ -625,7 +644,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (exitCode == -1 || !file.Exists || file.Length == 0)
{
- var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
+ var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath);
_logger.LogError(msg);
@@ -645,7 +664,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public string GetTimeParameter(TimeSpan time)
{
- return time.ToString(@"hh\:mm\:ss\.fff", UsCulture);
+ return time.ToString(@"hh\:mm\:ss\.fff", _usCulture);
}
public async Task ExtractVideoImagesOnInterval(
@@ -662,19 +681,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var inputArgument = GetInputArgument(inputFiles, protocol);
- var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture);
+ var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture);
if (maxWidth.HasValue)
{
- var maxWidthParam = maxWidth.Value.ToString(UsCulture);
+ var maxWidthParam = maxWidth.Value.ToString(_usCulture);
- vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
+ vf += string.Format(CultureInfo.InvariantCulture, ",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
}
Directory.CreateDirectory(targetDirectory);
var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
- var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
+ var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
@@ -774,7 +793,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (exitCode == -1)
{
- var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
+ var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputArgument);
_logger.LogError(msg);
@@ -840,7 +859,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping
// We need to double escape
- return path.Replace('\\', '/').Replace(":", "\\:").Replace("'", "'\\\\\\''");
+ return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", "'\\\\\\''", StringComparison.Ordinal);
}
/// <inheritdoc />
@@ -859,6 +878,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (dispose)
{
StopProcesses();
+ _thumbnailResourcePool.Dispose();
}
}