فهرست منبع

Merge pull request #6013 from Bond-009/minor13

Bond-009 4 سال پیش
والد
کامیت
a937a854f2

+ 26 - 28
Jellyfin.Api/Controllers/DynamicHlsController.cs

@@ -28,7 +28,6 @@ using MediaBrowser.Model.Net;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 using Microsoft.Net.Http.Headers;
 using Microsoft.Net.Http.Headers;
 
 
@@ -545,7 +544,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery] EncodingContext? context,
             [FromQuery] EncodingContext? context,
             [FromQuery] Dictionary<string, string> streamOptions)
             [FromQuery] Dictionary<string, string> streamOptions)
         {
         {
-            var cancellationTokenSource = new CancellationTokenSource();
+            using var cancellationTokenSource = new CancellationTokenSource();
             var streamingRequest = new VideoRequestDto
             var streamingRequest = new VideoRequestDto
             {
             {
                 Id = itemId,
                 Id = itemId,
@@ -710,7 +709,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery] EncodingContext? context,
             [FromQuery] EncodingContext? context,
             [FromQuery] Dictionary<string, string> streamOptions)
             [FromQuery] Dictionary<string, string> streamOptions)
         {
         {
-            var cancellationTokenSource = new CancellationTokenSource();
+            using var cancellationTokenSource = new CancellationTokenSource();
             var streamingRequest = new StreamingRequestDto
             var streamingRequest = new StreamingRequestDto
             {
             {
                 Id = itemId,
                 Id = itemId,
@@ -1138,7 +1137,7 @@ namespace Jellyfin.Api.Controllers
             var isHlsInFmp4 = string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase);
             var isHlsInFmp4 = string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase);
             var hlsVersion = isHlsInFmp4 ? "7" : "3";
             var hlsVersion = isHlsInFmp4 ? "7" : "3";
 
 
-            var builder = new StringBuilder();
+            var builder = new StringBuilder(128);
 
 
             builder.AppendLine("#EXTM3U")
             builder.AppendLine("#EXTM3U")
                 .AppendLine("#EXT-X-PLAYLIST-TYPE:VOD")
                 .AppendLine("#EXT-X-PLAYLIST-TYPE:VOD")
@@ -1191,7 +1190,7 @@ namespace Jellyfin.Api.Controllers
                 throw new ArgumentException("StartTimeTicks is not allowed.");
                 throw new ArgumentException("StartTimeTicks is not allowed.");
             }
             }
 
 
-            var cancellationTokenSource = new CancellationTokenSource();
+            using var cancellationTokenSource = new CancellationTokenSource();
             var cancellationToken = cancellationTokenSource.Token;
             var cancellationToken = cancellationTokenSource.Token;
 
 
             using var state = await StreamingHelpers.GetStreamingState(
             using var state = await StreamingHelpers.GetStreamingState(
@@ -1208,7 +1207,7 @@ namespace Jellyfin.Api.Controllers
                     _deviceManager,
                     _deviceManager,
                     _transcodingJobHelper,
                     _transcodingJobHelper,
                     TranscodingJobType,
                     TranscodingJobType,
-                    cancellationTokenSource.Token)
+                    cancellationToken)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
             var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
@@ -1227,7 +1226,7 @@ namespace Jellyfin.Api.Controllers
             }
             }
 
 
             var transcodingLock = _transcodingJobHelper.GetTranscodingLock(playlistPath);
             var transcodingLock = _transcodingJobHelper.GetTranscodingLock(playlistPath);
-            await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
+            await transcodingLock.WaitAsync(cancellationToken).ConfigureAwait(false);
             var released = false;
             var released = false;
             var startTranscoding = false;
             var startTranscoding = false;
 
 
@@ -1323,24 +1322,28 @@ namespace Jellyfin.Api.Controllers
             return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, segmentId, job, cancellationToken).ConfigureAwait(false);
             return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, segmentId, job, cancellationToken).ConfigureAwait(false);
         }
         }
 
 
-        private double[] GetSegmentLengths(StreamState state)
-        {
-            var result = new List<double>();
-
-            var ticks = state.RunTimeTicks ?? 0;
+        private static double[] GetSegmentLengths(StreamState state)
+            => GetSegmentLengthsInternal(state.RunTimeTicks ?? 0, state.SegmentLength);
 
 
-            var segmentLengthTicks = TimeSpan.FromSeconds(state.SegmentLength).Ticks;
+        internal static double[] GetSegmentLengthsInternal(long runtimeTicks, int segmentlength)
+        {
+            var segmentLengthTicks = TimeSpan.FromSeconds(segmentlength).Ticks;
+            var wholeSegments = runtimeTicks / segmentLengthTicks;
+            var remainingTicks = runtimeTicks % segmentLengthTicks;
 
 
-            while (ticks > 0)
+            var segmentsLen = wholeSegments + (remainingTicks == 0 ? 0 : 1);
+            var segments = new double[segmentsLen];
+            for (int i = 0; i < wholeSegments; i++)
             {
             {
-                var length = ticks >= segmentLengthTicks ? segmentLengthTicks : ticks;
-
-                result.Add(TimeSpan.FromTicks(length).TotalSeconds);
+                segments[i] = segmentlength;
+            }
 
 
-                ticks -= length;
+            if (remainingTicks != 0)
+            {
+                segments[^1] = TimeSpan.FromTicks(remainingTicks).TotalSeconds;
             }
             }
 
 
-            return result.ToArray();
+            return segments;
         }
         }
 
 
         private string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding, int startNumber)
         private string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding, int startNumber)
@@ -1376,18 +1379,13 @@ namespace Jellyfin.Api.Controllers
             }
             }
             else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase))
             else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase))
             {
             {
-                var outputFmp4HeaderArg = string.Empty;
-                var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
-                if (isWindows)
+                var outputFmp4HeaderArg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) switch
                 {
                 {
                     // on Windows, the path of fmp4 header file needs to be configured
                     // on Windows, the path of fmp4 header file needs to be configured
-                    outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\"";
-                }
-                else
-                {
+                    true => " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\"",
                     // on Linux/Unix, ffmpeg generate fmp4 header file to m3u8 output folder
                     // on Linux/Unix, ffmpeg generate fmp4 header file to m3u8 output folder
-                    outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputFileNameWithoutExtension + "-1" + outputExtension + "\"";
-                }
+                    false => " -hls_fmp4_init_filename \"" + outputFileNameWithoutExtension + "-1" + outputExtension + "\""
+                };
 
 
                 segmentFormat = "fmp4" + outputFmp4HeaderArg;
                 segmentFormat = "fmp4" + outputFmp4HeaderArg;
             }
             }

+ 0 - 1
Jellyfin.Api/Helpers/TranscodingJobHelper.cs

@@ -22,7 +22,6 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Session;
 using MediaBrowser.Model.Session;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 
 
 namespace Jellyfin.Api.Helpers
 namespace Jellyfin.Api.Helpers

+ 0 - 49
MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs

@@ -4,59 +4,10 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Linq;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace MediaBrowser.Controller.MediaEncoding
 namespace MediaBrowser.Controller.MediaEncoding
 {
 {
-    public class EncodingJobOptions : BaseEncodingJobOptions
-    {
-        public string OutputDirectory { get; set; }
-
-        public string ItemId { get; set; }
-
-        public string TempDirectory { get; set; }
-
-        public bool ReadInputAtNativeFramerate { get; set; }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance has fixed resolution.
-        /// </summary>
-        /// <value><c>true</c> if this instance has fixed resolution; otherwise, <c>false</c>.</value>
-        public bool HasFixedResolution => Width.HasValue || Height.HasValue;
-
-        public DeviceProfile DeviceProfile { get; set; }
-
-        public EncodingJobOptions(StreamInfo info, DeviceProfile deviceProfile)
-        {
-            Container = info.Container;
-            StartTimeTicks = info.StartPositionTicks;
-            MaxWidth = info.MaxWidth;
-            MaxHeight = info.MaxHeight;
-            MaxFramerate = info.MaxFramerate;
-            Id = info.ItemId;
-            MediaSourceId = info.MediaSourceId;
-            AudioCodec = info.TargetAudioCodec.FirstOrDefault();
-            MaxAudioChannels = info.GlobalMaxAudioChannels;
-            AudioBitRate = info.AudioBitrate;
-            AudioSampleRate = info.TargetAudioSampleRate;
-            DeviceProfile = deviceProfile;
-            VideoCodec = info.TargetVideoCodec.FirstOrDefault();
-            VideoBitRate = info.VideoBitrate;
-            AudioStreamIndex = info.AudioStreamIndex;
-            SubtitleMethod = info.SubtitleDeliveryMethod;
-            Context = info.Context;
-            TranscodingMaxAudioChannels = info.TranscodingMaxAudioChannels;
-
-            if (info.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External)
-            {
-                SubtitleStreamIndex = info.SubtitleStreamIndex;
-            }
-
-            StreamOptions = info.StreamOptions;
-        }
-    }
-
     // For now until api and media encoding layers are unified
     // For now until api and media encoding layers are unified
     public class BaseEncodingJobOptions
     public class BaseEncodingJobOptions
     {
     {

+ 58 - 0
tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs

@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using AutoFixture;
+using AutoFixture.AutoMoq;
+using Jellyfin.Api.Controllers;
+using Jellyfin.Api.Helpers;
+using Jellyfin.Api.Models.StreamingDtos;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.MediaEncoding;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Controllers
+{
+    public class DynamicHlsControllerTests
+    {
+        [Theory]
+        [MemberData(nameof(GetSegmentLengths_Success_TestData))]
+        public void GetSegmentLengths_Success(long runtimeTicks, int segmentlength, double[] expected)
+        {
+            var res = DynamicHlsController.GetSegmentLengthsInternal(runtimeTicks, segmentlength);
+            Assert.Equal(expected.Length, res.Length);
+            for (int i = 0; i < expected.Length; i++)
+            {
+                Assert.Equal(expected[i], res[i]);
+            }
+        }
+
+        public static IEnumerable<object[]> GetSegmentLengths_Success_TestData()
+        {
+            yield return new object[] { 0, 6, Array.Empty<double>() };
+            yield return new object[]
+            {
+                TimeSpan.FromSeconds(3).Ticks,
+                6,
+                new double[] { 3 }
+            };
+            yield return new object[]
+            {
+                TimeSpan.FromSeconds(6).Ticks,
+                6,
+                new double[] { 6 }
+            };
+            yield return new object[]
+            {
+                TimeSpan.FromSeconds(3.3333333).Ticks,
+                6,
+                new double[] { 3.3333333 }
+            };
+            yield return new object[]
+            {
+                TimeSpan.FromSeconds(9.3333333).Ticks,
+                6,
+                new double[] { 6, 3.3333333 }
+            };
+        }
+    }
+}