< Summary - Jellyfin

Information
Class: MediaBrowser.Controller.MediaEncoding.JobLogger
Assembly: MediaBrowser.Controller
File(s): /srv/git/jellyfin/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 53
Coverable lines: 53
Total lines: 163
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 42
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
ParseLogLine(...)0%1806420%

File(s)

/srv/git/jellyfin/MediaBrowser.Controller/MediaEncoding/JobLogger.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Globalization;
 7using System.IO;
 8using System.Text;
 9using System.Threading.Tasks;
 10using Microsoft.Extensions.Logging;
 11
 12namespace MediaBrowser.Controller.MediaEncoding
 13{
 14    public class JobLogger
 15    {
 16        private readonly ILogger _logger;
 17
 18        public JobLogger(ILogger logger)
 19        {
 020            _logger = logger;
 021        }
 22
 23        public async Task StartStreamingLog(EncodingJobInfo state, StreamReader reader, Stream target)
 24        {
 25            try
 26            {
 27                using (target)
 28                using (reader)
 29                {
 30                    while (!reader.EndOfStream && reader.BaseStream.CanRead)
 31                    {
 32                        var line = await reader.ReadLineAsync().ConfigureAwait(false);
 33
 34                        ParseLogLine(line, state);
 35
 36                        var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
 37
 38                        // If ffmpeg process is closed, the state is disposed, so don't write to target in that case
 39                        if (!target.CanWrite)
 40                        {
 41                            break;
 42                        }
 43
 44                        await target.WriteAsync(bytes).ConfigureAwait(false);
 45
 46                        // Check again, the stream could have been closed
 47                        if (!target.CanWrite)
 48                        {
 49                            break;
 50                        }
 51
 52                        await target.FlushAsync().ConfigureAwait(false);
 53                    }
 54                }
 55            }
 56            catch (Exception ex)
 57            {
 58                _logger.LogError(ex, "Error reading ffmpeg log");
 59            }
 60        }
 61
 62        private void ParseLogLine(string line, EncodingJobInfo state)
 63        {
 064            float? framerate = null;
 065            double? percent = null;
 066            TimeSpan? transcodingPosition = null;
 067            long? bytesTranscoded = null;
 068            int? bitRate = null;
 69
 070            var parts = line.Split(' ');
 71
 072            var totalMs = state.RunTimeTicks.HasValue
 073                ? TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds
 074                : 0;
 75
 076            var startMs = state.BaseRequest.StartTimeTicks.HasValue
 077                ? TimeSpan.FromTicks(state.BaseRequest.StartTimeTicks.Value).TotalMilliseconds
 078                : 0;
 79
 080            for (var i = 0; i < parts.Length; i++)
 81            {
 082                var part = parts[i];
 83
 084                if (string.Equals(part, "fps=", StringComparison.OrdinalIgnoreCase) &&
 085                    (i + 1 < parts.Length))
 86                {
 087                    var rate = parts[i + 1];
 88
 089                    if (float.TryParse(rate, CultureInfo.InvariantCulture, out var val))
 90                    {
 091                        framerate = val;
 92                    }
 93                }
 094                else if (part.StartsWith("fps=", StringComparison.OrdinalIgnoreCase))
 95                {
 096                    var rate = part.Split('=', 2)[^1];
 97
 098                    if (float.TryParse(rate, CultureInfo.InvariantCulture, out var val))
 99                    {
 0100                        framerate = val;
 101                    }
 102                }
 0103                else if (state.RunTimeTicks.HasValue &&
 0104                    part.StartsWith("time=", StringComparison.OrdinalIgnoreCase))
 105                {
 0106                    var time = part.Split('=', 2)[^1];
 107
 0108                    if (TimeSpan.TryParse(time, CultureInfo.InvariantCulture, out var val))
 109                    {
 0110                        var currentMs = startMs + val.TotalMilliseconds;
 111
 0112                        percent = 100.0 * currentMs / totalMs;
 113
 0114                        transcodingPosition = TimeSpan.FromMilliseconds(currentMs);
 115                    }
 116                }
 0117                else if (part.StartsWith("size=", StringComparison.OrdinalIgnoreCase))
 118                {
 0119                    var size = part.Split('=', 2)[^1];
 120
 0121                    int? scale = null;
 0122                    if (size.Contains("kb", StringComparison.OrdinalIgnoreCase))
 123                    {
 0124                        scale = 1024;
 0125                        size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase);
 126                    }
 127
 0128                    if (scale.HasValue)
 129                    {
 0130                        if (long.TryParse(size, CultureInfo.InvariantCulture, out var val))
 131                        {
 0132                            bytesTranscoded = val * scale.Value;
 133                        }
 134                    }
 135                }
 0136                else if (part.StartsWith("bitrate=", StringComparison.OrdinalIgnoreCase))
 137                {
 0138                    var rate = part.Split('=', 2)[^1];
 139
 0140                    int? scale = null;
 0141                    if (rate.Contains("kbits/s", StringComparison.OrdinalIgnoreCase))
 142                    {
 0143                        scale = 1024;
 0144                        rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase);
 145                    }
 146
 0147                    if (scale.HasValue)
 148                    {
 0149                        if (float.TryParse(rate, CultureInfo.InvariantCulture, out var val))
 150                        {
 0151                            bitRate = (int)Math.Ceiling(val * scale.Value);
 152                        }
 153                    }
 154                }
 155            }
 156
 0157            if (framerate.HasValue || percent.HasValue)
 158            {
 0159                state.ReportTranscodingProgress(transcodingPosition, framerate, percent, bytesTranscoded, bitRate);
 160            }
 0161        }
 162    }
 163}