diff options
Diffstat (limited to 'Jellyfin.Api/Controllers')
| -rw-r--r-- | Jellyfin.Api/Controllers/DynamicHlsController.cs | 33 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/HlsSegmentController.cs | 9 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/ImageController.cs | 43 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/SubtitleController.cs | 8 |
4 files changed, 46 insertions, 47 deletions
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 065a4ce5c6..7bf366e5d0 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -45,6 +45,8 @@ public class DynamicHlsController : BaseJellyfinApiController private const string DefaultEventEncoderPreset = "superfast"; private const TranscodingJobType TranscodingJobType = MediaBrowser.Controller.MediaEncoding.TranscodingJobType.Hls; + private readonly Version _minFFmpegFlacInMp4 = new Version(6, 0); + private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; private readonly IDlnaManager _dlnaManager; @@ -1705,16 +1707,28 @@ public class DynamicHlsController : BaseJellyfinApiController var audioCodec = _encodingHelper.GetAudioEncoder(state); var bitStreamArgs = EncodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container); + // opus, dts, truehd and flac (in FFmpeg 5 and older) are experimental in mp4 muxer + var strictArgs = string.Empty; + var actualOutputAudioCodec = state.ActualOutputAudioCodec; + if (string.Equals(actualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase) + || string.Equals(actualOutputAudioCodec, "dts", StringComparison.OrdinalIgnoreCase) + || string.Equals(actualOutputAudioCodec, "truehd", StringComparison.OrdinalIgnoreCase) + || (string.Equals(actualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase) + && _mediaEncoder.EncoderVersion < _minFFmpegFlacInMp4)) + { + strictArgs = " -strict -2"; + } + if (!state.IsOutputVideo) { if (EncodingHelper.IsCopyCodec(audioCodec)) { - return "-acodec copy -strict -2" + bitStreamArgs; + return "-acodec copy" + bitStreamArgs + strictArgs; } var audioTranscodeParams = string.Empty; - audioTranscodeParams += "-acodec " + audioCodec + bitStreamArgs; + audioTranscodeParams += "-acodec " + audioCodec + bitStreamArgs + strictArgs; var audioBitrate = state.OutputAudioBitrate; var audioChannels = state.OutputAudioChannels; @@ -1746,17 +1760,6 @@ public class DynamicHlsController : BaseJellyfinApiController return audioTranscodeParams; } - // dts, flac, opus and truehd are experimental in mp4 muxer - var strictArgs = string.Empty; - var actualOutputAudioCodec = state.ActualOutputAudioCodec; - if (string.Equals(actualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase) - || string.Equals(actualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase) - || string.Equals(actualOutputAudioCodec, "dts", StringComparison.OrdinalIgnoreCase) - || string.Equals(actualOutputAudioCodec, "truehd", StringComparison.OrdinalIgnoreCase)) - { - strictArgs = " -strict -2"; - } - if (EncodingHelper.IsCopyCodec(audioCodec)) { var videoCodec = _encodingHelper.GetVideoEncoder(state, _encodingOptions); @@ -2041,9 +2044,9 @@ public class DynamicHlsController : BaseJellyfinApiController return null; } - var playlistFilename = Path.GetFileNameWithoutExtension(playlist); + var playlistFilename = Path.GetFileNameWithoutExtension(playlist.AsSpan()); - var indexString = Path.GetFileNameWithoutExtension(file.Name).Substring(playlistFilename.Length); + var indexString = Path.GetFileNameWithoutExtension(file.Name.AsSpan()).Slice(playlistFilename.Length); return int.Parse(indexString, NumberStyles.Integer, CultureInfo.InvariantCulture); } diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index d7cec865e1..6eedfd8c7f 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -59,7 +59,7 @@ public class HlsSegmentController : BaseJellyfinApiController public ActionResult GetHlsAudioSegmentLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string segmentId) { // TODO: Deprecate with new iOS app - var file = segmentId + Path.GetExtension(Request.Path); + var file = string.Concat(segmentId, Path.GetExtension(Request.Path.Value.AsSpan())); var transcodePath = _serverConfigurationManager.GetTranscodePath(); file = Path.GetFullPath(Path.Combine(transcodePath, file)); var fileDir = Path.GetDirectoryName(file); @@ -85,11 +85,12 @@ public class HlsSegmentController : BaseJellyfinApiController [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId) { - var file = playlistId + Path.GetExtension(Request.Path); + var file = string.Concat(playlistId, Path.GetExtension(Request.Path.Value.AsSpan())); var transcodePath = _serverConfigurationManager.GetTranscodePath(); file = Path.GetFullPath(Path.Combine(transcodePath, file)); var fileDir = Path.GetDirectoryName(file); - if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath, StringComparison.InvariantCulture) || Path.GetExtension(file) != ".m3u8") + if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath, StringComparison.InvariantCulture) + || Path.GetExtension(file.AsSpan()).Equals(".m3u8", StringComparison.OrdinalIgnoreCase)) { return BadRequest("Invalid segment."); } @@ -138,7 +139,7 @@ public class HlsSegmentController : BaseJellyfinApiController [FromRoute, Required] string segmentId, [FromRoute, Required] string segmentContainer) { - var file = segmentId + Path.GetExtension(Request.Path); + var file = string.Concat(segmentId, Path.GetExtension(Request.Path.Value.AsSpan())); var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath(); file = Path.GetFullPath(Path.Combine(transcodeFolderPath, file)); diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 3c5f18af55..7b10ea170f 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net.Mime; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; @@ -78,6 +79,9 @@ public class ImageController : BaseJellyfinApiController _appPaths = appPaths; } + private static Stream GetFromBase64Stream(Stream inputStream) + => new CryptoStream(inputStream, new FromBase64Transform(), CryptoStreamMode.Read); + /// <summary> /// Sets the user image. /// </summary> @@ -116,8 +120,8 @@ public class ImageController : BaseJellyfinApiController return BadRequest("Incorrect ContentType."); } - var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - await using (memoryStream.ConfigureAwait(false)) + var stream = GetFromBase64Stream(Request.Body); + await using (stream.ConfigureAwait(false)) { // Handle image/png; charset=utf-8 var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); @@ -130,7 +134,7 @@ public class ImageController : BaseJellyfinApiController user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension)); await _providerManager - .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .SaveImage(stream, mimeType, user.ProfileImage.Path) .ConfigureAwait(false); await _userManager.UpdateUserAsync(user).ConfigureAwait(false); @@ -176,8 +180,8 @@ public class ImageController : BaseJellyfinApiController return BadRequest("Incorrect ContentType."); } - var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - await using (memoryStream.ConfigureAwait(false)) + var stream = GetFromBase64Stream(Request.Body); + await using (stream.ConfigureAwait(false)) { // Handle image/png; charset=utf-8 var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); @@ -190,7 +194,7 @@ public class ImageController : BaseJellyfinApiController user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension)); await _providerManager - .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .SaveImage(stream, mimeType, user.ProfileImage.Path) .ConfigureAwait(false); await _userManager.UpdateUserAsync(user).ConfigureAwait(false); @@ -372,12 +376,12 @@ public class ImageController : BaseJellyfinApiController return BadRequest("Incorrect ContentType."); } - var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - await using (memoryStream.ConfigureAwait(false)) + var stream = GetFromBase64Stream(Request.Body); + await using (stream.ConfigureAwait(false)) { // Handle image/png; charset=utf-8 var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(item, stream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return NoContent(); @@ -416,12 +420,12 @@ public class ImageController : BaseJellyfinApiController return BadRequest("Incorrect ContentType."); } - var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - await using (memoryStream.ConfigureAwait(false)) + var stream = GetFromBase64Stream(Request.Body); + await using (stream.ConfigureAwait(false)) { // Handle image/png; charset=utf-8 var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(item, stream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return NoContent(); @@ -1792,8 +1796,8 @@ public class ImageController : BaseJellyfinApiController return BadRequest("Incorrect ContentType."); } - var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - await using (memoryStream.ConfigureAwait(false)) + var stream = GetFromBase64Stream(Request.Body); + await using (stream.ConfigureAwait(false)) { var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension); var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding"); @@ -1803,7 +1807,7 @@ public class ImageController : BaseJellyfinApiController var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await using (fs.ConfigureAwait(false)) { - await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false); + await stream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false); } return NoContent(); @@ -1833,15 +1837,6 @@ public class ImageController : BaseJellyfinApiController return NoContent(); } - private static async Task<MemoryStream> GetMemoryStream(Stream inputStream) - { - using var reader = new StreamReader(inputStream); - var text = await reader.ReadToEndAsync().ConfigureAwait(false); - - var bytes = Convert.FromBase64String(text); - return new MemoryStream(bytes, 0, bytes.Length, false, true); - } - private ImageInfo? GetImageInfo(BaseItem item, ItemImageInfo info, int? imageIndex) { int? width = null; diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 7d02550b68..fb89e96108 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net.Mime; +using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -405,9 +406,8 @@ public class SubtitleController : BaseJellyfinApiController [FromBody, Required] UploadSubtitleDto body) { var video = (Video)_libraryManager.GetItemById(itemId); - var data = Convert.FromBase64String(body.Data); - var memoryStream = new MemoryStream(data, 0, data.Length, false, true); - await using (memoryStream.ConfigureAwait(false)) + var stream = new CryptoStream(Request.Body, new FromBase64Transform(), CryptoStreamMode.Read); + await using (stream.ConfigureAwait(false)) { await _subtitleManager.UploadSubtitle( video, @@ -417,7 +417,7 @@ public class SubtitleController : BaseJellyfinApiController Language = body.Language, IsForced = body.IsForced, IsHearingImpaired = body.IsHearingImpaired, - Stream = memoryStream + Stream = stream }).ConfigureAwait(false); _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High); |
