mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-13 12:33:01 +03:00
Merge branch 'master' into sort-nfo-data
This commit is contained in:
@@ -84,7 +84,7 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
|
||||
/// Gets the files matching a pattern.
|
||||
/// </summary>
|
||||
/// <param name="searchPattern">The search pattern.</param>
|
||||
/// <returns>All files of the directory matchign the search pattern.</returns>
|
||||
/// <returns>All files of the directory matching the search pattern.</returns>
|
||||
public IFileInfo[] GetFiles(string searchPattern)
|
||||
{
|
||||
return _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false)
|
||||
@@ -96,8 +96,8 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
|
||||
/// Gets the files matching a pattern and search options.
|
||||
/// </summary>
|
||||
/// <param name="searchPattern">The search pattern.</param>
|
||||
/// <param name="searchOption">The search optin.</param>
|
||||
/// <returns>All files of the directory matchign the search pattern and options.</returns>
|
||||
/// <param name="searchOption">The search option.</param>
|
||||
/// <returns>All files of the directory matching the search pattern and options.</returns>
|
||||
public IFileInfo[] GetFiles(string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
return _fileSystem.GetFiles(
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
private static readonly Dictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
|
||||
{
|
||||
{ 0, new string[] { "scale_cuda", "Output format (default \"same\")" } },
|
||||
{ 0, new string[] { "scale_cuda", "format" } },
|
||||
{ 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } },
|
||||
{ 2, new string[] { "tonemap_opencl", "bt2390" } },
|
||||
{ 3, new string[] { "overlay_opencl", "Action to take when encountering EOF from secondary input" } },
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
private readonly AsyncNonKeyedLocker _thumbnailResourcePool;
|
||||
|
||||
private readonly object _runningProcessesLock = new object();
|
||||
private readonly Lock _runningProcessesLock = new();
|
||||
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
||||
|
||||
// MediaEncoder is registered as a Singleton
|
||||
@@ -650,6 +650,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(inputPath);
|
||||
|
||||
var useTradeoff = _config.GetFFmpegImgExtractPerfTradeoff();
|
||||
|
||||
var outputExtension = targetFormat?.GetExtension() ?? ".jpg";
|
||||
|
||||
var tempExtractPath = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + outputExtension);
|
||||
@@ -684,7 +686,7 @@ 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.
|
||||
// mpegts need larger batch size otherwise the corrupted thumbnail will be created. Larger batch size will lower the processing speed.
|
||||
var enableThumbnail = useIFrame && !string.Equals("wtv", container, StringComparison.OrdinalIgnoreCase);
|
||||
var enableThumbnail = !useTradeoff && useIFrame && !string.Equals("wtv", container, StringComparison.OrdinalIgnoreCase);
|
||||
if (enableThumbnail)
|
||||
{
|
||||
var useLargerBatchSize = string.Equals("mpegts", container, StringComparison.OrdinalIgnoreCase);
|
||||
@@ -699,8 +701,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
{
|
||||
if (SupportsFilter("tonemapx"))
|
||||
{
|
||||
var peak = videoStream.VideoRangeType == VideoRangeType.DOVI ? "400" : "100";
|
||||
enableHdrExtraction = true;
|
||||
filters.Add("tonemapx=tonemap=bt2390:desat=0:peak=100:t=bt709:m=bt709:p=bt709:format=yuv420p");
|
||||
filters.Add($"tonemapx=tonemap=bt2390:desat=0:peak={peak}:t=bt709:m=bt709:p=bt709:format=yuv420p");
|
||||
}
|
||||
else if (SupportsFilter("zscale") && videoStream.VideoRangeType != VideoRangeType.DOVI)
|
||||
{
|
||||
@@ -718,6 +721,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
args = string.Format(CultureInfo.InvariantCulture, "-ss {0} ", GetTimeParameter(offset.Value)) + args;
|
||||
}
|
||||
|
||||
if (useIFrame && useTradeoff)
|
||||
{
|
||||
args = "-skip_frame nokey " + args;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(container))
|
||||
{
|
||||
var inputFormat = EncodingHelper.GetInputFormat(container);
|
||||
@@ -804,7 +812,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|| (hardwareAccelerationType == HardwareAccelerationType.amf && OperatingSystem.IsWindows())
|
||||
|| (hardwareAccelerationType == HardwareAccelerationType.qsv && options.PreferSystemNativeHwDecoder)
|
||||
|| hardwareAccelerationType == HardwareAccelerationType.vaapi
|
||||
|| hardwareAccelerationType == HardwareAccelerationType.videotoolbox;
|
||||
|| hardwareAccelerationType == HardwareAccelerationType.videotoolbox
|
||||
|| hardwareAccelerationType == HardwareAccelerationType.rkmpp;
|
||||
if (!supportsKeyFrameOnly)
|
||||
{
|
||||
// Disable hardware acceleration when the hardware decoder does not support keyframe only mode.
|
||||
@@ -930,13 +939,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
// Final command arguments
|
||||
var args = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"-loglevel error {0} -an -sn {1} -threads {2} -c:v {3} {4}{5}-f {6} \"{7}\"",
|
||||
"-loglevel error {0} -an -sn {1} -threads {2} -c:v {3} {4}{5}{6}-f {7} \"{8}\"",
|
||||
inputArg,
|
||||
filterParam,
|
||||
outputThreads.GetValueOrDefault(_threads),
|
||||
vidEncoder,
|
||||
encoderQualityOption + encoderQuality + " ",
|
||||
vidEncoder.Contains("videotoolbox", StringComparison.InvariantCultureIgnoreCase) ? "-allow_sw 1 " : string.Empty, // allow_sw fallback for some intel macs
|
||||
EncodingHelper.GetVideoSyncOption("0", EncoderVersion).Trim() + " ", // passthrough timestamp
|
||||
"image2",
|
||||
outputPath);
|
||||
|
||||
@@ -1025,6 +1035,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
if (exitCode == -1)
|
||||
{
|
||||
_logger.LogError("ffmpeg image extraction failed for {ProcessDescription}", processDescription);
|
||||
// Cleanup temp folder here, because the targetDirectory is not returned and the cleanup for failed ffmpeg process is not possible for caller.
|
||||
// Ideally the ffmpeg should not write any files if it fails, but it seems like it is not guaranteed.
|
||||
try
|
||||
{
|
||||
Directory.Delete(targetDirectory, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Failed to delete ffmpeg temp directory {TargetDirectory}", targetDirectory);
|
||||
}
|
||||
|
||||
throw new FfmpegException(string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", processDescription));
|
||||
}
|
||||
@@ -1081,14 +1101,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
private void StopProcesses()
|
||||
{
|
||||
List<ProcessWrapper> proceses;
|
||||
List<ProcessWrapper> processes;
|
||||
lock (_runningProcessesLock)
|
||||
{
|
||||
proceses = _runningProcesses.ToList();
|
||||
processes = _runningProcesses.ToList();
|
||||
_runningProcesses.Clear();
|
||||
}
|
||||
|
||||
foreach (var process in proceses)
|
||||
foreach (var process in processes)
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
@@ -1102,7 +1122,11 @@ 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)
|
||||
.Replace("\"", "\\\"", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||
|
||||
if (result.Streams is not null)
|
||||
{
|
||||
// Convert all dictionaries to case insensitive
|
||||
// Convert all dictionaries to case-insensitive
|
||||
foreach (var stream in result.Streams)
|
||||
{
|
||||
if (stream.Tags is not null)
|
||||
@@ -70,7 +70,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a dictionary to case insensitive.
|
||||
/// Converts a dictionary to case-insensitive.
|
||||
/// </summary>
|
||||
/// <param name="dict">The dict.</param>
|
||||
/// <returns>Dictionary{System.StringSystem.String}.</returns>
|
||||
|
||||
@@ -1652,7 +1652,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||
|
||||
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1))
|
||||
{
|
||||
fs.Read(packetBuffer);
|
||||
fs.ReadExactly(packetBuffer);
|
||||
}
|
||||
|
||||
if (packetBuffer[0] == 71)
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
public class SubtitleEditParser : ISubtitleParser
|
||||
{
|
||||
private readonly ILogger<SubtitleEditParser> _logger;
|
||||
private readonly Dictionary<string, SubtitleFormat[]> _subtitleFormats;
|
||||
private readonly Dictionary<string, List<Type>> _subtitleFormatTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubtitleEditParser"/> class.
|
||||
@@ -26,10 +26,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
public SubtitleEditParser(ILogger<SubtitleEditParser> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_subtitleFormats = GetSubtitleFormats()
|
||||
.Where(subtitleFormat => !string.IsNullOrEmpty(subtitleFormat.Extension))
|
||||
.GroupBy(subtitleFormat => subtitleFormat.Extension.TrimStart('.'), StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(g => g.Key, g => g.ToArray(), StringComparer.OrdinalIgnoreCase);
|
||||
_subtitleFormatTypes = GetSubtitleFormatTypes();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -38,13 +35,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
var subtitle = new Subtitle();
|
||||
var lines = stream.ReadAllLines().ToList();
|
||||
|
||||
if (!_subtitleFormats.TryGetValue(fileExtension, out var subtitleFormats))
|
||||
if (!_subtitleFormatTypes.TryGetValue(fileExtension, out var subtitleFormatTypesForExtension))
|
||||
{
|
||||
throw new ArgumentException($"Unsupported file extension: {fileExtension}", nameof(fileExtension));
|
||||
}
|
||||
|
||||
foreach (var subtitleFormat in subtitleFormats)
|
||||
foreach (var subtitleFormatType in subtitleFormatTypesForExtension)
|
||||
{
|
||||
var subtitleFormat = (SubtitleFormat)Activator.CreateInstance(subtitleFormatType, true)!;
|
||||
_logger.LogDebug(
|
||||
"Trying to parse '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser",
|
||||
fileExtension,
|
||||
@@ -97,11 +95,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SupportsFileExtension(string fileExtension)
|
||||
=> _subtitleFormats.ContainsKey(fileExtension);
|
||||
=> _subtitleFormatTypes.ContainsKey(fileExtension);
|
||||
|
||||
private List<SubtitleFormat> GetSubtitleFormats()
|
||||
private Dictionary<string, List<Type>> GetSubtitleFormatTypes()
|
||||
{
|
||||
var subtitleFormats = new List<SubtitleFormat>();
|
||||
var subtitleFormatTypes = new Dictionary<string, List<Type>>(StringComparer.OrdinalIgnoreCase);
|
||||
var assembly = typeof(SubtitleFormat).Assembly;
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
@@ -113,9 +111,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
try
|
||||
{
|
||||
// It shouldn't be null, but the exception is caught if it is
|
||||
var subtitleFormat = (SubtitleFormat)Activator.CreateInstance(type, true)!;
|
||||
subtitleFormats.Add(subtitleFormat);
|
||||
var tempInstance = (SubtitleFormat)Activator.CreateInstance(type, true)!;
|
||||
var extension = tempInstance.Extension.TrimStart('.');
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
// Store only the type, we will instantiate from it later
|
||||
if (!subtitleFormatTypes.TryGetValue(extension, out var subtitleFormatTypesForExtension))
|
||||
{
|
||||
subtitleFormatTypes[extension] = [type];
|
||||
}
|
||||
else
|
||||
{
|
||||
subtitleFormatTypesForExtension.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -123,7 +132,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
}
|
||||
}
|
||||
|
||||
return subtitleFormats;
|
||||
return subtitleFormatTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user