diff options
23 files changed, 144 insertions, 87 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1f0e028c1..f23ecf942 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -155,6 +155,7 @@ - [MBR-0001](https://github.com/MBR-0001) - [jonas-resch](https://github.com/jonas-resch) - [vgambier](https://github.com/vgambier) + - [MinecraftPlaye](https://github.com/MinecraftPlaye) # Emby Contributors diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index a5cc125ec..886da1390 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -29,7 +29,7 @@ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.2" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" /> <PackageReference Include="Mono.Nat" Version="3.0.2" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.3" /> <PackageReference Include="sharpcompress" Version="0.30.1" /> diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 34fdfbe8d..e45baedd7 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.EntryPoints { CheckDisposed(); - if (_configurationManager.GetNetworkConfiguration().AutoDiscovery) + if (!_configurationManager.GetNetworkConfiguration().AutoDiscovery) { return Task.CompletedTask; } diff --git a/Emby.Server.Implementations/Localization/Core/mr.json b/Emby.Server.Implementations/Localization/Core/mr.json index fdb4171b5..5aad4b0ed 100644 --- a/Emby.Server.Implementations/Localization/Core/mr.json +++ b/Emby.Server.Implementations/Localization/Core/mr.json @@ -58,5 +58,47 @@ "Application": "अॅप्लिकेशन", "AppDeviceValues": "अॅप: {0}, यंत्र: {1}", "Collections": "संग्रह", - "ChapterNameValue": "धडा {0}" + "ChapterNameValue": "धडा {0}", + "TaskDownloadMissingSubtitlesDescription": "नसलेल्या उपशिर्षकांचा मेटाडॅटा कॉन्फिग्युरेशनप्रमाणे इन्टरनेटवर शोध घेतो.", + "TaskRefreshChannelsDescription": "इन्टरनेट वाहिन्यांची माहिती ताजी करतो.", + "TaskUpdatePluginsDescription": "आपोआप अपडेट करण्यासाठी कॉन्फिगर केलेल्या प्लगइनसाठी अपडेट डाउनलोड करून इन्स्टॉल करतो.", + "TaskRefreshChannels": "वाहिन्या ताज्या करा", + "TaskRefreshPeopleDescription": "आपल्या माध्यम संग्रहातील अभिनेत्यांचा व दिग्दर्शकांचा मेटाडॅटा ताजा करतो.", + "TaskRefreshPeople": "लोकांची माहिती ताजी करा", + "TaskRefreshLibraryDescription": "माध्यम संग्रह स्कॅन करून नवीन फायली शोधतो व मेटाडॅटा ताजे करतो.", + "TaskRefreshLibrary": "माध्यम संग्रह स्कॅन करा", + "TaskRefreshChapterImagesDescription": "अध्याय असलेल्या व्हिडियोंसाठी थंबनेल चित्र बनवतो.", + "TaskRefreshChapterImages": "अध्याय चित्र काढून घ्या", + "TasksMaintenanceCategory": "देखरेख", + "ValueHasBeenAddedToLibrary": "{0} हे तुमच्या माध्यम संग्रहात जोडण्यात आले आहे", + "UserStoppedPlayingItemWithValues": "{0} यांचं {2} वर {1} पूर्णपणे प्ले करून झालं आहे", + "UserStartedPlayingItemWithValues": "{0} हे {2} वर {1} प्ले करत आहे", + "UserDownloadingItemWithValues": "{0} हे {1} डाउनलोड करत आहे", + "System": "प्रणाली", + "Undefined": "अव्याख्यात", + "Sync": "सिंक", + "ServerNameNeedsToBeRestarted": "{0} याला बंद करून पुन्हा सुरू करायची गरज आहे", + "SubtitleDownloadFailureFromForItem": "{0} येथून {1} यासाठी उपशिर्षक डाउनलोड करण्यात अपयश", + "ScheduledTaskStartedWithName": "{0} सुरू झाले", + "ScheduledTaskFailedWithName": "{0} अपयशी झाले", + "ProviderValue": "पुरवणारा: {0}", + "PluginUpdatedWithName": "{0} अपडेट केले", + "PluginUninstalledWithName": "{0} अनिन्स्टॉल केले", + "PluginInstalledWithName": "{0} इन्स्टॉल केले", + "NotificationOptionVideoPlaybackStopped": "व्हिडियो प्लेबॅक बंद केले", + "NotificationOptionVideoPlayback": "व्हिडियो प्लेबॅक सुरू केले", + "NotificationOptionTaskFailed": "अनुसूचित कार्यात अपयश", + "NotificationOptionServerRestartRequired": "सर्व्हर बंद करून पुन्हा सुरू करावा लागेल", + "NotificationOptionPluginUpdateInstalled": "प्लगइन अपडेट इन्स्टॉल झाले", + "NotificationOptionPluginUninstalled": "प्लगइन अनिन्स्टॉल झाले", + "NotificationOptionPluginInstalled": "प्लगइन इन्स्टॉल झाले", + "NotificationOptionPluginError": "प्लगइनमध्ये अपयश", + "NotificationOptionNewLibraryContent": "नवीन सामग्री जोडली गेली", + "NotificationOptionInstallationFailed": "इन्स्टॉल करण्यात अपयश", + "NotificationOptionAudioPlayback": "ऑडियो प्लेबॅक सुरू झाले", + "NotificationOptionAudioPlaybackStopped": "ऑडियो प्लेबॅक बंद झाले", + "MixedContent": "मिश्रित सामग्री", + "LabelRunningTimeValue": "चालू काल: {0}", + "HeaderContinueWatching": "बघणे चालू ठेवा", + "Default": "डीफॉल्ट" } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index af6916630..f8e8d975c 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1599,7 +1599,6 @@ namespace Jellyfin.Api.Controllers state.BaseRequest.BreakOnNonKeyFrames = false; } - var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions); var mapArgs = state.IsOutputVideo ? _encodingHelper.GetMapArgs(state) : string.Empty; var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath)); @@ -1608,12 +1607,15 @@ namespace Jellyfin.Api.Controllers var outputExtension = EncodingHelper.GetSegmentFileExtension(state.Request.SegmentContainer); var outputTsArg = outputPrefix + "%d" + outputExtension; - var segmentFormat = outputExtension.TrimStart('.'); - if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase)) + var segmentFormat = string.Empty; + var segmentContainer = outputExtension.TrimStart('.'); + var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions, segmentContainer); + + if (string.Equals(segmentContainer, "ts", StringComparison.OrdinalIgnoreCase)) { segmentFormat = "mpegts"; } - else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase)) { var outputFmp4HeaderArg = OperatingSystem.IsWindows() switch { @@ -1627,7 +1629,8 @@ namespace Jellyfin.Api.Controllers } else { - _logger.LogError("Invalid HLS segment container: {SegmentFormat}", segmentFormat); + _logger.LogError("Invalid HLS segment container: {SegmentContainer}, default to mpegts", segmentContainer); + segmentFormat = "mpegts"; } var maxMuxingQueueSize = _encodingOptions.MaxMuxingQueueSize > 128 @@ -1647,7 +1650,7 @@ namespace Jellyfin.Api.Controllers CultureInfo.InvariantCulture, "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size {6} -f hls -max_delay 5000000 -hls_time {7} -hls_segment_type {8} -start_number {9}{10} -hls_segment_filename \"{12}\" -hls_playlist_type {11} -hls_list_size 0 -y \"{13}\"", inputModifier, - _encodingHelper.GetInputArgument(state, _encodingOptions), + _encodingHelper.GetInputArgument(state, _encodingOptions, segmentContainer), threads, mapArgs, GetVideoArguments(state, startNumber, isEventPlaylist), diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index c5b240e92..b0b74e7ed 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -17,7 +17,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.2.3" /> diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index b7dab82af..2a75c2bf4 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -27,13 +27,13 @@ <ItemGroup> <PackageReference Include="System.Linq.Async" Version="6.0.1" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.2" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.2" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.3" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.2"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 4c5d6aa5d..fadacc0b5 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -37,8 +37,8 @@ <PackageReference Include="CommandLineParser" Version="2.8.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" /> - <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.2" /> - <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.2" /> + <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.3" /> + <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.3" /> <PackageReference Include="prometheus-net" Version="6.0.0" /> <PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index f7248acac..2e7349f00 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -842,8 +842,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// </summary> /// <param name="state">Encoding state.</param> /// <param name="options">Encoding options.</param> + /// <param name="segmentContainer">Segment Container.</param> /// <returns>Input arguments.</returns> - public string GetInputArgument(EncodingJobInfo state, EncodingOptions options) + public string GetInputArgument(EncodingJobInfo state, EncodingOptions options, string segmentContainer) { var arg = new StringBuilder(); var inputVidHwaccelArgs = GetInputVideoHwaccelArgs(state, options); @@ -880,7 +881,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // Also seek the external subtitles stream. - var seekSubParam = GetFastSeekCommandLineParameter(state, options); + var seekSubParam = GetFastSeekCommandLineParameter(state, options, segmentContainer); if (!string.IsNullOrEmpty(seekSubParam)) { arg.Append(' ').Append(seekSubParam); @@ -897,7 +898,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.AudioStream != null && state.AudioStream.IsExternal) { // Also seek the external audio stream. - var seekAudioParam = GetFastSeekCommandLineParameter(state, options); + var seekAudioParam = GetFastSeekCommandLineParameter(state, options, segmentContainer); if (!string.IsNullOrEmpty(seekAudioParam)) { arg.Append(' ').Append(seekAudioParam); @@ -2167,9 +2168,10 @@ namespace MediaBrowser.Controller.MediaEncoding /// </summary> /// <param name="state">The state.</param> /// <param name="options">The options.</param> + /// <param name="segmentContainer">Segment Container.</param> /// <returns>System.String.</returns> /// <value>The fast seek command line parameter.</value> - public string GetFastSeekCommandLineParameter(EncodingJobInfo state, EncodingOptions options) + public string GetFastSeekCommandLineParameter(EncodingJobInfo state, EncodingOptions options, string segmentContainer) { var time = state.BaseRequest.StartTimeTicks ?? 0; var seekParam = string.Empty; @@ -2181,11 +2183,14 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest) { var outputVideoCodec = GetVideoEncoder(state, options); + var segmentFormat = GetSegmentFileExtension(segmentContainer).TrimStart('.'); // Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking + // Disable -noaccurate_seek on mpegts container due to the timestamps issue on some clients, + // but it's still required for fMP4 container otherwise the audio can't be synced to the video. if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) + && !string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase) && state.TranscodingType != TranscodingJobType.Progressive - && state.TranscodingType != TranscodingJobType.Hls && !state.EnableBreakOnNonKeyFrames(outputVideoCodec) && (state.BaseRequest.StartTimeTicks ?? 0) > 0) { @@ -2797,16 +2802,15 @@ namespace MediaBrowser.Controller.MediaEncoding var isSwDecoder = string.IsNullOrEmpty(vidDecoder); var isSwEncoder = !vidEncoder.Contains("nvenc", StringComparison.OrdinalIgnoreCase); - // legacy cuvid(resize/deint/sw) pipeline(copy-back) + // legacy cuvid pipeline(copy-back) if ((isSwDecoder && isSwEncoder) || !IsCudaFullSupported() - || !options.EnableEnhancedNvdecDecoder || !_mediaEncoder.SupportsFilter("alphasrc")) { return GetSwVidFilterChain(state, options, vidEncoder); } - // prefered nvdec + cuda filters + nvenc pipeline + // prefered nvdec/cuvid + cuda filters + nvenc pipeline return GetNvidiaVidFiltersPrefered(state, options, vidDecoder, vidEncoder); } @@ -2824,11 +2828,11 @@ namespace MediaBrowser.Controller.MediaEncoding var reqMaxH = state.BaseRequest.MaxHeight; var threeDFormat = state.MediaSource.Video3DFormat; - var isNvdecDecoder = vidDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); + var isNvDecoder = vidDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); var isNvencEncoder = vidEncoder.Contains("nvenc", StringComparison.OrdinalIgnoreCase); var isSwDecoder = string.IsNullOrEmpty(vidDecoder); var isSwEncoder = !isNvencEncoder; - var isCuInCuOut = isNvdecDecoder && isNvencEncoder; + var isCuInCuOut = isNvDecoder && isNvencEncoder; var doubleRateDeint = options.DeinterlaceDoubleRate && (state.VideoStream?.AverageFrameRate ?? 60) <= 30; var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); @@ -2871,7 +2875,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (isNvdecDecoder) + if (isNvDecoder) { // INPUT cuda surface(vram) // hw deint @@ -2896,7 +2900,7 @@ namespace MediaBrowser.Controller.MediaEncoding var memoryOutput = false; var isUploadForOclTonemap = isSwDecoder && doCuTonemap; - if ((isNvdecDecoder && isSwEncoder) || isUploadForOclTonemap) + if ((isNvDecoder && isSwEncoder) || isUploadForOclTonemap) { memoryOutput = true; @@ -4428,10 +4432,18 @@ namespace MediaBrowser.Controller.MediaEncoding // Nvidia cuda if (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { - if (options.EnableEnhancedNvdecDecoder && isCudaSupported && isCodecAvailable) + if (isCudaSupported && isCodecAvailable) { - // set -threads 1 to nvdec decoder explicitly since it doesn't implement threading support. - return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : string.Empty); + if (options.EnableEnhancedNvdecDecoder) + { + // set -threads 1 to nvdec decoder explicitly since it doesn't implement threading support. + return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : string.Empty); + } + else + { + // cuvid decoder doesn't have threading issue. + return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty); + } } } @@ -4541,9 +4553,7 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - var hwSurface = IsCudaFullSupported() - && options.EnableEnhancedNvdecDecoder - && _mediaEncoder.SupportsFilter("alphasrc"); + var hwSurface = IsCudaFullSupported() && _mediaEncoder.SupportsFilter("alphasrc"); var is8bitSwFormatsNvdec = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsNvdec = is8bitSwFormatsNvdec || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); // TODO: add more 8/10/12bit and 4:4:4 formats for Nvdec after finishing the ffcheck tool @@ -4831,7 +4841,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions) + public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions, string segmentContainer) { var inputModifier = string.Empty; var probeSizeArgument = string.Empty; @@ -4867,7 +4877,7 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier = inputModifier.Trim(); - inputModifier += " " + GetFastSeekCommandLineParameter(state, encodingOptions); + inputModifier += " " + GetFastSeekCommandLineParameter(state, encodingOptions, segmentContainer); inputModifier = inputModifier.Trim(); if (state.InputProtocol == MediaProtocol.Rtsp) @@ -5174,13 +5184,13 @@ namespace MediaBrowser.Controller.MediaEncoding var threads = GetNumberOfThreads(state, encodingOptions, videoCodec); - var inputModifier = GetInputModifier(state, encodingOptions); + var inputModifier = GetInputModifier(state, encodingOptions, null); return string.Format( CultureInfo.InvariantCulture, "{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"", inputModifier, - GetInputArgument(state, encodingOptions), + GetInputArgument(state, encodingOptions, null), keyFrame, GetMapArgs(state), GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultPreset), @@ -5362,13 +5372,13 @@ namespace MediaBrowser.Controller.MediaEncoding var threads = GetNumberOfThreads(state, encodingOptions, null); - var inputModifier = GetInputModifier(state, encodingOptions); + var inputModifier = GetInputModifier(state, encodingOptions, null); return string.Format( CultureInfo.InvariantCulture, "{0} {1}{7}{8} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{6} -y \"{5}\"", inputModifier, - GetInputArgument(state, encodingOptions), + GetInputArgument(state, encodingOptions, null), threads, " -vn", string.Join(' ', audioTranscodeParams), diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 8313ab5bc..8c0abe10d 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -613,6 +613,17 @@ namespace MediaBrowser.MediaEncoding.Probing } /// <summary> + /// Determines whether a stream code time base is double the frame rate. + /// </summary> + /// <param name="averageFrameRate">average frame rate.</param> + /// <param name="codecTimeBase">codec time base string.</param> + /// <returns>true if the codec time base is double the frame rate.</returns> + internal static bool IsCodecTimeBaseDoubleTheFrameRate(float? averageFrameRate, string codecTimeBase) + { + return MathF.Abs(((averageFrameRate ?? 0) * (GetFrameRate(codecTimeBase) ?? 0)) - 0.5f) <= float.Epsilon; + } + + /// <summary> /// Converts ffprobe stream info to our MediaStream class. /// </summary> /// <param name="isAudio">if set to <c>true</c> [is info].</param> @@ -722,17 +733,16 @@ namespace MediaBrowser.MediaEncoding.Probing stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate); stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate); + bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder) + && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase); + // Some interlaced H.264 files in mp4 containers using MBAFF coding aren't flagged as being interlaced by FFprobe, // so for H.264 files we also calculate the frame rate from the codec time base and check if it is double the reported - // frame rate (both rounded to the nearest integer) to determine if the file is interlaced - int roundedTimeBaseFPS = Convert.ToInt32(1 / GetFrameRate(stream.CodecTimeBase) ?? 0); - int roundedDoubleFrameRate = Convert.ToInt32(stream.AverageFrameRate * 2 ?? 0); + // frame rate to determine if the file is interlaced - bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder) - && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase); bool h264MbaffCoded = string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(streamInfo.FieldOrder) - && roundedTimeBaseFPS == roundedDoubleFrameRate; + && IsCodecTimeBaseDoubleTheFrameRate(stream.AverageFrameRate, stream.CodecTimeBase); if (videoInterlaced || h264MbaffCoded) { diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 341e4846e..e2616d92a 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -161,7 +161,7 @@ namespace MediaBrowser.Model.Entities attributes.Add(StringHelper.FirstToUpper(fullLanguage ?? Language)); } - if (!string.IsNullOrEmpty(Codec) && !string.Equals(Codec, "dca", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(Codec) && !string.Equals(Codec, "dca", StringComparison.OrdinalIgnoreCase) && !string.Equals(Codec, "dts", StringComparison.OrdinalIgnoreCase)) { attributes.Add(AudioCodec.GetFriendlyName(Codec)); } diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 4386f75af..dba3b557d 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -34,7 +34,7 @@ <ItemGroup> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" /> <PackageReference Include="MimeTypes" Version="2.3.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs b/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs index e81324a6b..ce267ac84 100644 --- a/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs @@ -50,41 +50,29 @@ namespace MediaBrowser.Providers.Studios { return new List<ImageType> { - ImageType.Primary, ImageType.Thumb }; } - public Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken) + public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken) { - return GetImages(item, true, true, cancellationToken); - } - - private async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, bool posters, bool thumbs, CancellationToken cancellationToken) - { - var list = new List<RemoteImageInfo>(); - - if (posters) - { - var posterPath = Path.Combine(_config.ApplicationPaths.CachePath, "imagesbyname", "remotestudioposters.txt"); + var thumbsPath = Path.Combine(_config.ApplicationPaths.CachePath, "imagesbyname", "remotestudiothumbs.txt"); - posterPath = await EnsurePosterList(posterPath, cancellationToken).ConfigureAwait(false); - - list.Add(GetImage(item, posterPath, ImageType.Primary, "folder")); - } + thumbsPath = await EnsureThumbsList(thumbsPath, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - if (thumbs) - { - var thumbsPath = Path.Combine(_config.ApplicationPaths.CachePath, "imagesbyname", "remotestudiothumbs.txt"); - - thumbsPath = await EnsureThumbsList(thumbsPath, cancellationToken).ConfigureAwait(false); + var imageInfo = GetImage(item, thumbsPath, ImageType.Thumb, "thumb"); - list.Add(GetImage(item, thumbsPath, ImageType.Thumb, "thumb")); + if (imageInfo == null) + { + return Enumerable.Empty<RemoteImageInfo>(); } - return list.Where(i => i != null); + return new RemoteImageInfo[] + { + imageInfo + }; } private RemoteImageInfo GetImage(BaseItem item, string filename, ImageType type, string remoteFilename) @@ -120,13 +108,6 @@ namespace MediaBrowser.Providers.Studios return EnsureList(url, file, _fileSystem, cancellationToken); } - private Task<string> EnsurePosterList(string file, CancellationToken cancellationToken) - { - string url = string.Format(CultureInfo.InvariantCulture, "{0}/posters.txt", repositoryUrl); - - return EnsureList(url, file, _fileSystem, cancellationToken); - } - public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); diff --git a/deployment/Dockerfile.centos.amd64 b/deployment/Dockerfile.centos.amd64 index 350f0076a..a4638c03b 100644 --- a/deployment/Dockerfile.centos.amd64 +++ b/deployment/Dockerfile.centos.amd64 @@ -13,7 +13,7 @@ RUN yum update -yq \ && yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/e7acb87d-ab08-4620-9050-b3e80f688d36/e93bbadc19b12f81e3a6761719f28b47/dotnet-sdk-6.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/c505a449-9ecf-4352-8629-56216f521616/bd6807340faae05b61de340c8bf161e8/dotnet-sdk-6.0.201-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.fedora.amd64 b/deployment/Dockerfile.fedora.amd64 index eeff9a96f..8f564bb12 100644 --- a/deployment/Dockerfile.fedora.amd64 +++ b/deployment/Dockerfile.fedora.amd64 @@ -12,7 +12,7 @@ RUN dnf update -yq \ && dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/e7acb87d-ab08-4620-9050-b3e80f688d36/e93bbadc19b12f81e3a6761719f28b47/dotnet-sdk-6.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/c505a449-9ecf-4352-8629-56216f521616/bd6807340faae05b61de340c8bf161e8/dotnet-sdk-6.0.201-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.amd64 b/deployment/Dockerfile.ubuntu.amd64 index 9d2deb1c6..f5a5b54fc 100644 --- a/deployment/Dockerfile.ubuntu.amd64 +++ b/deployment/Dockerfile.ubuntu.amd64 @@ -17,7 +17,7 @@ RUN apt-get update -yqq \ libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/e7acb87d-ab08-4620-9050-b3e80f688d36/e93bbadc19b12f81e3a6761719f28b47/dotnet-sdk-6.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/c505a449-9ecf-4352-8629-56216f521616/bd6807340faae05b61de340c8bf161e8/dotnet-sdk-6.0.201-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.arm64 b/deployment/Dockerfile.ubuntu.arm64 index ec90dba83..7ca0f6470 100644 --- a/deployment/Dockerfile.ubuntu.arm64 +++ b/deployment/Dockerfile.ubuntu.arm64 @@ -16,7 +16,7 @@ RUN apt-get update -yqq \ mmv build-essential lsb-release # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/e7acb87d-ab08-4620-9050-b3e80f688d36/e93bbadc19b12f81e3a6761719f28b47/dotnet-sdk-6.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/c505a449-9ecf-4352-8629-56216f521616/bd6807340faae05b61de340c8bf161e8/dotnet-sdk-6.0.201-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.armhf b/deployment/Dockerfile.ubuntu.armhf index 3685e16c4..384e49bf0 100644 --- a/deployment/Dockerfile.ubuntu.armhf +++ b/deployment/Dockerfile.ubuntu.armhf @@ -16,7 +16,7 @@ RUN apt-get update -yqq \ mmv build-essential lsb-release # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/e7acb87d-ab08-4620-9050-b3e80f688d36/e93bbadc19b12f81e3a6761719f28b47/dotnet-sdk-6.0.102-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/c505a449-9ecf-4352-8629-56216f521616/bd6807340faae05b61de340c8bf161e8/dotnet-sdk-6.0.201-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj b/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj index 31da11e24..d5e36cb23 100644 --- a/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj +++ b/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj @@ -21,7 +21,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" /> </ItemGroup> <ItemGroup> diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 80667aa3d..6f3b83455 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -15,7 +15,7 @@ <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index 0fc8724b6..53e1550ed 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -31,6 +31,16 @@ namespace Jellyfin.MediaEncoding.Tests.Probing public void GetFrameRate_Success(string value, float? expected) => Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value)); + [Theory] + [InlineData(0.5f, "0/1", false)] + [InlineData(24.5f, "8/196", false)] + [InlineData(63.5f, "1/127", true)] + [InlineData(null, "1/60", false)] + [InlineData(30f, "2/120", true)] + [InlineData(59.999996f, "1563/187560", true)] + public void IsCodecTimeBaseDoubleTheFrameRate_Success(float? frameRate, string codecTimeBase, bool expected) + => Assert.Equal(expected, ProbeResultNormalizer.IsCodecTimeBaseDoubleTheFrameRate(frameRate, codecTimeBase)); + [Fact] public void GetMediaInfo_MetaData_Success() { diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 67564ff8e..55101ce10d 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -9,7 +9,7 @@ <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index c66fca044..f5d60d2d3 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -10,7 +10,7 @@ <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.2" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="xunit" Version="2.4.1" /> |
