diff options
Diffstat (limited to 'MediaBrowser.MediaEncoding')
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 21 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/JobLogger.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 74 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs | 21 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 87 |
7 files changed, 129 insertions, 80 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index ecf5d72d5..5a00c3d3f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -248,7 +248,7 @@ namespace MediaBrowser.MediaEncoding.Encoder protected virtual void DeleteFiles(EncodingJob job) { - File.Delete(job.OutputFilePath); + FileSystem.DeleteFile(job.OutputFilePath); } private void OnTranscodeBeginning(EncodingJob job) @@ -280,13 +280,14 @@ namespace MediaBrowser.MediaEncoding.Encoder private string GetOutputFilePath(EncodingJob state) { - var folder = ConfigurationManager.ApplicationPaths.TranscodingTempPath; + var folder = string.IsNullOrWhiteSpace(state.Options.OutputDirectory) ? + ConfigurationManager.ApplicationPaths.TranscodingTempPath : + state.Options.OutputDirectory; var outputFileExtension = GetOutputFileExtension(state); - var context = state.Options.Context; var filename = state.Id + (outputFileExtension ?? string.Empty).ToLower(); - return Path.Combine(folder, context.ToString().ToLower(), filename); + return Path.Combine(folder, filename); } protected virtual string GetOutputFileExtension(EncodingJob state) @@ -460,7 +461,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // { // if (SupportsThrottleWithStream) // { - // var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/mediabrowser/videos/" + job.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + job.Request.MediaSourceId; + // var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/videos/" + job.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + job.Request.MediaSourceId; // url += "&transcodingJobId=" + transcodingJobId; @@ -630,13 +631,13 @@ namespace MediaBrowser.MediaEncoding.Encoder switch (qualitySetting) { case EncodingQuality.HighSpeed: - param += " -crf 23"; + param += " -subq 0 -crf 23"; break; case EncodingQuality.HighQuality: - param += " -crf 20"; + param += " -subq 3 -crf 20"; break; case EncodingQuality.MaxQuality: - param += " -crf 18"; + param += " -subq 6 -crf 18"; break; } } @@ -739,7 +740,7 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -level " + state.Options.Level.Value.ToString(UsCulture); } - return param; + return "-pix_fmt yuv420p " + param; } protected string GetVideoBitrateParam(EncodingJob state, string videoCodec, bool isHls) @@ -1014,7 +1015,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!string.IsNullOrEmpty(state.SubtitleStream.Language)) { - var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language); + var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath); if (!string.IsNullOrEmpty(charenc)) { diff --git a/MediaBrowser.MediaEncoding/Encoder/JobLogger.cs b/MediaBrowser.MediaEncoding/Encoder/JobLogger.cs index 6be870519..cb6e58f17 100644 --- a/MediaBrowser.MediaEncoding/Encoder/JobLogger.cs +++ b/MediaBrowser.MediaEncoding/Encoder/JobLogger.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Logging; using System; using System.Globalization; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a4ab1c551..b75d7bee3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -37,6 +37,11 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly IJsonSerializer _jsonSerializer; /// <summary> + /// The _thumbnail resource pool + /// </summary> + private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1); + + /// <summary> /// The video image resource pool /// </summary> private readonly SemaphoreSlim _videoImageResourcePool = new SemaphoreSlim(1, 1); @@ -326,8 +331,8 @@ namespace MediaBrowser.MediaEncoding.Encoder // -f image2 -f webp // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. - var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) : - string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf); + var args = useIFrame ? string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) : + string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf); var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol); @@ -357,6 +362,8 @@ namespace MediaBrowser.MediaEncoding.Encoder } }; + _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); process.Start(); @@ -456,7 +463,7 @@ namespace MediaBrowser.MediaEncoding.Encoder int? maxWidth, CancellationToken cancellationToken) { - var resourcePool = _videoImageResourcePool; + var resourcePool = _thumbnailResourcePool; var inputArgument = GetInputArgument(inputFiles, protocol); @@ -472,7 +479,7 @@ namespace MediaBrowser.MediaEncoding.Encoder Directory.CreateDirectory(targetDirectory); var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg"); - var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); + var args = string.Format("-i {0} -threads 1 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol); @@ -499,41 +506,52 @@ namespace MediaBrowser.MediaEncoding.Encoder await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - process.Start(); - - // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, - // but we still need to detect if the process hangs. - // Making the assumption that as long as new jpegs are showing up, everything is good. + bool ranToCompletion; - bool isResponsive = true; - int lastCount = 0; - - while (isResponsive && !process.WaitForExit(120000)) + try { - int jpegCount = Directory.GetFiles(targetDirectory, "*.jpg").Count(); - isResponsive = (jpegCount > lastCount); - lastCount = jpegCount; - } + process.Start(); - bool ranToCompletion = process.HasExited; + // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, + // but we still need to detect if the process hangs. + // Making the assumption that as long as new jpegs are showing up, everything is good. - if (!ranToCompletion) - { - try + bool isResponsive = true; + int lastCount = 0; + + while (isResponsive && !process.WaitForExit(30000)) { - _logger.Info("Killing ffmpeg process"); + cancellationToken.ThrowIfCancellationRequested(); - process.StandardInput.WriteLine("q"); + int jpegCount = Directory.GetFiles(targetDirectory) + .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); - process.WaitForExit(1000); + isResponsive = (jpegCount > lastCount); + lastCount = jpegCount; } - catch (Exception ex) + + ranToCompletion = process.HasExited; + + if (!ranToCompletion) { - _logger.ErrorException("Error killing process", ex); + try + { + _logger.Info("Killing ffmpeg process"); + + process.StandardInput.WriteLine("q"); + + process.WaitForExit(1000); + } + catch (Exception ex) + { + _logger.ErrorException("Error killing process", ex); + } } } - - resourcePool.Release(); + finally + { + resourcePool.Release(); + } var exitCode = ranToCompletion ? process.ExitCode : -1; diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index aaaafc226..f28944945 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Model.Extensions; using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index ea565f70a..9751176cb 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -1,16 +1,25 @@ -using System; +using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.Logging; +using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text.RegularExpressions; using System.Threading; -using MediaBrowser.Common.Extensions; namespace MediaBrowser.MediaEncoding.Subtitles { public class SrtParser : ISubtitleParser { + private readonly ILogger _logger; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + public SrtParser(ILogger logger) + { + _logger = logger; + } + public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); @@ -34,6 +43,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles } var time = Regex.Split(line, @"[\t ]*-->[\t ]*"); + + if (time.Length < 2) + { + // This occurs when subtitle text has an empty line as part of the text. + // Need to adjust the break statement below to resolve this. + _logger.Warn("Unrecognized line in srt: {0}", line); + continue; + } subEvent.StartPositionTicks = GetTicks(time[0]); var endTime = time[1]; var idx = endTime.IndexOf(" ", StringComparison.Ordinal); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index d82ef4e24..358251625 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Model.Extensions; using System; using System.IO; using System.Text; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 4f8b6c6ac..b9cad27e0 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -149,22 +149,22 @@ namespace MediaBrowser.MediaEncoding.Subtitles var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false); - var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language, fileInfo.Item3).ConfigureAwait(false); + var stream = await GetSubtitleStream(fileInfo.Item1, fileInfo.Item3).ConfigureAwait(false); return new Tuple<Stream, string>(stream, fileInfo.Item2); } - private async Task<Stream> GetSubtitleStream(string path, string language, bool requiresCharset) + private async Task<Stream> GetSubtitleStream(string path, bool requiresCharset) { - if (requiresCharset && !string.IsNullOrEmpty(language)) + if (requiresCharset) { - var charset = GetSubtitleFileCharacterSet(path, language); + var charset = GetSubtitleFileCharacterSet(path); if (!string.IsNullOrEmpty(charset)) { using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) { - using (var reader = new StreamReader(fs, Encoding.GetEncoding(charset))) + using (var reader = new StreamReader(fs, GetEncoding(charset))) { var text = await reader.ReadToEndAsync().ConfigureAwait(false); @@ -179,6 +179,23 @@ namespace MediaBrowser.MediaEncoding.Subtitles return File.OpenRead(path); } + private Encoding GetEncoding(string charset) + { + if (string.IsNullOrWhiteSpace(charset)) + { + throw new ArgumentNullException("charset"); + } + + try + { + return Encoding.GetEncoding(charset); + } + catch (ArgumentException) + { + return Encoding.GetEncoding(charset.Replace("-", string.Empty)); + } + } + private async Task<Tuple<string, string, bool>> GetReadableFile(string mediaPath, string[] inputFiles, MediaProtocol protocol, @@ -227,8 +244,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // Convert var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".srt"); - await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken) - .ConfigureAwait(false); + await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, cancellationToken).ConfigureAwait(false); return new Tuple<string, string, bool>(outputPath, "srt", true); } @@ -254,7 +270,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)) { - return new SrtParser(); + return new SrtParser(_logger); } if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)) { @@ -321,11 +337,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// </summary> /// <param name="inputPath">The input path.</param> /// <param name="outputPath">The output path.</param> - /// <param name="language">The language.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - public async Task ConvertTextSubtitleToSrt(string inputPath, string outputPath, string language, - CancellationToken cancellationToken) + public async Task ConvertTextSubtitleToSrt(string inputPath, string outputPath, CancellationToken cancellationToken) { var semaphore = GetLock(outputPath); @@ -335,7 +349,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { if (!File.Exists(outputPath)) { - await ConvertTextSubtitleToSrtInternal(inputPath, outputPath, language).ConfigureAwait(false); + await ConvertTextSubtitleToSrtInternal(inputPath, outputPath).ConfigureAwait(false); } } finally @@ -349,15 +363,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// </summary> /// <param name="inputPath">The input path.</param> /// <param name="outputPath">The output path.</param> - /// <param name="language">The language.</param> /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException"> - /// inputPath + /// <exception cref="System.ArgumentNullException">inputPath /// or - /// outputPath - /// </exception> + /// outputPath</exception> /// <exception cref="System.ApplicationException"></exception> - private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string outputPath, string language) + private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string outputPath) { if (string.IsNullOrEmpty(inputPath)) { @@ -371,9 +382,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); - var encodingParam = string.IsNullOrEmpty(language) - ? string.Empty - : GetSubtitleFileCharacterSet(inputPath, language); + var encodingParam = GetSubtitleFileCharacterSet(inputPath); if (!string.IsNullOrEmpty(encodingParam)) { @@ -459,7 +468,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { _logger.Info("Deleting converted subtitle due to failure: ", outputPath); - File.Delete(outputPath); + _fileSystem.DeleteFile(outputPath); } catch (IOException ex) { @@ -608,7 +617,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { _logger.Info("Deleting extracted subtitle due to failure: {0}", outputPath); - File.Delete(outputPath); + _fileSystem.DeleteFile(outputPath); } catch (FileNotFoundException) { @@ -696,27 +705,31 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Gets the subtitle language encoding param. /// </summary> /// <param name="path">The path.</param> - /// <param name="language">The language.</param> /// <returns>System.String.</returns> - public string GetSubtitleFileCharacterSet(string path, string language) + public string GetSubtitleFileCharacterSet(string path) { - //var charset = DetectCharset(path); - - //if (!string.IsNullOrWhiteSpace(charset)) - //{ - // if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase)) - // { - // return null; - // } - - // return charset; - //} - if (GetFileEncoding(path).Equals(Encoding.UTF8)) { return string.Empty; } + var charset = DetectCharset(path); + + if (!string.IsNullOrWhiteSpace(charset)) + { + if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + return charset; + } + + return null; + } + + public string GetSubtitleFileCharacterSetFromLanguage(string language) + { switch (language.ToLower()) { case "pol": |
