aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding/Encoder
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs42
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs96
2 files changed, 75 insertions, 63 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index e1a0e8d67..f12ef7e63 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging;
namespace MediaBrowser.MediaEncoding.Encoder
{
- public class EncoderValidator
+ public partial class EncoderValidator
{
private static readonly string[] _requiredDecoders = new[]
{
@@ -165,6 +165,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
public static Version? MaxVersion { get; } = null;
+ [GeneratedRegex(@"^ffmpeg version n?((?:[0-9]+\.?)+)")]
+ private static partial Regex FfmpegVersionRegex();
+
+ [GeneratedRegex(@"((?<name>lib\w+)\s+(?<major>[0-9]+)\.\s*(?<minor>[0-9]+))", RegexOptions.Multiline)]
+ private static partial Regex LibraryRegex();
+
public bool ValidateVersion()
{
string output;
@@ -283,7 +289,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
internal Version? GetFFmpegVersionInternal(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]+\.?)+)");
+ var match = FfmpegVersionRegex().Match(output);
if (match.Success)
{
@@ -331,10 +337,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
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))
+ foreach (Match match in LibraryRegex().Matches(output))
{
var version = new Version(
int.Parse(match.Groups["major"].ValueSpan, CultureInfo.InvariantCulture),
@@ -496,8 +499,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders;
- var found = Regex
- .Matches(output, @"^\s\S{6}\s(?<codec>[\w|-]+)\s+.+$", RegexOptions.Multiline)
+ var found = CodecRegex()
+ .Matches(output)
.Select(x => x.Groups["codec"].Value)
.Where(x => required.Contains(x));
@@ -524,8 +527,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
return Enumerable.Empty<string>();
}
- var found = Regex
- .Matches(output, @"^\s\S{3}\s(?<filter>[\w|-]+)\s+.+$", RegexOptions.Multiline)
+ var found = FilterRegex()
+ .Matches(output)
.Select(x => x.Groups["filter"].Value)
.Where(x => _requiredFilters.Contains(x));
@@ -550,7 +553,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string GetProcessOutput(string path, string arguments, bool readStdErr, string? testKey)
{
- using (var process = new Process()
+ var redirectStandardIn = !string.IsNullOrEmpty(testKey);
+ using (var process = new Process
{
StartInfo = new ProcessStartInfo(path, arguments)
{
@@ -558,7 +562,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false,
- RedirectStandardInput = !string.IsNullOrEmpty(testKey),
+ RedirectStandardInput = redirectStandardIn,
RedirectStandardOutput = true,
RedirectStandardError = true
}
@@ -568,13 +572,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
process.Start();
- if (!string.IsNullOrEmpty(testKey))
+ if (redirectStandardIn)
{
- process.StandardInput.Write(testKey);
+ using var writer = process.StandardInput;
+ writer.Write(testKey);
}
- return readStdErr ? process.StandardError.ReadToEnd() : process.StandardOutput.ReadToEnd();
+ using var reader = readStdErr ? process.StandardError : process.StandardOutput;
+ return reader.ReadToEnd();
}
}
+
+ [GeneratedRegex("^\\s\\S{6}\\s(?<codec>[\\w|-]+)\\s+.+$", RegexOptions.Multiline)]
+ private static partial Regex CodecRegex();
+
+ [GeneratedRegex("^\\s\\S{3}\\s(?<filter>[\\w|-]+)\\s+.+$", RegexOptions.Multiline)]
+ private static partial Regex FilterRegex();
}
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index fa695bbdc..0b603715d 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -39,7 +39,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <summary>
/// Class MediaEncoder.
/// </summary>
- public class MediaEncoder : IMediaEncoder, IDisposable
+ public partial class MediaEncoder : IMediaEncoder, IDisposable
{
/// <summary>
/// The default SDR image extraction timeout in milliseconds.
@@ -79,12 +79,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
private bool _isVaapiDeviceAmd = false;
private bool _isVaapiDeviceInteliHD = false;
private bool _isVaapiDeviceInteli965 = false;
- private bool _isVaapiDeviceSupportVulkanFmtModifier = false;
+ private bool _isVaapiDeviceSupportVulkanDrmInterop = false;
- private static string[] _vulkanFmtModifierExts =
+ private static string[] _vulkanExternalMemoryDmaBufExts =
{
- "VK_KHR_sampler_ycbcr_conversion",
- "VK_EXT_image_drm_format_modifier",
"VK_KHR_external_memory_fd",
"VK_EXT_external_memory_dma_buf",
"VK_KHR_external_semaphore_fd",
@@ -143,7 +141,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
public bool IsVaapiDeviceInteli965 => _isVaapiDeviceInteli965;
/// <inheritdoc />
- public bool IsVaapiDeviceSupportVulkanFmtModifier => _isVaapiDeviceSupportVulkanFmtModifier;
+ public bool IsVaapiDeviceSupportVulkanDrmInterop => _isVaapiDeviceSupportVulkanDrmInterop;
+
+ [GeneratedRegex(@"[^\/\\]+?(\.[^\/\\\n.]+)?$")]
+ private static partial Regex FfprobePathRegex();
/// <summary>
/// Run at startup or if the user removes a Custom path from transcode page.
@@ -179,7 +180,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (_ffmpegPath is not null)
{
// Determine a probe path from the mpeg path
- _ffprobePath = Regex.Replace(_ffmpegPath, @"[^\/\\]+?(\.[^\/\\\n.]+)?$", @"ffprobe$1");
+ _ffprobePath = FfprobePathRegex().Replace(_ffmpegPath, "ffprobe$1");
// Interrogate to understand what coders are supported
var validator = new EncoderValidator(_logger, _ffmpegPath);
@@ -204,7 +205,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_isVaapiDeviceAmd = validator.CheckVaapiDeviceByDriverName("Mesa Gallium driver", options.VaapiDevice);
_isVaapiDeviceInteliHD = validator.CheckVaapiDeviceByDriverName("Intel iHD driver", options.VaapiDevice);
_isVaapiDeviceInteli965 = validator.CheckVaapiDeviceByDriverName("Intel i965 driver", options.VaapiDevice);
- _isVaapiDeviceSupportVulkanFmtModifier = validator.CheckVulkanDrmDeviceByExtensionName(options.VaapiDevice, _vulkanFmtModifierExts);
+ _isVaapiDeviceSupportVulkanDrmInterop = validator.CheckVulkanDrmDeviceByExtensionName(options.VaapiDevice, _vulkanExternalMemoryDmaBufExts);
if (_isVaapiDeviceAmd)
{
@@ -219,9 +220,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.LogInformation("VAAPI device {RenderNodePath} is Intel GPU (i965)", options.VaapiDevice);
}
- if (_isVaapiDeviceSupportVulkanFmtModifier)
+ if (_isVaapiDeviceSupportVulkanDrmInterop)
{
- _logger.LogInformation("VAAPI device {RenderNodePath} supports Vulkan DRM format modifier", options.VaapiDevice);
+ _logger.LogInformation("VAAPI device {RenderNodePath} supports Vulkan DRM interop", options.VaapiDevice);
}
}
}
@@ -318,10 +319,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var files = _fileSystem.GetFilePaths(path, recursive);
- var excludeExtensions = new[] { ".c" };
-
- return files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), filename, StringComparison.OrdinalIgnoreCase)
- && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty));
+ return files.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i.AsSpan()).Equals(filename, StringComparison.OrdinalIgnoreCase)
+ && !Path.GetExtension(i.AsSpan()).Equals(".c", StringComparison.OrdinalIgnoreCase));
}
catch (Exception)
{
@@ -419,24 +418,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
public Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
{
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
- string analyzeDuration = string.Empty;
- string ffmpegAnalyzeDuration = _config.GetFFmpegAnalyzeDuration() ?? string.Empty;
+ var analyzeDuration = string.Empty;
+ var ffmpegAnalyzeDuration = _config.GetFFmpegAnalyzeDuration() ?? string.Empty;
+ var ffmpegProbeSize = _config.GetFFmpegProbeSize() ?? string.Empty;
+ var extraArgs = string.Empty;
if (request.MediaSource.AnalyzeDurationMs > 0)
{
- analyzeDuration = "-analyzeduration " + (request.MediaSource.AnalyzeDurationMs * 1000).ToString();
+ analyzeDuration = "-analyzeduration " + (request.MediaSource.AnalyzeDurationMs * 1000);
}
else if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
analyzeDuration = "-analyzeduration " + ffmpegAnalyzeDuration;
}
+ if (!string.IsNullOrEmpty(analyzeDuration))
+ {
+ extraArgs = analyzeDuration;
+ }
+
+ if (!string.IsNullOrEmpty(ffmpegProbeSize))
+ {
+ extraArgs += " -probesize " + ffmpegProbeSize;
+ }
+
return GetMediaInfoInternal(
GetInputArgument(request.MediaSource.Path, request.MediaSource),
request.MediaSource.Path,
request.MediaSource.Protocol,
extractChapters,
- analyzeDuration,
+ extraArgs,
request.MediaType == DlnaProfileType.Audio,
request.MediaSource.VideoType,
cancellationToken);
@@ -513,7 +524,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
using (var processWrapper = new ProcessWrapper(process, this))
{
StartProcess(processWrapper);
- await process.StandardOutput.BaseStream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
+ using var reader = process.StandardOutput;
+ await reader.BaseStream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
memoryStream.Seek(0, SeekOrigin.Begin);
InternalMediaInfoResult result;
try
@@ -614,9 +626,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string GetImageResolutionParameter()
{
- string imageResolutionParameter;
-
- imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch
+ var imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch
{
ImageResolution.P144 => "256x144",
ImageResolution.P240 => "426x240",
@@ -641,15 +651,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
ArgumentException.ThrowIfNullOrEmpty(inputPath);
- var outputExtension = targetFormat switch
- {
- ImageFormat.Bmp => ".bmp",
- ImageFormat.Gif => ".gif",
- ImageFormat.Jpg => ".jpg",
- ImageFormat.Png => ".png",
- ImageFormat.Webp => ".webp",
- _ => ".jpg"
- };
+ var outputExtension = targetFormat?.GetExtension() ?? ".jpg";
var tempExtractPath = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + outputExtension);
Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath));
@@ -669,13 +671,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
var scaler = threedFormat switch
{
// hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
- Video3DFormat.HalfSideBySide => "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ Video3DFormat.HalfSideBySide => @"crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
// fsbs crop width in half,set the display aspect,crop out any black bars we may have made
- Video3DFormat.FullSideBySide => "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ Video3DFormat.FullSideBySide => @"crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
// htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made
- Video3DFormat.HalfTopAndBottom => "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ Video3DFormat.HalfTopAndBottom => @"crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
// ftab crop height in half, set the display aspect,crop out any black bars we may have made
- Video3DFormat.FullTopAndBottom => "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ Video3DFormat.FullTopAndBottom => @"crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
_ => "scale=trunc(iw*sar):ih"
};
@@ -751,11 +753,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
timeoutMs = enableHdrExtraction ? DefaultHdrImageExtractionTimeout : DefaultSdrImageExtractionTimeout;
}
- ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false);
-
- if (!ranToCompletion)
+ try
{
- StopProcess(processWrapper, 1000);
+ await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false);
+ ranToCompletion = true;
+ }
+ catch (OperationCanceledException)
+ {
+ process.Kill(true);
+ ranToCompletion = false;
}
}
finally
@@ -1024,7 +1030,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping
// We need to double escape
- return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", "'\\\\\\''", StringComparison.Ordinal);
+ return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", @"'\\\''", StringComparison.Ordinal);
}
/// <inheritdoc />
@@ -1167,7 +1173,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return true;
}
- private class ProcessWrapper : IDisposable
+ private sealed class ProcessWrapper : IDisposable
{
private readonly MediaEncoder _mediaEncoder;
@@ -1210,13 +1216,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_mediaEncoder._runningProcesses.Remove(this);
}
- try
- {
- process.Dispose();
- }
- catch
- {
- }
+ process.Dispose();
}
public void Dispose()