From 71b8f87cb70417d56d14c4912a0e5b94077d9c87 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 20 May 2015 12:28:55 -0400 Subject: [PATCH] hls updates --- .../Playback/BaseStreamingService.cs | 4 +- .../Playback/Hls/DynamicHlsService.cs | 76 +++++++++++++++++-- .../Api/PackageCreator.cs | 1 - 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a33a7df8d3..6f1edb1650 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Api.Playback } protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - private readonly long _slowSeekTicks = TimeSpan.FromSeconds(2).Ticks; + private readonly long _slowSeekTicks = TimeSpan.FromSeconds(0).Ticks; /// /// Gets the fast seek command line parameter. @@ -177,7 +177,7 @@ namespace MediaBrowser.Api.Playback { var time = request.StartTimeTicks ?? 0; - if (time > _slowSeekTicks) + if (time > _slowSeekTicks && _slowSeekTicks > 0) { return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(_slowSeekTicks)); } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index f5345df723..2d8b71a0cc 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -13,6 +13,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using ServiceStack; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -156,12 +157,14 @@ namespace MediaBrowser.Api.Playback.Hls { ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, p => false); + await ReadSegmentLengths(playlistPath).ConfigureAwait(false); + if (currentTranscodingIndex.HasValue) { DeleteLastFile(playlistPath, segmentExtension, 0); } - request.StartTimeTicks = GetSeekPositionTicks(state, requestedIndex); + request.StartTimeTicks = GetSeekPositionTicks(state, playlistPath, requestedIndex); job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false); } @@ -199,11 +202,73 @@ namespace MediaBrowser.Api.Playback.Hls return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); } - private long GetSeekPositionTicks(StreamState state, int requestedIndex) + private static readonly ConcurrentDictionary SegmentLengths = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private async Task ReadSegmentLengths(string playlist) { - var startSeconds = requestedIndex * state.SegmentLength; - var position = TimeSpan.FromSeconds(startSeconds).Ticks; + try + { + using (var fileStream = GetPlaylistFileStream(playlist)) + { + using (var reader = new StreamReader(fileStream)) + { + double duration = -1; + while (!reader.EndOfStream) + { + var text = await reader.ReadLineAsync().ConfigureAwait(false); + + if (text.StartsWith("#EXTINF", StringComparison.OrdinalIgnoreCase)) + { + var parts = text.Split(new[] { ':' }, 2); + if (parts.Length == 2) + { + var time = parts[1].Trim(new[] { ',' }).Trim(); + double timeValue; + if (double.TryParse(time, NumberStyles.Any, CultureInfo.InvariantCulture, out timeValue)) + { + duration = timeValue; + continue; + } + } + } + else if (duration != -1) + { + SegmentLengths.AddOrUpdate(text, duration, (k, v) => duration); + Logger.Debug("Added segment length of {0} for {1}", duration, text); + } + + duration = -1; + } + } + } + } + catch (FileNotFoundException) + { + + } + } + + private long GetSeekPositionTicks(StreamState state, string playlist, int requestedIndex) + { + double startSeconds = 0; + + for (var i = 0; i < requestedIndex; i++) + { + var segmentPath = GetSegmentPath(playlist, i); + + double length; + if (SegmentLengths.TryGetValue(Path.GetFileName(segmentPath), out length)) + { + Logger.Debug("Found segment length of {0} for index {1}", length, i); + startSeconds += length; + } + else + { + startSeconds += state.SegmentLength; + } + } + + var position = TimeSpan.FromSeconds(startSeconds).Ticks; return position; } @@ -693,7 +758,7 @@ namespace MediaBrowser.Api.Playback.Hls } var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", - state.SegmentLength.ToString(UsCulture)); + 1.ToString(UsCulture)); var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; @@ -728,6 +793,7 @@ namespace MediaBrowser.Api.Playback.Hls { var startTime = state.Request.StartTimeTicks ?? 0; var durationSeconds = ApiEntryPoint.Instance.GetEncodingOptions().ThrottleThresholdInSeconds; + var endTime = startTime + TimeSpan.FromSeconds(durationSeconds).Ticks; endTime = Math.Min(endTime, state.RunTimeTicks.Value); diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 6b8c17002a..2823733ea8 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -619,7 +619,6 @@ namespace MediaBrowser.WebDashboard.Api "scheduledtaskpage.js", "scheduledtaskspage.js", "search.js", - "supporterkeypage.js", "syncactivity.js", "syncsettings.js", "thememediaplayer.js",