From 64a13a5d42da4a27d203f49d69069a635b5f199e Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 25 Sep 2021 23:28:10 +0200 Subject: [PATCH] Add ComputeSegments test --- .../Playlist/DynamicHlsPlaylistGenerator.cs | 7 +- .../DynamicHlsPlaylistGeneratorTests.cs | 64 ++++++++++++++++--- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs b/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs index 5c6809a87..5411d5667 100644 --- a/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs +++ b/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs @@ -198,6 +198,11 @@ namespace Jellyfin.MediaEncoding.Hls.Playlist internal static IReadOnlyList ComputeSegments(KeyframeData keyframeData, int desiredSegmentLengthMs) { + if (keyframeData.KeyframeTicks.Count > 0 && keyframeData.TotalDuration < keyframeData.KeyframeTicks[^1]) + { + throw new ArgumentException("Invalid duration in keyframe data", nameof(keyframeData)); + } + long lastKeyframe = 0; var result = new List(); // Scale the segment length to ticks to match the keyframes @@ -219,7 +224,7 @@ namespace Jellyfin.MediaEncoding.Hls.Playlist return result; } - internal static double[] ComputeEqualLengthSegments(long desiredSegmentLengthMs, long totalRuntimeTicks) + internal static double[] ComputeEqualLengthSegments(int desiredSegmentLengthMs, long totalRuntimeTicks) { if (desiredSegmentLengthMs == 0 || totalRuntimeTicks == 0) { diff --git a/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs b/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs index 4b2fce171..264fb6f4c 100644 --- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs +++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs @@ -1,14 +1,29 @@ using System; using Jellyfin.MediaEncoding.Hls.Playlist; +using Jellyfin.MediaEncoding.Keyframes; using Xunit; namespace Jellyfin.MediaEncoding.Hls.Tests.Playlist { public class DynamicHlsPlaylistGeneratorTests { + [Theory] + [MemberData(nameof(ComputeSegments_Valid_Success_Data))] + public void ComputeSegments_Valid_Success(KeyframeData keyframeData, int desiredSegmentLengthMs, double[] segments) + { + Assert.Equal(segments, DynamicHlsPlaylistGenerator.ComputeSegments(keyframeData, desiredSegmentLengthMs)); + } + + [Fact] + public void ComputeSegments_InvalidDuration_ThrowsArgumentException() + { + var keyframeData = new KeyframeData(0, new[] { MsToTicks(10000) }); + Assert.Throws(() => DynamicHlsPlaylistGenerator.ComputeSegments(keyframeData, 6000)); + } + [Theory] [MemberData(nameof(ComputeEqualLengthSegments_Valid_Success_Data))] - public void ComputeEqualLengthSegments_Valid_Success(long desiredSegmentLengthMs, long totalRuntimeTicks, double[] segments) + public void ComputeEqualLengthSegments_Valid_Success(int desiredSegmentLengthMs, long totalRuntimeTicks, double[] segments) { Assert.Equal(segments, DynamicHlsPlaylistGenerator.ComputeEqualLengthSegments(desiredSegmentLengthMs, totalRuntimeTicks)); } @@ -16,7 +31,7 @@ namespace Jellyfin.MediaEncoding.Hls.Tests.Playlist [Theory] [InlineData(0, 1000000)] [InlineData(1000, 0)] - public void ComputeEqualLengthSegments_Invalid_ThrowsInvalidOperationException(long desiredSegmentLengthMs, long totalRuntimeTicks) + public void ComputeEqualLengthSegments_Invalid_ThrowsInvalidOperationException(int desiredSegmentLengthMs, long totalRuntimeTicks) { Assert.Throws(() => DynamicHlsPlaylistGenerator.ComputeEqualLengthSegments(desiredSegmentLengthMs, totalRuntimeTicks)); } @@ -38,18 +53,49 @@ namespace Jellyfin.MediaEncoding.Hls.Tests.Playlist Assert.False(DynamicHlsPlaylistGenerator.IsExtractionAllowedForFile(filePath, allowedExtensions)); } - private static TheoryData ComputeEqualLengthSegments_Valid_Success_Data() + private static TheoryData ComputeEqualLengthSegments_Valid_Success_Data() { - var data = new TheoryData + var data = new TheoryData { - { 6000, TimeSpan.FromMilliseconds(13000).Ticks, new[] { 6.0, 6.0, 1.0 } }, - { 3000, TimeSpan.FromMilliseconds(15000).Ticks, new[] { 3.0, 3.0, 3.0, 3.0, 3.0 } }, - { 6000, TimeSpan.FromMilliseconds(25000).Ticks, new[] { 6.0, 6.0, 6.0, 6.0, 1.0 } }, - { 6000, TimeSpan.FromMilliseconds(20123).Ticks, new[] { 6.0, 6.0, 6.0, 2.123 } }, - { 6000, TimeSpan.FromMilliseconds(1234).Ticks, new[] { 1.234 } } + { 6000, MsToTicks(13000), new[] { 6.0, 6.0, 1.0 } }, + { 3000, MsToTicks(15000), new[] { 3.0, 3.0, 3.0, 3.0, 3.0 } }, + { 6000, MsToTicks(25000), new[] { 6.0, 6.0, 6.0, 6.0, 1.0 } }, + { 6000, MsToTicks(20123), new[] { 6.0, 6.0, 6.0, 2.123 } }, + { 6000, MsToTicks(1234), new[] { 1.234 } } }; return data; } + + private static TheoryData ComputeSegments_Valid_Success_Data() + { + var data = new TheoryData + { + { + new KeyframeData(MsToTicks(35000), new[] { 0, MsToTicks(10427), MsToTicks(20854), MsToTicks(31240) }), + 6000, + new[] { 10.427, 10.427, 10.386, 3.760 } + }, + { + new KeyframeData(MsToTicks(10000), new[] { 0, MsToTicks(1000), MsToTicks(2000), MsToTicks(3000), MsToTicks(4000), MsToTicks(5000) }), + 2000, + new[] { 2.0, 2.0, 6.0 } + }, + { + new KeyframeData(MsToTicks(10000), new[] { 0L }), + 6000, + new[] { 10.0 } + }, + { + new KeyframeData(MsToTicks(10000), Array.Empty()), + 6000, + new[] { 10.0 } + } + }; + + return data; + } + + private static long MsToTicks(int value) => TimeSpan.FromMilliseconds(value).Ticks; } }