diff options
Diffstat (limited to 'MediaBrowser.Api/Playback/BaseStreamingService.cs')
| -rw-r--r-- | MediaBrowser.Api/Playback/BaseStreamingService.cs | 131 |
1 files changed, 108 insertions, 23 deletions
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 99de46c7d..202862da4 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <param name="state">The state.</param> /// <returns>System.String.</returns> - protected string GetOutputFilePath(StreamState state) + private string GetOutputFilePath(StreamState state) { var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath; @@ -726,12 +726,13 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <param name="request">The request.</param> /// <param name="audioStream">The audio stream.</param> + /// <param name="outputAudioCodec">The output audio codec.</param> /// <returns>System.Nullable{System.Int32}.</returns> - private int? GetNumAudioChannelsParam(StreamRequest request, MediaStream audioStream) + private int? GetNumAudioChannelsParam(StreamRequest request, MediaStream audioStream, string outputAudioCodec) { if (audioStream != null) { - var codec = request.AudioCodec ?? string.Empty; + var codec = outputAudioCodec ?? string.Empty; if (audioStream.Channels > 2 && codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1) { @@ -769,7 +770,7 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <param name="request">The request.</param> /// <returns>System.String.</returns> - protected string GetAudioCodec(StreamRequest request) + private string GetAudioCodec(StreamRequest request) { var codec = request.AudioCodec; @@ -798,7 +799,7 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <param name="request">The request.</param> /// <returns>System.String.</returns> - protected string GetVideoCodec(VideoStreamRequest request) + private string GetVideoCodec(VideoStreamRequest request) { var codec = request.VideoCodec; @@ -866,7 +867,7 @@ namespace MediaBrowser.Api.Playback Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); - if (state.IsInputVideo && state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath)) + if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath)) { state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); } @@ -900,7 +901,13 @@ namespace MediaBrowser.Api.Playback EnableRaisingEvents = true }; - ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, state.Request.StartTimeTicks, state.MediaPath, state.Request.DeviceId, cancellationTokenSource); + ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, + TranscodingJobType, + process, + state.Request.StartTimeTicks, + state.Request.DeviceId, + state, + cancellationTokenSource); var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; Logger.Info(commandLineLogMessage); @@ -924,7 +931,7 @@ namespace MediaBrowser.Api.Playback { Logger.ErrorException("Error starting ffmpeg", ex); - ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType); + ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state); throw; } @@ -932,10 +939,8 @@ namespace MediaBrowser.Api.Playback // MUST read both stdout and stderr asynchronously or a deadlock may occurr process.BeginOutputReadLine(); -#pragma warning disable 4014 // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - process.StandardError.BaseStream.CopyToAsync(state.LogFileStream); -#pragma warning restore 4014 + StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream); // Wait for the file to exist before proceeeding while (!File.Exists(outputPath)) @@ -956,6 +961,82 @@ namespace MediaBrowser.Api.Playback } } + private async void StartStreamingLog(StreamState state, Stream source, Stream target) + { + try + { + using (var reader = new StreamReader(source)) + { + while (!reader.EndOfStream) + { + var line = await reader.ReadLineAsync().ConfigureAwait(false); + + ParseLogLine(line, state); + + var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line); + + await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + } + } + } + catch (Exception ex) + { + Logger.ErrorException("Error reading ffmpeg log", ex); + } + } + + private void ParseLogLine(string line, StreamState state) + { + float? framerate = null; + double? percent = null; + + var parts = line.Split(' '); + + var totalMs = state.RunTimeTicks.HasValue + ? TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds + : 0; + + var startMs = state.Request.StartTimeTicks.HasValue + ? TimeSpan.FromTicks(state.Request.StartTimeTicks.Value).TotalMilliseconds + : 0; + + for (var i = 0; i < parts.Length; i++) + { + var part = parts[i]; + + if (string.Equals(part, "fps=", StringComparison.OrdinalIgnoreCase) && + (i + 1 < parts.Length)) + { + var rate = parts[i + 1]; + float val; + + if (float.TryParse(rate, NumberStyles.Any, UsCulture, out val)) + { + framerate = val; + } + } + else if (state.RunTimeTicks.HasValue && + part.StartsWith("time=", StringComparison.OrdinalIgnoreCase)) + { + var time = part.Split(new[] { '=' }, 2).Last(); + TimeSpan val; + + if (TimeSpan.TryParse(time, UsCulture, out val)) + { + var currentMs = startMs + val.TotalMilliseconds; + + var percentVal = currentMs / totalMs; + percent = 100 * percentVal; + } + } + } + + if (framerate.HasValue || percent.HasValue) + { + ApiEntryPoint.Instance.ReportTranscodingProgress(state, framerate, percent); + } + } + private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream) { var bitrate = request.VideoBitRate; @@ -1500,23 +1581,27 @@ namespace MediaBrowser.Api.Playback state.OutputAudioBitrate = GetAudioBitrateParam(state.Request, state.AudioStream); state.OutputAudioSampleRate = request.AudioSampleRate; - state.OutputAudioChannels = GetNumAudioChannelsParam(state.Request, state.AudioStream); + + state.OutputAudioCodec = GetAudioCodec(state.Request); if (videoRequest != null) { + state.OutputVideoCodec = GetVideoCodec(videoRequest); state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream); if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream)) { - videoRequest.VideoCodec = "copy"; + state.OutputVideoCodec = "copy"; } if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream, state.SupportedAudioCodecs)) { - request.AudioCodec = "copy"; + state.OutputAudioCodec = "copy"; } } + state.OutputFilePath = GetOutputFilePath(state); + return state; } @@ -1729,14 +1814,14 @@ namespace MediaBrowser.Api.Playback return; } - var audioCodec = state.Request.AudioCodec; + var audioCodec = state.OutputAudioCodec; if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) { audioCodec = state.AudioStream.Codec; } - var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec; + var videoCodec = state.OutputVideoCodec; if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null) { @@ -1807,7 +1892,12 @@ namespace MediaBrowser.Api.Playback profile = DlnaManager.GetDefaultProfile(); } - var audioCodec = state.Request.AudioCodec; + var audioCodec = state.OutputAudioCodec; + + if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) + { + audioCodec = state.AudioStream.Codec; + } if (state.VideoRequest == null) { @@ -1825,12 +1915,7 @@ namespace MediaBrowser.Api.Playback } else { - if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) - { - audioCodec = state.AudioStream.Codec; - } - - var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec; + var videoCodec = state.OutputVideoCodec; if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null) { |
