From 6ba2a9ebd2cc42d83b8bbef959b8d5b71c0fee4d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 2 Apr 2016 21:19:27 -0400 Subject: [PATCH] update subtitle encoding --- .../Playback/BaseStreamingService.cs | 2 +- .../MediaEncoding/ISubtitleEncoder.cs | 2 +- .../Encoder/BaseEncoder.cs | 2 +- .../Subtitles/SubtitleEncoder.cs | 63 ++++++++++++------- MediaBrowser.Model/Dlna/StreamBuilder.cs | 2 +- 5 files changed, 45 insertions(+), 26 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 44bc95ed1c..00ac7be879 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -614,7 +614,7 @@ namespace MediaBrowser.Api.Playback if (!string.IsNullOrEmpty(state.SubtitleStream.Language)) { - var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.MediaSource.Protocol, CancellationToken.None).Result; + var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language, state.MediaSource.Protocol, CancellationToken.None).Result; if (!string.IsNullOrEmpty(charenc)) { diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index 826711e51d..e538b84d8f 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -33,6 +33,6 @@ namespace MediaBrowser.Controller.MediaEncoding /// The protocol. /// The cancellation token. /// System.String. - Task GetSubtitleFileCharacterSet(string path, MediaProtocol protocol, CancellationToken cancellationToken); + Task GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 8c0a7b0b55..263efbb629 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -969,7 +969,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!string.IsNullOrEmpty(state.SubtitleStream.Language)) { - var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.MediaSource.Protocol, CancellationToken.None).Result; + var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language, state.MediaSource.Protocol, CancellationToken.None).Result; if (!string.IsNullOrEmpty(charenc)) { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index baf78ad926..8c33cc7c0b 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -161,16 +161,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false); - var stream = await GetSubtitleStream(fileInfo.Item1, fileInfo.Item2, fileInfo.Item4, cancellationToken).ConfigureAwait(false); + var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language, fileInfo.Item2, fileInfo.Item4, cancellationToken).ConfigureAwait(false); return new Tuple(stream, fileInfo.Item3); } - private async Task GetSubtitleStream(string path, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken) + private async Task GetSubtitleStream(string path, string language, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken) { if (requiresCharset) { - var charset = await GetSubtitleFileCharacterSet(path, protocol, cancellationToken).ConfigureAwait(false); + var charset = await GetSubtitleFileCharacterSet(path, language, protocol, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(charset)) { @@ -197,14 +197,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles { throw new ArgumentNullException("charset"); } - + + _logger.Debug("Getting encoding object for character set: {0}", charset); + try { return Encoding.GetEncoding(charset); } catch (ArgumentException) { - return Encoding.GetEncoding(charset.Replace("-", string.Empty)); + charset = charset.Replace("-", string.Empty); + _logger.Debug("Getting encoding object for character set: {0}", charset); + + return Encoding.GetEncoding(charset); } } @@ -257,7 +262,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // Convert var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, ".srt"); - await ConvertTextSubtitleToSrt(subtitleStream.Path, protocol, outputPath, cancellationToken).ConfigureAwait(false); + await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, protocol, outputPath, cancellationToken).ConfigureAwait(false); return new Tuple(outputPath, MediaProtocol.File, "srt", true); } @@ -356,7 +361,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The output path. /// The cancellation token. /// Task. - private async Task ConvertTextSubtitleToSrt(string inputPath, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) + private async Task ConvertTextSubtitleToSrt(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) { var semaphore = GetLock(outputPath); @@ -364,9 +369,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - if (!_fileSystem.FileExists(outputPath)) + if (!_fileSystem.FileExists(outputPath)) { - await ConvertTextSubtitleToSrtInternal(inputPath, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false); + await ConvertTextSubtitleToSrtInternal(inputPath, language, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false); } } finally @@ -389,7 +394,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// outputPath /// /// - private async Task ConvertTextSubtitleToSrtInternal(string inputPath, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) + private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { @@ -401,9 +406,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException("outputPath"); } - _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); - var encodingParam = await GetSubtitleFileCharacterSet(inputPath, inputProtocol, cancellationToken).ConfigureAwait(false); + var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(encodingParam)) { @@ -431,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true); @@ -484,7 +489,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { failed = true; - if (_fileSystem.FileExists(outputPath)) + if (_fileSystem.FileExists(outputPath)) { try { @@ -497,7 +502,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } } - else if (!_fileSystem.FileExists(outputPath)) + else if (!_fileSystem.FileExists(outputPath)) { failed = true; } @@ -533,7 +538,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - if (!_fileSystem.FileExists(outputPath)) + if (!_fileSystem.FileExists(outputPath)) { await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex, outputCodec, outputPath, cancellationToken).ConfigureAwait(false); @@ -558,7 +563,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException("outputPath"); } - _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath, subtitleStreamIndex, outputCodec, outputPath); @@ -584,7 +589,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true); @@ -653,7 +658,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.ErrorException("Error deleting extracted subtitle {0}", ex, outputPath); } } - else if (!_fileSystem.FileExists(outputPath)) + else if (!_fileSystem.FileExists(outputPath)) { failed = true; } @@ -733,7 +738,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - public async Task GetSubtitleFileCharacterSet(string path, MediaProtocol protocol, CancellationToken cancellationToken) + public async Task GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken) { if (protocol == MediaProtocol.File) { @@ -743,7 +748,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - var charset = await DetectCharset(path, protocol, cancellationToken).ConfigureAwait(false); + var charset = await DetectCharset(path, language, protocol, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(charset)) { @@ -755,6 +760,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles return charset; } + if (!string.IsNullOrWhiteSpace(language)) + { + return GetSubtitleFileCharacterSetFromLanguage(language); + } + return null; } @@ -799,7 +809,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - private async Task DetectCharset(string path, MediaProtocol protocol, CancellationToken cancellationToken) + private async Task DetectCharset(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken) { try { @@ -816,6 +826,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.Info("UniversalDetector detected charset {0} for {1}", charset, path); } + // This is often incorrectly indetected. If this happens, try to use other techniques instead + if (string.Equals("x-mac-cyrillic", charset, StringComparison.OrdinalIgnoreCase)) + { + if (!string.IsNullOrWhiteSpace(language)) + { + return null; + } + } + return charset; } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index a080011eca..e5477cfd03 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -776,7 +776,7 @@ namespace MediaBrowser.Model.Dlna } // Look for an external or hls profile that matches the stream type (text/graphical) and doesn't require conversion - return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, false) ?? GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, false) ?? new SubtitleProfile + return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, false) ?? GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, true) ?? new SubtitleProfile { Method = SubtitleDeliveryMethod.Encode, Format = subtitleStream.Codec