diff options
| -rw-r--r-- | .github/workflows/ci-compat.yml (renamed from .github/workflows/compat.yml) | 16 | ||||
| -rw-r--r-- | CONTRIBUTORS.md | 1 | ||||
| -rw-r--r-- | Directory.Packages.props | 6 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Localization/Core/de.json | 4 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Localization/Core/fa.json | 6 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Localization/Core/it.json | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 94 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs | 23 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Subtitles/SubtitleFormatExtensions.cs | 29 |
9 files changed, 148 insertions, 35 deletions
diff --git a/.github/workflows/compat.yml b/.github/workflows/ci-compat.yml index 058a09749..12532a13b 100644 --- a/.github/workflows/compat.yml +++ b/.github/workflows/ci-compat.yml @@ -12,7 +12,7 @@ jobs: permissions: read-all steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} @@ -22,7 +22,7 @@ jobs: dotnet build Jellyfin.Server -o ./out - name: Upload Head - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: abi-head retention-days: 14 @@ -36,7 +36,7 @@ jobs: permissions: read-all steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} @@ -56,7 +56,7 @@ jobs: dotnet build Jellyfin.Server -o ./out - name: Upload Head - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: abi-base retention-days: 14 @@ -75,13 +75,13 @@ jobs: steps: - name: Download abi-head - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: abi-head path: abi-head - name: Download abi-base - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: abi-base path: abi-base @@ -105,7 +105,7 @@ jobs: } >> $GITHUB_OUTPUT - name: Find difference comment - uses: peter-evans/find-comment@d5fe37641ad8451bdd80312415672ba26c86575e # v3.0.0 + uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0 id: find-comment with: issue-number: ${{ github.event.pull_request.number }} @@ -119,7 +119,6 @@ jobs: issue-number: ${{ github.event.pull_request.number }} comment-id: ${{ steps.find-comment.outputs.comment-id }} edit-mode: replace - token: ${{ secrets.JF_BOT_TOKEN }} body: | <!--abi-diff-workflow-comment--> <details> @@ -138,7 +137,6 @@ jobs: issue-number: ${{ github.event.pull_request.number }} comment-id: ${{ steps.find-comment.outputs.comment-id }} edit-mode: replace - token: ${{ secrets.JF_BOT_TOKEN }} body: | <!--abi-diff-workflow-comment--> <details> diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 7c2e72327..cdf8df17f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -187,6 +187,7 @@ - [HonestlyWhoKnows](https://github.com/honestlywhoknows) - [TheMelmacian](https://github.com/TheMelmacian) - [ItsAllAboutTheCode](https://github.com/ItsAllAboutTheCode) + - [pret0rian8](https://github.com/pret0rian) # Emby Contributors diff --git a/Directory.Packages.props b/Directory.Packages.props index 17bd969b5..02937b193 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,8 +9,8 @@ <PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1" /> <PackageVersion Include="AutoFixture" Version="4.18.1" /> <PackageVersion Include="BDInfo" Version="0.8.0" /> - <PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.3.2" /> - <PackageVersion Include="BlurHashSharp" Version="1.3.2" /> + <PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.3.3" /> + <PackageVersion Include="BlurHashSharp" Version="1.3.3" /> <PackageVersion Include="CommandLineParser" Version="2.9.1" /> <PackageVersion Include="coverlet.collector" Version="6.0.2" /> <PackageVersion Include="Diacritics" Version="3.3.29" /> @@ -21,7 +21,7 @@ <PackageVersion Include="ICU4N.Transliterator" Version="60.1.0-alpha.356" /> <PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" /> <PackageVersion Include="Jellyfin.XmlTv" Version="10.8.0" /> - <PackageVersion Include="libse" Version="4.0.7" /> + <PackageVersion Include="libse" Version="4.0.8" /> <PackageVersion Include="LrcParser" Version="2024.0728.2" /> <PackageVersion Include="MetaBrainz.MusicBrainz" Version="6.1.0" /> <PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.8" /> diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json index 865a1ef95..bbb162c77 100644 --- a/Emby.Server.Implementations/Localization/Core/de.json +++ b/Emby.Server.Implementations/Localization/Core/de.json @@ -131,6 +131,6 @@ "TaskCleanCollectionsAndPlaylistsDescription": "Lösche nicht mehr vorhandene Einträge aus den Sammlungen und Playlisten.", "TaskAudioNormalization": "Audio Normalisierung", "TaskAudioNormalizationDescription": "Durchsucht Dateien nach Audionormalisierungsdaten.", - "TaskDownloadMissingLyricsDescription": "Lädt Liedtexte herunter", - "TaskDownloadMissingLyrics": "Fehlende Liedtexte herunterladen" + "TaskDownloadMissingLyricsDescription": "Lädt Songtexte herunter", + "TaskDownloadMissingLyrics": "Fehlende Songtexte herunterladen" } diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json index ce5177d1f..b0ddec104 100644 --- a/Emby.Server.Implementations/Localization/Core/fa.json +++ b/Emby.Server.Implementations/Localization/Core/fa.json @@ -128,5 +128,9 @@ "TaskRefreshTrickplayImages": "تولید تصاویر Trickplay", "TaskRefreshTrickplayImagesDescription": "تولید پیشنمایش های trickplay برای ویدیو های فعال شده در کتابخانه.", "TaskCleanCollectionsAndPlaylists": "پاکسازی مجموعه ها و لیست پخش", - "TaskCleanCollectionsAndPlaylistsDescription": "موارد را از مجموعه ها و لیست پخش هایی که دیگر وجود ندارند حذف میکند." + "TaskCleanCollectionsAndPlaylistsDescription": "موارد را از مجموعه ها و لیست پخش هایی که دیگر وجود ندارند حذف میکند.", + "TaskAudioNormalizationDescription": "بررسی فایل برای دادههای نرمال کردن صدا.", + "TaskDownloadMissingLyrics": "دانلود متنهای ناموجود", + "TaskDownloadMissingLyricsDescription": "دانلود متن شعرها", + "TaskAudioNormalization": "نرمال کردن صدا" } diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json index 0e694af02..961d1a0df 100644 --- a/Emby.Server.Implementations/Localization/Core/it.json +++ b/Emby.Server.Implementations/Localization/Core/it.json @@ -130,5 +130,7 @@ "TaskCleanCollectionsAndPlaylists": "Ripulire le collezioni e le playlist", "TaskCleanCollectionsAndPlaylistsDescription": "Rimuove gli elementi dalle collezioni e dalle playlist che non esistono più.", "TaskAudioNormalization": "Normalizzazione dell'audio", - "TaskAudioNormalizationDescription": "Scansiona i file alla ricerca dei dati per la normalizzazione dell'audio." + "TaskAudioNormalizationDescription": "Scansiona i file alla ricerca dei dati per la normalizzazione dell'audio.", + "TaskDownloadMissingLyricsDescription": "Scarica testi per le canzoni", + "TaskDownloadMissingLyrics": "Scarica testi mancanti" } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 27bf86edc..24cd141dc 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -68,6 +68,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly Version _minFFmpegDisplayRotationOption = new Version(6, 0); private readonly Version _minFFmpegAdvancedTonemapMode = new Version(7, 0, 1); private readonly Version _minFFmpegAlteredVaVkInterop = new Version(7, 0, 1); + private readonly Version _minFFmpegQsvVppTonemapOption = new Version(7, 0, 1); private static readonly Regex _validationRegex = new(ValidationRegex, RegexOptions.Compiled); @@ -348,7 +349,7 @@ namespace MediaBrowser.Controller.MediaEncoding && GetVideoColorBitDepth(state) == 10; } - private bool IsVaapiVppTonemapAvailable(EncodingJobInfo state, EncodingOptions options) + private bool IsIntelVppTonemapAvailable(EncodingJobInfo state, EncodingOptions options) { if (state.VideoStream is null || !options.EnableVppTonemapping @@ -357,7 +358,14 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - // Native VPP tonemapping may come to QSV in the future. + // prefer 'tonemap_vaapi' over 'vpp_qsv' on Linux for supporting Gen9/KBLx. + // 'vpp_qsv' requires VPL, which is only supported on Gen12/TGLx and newer. + if (OperatingSystem.IsWindows() + && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) + && _mediaEncoder.EncoderVersion < _minFFmpegQsvVppTonemapOption) + { + return false; + } return state.VideoStream.VideoRange == VideoRange.HDR && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 @@ -1662,7 +1670,7 @@ namespace MediaBrowser.Controller.MediaEncoding var doOclTonemap = _mediaEncoder.SupportsHwaccel("qsv") && IsVaapiSupported(state) && IsOpenclFullSupported() - && !IsVaapiVppTonemapAvailable(state, encodingOptions) + && !IsIntelVppTonemapAvailable(state, encodingOptions) && IsHwTonemapAvailable(state, encodingOptions); enableWaFori915Hang = isIntelDecoder && doOclTonemap; @@ -3285,14 +3293,31 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(hwTonemapSuffix, "vaapi", StringComparison.OrdinalIgnoreCase)) { - args = "procamp_vaapi=b={1}:c={2},tonemap_vaapi=format={0}:p=bt709:t=bt709:m=bt709:extra_hw_frames=32"; + var doVaVppProcamp = false; + var procampParams = string.Empty; + if (options.VppTonemappingBrightness != 0 + && options.VppTonemappingBrightness >= -100 + && options.VppTonemappingBrightness <= 100) + { + procampParams += $"=b={options.VppTonemappingBrightness}"; + doVaVppProcamp = true; + } + + if (options.VppTonemappingContrast > 1 + && options.VppTonemappingContrast <= 10) + { + procampParams += doVaVppProcamp ? ":" : "="; + procampParams += $"c={options.VppTonemappingContrast}"; + doVaVppProcamp = true; + } + + args = "{0}tonemap_vaapi=format={1}:p=bt709:t=bt709:m=bt709:extra_hw_frames=32"; return string.Format( CultureInfo.InvariantCulture, args, - videoFormat ?? "nv12", - options.VppTonemappingBrightness, - options.VppTonemappingContrast); + doVaVppProcamp ? $"procamp_vaapi{procampParams}," : string.Empty, + videoFormat ?? "nv12"); } else { @@ -4016,7 +4041,9 @@ namespace MediaBrowser.Controller.MediaEncoding var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); var doDeintH2645 = doDeintH264 || doDeintHevc; - var doOclTonemap = IsHwTonemapAvailable(state, options); + var doVppTonemap = IsIntelVppTonemapAvailable(state, options); + var doOclTonemap = !doVppTonemap && IsHwTonemapAvailable(state, options); + var doTonemap = doVppTonemap || doOclTonemap; var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream; @@ -4035,7 +4062,7 @@ namespace MediaBrowser.Controller.MediaEncoding /* Make main filters for video stream */ var mainFilters = new List<string>(); - mainFilters.Add(GetOverwriteColorPropertiesParam(state, doOclTonemap)); + mainFilters.Add(GetOverwriteColorPropertiesParam(state, doTonemap)); if (isSwDecoder) { @@ -4063,9 +4090,33 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (isD3d11vaDecoder || isQsvDecoder) { + var doVppProcamp = false; + var procampParams = string.Empty; + if (doVppTonemap) + { + if (options.VppTonemappingBrightness != 0 + && options.VppTonemappingBrightness >= -100 + && options.VppTonemappingBrightness <= 100) + { + procampParams += $":brightness={options.VppTonemappingBrightness}"; + doVppProcamp = true; + } + + if (options.VppTonemappingContrast > 1 + && options.VppTonemappingContrast <= 10) + { + procampParams += $":contrast={options.VppTonemappingContrast}"; + doVppProcamp = true; + } + + procampParams += doVppProcamp ? ":procamp=1:async_depth=2" : string.Empty; + } + var outFormat = doOclTonemap ? (doVppTranspose ? "p010" : string.Empty) : "nv12"; + outFormat = (doVppTonemap && doVppProcamp) ? "p010" : outFormat; + var swapOutputWandH = doVppTranspose && swapWAndH; - var hwScalePrefix = doVppTranspose ? "vpp" : "scale"; + var hwScalePrefix = (doVppTranspose || doVppTonemap) ? "vpp" : "scale"; var hwScaleFilter = GetHwScaleFilter(hwScalePrefix, "qsv", outFormat, swapOutputWandH, swpInW, swpInH, reqW, reqH, reqMaxW, reqMaxH); if (!string.IsNullOrEmpty(hwScaleFilter) && doVppTranspose) @@ -4073,6 +4124,11 @@ namespace MediaBrowser.Controller.MediaEncoding hwScaleFilter += $":transpose={tranposeDir}"; } + if (!string.IsNullOrEmpty(hwScaleFilter) && doVppTonemap) + { + hwScaleFilter += doVppProcamp ? procampParams : ":tonemap=1"; + } + if (isD3d11vaDecoder) { if (!string.IsNullOrEmpty(hwScaleFilter) || doDeintH2645) @@ -4090,8 +4146,20 @@ namespace MediaBrowser.Controller.MediaEncoding mainFilters.Add(deintFilter); } - // hw transpose & scale + // hw transpose & scale & tonemap(w/o procamp) mainFilters.Add(hwScaleFilter); + + // hw tonemap(w/ procamp) + if (doVppTonemap && doVppProcamp) + { + mainFilters.Add("vpp_qsv=tonemap=1:format=nv12:async_depth=2"); + } + + // force bt709 just in case vpp tonemap is not triggered or using MSDK instead of VPL. + if (doVppTonemap) + { + mainFilters.Add(GetOverwriteColorPropertiesParam(state, false)); + } } if (doOclTonemap && isHwDecoder) @@ -4224,7 +4292,7 @@ namespace MediaBrowser.Controller.MediaEncoding var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); - var doVaVppTonemap = IsVaapiVppTonemapAvailable(state, options); + var doVaVppTonemap = IsIntelVppTonemapAvailable(state, options); var doOclTonemap = !doVaVppTonemap && IsHwTonemapAvailable(state, options); var doTonemap = doVaVppTonemap || doOclTonemap; var doDeintH2645 = doDeintH264 || doDeintHevc; @@ -4535,7 +4603,7 @@ namespace MediaBrowser.Controller.MediaEncoding var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); - var doVaVppTonemap = isVaapiDecoder && IsVaapiVppTonemapAvailable(state, options); + var doVaVppTonemap = isVaapiDecoder && IsIntelVppTonemapAvailable(state, options); var doOclTonemap = !doVaVppTonemap && IsHwTonemapAvailable(state, options); var doTonemap = doVaVppTonemap || doOclTonemap; var doDeintH2645 = doDeintH264 || doDeintHevc; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index fd55db4ba..a79d801fb 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -54,12 +54,23 @@ namespace MediaBrowser.MediaEncoding.Subtitles { break; } - - _logger.LogError( - "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser", - subtitleFormat.ErrorCount, - fileExtension, - subtitleFormat.Name); + else if (subtitleFormat.TryGetErrors(out var errors)) + { + _logger.LogError( + "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser, errors: {Errors}", + subtitleFormat.ErrorCount, + fileExtension, + subtitleFormat.Name, + errors); + } + else + { + _logger.LogError( + "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser", + subtitleFormat.ErrorCount, + fileExtension, + subtitleFormat.Name); + } } if (subtitle.Paragraphs.Count == 0) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleFormatExtensions.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleFormatExtensions.cs new file mode 100644 index 000000000..88c2bf3db --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleFormatExtensions.cs @@ -0,0 +1,29 @@ +using System.Diagnostics.CodeAnalysis; +using Nikse.SubtitleEdit.Core.SubtitleFormats; + +namespace MediaBrowser.MediaEncoding.Subtitles; + +internal static class SubtitleFormatExtensions +{ + /// <summary> + /// Will try to find errors if supported by provider. + /// </summary> + /// <param name="format">The subtitle format.</param> + /// <param name="errors">The out errors value.</param> + /// <returns>True if errors are available for given format.</returns> + public static bool TryGetErrors(this SubtitleFormat format, [NotNullWhen(true)] out string? errors) + { + errors = format switch + { + SubStationAlpha ssa => ssa.Errors, + AdvancedSubStationAlpha assa => assa.Errors, + SubRip subRip => subRip.Errors, + MicroDvd microDvd => microDvd.Errors, + DCinemaSmpte2007 smpte2007 => smpte2007.Errors, + DCinemaSmpte2010 smpte2010 => smpte2010.Errors, + _ => null, + }; + + return !string.IsNullOrWhiteSpace(errors); + } +} |
