diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 590cdc33f0..1bdda8ad2f 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1604,7 +1604,7 @@ public class DynamicHlsController : BaseJellyfinApiController Path.GetFileNameWithoutExtension(outputPath)); } - var hlsArguments = GetHlsArguments(isEventPlaylist, state.SegmentLength); + var hlsArguments = $"-hls_playlist_type {(isEventPlaylist ? "event" : "vod")} -hls_list_size 0"; return string.Format( CultureInfo.InvariantCulture, @@ -1625,33 +1625,6 @@ public class DynamicHlsController : BaseJellyfinApiController EncodingUtils.NormalizePath(outputPath)).Trim(); } - /// - /// Gets the HLS arguments for transcoding. - /// - /// The command line arguments for HLS transcoding. - private string GetHlsArguments(bool isEventPlaylist, int segmentLength) - { - var enableThrottling = _encodingOptions.EnableThrottling; - var enableSegmentDeletion = _encodingOptions.EnableSegmentDeletion; - - // Only enable segment deletion when throttling is enabled - if (enableThrottling && enableSegmentDeletion) - { - // Store enough segments for configured seconds of playback; this needs to be above throttling settings - var segmentCount = _encodingOptions.SegmentKeepSeconds / segmentLength; - - _logger.LogDebug("Using throttling and segment deletion, keeping {0} segments", segmentCount); - - return string.Format(CultureInfo.InvariantCulture, "-hls_list_size {0} -hls_flags delete_segments", segmentCount.ToString(CultureInfo.InvariantCulture)); - } - else - { - _logger.LogDebug("Using normal playback, is event playlist? {0}", isEventPlaylist); - - return string.Format(CultureInfo.InvariantCulture, "-hls_playlist_type {0} -hls_list_size 0", isEventPlaylist ? "event" : "vod"); - } - } - /// /// Gets the audio arguments for transcoding. /// diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 946f7266c3..cdaa6a6cd2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -51,6 +51,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly Version _minFFmpegOclCuTonemapMode = new Version(5, 1, 3); private readonly Version _minFFmpegSvtAv1Params = new Version(5, 1); private readonly Version _minFFmpegVaapiH26xEncA53CcSei = new Version(6, 0); + private readonly Version _minFFmpegReadrateOption = new Version(5, 0); private static readonly string[] _videoProfilesH264 = new[] { @@ -1221,7 +1222,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Disable auto inserted SW scaler for HW decoders in case of changed resolution. var isSwDecoder = string.IsNullOrEmpty(GetHardwareVideoDecoder(state, options)); - if (!isSwDecoder && _mediaEncoder.EncoderVersion >= new Version(4, 4)) + if (!isSwDecoder) { arg.Append(" -noautoscale"); } @@ -6393,6 +6394,16 @@ namespace MediaBrowser.Controller.MediaEncoding { inputModifier += " -re"; } + else if (encodingOptions.EnableSegmentDeletion + && state.VideoStream is not null + && state.TranscodingType == TranscodingJobType.Hls + && IsCopyCodec(state.OutputVideoCodec) + && _mediaEncoder.EncoderVersion >= _minFFmpegReadrateOption) + { + // Set an input read rate limit 10x for using SegmentDeletion with stream-copy + // to prevent ffmpeg from exiting prematurely (due to fast drive) + inputModifier += " -readrate 10"; + } var flags = new List(); if (state.IgnoreInputDts) diff --git a/MediaBrowser.Controller/MediaEncoding/TranscodingJob.cs b/MediaBrowser.Controller/MediaEncoding/TranscodingJob.cs index 1e6d5933c8..2b6540ea88 100644 --- a/MediaBrowser.Controller/MediaEncoding/TranscodingJob.cs +++ b/MediaBrowser.Controller/MediaEncoding/TranscodingJob.cs @@ -136,6 +136,11 @@ public sealed class TranscodingJob : IDisposable /// public TranscodingThrottler? TranscodingThrottler { get; set; } + /// + /// Gets or sets transcoding segment cleaner. + /// + public TranscodingSegmentCleaner? TranscodingSegmentCleaner { get; set; } + /// /// Gets or sets last ping date. /// @@ -239,6 +244,7 @@ public sealed class TranscodingJob : IDisposable { #pragma warning disable CA1849 // Can't await in lock block TranscodingThrottler?.Stop().GetAwaiter().GetResult(); + TranscodingSegmentCleaner?.Stop(); var process = Process; @@ -276,5 +282,7 @@ public sealed class TranscodingJob : IDisposable CancellationTokenSource = null; TranscodingThrottler?.Dispose(); TranscodingThrottler = null; + TranscodingSegmentCleaner?.Dispose(); + TranscodingSegmentCleaner = null; } } diff --git a/MediaBrowser.Controller/MediaEncoding/TranscodingSegmentCleaner.cs b/MediaBrowser.Controller/MediaEncoding/TranscodingSegmentCleaner.cs new file mode 100644 index 0000000000..67bfcb02fd --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/TranscodingSegmentCleaner.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Controller.MediaEncoding; + +/// +/// Transcoding segment cleaner. +/// +public class TranscodingSegmentCleaner : IDisposable +{ + private readonly TranscodingJob _job; + private readonly ILogger _logger; + private readonly IConfigurationManager _config; + private readonly IFileSystem _fileSystem; + private readonly IMediaEncoder _mediaEncoder; + private Timer? _timer; + private int _segmentLength; + + /// + /// Initializes a new instance of the class. + /// + /// Transcoding job dto. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// The segment length of this transcoding job. + public TranscodingSegmentCleaner(TranscodingJob job, ILogger logger, IConfigurationManager config, IFileSystem fileSystem, IMediaEncoder mediaEncoder, int segmentLength) + { + _job = job; + _logger = logger; + _config = config; + _fileSystem = fileSystem; + _mediaEncoder = mediaEncoder; + _segmentLength = segmentLength; + } + + /// + /// Start timer. + /// + public void Start() + { + _timer = new Timer(TimerCallback, null, 20000, 20000); + } + + /// + /// Stop cleaner. + /// + public void Stop() + { + DisposeTimer(); + } + + /// + /// Dispose cleaner. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose cleaner. + /// + /// Disposing. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + DisposeTimer(); + } + } + + private EncodingOptions GetOptions() + { + return _config.GetEncodingOptions(); + } + + private async void TimerCallback(object? state) + { + if (_job.HasExited) + { + DisposeTimer(); + return; + } + + var options = GetOptions(); + var enableSegmentDeletion = options.EnableSegmentDeletion; + var segmentKeepSeconds = Math.Max(options.SegmentKeepSeconds, 20); + + if (enableSegmentDeletion) + { + var downloadPositionTicks = _job.DownloadPositionTicks ?? 0; + var downloadPositionSeconds = Convert.ToInt64(TimeSpan.FromTicks(downloadPositionTicks).TotalSeconds); + + if (downloadPositionSeconds > 0 && segmentKeepSeconds > 0 && downloadPositionSeconds > segmentKeepSeconds) + { + var idxMaxToDelete = (downloadPositionSeconds - segmentKeepSeconds) / _segmentLength; + + if (idxMaxToDelete > 0) + { + await DeleteSegmentFiles(_job, 0, idxMaxToDelete, 1500).ConfigureAwait(false); + } + } + } + } + + private async Task DeleteSegmentFiles(TranscodingJob job, long idxMin, long idxMax, int delayMs) + { + var path = job.Path ?? throw new ArgumentException("Path can't be null."); + + _logger.LogDebug("Deleting segment file(s) index {Min} to {Max} from {Path}", idxMin, idxMax, path); + + await Task.Delay(delayMs).ConfigureAwait(false); + + try + { + if (job.Type == TranscodingJobType.Hls) + { + DeleteHlsSegmentFiles(path, idxMin, idxMax); + } + } + catch (Exception ex) + { + _logger.LogDebug(ex, "Error deleting segment file(s) {Path}", path); + } + } + + private void DeleteHlsSegmentFiles(string outputFilePath, long idxMin, long idxMax) + { + var directory = Path.GetDirectoryName(outputFilePath) + ?? throw new ArgumentException("Path can't be a root directory.", nameof(outputFilePath)); + + var name = Path.GetFileNameWithoutExtension(outputFilePath); + + var filesToDelete = _fileSystem.GetFilePaths(directory) + .Where(f => long.TryParse(Path.GetFileNameWithoutExtension(f).Replace(name, string.Empty, StringComparison.Ordinal), out var idx) + && (idx >= idxMin && idx <= idxMax)); + + List? exs = null; + foreach (var file in filesToDelete) + { + try + { + _logger.LogDebug("Deleting HLS segment file {0}", file); + _fileSystem.DeleteFile(file); + } + catch (IOException ex) + { + (exs ??= new List()).Add(ex); + _logger.LogDebug(ex, "Error deleting HLS segment file {Path}", file); + } + } + + if (exs is not null) + { + throw new AggregateException("Error deleting HLS segment files", exs); + } + } + + private void DisposeTimer() + { + if (_timer is not null) + { + _timer.Dispose(); + _timer = null; + } + } +} diff --git a/MediaBrowser.Controller/MediaEncoding/TranscodingThrottler.cs b/MediaBrowser.Controller/MediaEncoding/TranscodingThrottler.cs index 813f13eaef..b95e6ed51f 100644 --- a/MediaBrowser.Controller/MediaEncoding/TranscodingThrottler.cs +++ b/MediaBrowser.Controller/MediaEncoding/TranscodingThrottler.cs @@ -115,7 +115,7 @@ public class TranscodingThrottler : IDisposable var options = GetOptions(); - if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleDelaySeconds)) + if (options.EnableThrottling && IsThrottleAllowed(_job, Math.Max(options.ThrottleDelaySeconds, 60))) { await PauseTranscoding().ConfigureAwait(false); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 6549125d36..6579f1abe5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -146,17 +146,18 @@ namespace MediaBrowser.MediaEncoding.Encoder { 5, new string[] { "overlay_vulkan", "Action to take when encountering EOF from secondary input" } } }; - // These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below + // These are the library versions that corresponds to our minimum ffmpeg version 4.4 according to the version table below + // Refers to the versions in https://ffmpeg.org/download.html private static readonly Dictionary _ffmpegMinimumLibraryVersions = new Dictionary { - { "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) } + { "libavutil", new Version(56, 70) }, + { "libavcodec", new Version(58, 134) }, + { "libavformat", new Version(58, 76) }, + { "libavdevice", new Version(58, 13) }, + { "libavfilter", new Version(7, 110) }, + { "libswscale", new Version(5, 9) }, + { "libswresample", new Version(3, 9) }, + { "libpostproc", new Version(55, 9) } }; private readonly ILogger _logger; @@ -176,7 +177,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } // When changing this, also change the minimum library versions in _ffmpegMinimumLibraryVersions - public static Version MinVersion { get; } = new Version(4, 0); + public static Version MinVersion { get; } = new Version(4, 4); public static Version? MaxVersion { get; } = null; diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index 5d51a901ad..a07a0f41bc 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -321,7 +321,7 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable } catch (IOException ex) { - (exs ??= new List(4)).Add(ex); + (exs ??= new List()).Add(ex); _logger.LogError(ex, "Error deleting HLS file {Path}", file); } } @@ -546,6 +546,7 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable if (!transcodingJob.HasExited) { StartThrottler(state, transcodingJob); + StartSegmentCleaner(state, transcodingJob); } else if (transcodingJob.ExitCode != 0) { @@ -573,6 +574,22 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable && state.IsInputVideo && state.VideoType == VideoType.VideoFile; + private void StartSegmentCleaner(StreamState state, TranscodingJob transcodingJob) + { + if (EnableSegmentCleaning(state)) + { + transcodingJob.TranscodingSegmentCleaner = new TranscodingSegmentCleaner(transcodingJob, _loggerFactory.CreateLogger(), _serverConfigurationManager, _fileSystem, _mediaEncoder, state.SegmentLength); + transcodingJob.TranscodingSegmentCleaner.Start(); + } + } + + private static bool EnableSegmentCleaning(StreamState state) + => state.InputProtocol is MediaProtocol.File or MediaProtocol.Http + && state.IsInputVideo + && state.TranscodingType == TranscodingJobType.Hls + && state.RunTimeTicks.HasValue + && state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks; + private TranscodingJob OnTranscodeBeginning( string path, string? playSessionId, diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs index db7e91c6a2..e0a7fa3aa7 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs @@ -17,16 +17,11 @@ namespace Jellyfin.MediaEncoding.Tests } [Theory] + [InlineData(EncoderValidatorTestsData.FFmpegV611Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV60Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV512Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV44Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV432Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV431Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV43Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV421Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV42Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV414Output, true)] - [InlineData(EncoderValidatorTestsData.FFmpegV404Output, true)] + [InlineData(EncoderValidatorTestsData.FFmpegV432Output, false)] [InlineData(EncoderValidatorTestsData.FFmpegGitUnknownOutput2, true)] [InlineData(EncoderValidatorTestsData.FFmpegGitUnknownOutput, false)] public void ValidateVersionInternalTest(string versionOutput, bool valid) @@ -38,17 +33,12 @@ namespace Jellyfin.MediaEncoding.Tests { public GetFFmpegVersionTestData() { + Add(EncoderValidatorTestsData.FFmpegV611Output, new Version(6, 1, 1)); Add(EncoderValidatorTestsData.FFmpegV60Output, new Version(6, 0)); Add(EncoderValidatorTestsData.FFmpegV512Output, new Version(5, 1, 2)); Add(EncoderValidatorTestsData.FFmpegV44Output, new Version(4, 4)); Add(EncoderValidatorTestsData.FFmpegV432Output, new Version(4, 3, 2)); - Add(EncoderValidatorTestsData.FFmpegV431Output, new Version(4, 3, 1)); - Add(EncoderValidatorTestsData.FFmpegV43Output, new Version(4, 3)); - Add(EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1)); - Add(EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2)); - Add(EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4)); - Add(EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4)); - Add(EncoderValidatorTestsData.FFmpegGitUnknownOutput2, new Version(4, 0)); + Add(EncoderValidatorTestsData.FFmpegGitUnknownOutput2, new Version(4, 4)); Add(EncoderValidatorTestsData.FFmpegGitUnknownOutput, null); } } diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs index 89ba42da0c..30df949505 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs @@ -2,6 +2,18 @@ namespace Jellyfin.MediaEncoding.Tests { internal static class EncoderValidatorTestsData { + public const string FFmpegV611Output = @"ffmpeg version n6.1.1-16-g33efa50fa4-20240317 Copyright (c) 2000-2023 the FFmpeg developers +built with gcc 13.2.0 (crosstool-NG 1.26.0.65_ecc5e41) +configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-shared --disable-static --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libharfbuzz --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libaribcaption --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --enable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags='$FF_CFLAGS' --extra-cxxflags='$FF_CXXFLAGS' --extra-ldflags='$FF_LDFLAGS' --extra-ldexeflags='$FF_LDEXEFLAGS' --extra-libs='$FF_LIBS' --extra-version=20240317 +libavutil 58. 29.100 / 58. 29.100 +libavcodec 60. 31.102 / 60. 31.102 +libavformat 60. 16.100 / 60. 16.100 +libavdevice 60. 3.100 / 60. 3.100 +libavfilter 9. 12.100 / 9. 12.100 +libswscale 7. 5.100 / 7. 5.100 +libswresample 4. 12.100 / 4. 12.100 +libpostproc 57. 3.100 / 57. 3.100"; + public const string FFmpegV60Output = @"ffmpeg version 6.0-Jellyfin Copyright (c) 2000-2023 the FFmpeg developers built with gcc 12.2.0 (crosstool-NG 1.25.0.90_cf9beb1) configuration: --prefix=/ffbuild/prefix --pkg-config=pkg-config --pkg-config-flags=--static --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --extra-version=Jellyfin --extra-cflags= --extra-cxxflags= --extra-ldflags= --extra-ldexeflags= --extra-libs= --enable-gpl --enable-version3 --enable-lto --disable-ffplay --disable-debug --disable-doc --disable-ptx-compression --disable-sdl2 --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --enable-amf --enable-chromaprint --enable-libdav1d --enable-dxva2 --enable-d3d11va --enable-libfdk-aac --enable-ffnvcodec --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvdec --enable-nvenc --enable-libass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvpx --enable-libwebp --enable-libvpl --enable-schannel --enable-libsrt --enable-libsvtav1 --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libzimg --enable-libzvbi @@ -50,90 +62,17 @@ libswscale 5. 7.100 / 5. 7.100 libswresample 3. 7.100 / 3. 7.100 libpostproc 55. 7.100 / 55. 7.100"; - public const string FFmpegV431Output = @"ffmpeg version n4.3.1 Copyright (c) 2000-2020 the FFmpeg developers -built with gcc 10.1.0 (GCC) -configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-avisynth --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3 -libavutil 56. 51.100 / 56. 51.100 -libavcodec 58. 91.100 / 58. 91.100 -libavformat 58. 45.100 / 58. 45.100 -libavdevice 58. 10.100 / 58. 10.100 -libavfilter 7. 85.100 / 7. 85.100 -libswscale 5. 7.100 / 5. 7.100 -libswresample 3. 7.100 / 3. 7.100 -libpostproc 55. 7.100 / 55. 7.100"; - - public const string FFmpegV43Output = @"ffmpeg version 4.3 Copyright (c) 2000-2020 the FFmpeg developers -built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04) -configuration: --prefix=/usr/lib/jellyfin-ffmpeg --target-os=linux --disable-doc --disable-ffplay --disable-shared --disable-libxcb --disable-vdpau --disable-sdl2 --disable-xlib --enable-gpl --enable-version3 --enable-static --enable-libfontconfig --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libx264 --enable-libx265 --enable-libzvbi --arch=amd64 --enable-amf --enable-nvenc --enable-nvdec --enable-vaapi --enable-opencl -libavutil 56. 51.100 / 56. 51.100 -libavcodec 58. 91.100 / 58. 91.100 -libavformat 58. 45.100 / 58. 45.100 -libavdevice 58. 10.100 / 58. 10.100 -libavfilter 7. 85.100 / 7. 85.100 -libswscale 5. 7.100 / 5. 7.100 -libswresample 3. 7.100 / 3. 7.100 -libpostproc 55. 7.100 / 55. 7.100"; - - public const string FFmpegV421Output = @"ffmpeg version 4.2.1 Copyright (c) 2000-2019 the FFmpeg developers -built with gcc 9.1.1 (GCC) 20190807 -configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt -libavutil 56. 31.100 / 56. 31.100 -libavcodec 58. 54.100 / 58. 54.100 -libavformat 58. 29.100 / 58. 29.100 -libavdevice 58. 8.100 / 58. 8.100 -libavfilter 7. 57.100 / 7. 57.100 -libswscale 5. 5.100 / 5. 5.100 -libswresample 3. 5.100 / 3. 5.100 -libpostproc 55. 5.100 / 55. 5.100"; - - public const string FFmpegV42Output = @"ffmpeg version n4.2 Copyright (c) 2000-2019 the FFmpeg developers -built with gcc 9.1.0 (GCC) -configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3 -libavutil 56. 31.100 / 56. 31.100 -libavcodec 58. 54.100 / 58. 54.100 -libavformat 58. 29.100 / 58. 29.100 -libavdevice 58. 8.100 / 58. 8.100 -libavfilter 7. 57.100 / 7. 57.100 -libswscale 5. 5.100 / 5. 5.100 -libswresample 3. 5.100 / 3. 5.100 -libpostproc 55. 5.100 / 55. 5.100"; - - public const string FFmpegV414Output = @"ffmpeg version 4.1.4-1~deb10u1 Copyright (c) 2000-2019 the FFmpeg developers -built with gcc 8 (Raspbian 8.3.0-6+rpi1) -configuration: --prefix=/usr --extra-version='1~deb10u1' --toolchain=hardened --libdir=/usr/lib/arm-linux-gnueabihf --incdir=/usr/include/arm-linux-gnueabihf --arch=arm --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared -libavutil 56. 22.100 / 56. 22.100 -libavcodec 58. 35.100 / 58. 35.100 -libavformat 58. 20.100 / 58. 20.100 -libavdevice 58. 5.100 / 58. 5.100 -libavfilter 7. 40.101 / 7. 40.101 -libavresample 4. 0. 0 / 4. 0. 0 -libswscale 5. 3.100 / 5. 3.100 -libswresample 3. 3.100 / 3. 3.100 -libpostproc 55. 3.100 / 55. 3.100"; - - public const string FFmpegV404Output = @"ffmpeg version 4.0.4 Copyright (c) 2000-2019 the FFmpeg developers -built with gcc 8 (Debian 8.3.0-6) -configuration: --toolchain=hardened --prefix=/usr --target-os=linux --enable-cross-compile --extra-cflags=--static --enable-gpl --enable-static --disable-doc --disable-ffplay --disable-shared --disable-libxcb --disable-sdl2 --disable-xlib --enable-libfontconfig --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libx264 --enable-libx265 --enable-libzvbi --enable-omx --enable-omx-rpi --enable-version3 --enable-vaapi --enable-vdpau --arch=amd64 --enable-nvenc --enable-nvdec -libavutil 56. 14.100 / 56. 14.100 -libavcodec 58. 18.100 / 58. 18.100 -libavformat 58. 12.100 / 58. 12.100 -libavdevice 58. 3.100 / 58. 3.100 -libavfilter 7. 16.100 / 7. 16.100 -libswscale 5. 1.100 / 5. 1.100 -libswresample 3. 1.100 / 3. 1.100 -libpostproc 55. 1.100 / 55. 1.100"; - - public const string FFmpegGitUnknownOutput2 = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers -built with gcc 9.1.1 (GCC) 20190716 -configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt -libavutil 56. 30.100 / 56. 30.100 -libavcodec 58. 53.101 / 58. 53.101 -libavformat 58. 28.102 / 58. 28.102 -libavdevice 58. 7.100 / 58. 7.100 -libavfilter 7. 56.101 / 7. 56.101 -libswscale 5. 4.101 / 5. 4.101 -libswresample 3. 4.100 / 3. 4.100 -libpostproc 55. 4.100 / 55. 4.100"; + public const string FFmpegGitUnknownOutput2 = @"ffmpeg version N-g01fc3034ee-20240317 Copyright (c) 2000-2023 the FFmpeg developers +built with gcc 13.2.0 (crosstool-NG 1.26.0.65_ecc5e41) +configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-shared --disable-static --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --disable-libpulse --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --disable-chromaprint --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --disable-frei0r --enable-libgme --enable-libkvazaar --enable-libass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --disable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --disable-vaapi --enable-libvidstab --disable-vulkan --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags='$FF_CFLAGS' --extra-cxxflags='$FF_CXXFLAGS' --extra-ldflags='$FF_LDFLAGS' --extra-ldexeflags='$FF_LDEXEFLAGS' --extra-libs='$FF_LIBS' --extra-version=20240317 +libavutil 56. 70.100 / 56. 70.100 +libavcodec 58.134.100 / 58.134.100 +libavformat 58. 76.100 / 58. 76.100 +libavdevice 58. 13.100 / 58. 13.100 +libavfilter 7.110.100 / 7.110.100 +libswscale 5. 9.100 / 5. 9.100 +libswresample 3. 9.100 / 3. 9.100 +libpostproc 55. 9.100 / 55. 9.100"; public const string FFmpegGitUnknownOutput = @"ffmpeg version N-45325-gb173e0353-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2018 the FFmpeg developers built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516