Compare commits

...

72 Commits

Author SHA1 Message Date
Joshua M. Boniface a173d01139 Revert "Merge pull request #10514 from Bond-009/skia3"
This reverts commit 0bac1eab98, reversing
changes made to 4df1003029.

Causes segfaults on startup.
2023-11-05 11:47:36 -05:00
Joshua M. Boniface 3e7fad55de Bump version to 10.8.12 2023-11-04 14:42:59 -04:00
Joshua M. Boniface 8cd685a4e9 Merge pull request #10528 from nyanmisaka/backport-10451
Fix mismatched intel VAAPI UMD/KMD - Backport #10451
2023-11-04 14:36:05 -04:00
Joshua M. Boniface 9d565bbb83 Merge pull request #10454 from Shadowghost/env
Add MALLOC_TRIM_THRESHOLD_ to default ENV
2023-11-04 14:16:10 -04:00
nyanmisaka ab855af95e Fix mismatched intel VAAPI UMD/KMD introduced by pull request #10451
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-11-05 01:09:07 +08:00
Claus Vium 0bac1eab98 Merge pull request #10514 from Bond-009/skia3
Update SkiaSharp (v2.88.6) and BlurHashSharp (v1.3.1)
2023-11-02 08:58:34 +01:00
Bond_009 97c2ba0115 Update SkiaSharp (v2.88.6) and BlurHashSharp (v1.3.1) 2023-11-01 23:47:04 +01:00
Cody Robibero 4df1003029 Merge pull request #10487 from thornbill/backport-9485
Fix scaleFactor limit - Backport #9738
2023-10-28 08:44:56 -06:00
Oliver Weyhmüller 3269ce56ca Fix scaleFactor limitation to 1 introduced by pull request #9485 2023-10-28 01:02:27 -04:00
Claus Vium ce8eddd484 Merge pull request #10406 from thornbill/fix-playlists
Fix playlist listings
2023-10-27 09:47:11 +02:00
Shadowghost 5e2872509a Add MALLOC_TRIM_THRESHOLD_=131072 to default ENV 2023-10-22 17:55:36 +02:00
Bill Thornton d3f4dcf6f6 Revert "Don't ignore parentId for playlists"
This reverts commit 98c6c34fbb.
2023-10-15 02:16:27 -04:00
Joshua M. Boniface be5e10ac37 Bump version to 10.8.11 2023-09-23 21:40:40 -04:00
Cody Robibero b85a0288a7 Merge pull request #10265 from Shadowghost/backport-10173 2023-09-23 09:14:30 -06:00
Shadowghost f8fd851961 Backport #10173 2023-09-23 13:46:49 +02:00
Bond-009 757f88b1a2 Merge pull request #10151 from jellyfin/faster-tm-qsv-windows 2023-08-27 10:17:47 +02:00
Nyanmisaka fa732bf4a1 Fix performance loss of QSV HDR tone-mapping on Windows
jellyfin-ffmpeg 5.1.3-5, 6.0-6 or newer contains a more efficient fix than this one.
2023-08-26 03:06:16 +08:00
Cody Robibero 4f6edd9c3c Merge pull request #9952 from Bond-009/backportfix9503
fix for #9503
2023-07-02 18:18:21 -06:00
Bond_009 768497d0ff Backport fix for #9503 2023-07-03 00:07:04 +02:00
Bond-009 f1dc7d3a66 Merge pull request #9916 from Bond-009/playlist-backport 2023-06-27 16:22:14 +02:00
Bond-009 a732a28229 Merge pull request #9928 from nyanmisaka/disable-amd-global-header 2023-06-27 15:58:22 +02:00
nyanmisaka 17626b8e48 Disable global_header on AMD VA-API encoder
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-06-25 21:46:14 +08:00
Bond_009 98c6c34fbb Don't ignore parentId for playlists 2023-06-22 00:43:32 +02:00
Bond-009 bec8d7b3f5 Merge pull request #9723 from dmitrylyzo/fix-multiple-codec-checking 2023-06-13 14:54:57 +02:00
Bond-009 2acae258b8 Check for Imdb id for series (#9829) 2023-05-29 18:40:07 -06:00
Bond-009 643df48707 Don't crash when IPv6 subnet in LocalNetworkSubnets (backport) (#9832) 2023-05-29 18:38:59 -06:00
Bond-009 2b98ce052e Allow webp for local images (backport) (#9831) 2023-05-29 18:38:43 -06:00
Bond-009 702347df50 Don't add .spc audio files (backport) (#9830) 2023-05-29 18:38:29 -06:00
Dmitry Lyzo 9e5aa3e87e Fix multiple codec checking in CodecProfiles conditions
Partial revert 6d662b6587
2023-05-03 00:53:20 +03:00
Joshua M. Boniface 2cd29d1cfd Bump version to 10.8.10 2023-04-23 11:03:46 -04:00
Joshua M. Boniface eba95cc7f0 Merge pull request #9671 from nyanmisaka/fix-canvas-dvbsub 2023-04-23 11:03:17 -04:00
Joshua M. Boniface 82ad2633fd Merge pull request from GHSA-9p5f-5x8v-x65m
Throw exception on path traversal in WriteDocumentAsync
2023-04-23 10:59:32 -04:00
nyanmisaka d9f5619c9a Fix the canvas size for DVBSUB and DVDSUB subtitles
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-04-23 20:15:12 +08:00
Cody Robibero d5a8419bc5 Merge pull request #9642 from nyanmisaka/tonemap-mode-selection
Fix the brightness of VPP tonemap and add the tonemap mode
2023-04-14 14:58:19 -06:00
nyanmisaka c448a4f6a5 Fix the brightness of VPP tonemap and add the tonemap mode
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-04-14 19:34:47 +08:00
David Ullmer faac37bcf9 Throw exception on path traversal in WriteDocumentAsync
This commit is not tested on a Windows machine. I however checked the
same behavior with UNIX paths and a client name resembling path traversal
path. With this change, an exception is thrown if the full path does not
start with the log directory path.
2023-04-12 16:57:45 +02:00
Bond-009 5921379a29 Merge pull request #9411 from nyanmisaka/next-fixes 2023-04-12 16:35:20 +02:00
Cody Robibero 79bb7560dc Merge pull request #9538 from TheTyrius/fix-nvenc-preset-order
Fix nvenc preset order
2023-03-25 09:04:08 -06:00
TheTyrius bf37db7f42 Add self to CONTRIBUTORS.md as per dev docs 2023-03-25 15:39:00 +01:00
TheTyrius 0ad70bb699 Fix nvenc preset ordering 2023-03-25 15:28:01 +01:00
Bond-009 e6313d01eb Merge pull request #9409 from Shadowghost/output-bitrate-channels-release
Multiple HLS codec and bitrate fixes (10.8.z)
2023-03-19 15:30:53 +01:00
Shadowghost 876a6b9aec Add DCA and TrueHD to fMP4 audio codecs to support remuxing 2023-03-19 15:07:20 +01:00
Cody Robibero e0344353cd Apply suggestions from code review
Co-authored-by: Bond-009 <bond.009@outlook.com>
2023-03-17 12:26:42 +01:00
nyanmisaka 9799136daf Add support for OPUS and fixes for FLAC case issue in HLS
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-03-17 12:26:40 +01:00
Shadowghost 3a5503be5f Fix condition in CanStreamCopyAudio 2023-03-17 12:16:50 +01:00
Shadowghost 2cc0869144 Prefer other codecs over DTS and TrueHD on transcode 2023-03-17 12:16:48 +01:00
Shadowghost 3d735e242a Use source audio bitrate if requested codec is lossless 2023-03-17 12:15:48 +01:00
Shadowghost 31712e5da9 Apply review suggestions 2023-03-17 12:01:34 +01:00
Shadowghost 060097703b Enforce HLS codec restrictions 2023-03-17 11:58:38 +01:00
Shadowghost 233e079e58 Add DTS and TrueHD bitrate limits, enforce bitrate limits if no bitrate is requested 2023-03-17 11:58:25 +01:00
Shadowghost eafd785eb6 Fix encoder checks for DTS and TrueHD 2023-03-17 11:58:09 +01:00
Shadowghost 9908dad045 Take channels into account when calculating fallback audio bitrate 2023-03-17 11:57:51 +01:00
knackebrot 2b4bf81575 Calculate output bitrate from output channel count 2023-03-17 11:57:41 +01:00
Nyanmisaka 0c7ceb1545 Backport HWA permissions fix (#9006) to 10.8.z (#9433)
Co-authored-by: Shadowghost <Shadowghost@users.noreply.github.com>
fix (#9006) to 10.8.z
2023-03-14 16:29:50 -06:00
Nyanmisaka 173a963dbf Fix the bitrate scale factor for h264-to-hevc transcoding (#9485) 2023-03-14 16:06:10 -06:00
Bond-009 6821a2ab35 Merge pull request #9422 from nyanmisaka/fix-stream-map-filter-complex 2023-03-07 16:25:30 +01:00
Bond-009 efc79295de Merge pull request #9430 from nyanmisaka/livetv-hwdec 2023-03-07 16:25:11 +01:00
nyanmisaka 4d1a583297 Fix LiveTV hardware decoding
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-03-05 03:51:14 +08:00
nyanmisaka c94a99fced Tiny optimizations for FFmpeg 6.0 2023-03-03 00:24:43 +08:00
nyanmisaka 5fdea32dca Add tests for FFmpeg version 5.1.2 and 6.0
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-03-02 21:21:44 +08:00
nyanmisaka d1c668e230 Fix stream map when using filter_complex with unlabeled output
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-03-02 21:15:16 +08:00
nyanmisaka 6d662b6587 Fix codec checking in CodecProfiles conditions
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-02-28 03:49:19 +08:00
Bond-009 22a8283a9e Merge pull request #9391 from nyanmisaka/next-fixes 2023-02-25 16:44:47 +01:00
nyanmisaka 0d9d2e0690 Enable enhanced Nvdec by default for using DoVi tone-mapping
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-02-24 23:39:32 +08:00
nyanmisaka edaba7dbe5 Fix H.264 baseline profile hwaccel
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-02-24 23:38:46 +08:00
Bond-009 e8b0ae07af Merge pull request #9351 from Shadowghost/condition-fix 2023-02-20 10:27:58 +01:00
Bond-009 c807712246 Merge pull request #9355 from nyanmisaka/va-vpp-pool-size 2023-02-20 10:27:47 +01:00
Shadowghost 9a14a624a8 Apply review suggestions 2023-02-19 15:11:15 +01:00
Shadowghost 037eeed746 Fix EqualsAny condition check for int and double 2023-02-19 14:59:30 +01:00
nyanmisaka 8ecb9558e2 Use CL_MAP_READ on OCL to reduce bandwidth overhead
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-02-19 21:26:15 +08:00
nyanmisaka 8d04c98e35 Increase pool size for VAAPI VPP
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2023-02-19 21:16:17 +08:00
Dmitry Lyzo 09f1c7f535 Escape the path to pass as a command line argument (#9178) 2023-01-28 07:42:58 -07:00
38 changed files with 498 additions and 143 deletions
+1
View File
@@ -160,6 +160,7 @@
- [vgambier](https://github.com/vgambier) - [vgambier](https://github.com/vgambier)
- [MinecraftPlaye](https://github.com/MinecraftPlaye) - [MinecraftPlaye](https://github.com/MinecraftPlaye)
- [RealGreenDragon](https://github.com/RealGreenDragon) - [RealGreenDragon](https://github.com/RealGreenDragon)
- [TheTyrius](https://github.com/TheTyrius)
# Emby Contributors # Emby Contributors
-1
View File
@@ -250,7 +250,6 @@ namespace Emby.Naming.Common
".sfx", ".sfx",
".shn", ".shn",
".sid", ".sid",
".spc",
".stm", ".stm",
".strm", ".strm",
".ult", ".ult",
+1 -1
View File
@@ -36,7 +36,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId> <PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.8.9</VersionPrefix> <VersionPrefix>10.8.12</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
@@ -183,6 +183,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
private static void SetProviderIdFromPath(Series item, string path) private static void SetProviderIdFromPath(Series item, string path)
{ {
var justName = Path.GetFileName(path.AsSpan()); var justName = Path.GetFileName(path.AsSpan());
var imdbId = justName.GetAttributeValue("imdbid");
if (!string.IsNullOrEmpty(imdbId))
{
item.SetProviderId(MetadataProvider.Imdb, imdbId);
}
var tvdbId = justName.GetAttributeValue("tvdbid"); var tvdbId = justName.GetAttributeValue("tvdbid");
if (!string.IsNullOrEmpty(tvdbId)) if (!string.IsNullOrEmpty(tvdbId))
@@ -13,6 +13,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.PlaybackDtos; using Jellyfin.Api.Models.PlaybackDtos;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using Jellyfin.Extensions;
using Jellyfin.MediaEncoding.Hls.Playlist; using Jellyfin.MediaEncoding.Hls.Playlist;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@@ -21,6 +22,7 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.MediaEncoding.Encoder;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
@@ -1662,8 +1664,8 @@ namespace Jellyfin.Api.Controllers
startNumber.ToString(CultureInfo.InvariantCulture), startNumber.ToString(CultureInfo.InvariantCulture),
baseUrlParam, baseUrlParam,
isEventPlaylist ? "event" : "vod", isEventPlaylist ? "event" : "vod",
outputTsArg, EncodingUtils.NormalizePath(outputTsArg),
outputPath).Trim(); EncodingUtils.NormalizePath(outputPath)).Trim();
} }
/// <summary> /// <summary>
@@ -1693,7 +1695,7 @@ namespace Jellyfin.Api.Controllers
audioTranscodeParams += "-acodec " + audioCodec; audioTranscodeParams += "-acodec " + audioCodec;
if (state.OutputAudioBitrate.HasValue) if (state.OutputAudioBitrate.HasValue && !EncodingHelper.LosslessAudioCodecs.Contains(state.ActualOutputAudioCodec, StringComparison.OrdinalIgnoreCase))
{ {
audioTranscodeParams += " -ab " + state.OutputAudioBitrate.Value.ToString(CultureInfo.InvariantCulture); audioTranscodeParams += " -ab " + state.OutputAudioBitrate.Value.ToString(CultureInfo.InvariantCulture);
} }
@@ -1714,11 +1716,11 @@ namespace Jellyfin.Api.Controllers
// dts, flac, opus and truehd are experimental in mp4 muxer // dts, flac, opus and truehd are experimental in mp4 muxer
var strictArgs = string.Empty; var strictArgs = string.Empty;
var actualOutputAudioCodec = state.ActualOutputAudioCodec;
if (string.Equals(state.ActualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase) if (string.Equals(actualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.ActualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase) || string.Equals(actualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.ActualOutputAudioCodec, "dts", StringComparison.OrdinalIgnoreCase) || string.Equals(actualOutputAudioCodec, "dts", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.ActualOutputAudioCodec, "truehd", StringComparison.OrdinalIgnoreCase)) || string.Equals(actualOutputAudioCodec, "truehd", StringComparison.OrdinalIgnoreCase))
{ {
strictArgs = " -strict -2"; strictArgs = " -strict -2";
} }
@@ -1747,8 +1749,7 @@ namespace Jellyfin.Api.Controllers
} }
var bitrate = state.OutputAudioBitrate; var bitrate = state.OutputAudioBitrate;
if (bitrate.HasValue && !EncodingHelper.LosslessAudioCodecs.Contains(actualOutputAudioCodec, StringComparison.OrdinalIgnoreCase))
if (bitrate.HasValue)
{ {
args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture);
} }
@@ -1843,7 +1844,11 @@ namespace Jellyfin.Api.Controllers
// args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0"; // args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
// video processing filters. // video processing filters.
args += _encodingHelper.GetVideoProcessingFilterParam(state, _encodingOptions, codec); var videoProcessParam = _encodingHelper.GetVideoProcessingFilterParam(state, _encodingOptions, codec);
var negativeMapArgs = _encodingHelper.GetNegativeMapArgsByFilters(state, videoProcessParam);
args = negativeMapArgs + args + videoProcessParam;
// -start_at_zero is necessary to use with -ss when seeking, // -start_at_zero is necessary to use with -ss when seeking,
// otherwise the target position cannot be determined. // otherwise the target position cannot be determined.
+51 -4
View File
@@ -8,6 +8,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
@@ -203,6 +204,13 @@ namespace Jellyfin.Api.Helpers
if (state.VideoStream != null && state.VideoRequest != null) if (state.VideoStream != null && state.VideoRequest != null)
{ {
// Provide a workaround for the case issue between flac and fLaC.
var flacWaPlaylist = ApplyFlacCaseWorkaround(state, basicPlaylist.ToString());
if (!string.IsNullOrEmpty(flacWaPlaylist))
{
builder.Append(flacWaPlaylist);
}
var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
// Provide SDR HEVC entrance for backward compatibility. // Provide SDR HEVC entrance for backward compatibility.
@@ -221,10 +229,25 @@ namespace Jellyfin.Api.Helpers
sdrVideoUrl += "&AllowVideoStreamCopy=false"; sdrVideoUrl += "&AllowVideoStreamCopy=false";
var sdrOutputVideoBitrate = _encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec); var sdrOutputVideoBitrate = _encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
var sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream) ?? 0; var sdrOutputAudioBitrate = 0;
var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate; if (EncodingHelper.LosslessAudioCodecs.Contains(state.VideoRequest.AudioCodec, StringComparison.OrdinalIgnoreCase))
{
sdrOutputAudioBitrate = state.AudioStream.BitRate ?? 0;
}
else
{
sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream, state.OutputAudioChannels) ?? 0;
}
AppendPlaylist(builder, state, sdrVideoUrl, sdrTotalBitrate, subtitleGroup); var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate;
var sdrPlaylist = AppendPlaylist(builder, state, sdrVideoUrl, sdrTotalBitrate, subtitleGroup);
// Provide a workaround for the case issue between flac and fLaC.
flacWaPlaylist = ApplyFlacCaseWorkaround(state, sdrPlaylist.ToString());
if (!string.IsNullOrEmpty(flacWaPlaylist))
{
builder.Append(flacWaPlaylist);
}
// Restore the video codec // Restore the video codec
state.OutputVideoCodec = "copy"; state.OutputVideoCodec = "copy";
@@ -254,6 +277,13 @@ namespace Jellyfin.Api.Helpers
state.VideoStream.Level = originalLevel; state.VideoStream.Level = originalLevel;
var newPlaylist = ReplacePlaylistCodecsField(basicPlaylist, playlistCodecsField, newPlaylistCodecsField); var newPlaylist = ReplacePlaylistCodecsField(basicPlaylist, playlistCodecsField, newPlaylistCodecsField);
builder.Append(newPlaylist); builder.Append(newPlaylist);
// Provide a workaround for the case issue between flac and fLaC.
flacWaPlaylist = ApplyFlacCaseWorkaround(state, newPlaylist);
if (!string.IsNullOrEmpty(flacWaPlaylist))
{
builder.Append(flacWaPlaylist);
}
} }
} }
@@ -612,6 +642,11 @@ namespace Jellyfin.Api.Helpers
return HlsCodecStringHelpers.GetALACString(); return HlsCodecStringHelpers.GetALACString();
} }
if (string.Equals(state.ActualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase))
{
return HlsCodecStringHelpers.GetOPUSString();
}
return string.Empty; return string.Empty;
} }
@@ -710,7 +745,19 @@ namespace Jellyfin.Api.Helpers
return oldPlaylist.Replace( return oldPlaylist.Replace(
oldValue.ToString(), oldValue.ToString(),
newValue.ToString(), newValue.ToString(),
StringComparison.OrdinalIgnoreCase); StringComparison.Ordinal);
}
private string ApplyFlacCaseWorkaround(StreamState state, string srcPlaylist)
{
if (!string.Equals(state.ActualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase))
{
return string.Empty;
}
var newPlaylist = srcPlaylist.Replace(",flac\"", ",fLaC\"", StringComparison.Ordinal);
return newPlaylist.Contains(",fLaC\"", StringComparison.Ordinal) ? newPlaylist : string.Empty;
} }
} }
} }
+15 -1
View File
@@ -27,13 +27,18 @@ namespace Jellyfin.Api.Helpers
/// <summary> /// <summary>
/// Codec name for FLAC. /// Codec name for FLAC.
/// </summary> /// </summary>
public const string FLAC = "fLaC"; public const string FLAC = "flac";
/// <summary> /// <summary>
/// Codec name for ALAC. /// Codec name for ALAC.
/// </summary> /// </summary>
public const string ALAC = "alac"; public const string ALAC = "alac";
/// <summary>
/// Codec name for OPUS.
/// </summary>
public const string OPUS = "opus";
/// <summary> /// <summary>
/// Gets a MP3 codec string. /// Gets a MP3 codec string.
/// </summary> /// </summary>
@@ -101,6 +106,15 @@ namespace Jellyfin.Api.Helpers
return ALAC; return ALAC;
} }
/// <summary>
/// Gets an OPUS codec string.
/// </summary>
/// <returns>OPUS codec string.</returns>
public static string GetOPUSString()
{
return OPUS;
}
/// <summary> /// <summary>
/// Gets a H.264 codec string. /// Gets a H.264 codec string.
/// </summary> /// </summary>
+11 -5
View File
@@ -182,12 +182,18 @@ namespace Jellyfin.Api.Helpers
: GetOutputFileExtension(state, mediaSource); : GetOutputFileExtension(state, mediaSource);
} }
var outputAudioCodec = streamingRequest.AudioCodec;
if (EncodingHelper.LosslessAudioCodecs.Contains(outputAudioCodec))
{
state.OutputAudioBitrate = state.AudioStream.BitRate ?? 0;
}
else
{
state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(streamingRequest.AudioBitRate, streamingRequest.AudioCodec, state.AudioStream, state.OutputAudioChannels) ?? 0;
}
state.OutputAudioCodec = outputAudioCodec;
state.OutputContainer = (containerInternal ?? string.Empty).TrimStart('.'); state.OutputContainer = (containerInternal ?? string.Empty).TrimStart('.');
state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(streamingRequest.AudioBitRate, streamingRequest.AudioCodec, state.AudioStream);
state.OutputAudioCodec = streamingRequest.AudioCodec;
state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec); state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec);
if (state.VideoRequest != null) if (state.VideoRequest != null)
+1
View File
@@ -26,6 +26,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj" /> <ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj" />
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" /> <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
<ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj" />
<ProjectReference Include="..\src\Jellyfin.MediaEncoding.Hls\Jellyfin.MediaEncoding.Hls.csproj" /> <ProjectReference Include="..\src\Jellyfin.MediaEncoding.Hls\Jellyfin.MediaEncoding.Hls.csproj" />
</ItemGroup> </ItemGroup>
+1 -1
View File
@@ -18,7 +18,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Data</PackageId> <PackageId>Jellyfin.Data</PackageId>
<VersionPrefix>10.8.9</VersionPrefix> <VersionPrefix>10.8.12</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
@@ -8,7 +8,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Common</PackageId> <PackageId>Jellyfin.Common</PackageId>
<VersionPrefix>10.8.9</VersionPrefix> <VersionPrefix>10.8.12</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
+5
View File
@@ -170,6 +170,11 @@ namespace MediaBrowser.Common.Net
address = address.MapToIPv4(); address = address.MapToIPv4();
} }
if (address.AddressFamily != AddressFamily)
{
return false;
}
var (altAddress, altPrefix) = NetworkAddressOf(address, PrefixLength); var (altAddress, altPrefix) = NetworkAddressOf(address, PrefixLength);
return NetworkAddress.Address.Equals(altAddress) && NetworkAddress.PrefixLength >= altPrefix; return NetworkAddress.Address.Equals(altAddress) && NetworkAddress.PrefixLength >= altPrefix;
} }
@@ -23,6 +23,11 @@ namespace MediaBrowser.Controller.ClientEvent
{ {
var fileName = $"upload_{clientName}_{clientVersion}_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}.log"; var fileName = $"upload_{clientName}_{clientVersion}_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}.log";
var logFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, fileName); var logFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, fileName);
if (!Path.GetFullPath(logFilePath).StartsWith(_applicationPaths.LogDirectoryPath, StringComparison.Ordinal))
{
throw new ArgumentException("Path resolved to filename not in log directory");
}
await using var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None); await using var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
await fileContents.CopyToAsync(fileStream).ConfigureAwait(false); await fileContents.CopyToAsync(fileStream).ConfigureAwait(false);
return fileName; return fileName;
+1 -1
View File
@@ -47,7 +47,7 @@ namespace MediaBrowser.Controller.Entities
/// The supported image extensions. /// The supported image extensions.
/// </summary> /// </summary>
public static readonly string[] SupportedImageExtensions public static readonly string[] SupportedImageExtensions
= new[] { ".png", ".jpg", ".jpeg", ".tbn", ".gif" }; = new[] { ".png", ".jpg", ".jpeg", ".webp", ".tbn", ".gif" };
private static readonly List<string> _supportedExtensions = new List<string>(SupportedImageExtensions) private static readonly List<string> _supportedExtensions = new List<string>(SupportedImageExtensions)
{ {
@@ -8,7 +8,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId> <PackageId>Jellyfin.Controller</PackageId>
<VersionPrefix>10.8.9</VersionPrefix> <VersionPrefix>10.8.12</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
@@ -41,6 +41,10 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly Version _maxKerneli915Hang = new Version(6, 1, 3); private readonly Version _maxKerneli915Hang = new Version(6, 1, 3);
private readonly Version _minFixedKernel60i915Hang = new Version(6, 0, 18); private readonly Version _minFixedKernel60i915Hang = new Version(6, 0, 18);
private readonly Version _minFFmpegImplictHwaccel = new Version(6, 0);
private readonly Version _minFFmpegHwaUnsafeOutput = new Version(6, 0);
private readonly Version _minFFmpegOclCuTonemapMode = new Version(5, 1, 3);
private static readonly string[] _videoProfilesH264 = new[] private static readonly string[] _videoProfilesH264 = new[]
{ {
"ConstrainedBaseline", "ConstrainedBaseline",
@@ -59,6 +63,16 @@ namespace MediaBrowser.Controller.MediaEncoding
"Main10" "Main10"
}; };
public static readonly string[] LosslessAudioCodecs = new string[]
{
"alac",
"ape",
"flac",
"mlp",
"truehd",
"wavpack"
};
public EncodingHelper( public EncodingHelper(
IApplicationPaths appPaths, IApplicationPaths appPaths,
IMediaEncoder mediaEncoder, IMediaEncoder mediaEncoder,
@@ -545,6 +559,11 @@ namespace MediaBrowser.Controller.MediaEncoding
return "flac"; return "flac";
} }
if (string.Equals(codec, "dts", StringComparison.OrdinalIgnoreCase))
{
return "dca";
}
return codec.ToLowerInvariant(); return codec.ToLowerInvariant();
} }
@@ -608,14 +627,20 @@ namespace MediaBrowser.Controller.MediaEncoding
private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string alias) private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string alias)
{ {
alias ??= VaapiAlias; alias ??= VaapiAlias;
renderNodePath = renderNodePath ?? "/dev/dri/renderD128";
var options = string.IsNullOrEmpty(driver) // 'renderNodePath' has higher priority than 'kernelDriver'
? renderNodePath var driverOpts = string.IsNullOrEmpty(renderNodePath)
: ",driver=" + driver + (string.IsNullOrEmpty(kernelDriver) ? string.Empty : ",kernel_driver=" + kernelDriver); ? (string.IsNullOrEmpty(kernelDriver) ? string.Empty : ",kernel_driver=" + kernelDriver)
: renderNodePath;
// 'driver' behaves similarly to env LIBVA_DRIVER_NAME
driverOpts += string.IsNullOrEmpty(driver) ? string.Empty : ",driver=" + driver;
var options = string.IsNullOrEmpty(driverOpts) ? string.Empty : ":" + driverOpts;
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
" -init_hw_device vaapi={0}:{1}", " -init_hw_device vaapi={0}{1}",
alias, alias,
options); options);
} }
@@ -647,9 +672,12 @@ namespace MediaBrowser.Controller.MediaEncoding
public string GetGraphicalSubCanvasSize(EncodingJobInfo state) public string GetGraphicalSubCanvasSize(EncodingJobInfo state)
{ {
// DVBSUB and DVDSUB use the fixed canvas size 720x576
if (state.SubtitleStream != null if (state.SubtitleStream != null
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
&& !state.SubtitleStream.IsTextSubtitleStream) && !state.SubtitleStream.IsTextSubtitleStream
&& !string.Equals(state.SubtitleStream.Codec, "DVBSUB", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(state.SubtitleStream.Codec, "DVDSUB", StringComparison.OrdinalIgnoreCase))
{ {
var inW = state.VideoStream?.Width; var inW = state.VideoStream?.Width;
var inH = state.VideoStream?.Height; var inH = state.VideoStream?.Height;
@@ -717,14 +745,14 @@ namespace MediaBrowser.Controller.MediaEncoding
if (_mediaEncoder.IsVaapiDeviceInteliHD) if (_mediaEncoder.IsVaapiDeviceInteliHD)
{ {
args.Append(GetVaapiDeviceArgs(null, "iHD", null, VaapiAlias)); args.Append(GetVaapiDeviceArgs(options.VaapiDevice, "iHD", null, VaapiAlias));
} }
else if (_mediaEncoder.IsVaapiDeviceInteli965) else if (_mediaEncoder.IsVaapiDeviceInteli965)
{ {
// Only override i965 since it has lower priority than iHD in libva lookup. // Only override i965 since it has lower priority than iHD in libva lookup.
Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME", "i965"); Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME", "i965");
Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME_JELLYFIN", "i965"); Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME_JELLYFIN", "i965");
args.Append(GetVaapiDeviceArgs(null, "i965", null, VaapiAlias)); args.Append(GetVaapiDeviceArgs(options.VaapiDevice, "i965", null, VaapiAlias));
} }
else else
{ {
@@ -1291,6 +1319,13 @@ namespace MediaBrowser.Controller.MediaEncoding
args += keyFrameArg + gopArg; args += keyFrameArg + gopArg;
} }
// global_header produced by AMD VA-API encoder causes non-playable fMP4 on iOS
if (codec.Contains("vaapi", StringComparison.OrdinalIgnoreCase)
&& _mediaEncoder.IsVaapiDeviceAmd)
{
args += " -flags:v -global_header";
}
return args; return args;
} }
@@ -1441,11 +1476,11 @@ namespace MediaBrowser.Controller.MediaEncoding
param += " -preset p7"; param += " -preset p7";
break; break;
case "slow": case "slower":
param += " -preset p6"; param += " -preset p6";
break; break;
case "slower": case "slow":
param += " -preset p5"; param += " -preset p5";
break; break;
@@ -1478,8 +1513,8 @@ namespace MediaBrowser.Controller.MediaEncoding
switch (encodingOptions.EncoderPreset) switch (encodingOptions.EncoderPreset)
{ {
case "veryslow": case "veryslow":
case "slow":
case "slower": case "slower":
case "slow":
param += " -quality quality"; param += " -quality quality";
break; break;
@@ -1952,9 +1987,9 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
} }
// Video bitrate must fall within requested value // Audio bitrate must fall within requested value
if (request.AudioBitRate.HasValue if (request.AudioBitRate.HasValue
&& audioStream.BitDepth.HasValue && audioStream.BitRate.HasValue
&& audioStream.BitRate.Value > request.AudioBitRate.Value) && audioStream.BitRate.Value > request.AudioBitRate.Value)
{ {
return false; return false;
@@ -2018,14 +2053,20 @@ namespace MediaBrowser.Controller.MediaEncoding
private static double GetVideoBitrateScaleFactor(string codec) private static double GetVideoBitrateScaleFactor(string codec)
{ {
// hevc & vp9 - 40% more efficient than h.264
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase))
|| string.Equals(codec, "av1", StringComparison.OrdinalIgnoreCase))
{ {
return .6; return .6;
} }
// av1 - 50% more efficient than h.264
if (string.Equals(codec, "av1", StringComparison.OrdinalIgnoreCase))
{
return .5;
}
return 1; return 1;
} }
@@ -2033,7 +2074,9 @@ namespace MediaBrowser.Controller.MediaEncoding
{ {
var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec); var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec);
var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec); var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec);
var scaleFactor = outputScaleFactor / inputScaleFactor;
// Don't scale the real bitrate lower than the requested bitrate
var scaleFactor = Math.Max(outputScaleFactor / inputScaleFactor, 1);
if (bitrate <= 500000) if (bitrate <= 500000)
{ {
@@ -2055,56 +2098,55 @@ namespace MediaBrowser.Controller.MediaEncoding
return Convert.ToInt32(scaleFactor * bitrate); return Convert.ToInt32(scaleFactor * bitrate);
} }
public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream) public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream, int? outputAudioChannels)
{ {
return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec, audioStream); return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec, audioStream, outputAudioChannels);
} }
public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, MediaStream audioStream) public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, MediaStream audioStream, int? outputAudioChannels)
{ {
if (audioStream == null) if (audioStream == null)
{ {
return null; return null;
} }
if (audioBitRate.HasValue && string.IsNullOrEmpty(audioCodec)) var inputChannels = audioStream.Channels ?? 0;
var outputChannels = outputAudioChannels ?? 0;
var bitrate = audioBitRate ?? int.MaxValue;
if (string.IsNullOrEmpty(audioCodec)
|| string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase))
{ {
return Math.Min(384000, audioBitRate.Value); return (inputChannels, outputChannels) switch
{
(>= 6, >= 6 or 0) => Math.Min(640000, bitrate),
(> 0, > 0) => Math.Min(outputChannels * 128000, bitrate),
(> 0, _) => Math.Min(inputChannels * 128000, bitrate),
(_, _) => Math.Min(384000, bitrate)
};
} }
if (audioBitRate.HasValue && !string.IsNullOrEmpty(audioCodec)) if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "dca", StringComparison.OrdinalIgnoreCase))
{ {
if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase) return (inputChannels, outputChannels) switch
|| string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase))
{ {
if ((audioStream.Channels ?? 0) >= 6) (>= 6, >= 6 or 0) => Math.Min(768000, bitrate),
{ (> 0, > 0) => Math.Min(outputChannels * 136000, bitrate),
return Math.Min(640000, audioBitRate.Value); (> 0, _) => Math.Min(inputChannels * 136000, bitrate),
} (_, _) => Math.Min(672000, bitrate)
};
return Math.Min(384000, audioBitRate.Value);
}
if (string.Equals(audioCodec, "flac", StringComparison.OrdinalIgnoreCase)
|| string.Equals(audioCodec, "alac", StringComparison.OrdinalIgnoreCase))
{
if ((audioStream.Channels ?? 0) >= 6)
{
return Math.Min(3584000, audioBitRate.Value);
}
return Math.Min(1536000, audioBitRate.Value);
}
} }
// Empty bitrate area is not allow on iOS // Empty bitrate area is not allow on iOS
// Default audio bitrate to 128K if it is not being requested // Default audio bitrate to 128K per channel if we don't have codec specific defaults
// https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options // https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options
return 128000; return 128000 * (outputAudioChannels ?? audioStream.Channels ?? 2);
} }
public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions) public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions)
@@ -2397,6 +2439,30 @@ namespace MediaBrowser.Controller.MediaEncoding
return args; return args;
} }
/// <summary>
/// Gets the negative map args by filters.
/// </summary>
/// <param name="state">The state.</param>
/// <param name="videoProcessFilters">The videoProcessFilters.</param>
/// <returns>System.String.</returns>
public string GetNegativeMapArgsByFilters(EncodingJobInfo state, string videoProcessFilters)
{
string args = string.Empty;
// http://ffmpeg.org/ffmpeg-all.html#toc-Complex-filtergraphs-1
if (state.VideoStream != null && videoProcessFilters.Contains("-filter_complex", StringComparison.Ordinal))
{
int videoStreamIndex = FindIndex(state.MediaSource.MediaStreams, state.VideoStream);
args += string.Format(
CultureInfo.InvariantCulture,
"-map -0:{0} ",
videoStreamIndex);
}
return args;
}
/// <summary> /// <summary>
/// Determines which stream will be used for playback. /// Determines which stream will be used for playback.
/// </summary> /// </summary>
@@ -2767,7 +2833,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Empty; return string.Empty;
} }
public static string GetHwTonemapFilter(EncodingOptions options, string hwTonemapSuffix, string videoFormat) public string GetHwTonemapFilter(EncodingOptions options, string hwTonemapSuffix, string videoFormat)
{ {
if (string.IsNullOrEmpty(hwTonemapSuffix)) if (string.IsNullOrEmpty(hwTonemapSuffix))
{ {
@@ -2778,7 +2844,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase)) if (hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase))
{ {
args += ",procamp_vaapi=b={2}:c={3}:extra_hw_frames=16"; args = "procamp_vaapi=b={2}:c={3}," + args + ":extra_hw_frames=32";
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
args, args,
@@ -2791,14 +2858,24 @@ namespace MediaBrowser.Controller.MediaEncoding
{ {
args += ":tonemap={2}:peak={3}:desat={4}"; args += ":tonemap={2}:peak={3}:desat={4}";
if (options.TonemappingParam != 0) if (string.Equals(options.TonemappingMode, "max", StringComparison.OrdinalIgnoreCase)
|| string.Equals(options.TonemappingMode, "rgb", StringComparison.OrdinalIgnoreCase))
{ {
args += ":param={5}"; if (_mediaEncoder.EncoderVersion >= _minFFmpegOclCuTonemapMode)
{
args += ":tonemap_mode={5}";
}
} }
if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase)) if (options.TonemappingParam != 0)
{ {
args += ":range={6}"; args += ":param={6}";
}
if (string.Equals(options.TonemappingRange, "tv", StringComparison.OrdinalIgnoreCase)
|| string.Equals(options.TonemappingRange, "pc", StringComparison.OrdinalIgnoreCase))
{
args += ":range={7}";
} }
} }
@@ -2810,6 +2887,7 @@ namespace MediaBrowser.Controller.MediaEncoding
options.TonemappingAlgorithm, options.TonemappingAlgorithm,
options.TonemappingPeak, options.TonemappingPeak,
options.TonemappingDesat, options.TonemappingDesat,
options.TonemappingMode,
options.TonemappingParam, options.TonemappingParam,
options.TonemappingRange); options.TonemappingRange);
} }
@@ -3214,7 +3292,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl. // prefer hwmap to hwdownload on opencl.
var hwTransferFilter = hasGraphicalSubs ? "hwdownload" : "hwmap"; var hwTransferFilter = hasGraphicalSubs ? "hwdownload" : "hwmap=mode=read";
mainFilters.Add(hwTransferFilter); mainFilters.Add(hwTransferFilter);
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
@@ -3415,12 +3493,6 @@ namespace MediaBrowser.Controller.MediaEncoding
// map from d3d11va to qsv. // map from d3d11va to qsv.
mainFilters.Add("hwmap=derive_device=qsv"); mainFilters.Add("hwmap=derive_device=qsv");
} }
else
{
// Insert a qsv scaler to sync the decoder surface,
// msdk will passthrough this internally.
mainFilters.Add("hwmap=derive_device=qsv,scale_qsv");
}
} }
// hw deint // hw deint
@@ -3457,7 +3529,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl. // prefer hwmap to hwdownload on opencl.
// qsv hwmap is not fully implemented for the time being. // qsv hwmap is not fully implemented for the time being.
mainFilters.Add(isHwmapUsable ? "hwmap" : "hwdownload"); mainFilters.Add(isHwmapUsable ? "hwmap=mode=read" : "hwdownload");
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
@@ -3615,6 +3687,13 @@ namespace MediaBrowser.Controller.MediaEncoding
var outFormat = doTonemap ? string.Empty : "nv12"; var outFormat = doTonemap ? string.Empty : "nv12";
var hwScaleFilter = GetHwScaleFilter(isVaapiDecoder ? "vaapi" : "qsv", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH); var hwScaleFilter = GetHwScaleFilter(isVaapiDecoder ? "vaapi" : "qsv", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
// allocate extra pool sizes for vaapi vpp
if (!string.IsNullOrEmpty(hwScaleFilter) && isVaapiDecoder)
{
hwScaleFilter += ":extra_hw_frames=24";
}
// hw scale // hw scale
mainFilters.Add(hwScaleFilter); mainFilters.Add(hwScaleFilter);
} }
@@ -3661,7 +3740,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl/vaapi. // prefer hwmap to hwdownload on opencl/vaapi.
// qsv hwmap is not fully implemented for the time being. // qsv hwmap is not fully implemented for the time being.
mainFilters.Add(isHwmapUsable ? "hwmap" : "hwdownload"); mainFilters.Add(isHwmapUsable ? "hwmap=mode=read" : "hwdownload");
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
@@ -3878,6 +3957,13 @@ namespace MediaBrowser.Controller.MediaEncoding
var outFormat = doTonemap ? string.Empty : "nv12"; var outFormat = doTonemap ? string.Empty : "nv12";
var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH); var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
// allocate extra pool sizes for vaapi vpp
if (!string.IsNullOrEmpty(hwScaleFilter))
{
hwScaleFilter += ":extra_hw_frames=24";
}
// hw scale // hw scale
mainFilters.Add(hwScaleFilter); mainFilters.Add(hwScaleFilter);
} }
@@ -3919,7 +4005,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl/vaapi. // prefer hwmap to hwdownload on opencl/vaapi.
mainFilters.Add(isHwmapNotUsable ? "hwdownload" : "hwmap"); mainFilters.Add(isHwmapNotUsable ? "hwdownload" : "hwmap=mode=read");
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
@@ -4072,6 +4158,13 @@ namespace MediaBrowser.Controller.MediaEncoding
outFormat = doOclTonemap ? string.Empty : "nv12"; outFormat = doOclTonemap ? string.Empty : "nv12";
var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH); var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
// allocate extra pool sizes for vaapi vpp
if (!string.IsNullOrEmpty(hwScaleFilter))
{
hwScaleFilter += ":extra_hw_frames=24";
}
// hw scale // hw scale
mainFilters.Add(hwScaleFilter); mainFilters.Add(hwScaleFilter);
} }
@@ -4376,7 +4469,7 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
// HWA decoders can handle both video files and video folders. // HWA decoders can handle both video files and video folders.
var videoType = mediaSource.VideoType; var videoType = state.VideoType;
if (videoType != VideoType.VideoFile if (videoType != VideoType.VideoFile
&& videoType != VideoType.Iso && videoType != VideoType.Iso
&& videoType != VideoType.Dvd && videoType != VideoType.Dvd
@@ -4517,8 +4610,18 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVideotoolboxSupported = isMacOS && _mediaEncoder.SupportsHwaccel("videotoolbox"); var isVideotoolboxSupported = isMacOS && _mediaEncoder.SupportsHwaccel("videotoolbox");
var isCodecAvailable = options.HardwareDecodingCodecs.Contains(videoCodec, StringComparison.OrdinalIgnoreCase); var isCodecAvailable = options.HardwareDecodingCodecs.Contains(videoCodec, StringComparison.OrdinalIgnoreCase);
var ffmpegVersion = _mediaEncoder.EncoderVersion;
// Set the av1 codec explicitly to trigger hw accelerator, otherwise libdav1d will be used. // Set the av1 codec explicitly to trigger hw accelerator, otherwise libdav1d will be used.
var isAv1 = string.Equals(videoCodec, "av1", StringComparison.OrdinalIgnoreCase); var isAv1 = ffmpegVersion < _minFFmpegImplictHwaccel
&& string.Equals(videoCodec, "av1", StringComparison.OrdinalIgnoreCase);
// Allow profile mismatch if decoding H.264 baseline with d3d11va and vaapi hwaccels.
var profileMismatch = string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)
&& string.Equals(state.VideoStream?.Profile, "baseline", StringComparison.OrdinalIgnoreCase);
// Disable the extra internal copy in nvdec. We already handle it in filter chain.
var nvdecNoInternalCopy = ffmpegVersion >= _minFFmpegHwaUnsafeOutput;
if (bitDepth == 10 && isCodecAvailable) if (bitDepth == 10 && isCodecAvailable)
{ {
@@ -4544,14 +4647,14 @@ namespace MediaBrowser.Controller.MediaEncoding
{ {
if (isVaapiSupported && isCodecAvailable) if (isVaapiSupported && isCodecAvailable)
{ {
return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty)
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty);
} }
if (isD3d11Supported && isCodecAvailable) if (isD3d11Supported && isCodecAvailable)
{ {
// set -threads 3 to intel d3d11va decoder explicitly. Lower threads may result in dead lock. return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty)
// on newer devices such as Xe, the larger the init_pool_size, the longer the initialization time for opencl to derive from d3d11. + (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + " -threads 2" + (isAv1 ? " -c:v av1" : string.Empty);
return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : string.Empty);
} }
} }
else else
@@ -4571,7 +4674,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (options.EnableEnhancedNvdecDecoder) if (options.EnableEnhancedNvdecDecoder)
{ {
// set -threads 1 to nvdec decoder explicitly since it doesn't implement threading support. // 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); return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty)
+ (nvdecNoInternalCopy ? " -hwaccel_flags +unsafe_output" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : string.Empty);
} }
else else
{ {
@@ -4586,7 +4690,8 @@ namespace MediaBrowser.Controller.MediaEncoding
{ {
if (isD3d11Supported && isCodecAvailable) if (isD3d11Supported && isCodecAvailable)
{ {
return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty)
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty);
} }
} }
@@ -4595,9 +4700,11 @@ namespace MediaBrowser.Controller.MediaEncoding
&& isVaapiSupported && isVaapiSupported
&& isCodecAvailable) && isCodecAvailable)
{ {
return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty)
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty);
} }
// Apple videotoolbox
if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase) if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)
&& isVideotoolboxSupported && isVideotoolboxSupported
&& isCodecAvailable) && isCodecAvailable)
@@ -5213,15 +5320,23 @@ namespace MediaBrowser.Controller.MediaEncoding
return; return;
} }
var inputChannels = audioStream == null ? 6 : audioStream.Channels ?? 6; var inputChannels = audioStream is null ? 6 : audioStream.Channels ?? 6;
var shiftAudioCodecs = new List<string>();
if (inputChannels >= 6) if (inputChannels >= 6)
{ {
return; // DTS and TrueHD are not supported by HLS
// Keep them in the supported codecs list, but shift them to the end of the list so that if transcoding happens, another codec is used
shiftAudioCodecs.Add("dca");
shiftAudioCodecs.Add("truehd");
}
else
{
// Transcoding to 2ch ac3 or eac3 almost always causes a playback failure
// Keep them in the supported codecs list, but shift them to the end of the list so that if transcoding happens, another codec is used
shiftAudioCodecs.Add("ac3");
shiftAudioCodecs.Add("eac3");
} }
// Transcoding to 2ch ac3 almost always causes a playback failure
// Keep it in the supported codecs list, but shift it to the end of the list so that if transcoding happens, another codec is used
var shiftAudioCodecs = new[] { "ac3", "eac3" };
if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparison.OrdinalIgnoreCase))) if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparison.OrdinalIgnoreCase)))
{ {
return; return;
@@ -5398,7 +5513,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// video processing filters. // video processing filters.
var videoProcessParam = GetVideoProcessingFilterParam(state, encodingOptions, videoCodec); var videoProcessParam = GetVideoProcessingFilterParam(state, encodingOptions, videoCodec);
args += videoProcessParam; var negativeMapArgs = GetNegativeMapArgsByFilters(state, videoProcessParam);
args = negativeMapArgs + args + videoProcessParam;
hasCopyTs = videoProcessParam.Contains("copyts", StringComparison.OrdinalIgnoreCase); hasCopyTs = videoProcessParam.Contains("copyts", StringComparison.OrdinalIgnoreCase);
@@ -5463,7 +5580,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var bitrate = state.OutputAudioBitrate; var bitrate = state.OutputAudioBitrate;
if (bitrate.HasValue) if (bitrate.HasValue && !LosslessAudioCodecs.Contains(codec, StringComparison.OrdinalIgnoreCase))
{ {
args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture);
} }
@@ -5483,8 +5600,10 @@ namespace MediaBrowser.Controller.MediaEncoding
var audioTranscodeParams = new List<string>(); var audioTranscodeParams = new List<string>();
var bitrate = state.OutputAudioBitrate; var bitrate = state.OutputAudioBitrate;
var channels = state.OutputAudioChannels;
var outputCodec = state.OutputAudioCodec;
if (bitrate.HasValue) if (bitrate.HasValue && !LosslessAudioCodecs.Contains(outputCodec, StringComparison.OrdinalIgnoreCase))
{ {
audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture));
} }
@@ -5494,7 +5613,12 @@ namespace MediaBrowser.Controller.MediaEncoding
audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture));
} }
if (!string.Equals(state.OutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)) if (!string.IsNullOrEmpty(outputCodec))
{
audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state));
}
if (!string.Equals(outputCodec, "opus", StringComparison.OrdinalIgnoreCase))
{ {
// opus only supports specific sampling rates // opus only supports specific sampling rates
var sampleRate = state.OutputAudioSampleRate; var sampleRate = state.OutputAudioSampleRate;
@@ -14,6 +14,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Encoder;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
@@ -317,10 +318,10 @@ namespace MediaBrowser.MediaEncoding.Attachments
var processArgs = string.Format( var processArgs = string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"-dump_attachment:{1} {2} -i {0} -t 0 -f null null", "-dump_attachment:{1} \"{2}\" -i {0} -t 0 -f null null",
inputPath, inputPath,
attachmentStreamIndex, attachmentStreamIndex,
outputPath); EncodingUtils.NormalizePath(outputPath));
int exitCode; int exitCode;
@@ -25,11 +25,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
"mpeg2video", "mpeg2video",
"mpeg4", "mpeg4",
"msmpeg4", "msmpeg4",
"dts", "dca",
"ac3", "ac3",
"aac", "aac",
"mp3", "mp3",
"flac", "flac",
"truehd",
"h264_qsv", "h264_qsv",
"hevc_qsv", "hevc_qsv",
"mpeg2_qsv", "mpeg2_qsv",
@@ -58,10 +59,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
"aac", "aac",
"libfdk_aac", "libfdk_aac",
"ac3", "ac3",
"dca",
"libmp3lame", "libmp3lame",
"libopus", "libopus",
"libvorbis", "libvorbis",
"flac", "flac",
"truehd",
"srt", "srt",
"h264_amf", "h264_amf",
"hevc_amf", "hevc_amf",
@@ -56,7 +56,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
private static string NormalizePath(string path) public static string NormalizePath(string path)
{ {
// Quotes are valid path characters in linux and they need to be escaped here with a leading \ // Quotes are valid path characters in linux and they need to be escaped here with a leading \
return path.Replace("\"", "\\\"", StringComparison.Ordinal); return path.Replace("\"", "\\\"", StringComparison.Ordinal);
@@ -751,9 +751,11 @@ namespace MediaBrowser.MediaEncoding.Probing
} }
if (isAudio if (isAudio
|| string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) && (string.Equals(stream.Codec, "bmp", StringComparison.OrdinalIgnoreCase)
|| string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase)
|| string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)) || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)
|| string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)
|| string.Equals(stream.Codec, "webp", StringComparison.OrdinalIgnoreCase)))
{ {
stream.Type = MediaStreamType.EmbeddedImage; stream.Type = MediaStreamType.EmbeddedImage;
} }
@@ -21,20 +21,21 @@ namespace MediaBrowser.Model.Configuration
EnableTonemapping = false; EnableTonemapping = false;
EnableVppTonemapping = false; EnableVppTonemapping = false;
TonemappingAlgorithm = "bt2390"; TonemappingAlgorithm = "bt2390";
TonemappingMode = "auto";
TonemappingRange = "auto"; TonemappingRange = "auto";
TonemappingDesat = 0; TonemappingDesat = 0;
TonemappingThreshold = 0.8;
TonemappingPeak = 100; TonemappingPeak = 100;
TonemappingParam = 0; TonemappingParam = 0;
VppTonemappingBrightness = 0; VppTonemappingBrightness = 16;
VppTonemappingContrast = 1.2; VppTonemappingContrast = 1;
H264Crf = 23; H264Crf = 23;
H265Crf = 28; H265Crf = 28;
DeinterlaceDoubleRate = false; DeinterlaceDoubleRate = false;
DeinterlaceMethod = "yadif"; DeinterlaceMethod = "yadif";
EnableDecodingColorDepth10Hevc = true; EnableDecodingColorDepth10Hevc = true;
EnableDecodingColorDepth10Vp9 = true; EnableDecodingColorDepth10Vp9 = true;
EnableEnhancedNvdecDecoder = false; // Enhanced Nvdec or system native decoder is required for DoVi to SDR tone-mapping.
EnableEnhancedNvdecDecoder = true;
PreferSystemNativeHwDecoder = true; PreferSystemNativeHwDecoder = true;
EnableIntelLowPowerH264HwEncoder = false; EnableIntelLowPowerH264HwEncoder = false;
EnableIntelLowPowerHevcHwEncoder = false; EnableIntelLowPowerHevcHwEncoder = false;
@@ -81,12 +82,12 @@ namespace MediaBrowser.Model.Configuration
public string TonemappingAlgorithm { get; set; } public string TonemappingAlgorithm { get; set; }
public string TonemappingMode { get; set; }
public string TonemappingRange { get; set; } public string TonemappingRange { get; set; }
public double TonemappingDesat { get; set; } public double TonemappingDesat { get; set; }
public double TonemappingThreshold { get; set; }
public double TonemappingPeak { get; set; } public double TonemappingPeak { get; set; }
public double TonemappingParam { get; set; } public double TonemappingParam { get; set; }
+34 -5
View File
@@ -136,12 +136,26 @@ namespace MediaBrowser.Model.Dlna
return !condition.IsRequired; return !condition.IsRequired;
} }
if (int.TryParse(condition.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var expected)) var conditionType = condition.Condition;
if (condition.Condition == ProfileConditionType.EqualsAny)
{ {
switch (condition.Condition) foreach (var singleConditionString in condition.Value.AsSpan().Split('|'))
{
if (int.TryParse(singleConditionString, NumberStyles.Integer, CultureInfo.InvariantCulture, out int conditionValue)
&& conditionValue.Equals(currentValue))
{
return true;
}
}
return false;
}
if (int.TryParse(condition.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var expected))
{
switch (conditionType)
{ {
case ProfileConditionType.Equals: case ProfileConditionType.Equals:
case ProfileConditionType.EqualsAny:
return currentValue.Value.Equals(expected); return currentValue.Value.Equals(expected);
case ProfileConditionType.GreaterThanEqual: case ProfileConditionType.GreaterThanEqual:
return currentValue.Value >= expected; return currentValue.Value >= expected;
@@ -212,9 +226,24 @@ namespace MediaBrowser.Model.Dlna
return !condition.IsRequired; return !condition.IsRequired;
} }
if (double.TryParse(condition.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var expected)) var conditionType = condition.Condition;
if (condition.Condition == ProfileConditionType.EqualsAny)
{ {
switch (condition.Condition) foreach (var singleConditionString in condition.Value.AsSpan().Split('|'))
{
if (double.TryParse(singleConditionString, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out double conditionValue)
&& conditionValue.Equals(currentValue))
{
return true;
}
}
return false;
}
if (double.TryParse(condition.Value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var expected))
{
switch (conditionType)
{ {
case ProfileConditionType.Equals: case ProfileConditionType.Equals:
return currentValue.Value.Equals(expected); return currentValue.Value.Equals(expected);
+34 -7
View File
@@ -23,6 +23,9 @@ namespace MediaBrowser.Model.Dlna
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ITranscoderSupport _transcoderSupport; private readonly ITranscoderSupport _transcoderSupport;
private static readonly string[] _supportedHlsVideoCodecs = new string[] { "h264", "hevc" };
private static readonly string[] _supportedHlsAudioCodecsTs = new string[] { "aac", "ac3", "eac3", "mp3" };
private static readonly string[] _supportedHlsAudioCodecsMp4 = new string[] { "aac", "ac3", "eac3", "mp3", "alac", "flac", "opus", "dca", "truehd" };
public StreamBuilder(ITranscoderSupport transcoderSupport, ILogger logger) public StreamBuilder(ITranscoderSupport transcoderSupport, ILogger logger)
{ {
@@ -732,7 +735,7 @@ namespace MediaBrowser.Model.Dlna
if (options.AllowVideoStreamCopy) if (options.AllowVideoStreamCopy)
{ {
// prefer direct copy profile // prefer direct copy profile
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; float videoFramerate = videoStream?.AverageFrameRate ?? videoStream?.RealFrameRate ?? 0;
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
@@ -743,7 +746,7 @@ namespace MediaBrowser.Model.Dlna
if (ContainerProfile.ContainsContainer(videoCodecs, item.VideoStream?.Codec)) if (ContainerProfile.ContainsContainer(videoCodecs, item.VideoStream?.Codec))
{ {
var videoCodec = transcodingProfile.VideoCodec; var videoCodec = videoStream?.Codec;
var container = transcodingProfile.Container; var container = transcodingProfile.Container;
var appliedVideoConditions = options.Profile.CodecProfiles var appliedVideoConditions = options.Profile.CodecProfiles
.Where(i => i.Type == CodecType.Video && .Where(i => i.Type == CodecType.Video &&
@@ -770,6 +773,13 @@ namespace MediaBrowser.Model.Dlna
{ {
// Prefer matching video codecs // Prefer matching video codecs
var videoCodecs = ContainerProfile.SplitValue(videoCodec); var videoCodecs = ContainerProfile.SplitValue(videoCodec);
// Enforce HLS video codec restrictions
if (string.Equals(playlistItem.SubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
{
videoCodecs = videoCodecs.Where(codec => _supportedHlsVideoCodecs.Contains(codec)).ToArray();
}
var directVideoCodec = ContainerProfile.ContainsContainer(videoCodecs, videoStream?.Codec) ? videoStream?.Codec : null; var directVideoCodec = ContainerProfile.ContainsContainer(videoCodecs, videoStream?.Codec) ? videoStream?.Codec : null;
if (directVideoCodec != null) if (directVideoCodec != null)
{ {
@@ -805,6 +815,20 @@ namespace MediaBrowser.Model.Dlna
// Prefer matching audio codecs, could do better here // Prefer matching audio codecs, could do better here
var audioCodecs = ContainerProfile.SplitValue(audioCodec); var audioCodecs = ContainerProfile.SplitValue(audioCodec);
// Enforce HLS audio codec restrictions
if (string.Equals(playlistItem.SubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(playlistItem.Container, "mp4", StringComparison.OrdinalIgnoreCase))
{
audioCodecs = audioCodecs.Where(codec => _supportedHlsAudioCodecsMp4.Contains(codec)).ToArray();
}
else
{
audioCodecs = audioCodecs.Where(codec => _supportedHlsAudioCodecsTs.Contains(codec)).ToArray();
}
}
var directAudioStream = candidateAudioStreams.FirstOrDefault(stream => ContainerProfile.ContainsContainer(audioCodecs, stream.Codec)); var directAudioStream = candidateAudioStreams.FirstOrDefault(stream => ContainerProfile.ContainsContainer(audioCodecs, stream.Codec));
playlistItem.AudioCodecs = audioCodecs; playlistItem.AudioCodecs = audioCodecs;
if (directAudioStream != null) if (directAudioStream != null)
@@ -850,7 +874,7 @@ namespace MediaBrowser.Model.Dlna
var appliedVideoConditions = options.Profile.CodecProfiles var appliedVideoConditions = options.Profile.CodecProfiles
.Where(i => i.Type == CodecType.Video && .Where(i => i.Type == CodecType.Video &&
i.ContainsAnyCodec(videoCodec, container) && i.ContainsAnyCodec(videoStream?.Codec, container) &&
i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)));
var isFirstAppliedCodecProfile = true; var isFirstAppliedCodecProfile = true;
foreach (var i in appliedVideoConditions) foreach (var i in appliedVideoConditions)
@@ -882,7 +906,7 @@ namespace MediaBrowser.Model.Dlna
var appliedAudioConditions = options.Profile.CodecProfiles var appliedAudioConditions = options.Profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoAudio && .Where(i => i.Type == CodecType.VideoAudio &&
i.ContainsAnyCodec(audioCodec, container) && i.ContainsAnyCodec(audioStream?.Codec, container) &&
i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))); i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio)));
isFirstAppliedCodecProfile = true; isFirstAppliedCodecProfile = true;
foreach (var i in appliedAudioConditions) foreach (var i in appliedAudioConditions)
@@ -1114,7 +1138,8 @@ namespace MediaBrowser.Model.Dlna
profile, profile,
"VideoCodecProfile", "VideoCodecProfile",
profile.CodecProfiles profile.CodecProfiles
.Where(codecProfile => codecProfile.Type == CodecType.Video && codecProfile.ContainsAnyCodec(videoStream?.Codec, container) && .Where(codecProfile => codecProfile.Type == CodecType.Video &&
codecProfile.ContainsAnyCodec(videoStream?.Codec, container) &&
!checkVideoConditions(codecProfile.ApplyConditions).Any()) !checkVideoConditions(codecProfile.ApplyConditions).Any())
.SelectMany(codecProfile => checkVideoConditions(codecProfile.Conditions))); .SelectMany(codecProfile => checkVideoConditions(codecProfile.Conditions)));
@@ -1535,7 +1560,8 @@ namespace MediaBrowser.Model.Dlna
bool? isSecondaryAudio) bool? isSecondaryAudio)
{ {
return codecProfiles return codecProfiles
.Where(profile => profile.Type == CodecType.VideoAudio && profile.ContainsAnyCodec(codec, container) && .Where(profile => profile.Type == CodecType.VideoAudio &&
profile.ContainsAnyCodec(codec, container) &&
profile.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))) profile.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)))
.SelectMany(profile => profile.Conditions) .SelectMany(profile => profile.Conditions)
.Where(condition => !ConditionProcessor.IsVideoAudioConditionSatisfied(condition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)); .Where(condition => !ConditionProcessor.IsVideoAudioConditionSatisfied(condition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio));
@@ -1552,7 +1578,8 @@ namespace MediaBrowser.Model.Dlna
bool checkConditions) bool checkConditions)
{ {
var conditions = codecProfiles var conditions = codecProfiles
.Where(profile => profile.Type == CodecType.Audio && profile.ContainsAnyCodec(codec, container) && .Where(profile => profile.Type == CodecType.Audio &&
profile.ContainsAnyCodec(codec, container) &&
profile.ApplyConditions.All(applyCondition => ConditionProcessor.IsAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth))) profile.ApplyConditions.All(applyCondition => ConditionProcessor.IsAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth)))
.SelectMany(profile => profile.Conditions); .SelectMany(profile => profile.Conditions);
+1 -1
View File
@@ -8,7 +8,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Model</PackageId> <PackageId>Jellyfin.Model</PackageId>
<VersionPrefix>10.8.9</VersionPrefix> <VersionPrefix>10.8.12</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
@@ -181,6 +181,10 @@ namespace MediaBrowser.Providers.Manager
{ {
contentType = "image/png"; contentType = "image/png";
} }
else
{
throw new HttpRequestException("Invalid image received: contentType not set.", null, response.StatusCode);
}
} }
// thetvdb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons... // thetvdb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons...
@@ -176,9 +176,11 @@ namespace MediaBrowser.Providers.MediaInfo
var format = imageStream.Codec switch var format = imageStream.Codec switch
{ {
"bmp" => ImageFormat.Bmp,
"gif" => ImageFormat.Gif,
"mjpeg" => ImageFormat.Jpg, "mjpeg" => ImageFormat.Jpg,
"png" => ImageFormat.Png, "png" => ImageFormat.Png,
"gif" => ImageFormat.Gif, "webp" => ImageFormat.Webp,
_ => ImageFormat.Jpg _ => ImageFormat.Jpg
}; };
+2 -2
View File
@@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("10.8.9")] [assembly: AssemblyVersion("10.8.12")]
[assembly: AssemblyFileVersion("10.8.9")] [assembly: AssemblyFileVersion("10.8.12")]
+1 -1
View File
@@ -1,7 +1,7 @@
--- ---
# We just wrap `build` so this is really it # We just wrap `build` so this is really it
name: "jellyfin" name: "jellyfin"
version: "10.8.9" version: "10.8.12"
packages: packages:
- debian.amd64 - debian.amd64
- debian.arm64 - debian.arm64
+18
View File
@@ -1,3 +1,21 @@
jellyfin-server (10.8.12-1) unstable; urgency=medium
* New upstream version 10.8.12; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.12
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sat, 04 Nov 2023 14:42:37 -0400
jellyfin-server (10.8.11-1) unstable; urgency=medium
* New upstream version 10.8.11; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.11
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sat, 23 Sep 2023 21:40:37 -0400
jellyfin-server (10.8.10-1) unstable; urgency=medium
* New upstream version 10.8.10; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.10
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 23 Apr 2023 11:02:05 -0400
jellyfin-server (10.8.9-1) unstable; urgency=medium jellyfin-server (10.8.9-1) unstable; urgency=medium
* New upstream version 10.8.9; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.9 * New upstream version 10.8.9; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.9
+3
View File
@@ -27,6 +27,9 @@ JELLYFIN_RESTART_OPT="--restartpath=/usr/lib/jellyfin/restart.sh"
# ffmpeg binary paths, overriding the system values # ffmpeg binary paths, overriding the system values
JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg" JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg"
# Disable glibc dynamic heap adjustment
MALLOC_TRIM_THRESHOLD_=131072
# [OPTIONAL] run Jellyfin as a headless service # [OPTIONAL] run Jellyfin as a headless service
#JELLYFIN_SERVICE_OPT="--service" #JELLYFIN_SERVICE_OPT="--service"
+1 -1
View File
@@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
Standards-Version: 3.9.2 Standards-Version: 3.9.2
Package: jellyfin Package: jellyfin
Version: 10.8.9 Version: 10.8.12
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org> Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
Depends: jellyfin-server, jellyfin-web Depends: jellyfin-server, jellyfin-web
Description: Provides the Jellyfin Free Software Media System Description: Provides the Jellyfin Free Software Media System
+10
View File
@@ -10,6 +10,8 @@ if [[ -f $DEFAULT_FILE ]]; then
fi fi
JELLYFIN_USER=${JELLYFIN_USER:-jellyfin} JELLYFIN_USER=${JELLYFIN_USER:-jellyfin}
RENDER_GROUP=${RENDER_GROUP:-render}
VIDEO_GROUP=${VIDEO_GROUP:-video}
# Data directories for program data (cache, db), configs, and logs # Data directories for program data (cache, db), configs, and logs
PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME} PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
@@ -28,6 +30,14 @@ case "$1" in
adduser --system --ingroup ${JELLYFIN_USER} --shell /bin/false ${JELLYFIN_USER} --no-create-home --home ${PROGRAMDATA} \ adduser --system --ingroup ${JELLYFIN_USER} --shell /bin/false ${JELLYFIN_USER} --no-create-home --home ${PROGRAMDATA} \
--gecos "Jellyfin default user" > /dev/null 2>&1 --gecos "Jellyfin default user" > /dev/null 2>&1
fi fi
# Add jellyfin to the render group for hwa
if [[ ! -z "$(getent group ${RENDER_GROUP})" ]]; then
usermod -aG ${RENDER_GROUP} ${JELLYFIN_USER} > /dev/null 2>&1
fi
# Add jellyfin to the video group for hwa
if [[ ! -z "$(getent group ${VIDEO_GROUP})" ]]; then
usermod -aG ${VIDEO_GROUP} ${JELLYFIN_USER} > /dev/null 2>&1
fi
# ensure $PROGRAMDATA exists # ensure $PROGRAMDATA exists
if [[ ! -d $PROGRAMDATA ]]; then if [[ ! -d $PROGRAMDATA ]]; then
mkdir $PROGRAMDATA mkdir $PROGRAMDATA
+3
View File
@@ -26,6 +26,9 @@ JELLYFIN_CACHE_DIR="/var/cache/jellyfin"
# In-App service control # In-App service control
JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh" JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh"
# Disable glibc dynamic heap adjustment
MALLOC_TRIM_THRESHOLD_=131072
# [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values # [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values
#JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg" #JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg"
+10 -1
View File
@@ -7,7 +7,7 @@
%endif %endif
Name: jellyfin Name: jellyfin
Version: 10.8.9 Version: 10.8.12
Release: 1%{?dist} Release: 1%{?dist}
Summary: The Free Software Media System Summary: The Free Software Media System
License: GPLv2 License: GPLv2
@@ -139,6 +139,9 @@ getent group jellyfin >/dev/null || groupadd -r jellyfin
getent passwd jellyfin >/dev/null || \ getent passwd jellyfin >/dev/null || \
useradd -r -g jellyfin -d %{_sharedstatedir}/jellyfin -s /sbin/nologin \ useradd -r -g jellyfin -d %{_sharedstatedir}/jellyfin -s /sbin/nologin \
-c "Jellyfin default user" jellyfin -c "Jellyfin default user" jellyfin
# Add jellyfin to the render and video groups for hwa.
[ ! -z "$(getent group render)" ] && usermod -aG render jellyfin >/dev/null 2>&1
[ ! -z "$(getent group video)" ] && usermod -aG video jellyfin >/dev/null 2>&1
exit 0 exit 0
%post server %post server
@@ -176,6 +179,12 @@ fi
%systemd_postun_with_restart jellyfin.service %systemd_postun_with_restart jellyfin.service
%changelog %changelog
* Sat Nov 04 2023 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.12; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.12
* Sat Sep 23 2023 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.11; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.11
* Sun Apr 23 2023 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.10; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.10
* Sun Jan 22 2023 Jellyfin Packaging Team <packaging@jellyfin.org> * Sun Jan 22 2023 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.9; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.9 - New upstream version 10.8.9; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.9
* Tue Nov 29 2022 Jellyfin Packaging Team <packaging@jellyfin.org> * Tue Nov 29 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
@@ -13,7 +13,7 @@
<PropertyGroup> <PropertyGroup>
<Authors>Jellyfin Contributors</Authors> <Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Extensions</PackageId> <PackageId>Jellyfin.Extensions</PackageId>
<VersionPrefix>10.8.9</VersionPrefix> <VersionPrefix>10.8.12</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup> </PropertyGroup>
@@ -17,6 +17,8 @@ namespace Jellyfin.MediaEncoding.Tests
} }
[Theory] [Theory]
[InlineData(EncoderValidatorTestsData.FFmpegV60Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV512Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV44Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV44Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV432Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV432Output, true)]
[InlineData(EncoderValidatorTestsData.FFmpegV431Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV431Output, true)]
@@ -36,6 +38,8 @@ namespace Jellyfin.MediaEncoding.Tests
{ {
public GetFFmpegVersionTestData() public GetFFmpegVersionTestData()
{ {
Add(EncoderValidatorTestsData.FFmpegV60Output, new Version(6, 0));
Add(EncoderValidatorTestsData.FFmpegV512Output, new Version(5, 1, 2));
Add(EncoderValidatorTestsData.FFmpegV44Output, new Version(4, 4)); Add(EncoderValidatorTestsData.FFmpegV44Output, new Version(4, 4));
Add(EncoderValidatorTestsData.FFmpegV432Output, new Version(4, 3, 2)); Add(EncoderValidatorTestsData.FFmpegV432Output, new Version(4, 3, 2));
Add(EncoderValidatorTestsData.FFmpegV431Output, new Version(4, 3, 1)); Add(EncoderValidatorTestsData.FFmpegV431Output, new Version(4, 3, 1));
@@ -2,6 +2,30 @@ namespace Jellyfin.MediaEncoding.Tests
{ {
internal static class EncoderValidatorTestsData internal static class EncoderValidatorTestsData
{ {
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
libavutil 58. 2.100 / 58. 2.100
libavcodec 60. 3.100 / 60. 3.100
libavformat 60. 3.100 / 60. 3.100
libavdevice 60. 1.100 / 60. 1.100
libavfilter 9. 3.100 / 9. 3.100
libswscale 7. 1.100 / 7. 1.100
libswresample 4. 10.100 / 4. 10.100
libpostproc 57. 1.100 / 57. 1.100";
public const string FFmpegV512Output = @"ffmpeg version 5.1.2-Jellyfin Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 10-win32 (GCC) 20220324
configuration: --prefix=/opt/ffmpeg --arch=x86_64 --target-os=mingw32 --cross-prefix=x86_64-w64-mingw32- --pkg-config=pkg-config --pkg-config-flags=--static --extra-libs='-lfftw3f -lstdc++' --extra-cflags=-DCHROMAPRINT_NODLL --extra-version=Jellyfin --disable-ffplay --disable-debug --disable-doc --disable-sdl2 --disable-ptx-compression --disable-w32threads --enable-pthreads --enable-shared --enable-lto --enable-gpl --enable-version3 --enable-schannel --enable-iconv --enable-libxml2 --enable-zlib --enable-lzma --enable-gmp --enable-chromaprint --enable-libfreetype --enable-libfribidi --enable-libfontconfig --enable-libass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libvpx --enable-libzimg --enable-libx264 --enable-libx265 --enable-libsvtav1 --enable-libdav1d --enable-libfdk-aac --enable-opencl --enable-dxva2 --enable-d3d11va --enable-amf --enable-libmfx --enable-ffnvcodec --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvdec --enable-nvenc
libavutil 57. 28.100 / 57. 28.100
libavcodec 59. 37.100 / 59. 37.100
libavformat 59. 27.100 / 59. 27.100
libavdevice 59. 7.100 / 59. 7.100
libavfilter 8. 44.100 / 8. 44.100
libswscale 6. 7.100 / 6. 7.100
libswresample 4. 7.100 / 4. 7.100
libpostproc 56. 6.100 / 56. 6.100";
public const string FFmpegV44Output = @"ffmpeg version 4.4-Jellyfin Copyright (c) 2000-2021 the FFmpeg developers public const string FFmpegV44Output = @"ffmpeg version 4.4-Jellyfin Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 10.3.0 (Rev5, Built by MSYS2 project) built with gcc 10.3.0 (Rev5, Built by MSYS2 project)
configuration: --disable-static --enable-shared --extra-version=Jellyfin --disable-ffplay --disable-debug --enable-gpl --enable-version3 --enable-bzlib --enable-iconv --enable-lzma --enable-zlib --enable-sdl2 --enable-fontconfig --enable-gmp --enable-libass --enable-libzimg --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libvpx --enable-libx264 --enable-libx265 --enable-libdav1d --enable-opencl --enable-dxva2 --enable-d3d11va --enable-amf --enable-libmfx --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvenc --enable-nvdec --enable-ffnvcodec --enable-gnutls configuration: --disable-static --enable-shared --extra-version=Jellyfin --disable-ffplay --disable-debug --enable-gpl --enable-version3 --enable-bzlib --enable-iconv --enable-lzma --enable-zlib --enable-sdl2 --enable-fontconfig --enable-gmp --enable-libass --enable-libzimg --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libvpx --enable-libx264 --enable-libx265 --enable-libdav1d --enable-opencl --enable-dxva2 --enable-d3d11va --enable-amf --enable-libmfx --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvenc --enable-nvdec --enable-ffnvcodec --enable-gnutls
@@ -98,9 +98,11 @@ namespace Jellyfin.Providers.Tests.MediaInfo
[InlineData(null, null, 1, ImageType.Primary, ImageFormat.Jpg)] // no label, finds primary [InlineData(null, null, 1, ImageType.Primary, ImageFormat.Jpg)] // no label, finds primary
[InlineData("backdrop", null, 2, ImageType.Backdrop, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream [InlineData("backdrop", null, 2, ImageType.Backdrop, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
[InlineData("cover", null, 2, ImageType.Primary, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream [InlineData("cover", null, 2, ImageType.Primary, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
[InlineData(null, "bmp", 1, ImageType.Primary, ImageFormat.Bmp)]
[InlineData(null, "gif", 1, ImageType.Primary, ImageFormat.Gif)]
[InlineData(null, "mjpeg", 1, ImageType.Primary, ImageFormat.Jpg)] [InlineData(null, "mjpeg", 1, ImageType.Primary, ImageFormat.Jpg)]
[InlineData(null, "png", 1, ImageType.Primary, ImageFormat.Png)] [InlineData(null, "png", 1, ImageType.Primary, ImageFormat.Png)]
[InlineData(null, "gif", 1, ImageType.Primary, ImageFormat.Gif)] [InlineData(null, "webp", 1, ImageType.Primary, ImageFormat.Webp)]
public async void GetImage_Embedded_ReturnsCorrectSelection(string label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat) public async void GetImage_Embedded_ReturnsCorrectSelection(string label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat)
{ {
var streams = new List<MediaStream>(); var streams = new List<MediaStream>();