diff options
Diffstat (limited to 'MediaBrowser.Api/Playback/BaseStreamingService.cs')
| -rw-r--r-- | MediaBrowser.Api/Playback/BaseStreamingService.cs | 113 |
1 files changed, 109 insertions, 4 deletions
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 75321f872..827aed4f2 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1026,7 +1026,7 @@ namespace MediaBrowser.Api.Playback // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true); - var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine); + var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state); @@ -1515,6 +1515,10 @@ namespace MediaBrowser.Api.Playback } else if (i == 22) { + // api_key + } + else if (i == 23) + { request.LiveStreamId = val; } } @@ -1624,14 +1628,19 @@ namespace MediaBrowser.Api.Playback var archivable = item as IArchivable; state.IsInputArchive = archivable != null && archivable.IsArchive; - MediaSourceInfo mediaSource = null; + MediaSourceInfo mediaSource; if (string.IsNullOrWhiteSpace(request.LiveStreamId)) { - var mediaSources = await MediaSourceManager.GetPlayackMediaSources(request.Id, false, cancellationToken).ConfigureAwait(false); + var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList(); mediaSource = string.IsNullOrEmpty(request.MediaSourceId) ? mediaSources.First() - : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId)); + : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId)); + + if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase)) + { + mediaSource = mediaSources.First(); + } } else { @@ -1700,6 +1709,102 @@ namespace MediaBrowser.Api.Playback { state.OutputAudioCodec = "copy"; } + + if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && TranscodingJobType == TranscodingJobType.Hls) + { + var segmentLength = GetSegmentLength(state); + if (segmentLength.HasValue) + { + state.SegmentLength = segmentLength.Value; + } + } + } + + private int? GetSegmentLength(StreamState state) + { + var stream = state.VideoStream; + + if (stream == null) + { + return null; + } + + var frames = stream.KeyFrames; + + if (frames == null || frames.Count < 2) + { + return null; + } + + Logger.Debug("Found keyframes at {0}", string.Join(",", frames.ToArray())); + + var intervals = new List<int>(); + for (var i = 1; i < frames.Count; i++) + { + var start = frames[i - 1]; + var end = frames[i]; + intervals.Add(end - start); + } + + Logger.Debug("Found keyframes intervals {0}", string.Join(",", intervals.ToArray())); + + var results = new List<Tuple<int, int>>(); + + for (var i = 1; i <= 10; i++) + { + var idealMs = i*1000; + + if (intervals.Max() < idealMs - 1000) + { + break; + } + + var segments = PredictStreamCopySegments(intervals, idealMs); + var variance = segments.Select(s => Math.Abs(idealMs - s)).Sum(); + + results.Add(new Tuple<int, int>(i, variance)); + } + + if (results.Count == 0) + { + return null; + } + + return results.OrderBy(i => i.Item2).ThenBy(i => i.Item1).Select(i => i.Item1).First(); + } + + private List<int> PredictStreamCopySegments(List<int> intervals, int idealMs) + { + var segments = new List<int>(); + var currentLength = 0; + + foreach (var interval in intervals) + { + if (currentLength == 0 || (currentLength + interval) <= idealMs) + { + currentLength += interval; + } + + else + { + // The segment will either be above or below the ideal. + // Need to figure out which is preferable + var offset1 = Math.Abs(idealMs - currentLength); + var offset2 = Math.Abs(idealMs - (currentLength + interval)); + + if (offset1 <= offset2) + { + segments.Add(currentLength); + currentLength = interval; + } + else + { + currentLength += interval; + } + } + } + Logger.Debug("Predicted actual segment lengths for length {0}: {1}", idealMs, string.Join(",", segments.ToArray())); + return segments; } private void AttachMediaSourceInfo(StreamState state, |
