aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding
diff options
context:
space:
mode:
authorBond_009 <bond.009@outlook.com>2020-05-02 00:54:04 +0200
committerBond_009 <bond.009@outlook.com>2020-05-02 00:54:04 +0200
commit15634a1913e8c1ad4e921364f30055794644d0bd (patch)
treef0dfb3502728e4786de32c0cb4eaabd06f8e2d87 /MediaBrowser.MediaEncoding
parent407f54e7764a6bfd8e4ccc0df897fac7e8c658b4 (diff)
parent62e251663fce8216cea529f85382299ac2f39fbc (diff)
Merge branch 'master' into websocket
Diffstat (limited to 'MediaBrowser.MediaEncoding')
-rw-r--r--MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs67
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs38
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs14
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs5
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs198
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj9
-rw-r--r--MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs12
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/AssParser.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs168
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs1
13 files changed, 304 insertions, 213 deletions
diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
index c530c9fd81..3f177a9fa8 100644
--- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
+++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
@@ -1,6 +1,6 @@
using System;
-using System.Diagnostics;
using System.Collections.Concurrent;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -155,47 +155,44 @@ namespace MediaBrowser.MediaEncoding.Attachments
inputPath,
attachmentStreamIndex,
outputPath);
- var startInfo = new ProcessStartInfo
- {
- Arguments = processArgs,
- FileName = _mediaEncoder.EncoderPath,
- UseShellExecute = false,
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- ErrorDialog = false
- };
- var process = new Process
- {
- StartInfo = startInfo
- };
- _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ int exitCode;
- process.Start();
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ Arguments = processArgs,
+ FileName = _mediaEncoder.EncoderPath,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
- var processTcs = new TaskCompletionSource<bool>();
- process.EnableRaisingEvents = true;
- process.Exited += (sender, args) => processTcs.TrySetResult(true);
- var unregister = cancellationToken.Register(() => processTcs.TrySetResult(process.HasExited));
- var ranToCompletion = await processTcs.Task.ConfigureAwait(false);
- unregister.Dispose();
+ process.Start();
- if (!ranToCompletion)
- {
- try
- {
- _logger.LogWarning("Killing ffmpeg attachment extraction process");
- process.Kill();
- }
- catch (Exception ex)
+ var ranToCompletion = await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
+
+ if (!ranToCompletion)
{
- _logger.LogError(ex, "Error killing attachment extraction process");
+ try
+ {
+ _logger.LogWarning("Killing ffmpeg attachment extraction process");
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing attachment extraction process");
+ }
}
- }
- var exitCode = ranToCompletion ? process.ExitCode : -1;
-
- process.Dispose();
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
var failed = false;
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
index 91c8b27925..e040286ab9 100644
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
+++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
@@ -1,16 +1,27 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using BDInfo.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.MediaEncoding.BdInfo
{
- class BdInfoDirectoryInfo : BDInfo.IO.IDirectoryInfo
+ class BdInfoDirectoryInfo : IDirectoryInfo
{
- IFileSystem _fileSystem = null;
+ private readonly IFileSystem _fileSystem = null;
- FileSystemMetadata _impl = null;
+ private readonly FileSystemMetadata _impl = null;
+
+ public BdInfoDirectoryInfo(IFileSystem fileSystem, string path)
+ {
+ _fileSystem = fileSystem;
+ _impl = _fileSystem.GetDirectoryInfo(path);
+ }
+
+ private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl)
+ {
+ _fileSystem = fileSystem;
+ _impl = impl;
+ }
public string Name => _impl.Name;
@@ -25,22 +36,11 @@ namespace MediaBrowser.MediaEncoding.BdInfo
{
return new BdInfoDirectoryInfo(_fileSystem, parentFolder);
}
+
return null;
}
}
- public BdInfoDirectoryInfo(IFileSystem fileSystem, string path)
- {
- _fileSystem = fileSystem;
- _impl = _fileSystem.GetDirectoryInfo(path);
- }
-
- private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl)
- {
- _fileSystem = fileSystem;
- _impl = impl;
- }
-
public IDirectoryInfo[] GetDirectories()
{
return Array.ConvertAll(_fileSystem.GetDirectories(_impl.FullName).ToArray(),
@@ -50,20 +50,20 @@ namespace MediaBrowser.MediaEncoding.BdInfo
public IFileInfo[] GetFiles()
{
return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName).ToArray(),
- x => new BdInfoFileInfo(_fileSystem, x));
+ x => new BdInfoFileInfo(x));
}
public IFileInfo[] GetFiles(string searchPattern)
{
return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(),
- x => new BdInfoFileInfo(_fileSystem, x));
+ x => new BdInfoFileInfo(x));
}
public IFileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption)
{
return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false,
searchOption.HasFlag(System.IO.SearchOption.AllDirectories)).ToArray(),
- x => new BdInfoFileInfo(_fileSystem, x));
+ x => new BdInfoFileInfo(x));
}
public static IDirectoryInfo FromFileSystemPath(Model.IO.IFileSystem fs, string path)
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs
index de9d7cb784..a6ff4f7678 100644
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs
+++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs
@@ -1,11 +1,10 @@
+using System.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.MediaEncoding.BdInfo
{
class BdInfoFileInfo : BDInfo.IO.IFileInfo
{
- IFileSystem _fileSystem = null;
-
FileSystemMetadata _impl = null;
public string Name => _impl.Name;
@@ -18,18 +17,17 @@ namespace MediaBrowser.MediaEncoding.BdInfo
public bool IsDir => _impl.IsDirectory;
- public BdInfoFileInfo(IFileSystem fileSystem, FileSystemMetadata impl)
+ public BdInfoFileInfo(FileSystemMetadata impl)
{
- _fileSystem = fileSystem;
_impl = impl;
}
public System.IO.Stream OpenRead()
{
- return _fileSystem.GetFileStream(FullName,
- FileOpenMode.Open,
- FileAccessMode.Read,
- FileShareMode.Read);
+ return new FileStream(FullName,
+ FileMode.Open,
+ FileAccess.Read,
+ FileShare.Read);
}
public System.IO.StreamReader OpenText()
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index 1feca0ec92..6e036d24c1 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
"libvpx",
"libvpx-vp9",
"aac",
+ "libfdk_aac",
"libmp3lame",
"libopus",
"libvorbis",
@@ -55,7 +56,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
"h264_vaapi",
"hevc_vaapi",
"h264_v4l2m2m",
- "ac3"
+ "ac3",
+ "h264_amf",
+ "hevc_amf"
};
// Try and use the individual library versions to determine a FFmpeg version
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index e0f7b992ce..1377502dd9 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -13,7 +13,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@@ -21,7 +20,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Configuration;
+using System.Diagnostics;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -38,10 +37,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly ILogger _logger;
private readonly IServerConfigurationManager _configurationManager;
private readonly IFileSystem _fileSystem;
- private readonly IProcessFactory _processFactory;
private readonly ILocalizationManager _localization;
- private readonly Func<ISubtitleEncoder> _subtitleEncoder;
- private readonly IConfiguration _configuration;
+ private readonly Lazy<EncodingHelper> _encodingHelperFactory;
private readonly string _startupOptionFFmpegPath;
private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
@@ -49,8 +46,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly object _runningProcessesLock = new object();
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
- private EncodingHelper _encodingHelper;
-
private string _ffmpegPath;
private string _ffprobePath;
@@ -58,26 +53,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
ILogger<MediaEncoder> logger,
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
- IProcessFactory processFactory,
ILocalizationManager localization,
- Func<ISubtitleEncoder> subtitleEncoder,
- IConfiguration configuration,
+ Lazy<EncodingHelper> encodingHelperFactory,
string startupOptionsFFmpegPath)
{
_logger = logger;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
- _processFactory = processFactory;
_localization = localization;
+ _encodingHelperFactory = encodingHelperFactory;
_startupOptionFFmpegPath = startupOptionsFFmpegPath;
- _subtitleEncoder = subtitleEncoder;
- _configuration = configuration;
}
- private EncodingHelper EncodingHelper
- => LazyInitializer.EnsureInitialized(
- ref _encodingHelper,
- () => new EncodingHelper(this, _fileSystem, _subtitleEncoder(), _configuration));
+ private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
/// <inheritdoc />
public string EncoderPath => _ffmpegPath;
@@ -125,7 +113,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
SetAvailableEncoders(validator.GetEncoders());
}
- _logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation, _ffmpegPath ?? string.Empty);
+ _logger.LogInformation("FFmpeg: {EncoderLocation}: {FfmpegPath}", EncoderLocation, _ffmpegPath ?? string.Empty);
}
/// <summary>
@@ -138,7 +126,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
string newPath;
- _logger.LogInformation("Attempting to update encoder path to {0}. pathType: {1}", path ?? string.Empty, pathType ?? string.Empty);
+ _logger.LogInformation("Attempting to update encoder path to {Path}. pathType: {PathType}", path ?? string.Empty, pathType ?? string.Empty);
if (!string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase))
{
@@ -192,7 +180,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!rc)
{
- _logger.LogWarning("FFmpeg: {0}: Failed version check: {1}", location, path);
+ _logger.LogWarning("FFmpeg: {Location}: Failed version check: {Path}", location, path);
}
// ToDo - Enable the ffmpeg validator. At the moment any version can be used.
@@ -203,18 +191,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
else
{
- _logger.LogWarning("FFmpeg: {0}: File not found: {1}", location, path);
+ _logger.LogWarning("FFmpeg: {Location}: File not found: {Path}", location, path);
}
}
return rc;
}
- private string GetEncoderPathFromDirectory(string path, string filename)
+ private string GetEncoderPathFromDirectory(string path, string filename, bool recursive = false)
{
try
{
- var files = _fileSystem.GetFilePaths(path);
+ var files = _fileSystem.GetFilePaths(path, recursive);
var excludeExtensions = new[] { ".c" };
@@ -235,7 +223,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns></returns>
private string ExistsOnSystemPath(string fileName)
{
- string inJellyfinPath = GetEncoderPathFromDirectory(System.AppContext.BaseDirectory, fileName);
+ var inJellyfinPath = GetEncoderPathFromDirectory(AppContext.BaseDirectory, fileName, recursive: true);
if (!string.IsNullOrEmpty(inJellyfinPath))
{
return inJellyfinPath;
@@ -362,30 +350,33 @@ namespace MediaBrowser.MediaEncoding.Encoder
: "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_format";
args = string.Format(args, probeSizeArgument, inputPath).Trim();
- var process = _processFactory.Create(new ProcessOptions
+ var process = new Process
{
- CreateNoWindow = true,
- UseShellExecute = false,
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
- // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
- RedirectStandardOutput = true,
+ // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
+ RedirectStandardOutput = true,
- FileName = _ffprobePath,
- Arguments = args,
+ FileName = _ffprobePath,
+ Arguments = args,
- IsHidden = true,
- ErrorDialog = false,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ },
EnableRaisingEvents = true
- });
+ };
if (forceEnableLogging)
{
- _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.LogInformation("{ProcessFileName} {ProcessArgs}", process.StartInfo.FileName, process.StartInfo.Arguments);
}
else
{
- _logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.LogDebug("{ProcessFileName} {ProcessArgs}", process.StartInfo.FileName, process.StartInfo.Arguments);
}
using (var processWrapper = new ProcessWrapper(process, this))
@@ -429,7 +420,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- return new ProbeResultNormalizer(_logger, _fileSystem, _localization).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
+ return new ProbeResultNormalizer(_logger, _localization).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
}
}
@@ -478,7 +469,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
catch (Exception ex)
{
- _logger.LogError(ex, "I-frame image extraction failed, will attempt standard way. Input: {arguments}", inputArgument);
+ _logger.LogError(ex, "I-frame image extraction failed, will attempt standard way. Input: {Arguments}", inputArgument);
}
}
@@ -571,18 +562,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- var process = _processFactory.Create(new ProcessOptions
+ var process = new Process
{
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = _ffmpegPath,
- Arguments = args,
- IsHidden = true,
- ErrorDialog = false,
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _ffmpegPath,
+ Arguments = args,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ },
EnableRaisingEvents = true
- });
+ };
- _logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.LogDebug("{ProcessFileName} {ProcessArguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
using (var processWrapper = new ProcessWrapper(process, this))
{
@@ -599,7 +593,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
timeoutMs = DefaultImageExtractionTimeout;
}
- ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
+ ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false);
if (!ranToCompletion)
{
@@ -700,23 +694,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- var process = _processFactory.Create(new ProcessOptions
+ var processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
FileName = _ffmpegPath,
Arguments = args,
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ };
- _logger.LogInformation(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
+ _logger.LogInformation(processStartInfo.FileName + " " + processStartInfo.Arguments);
await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
bool ranToCompletion = false;
+ var process = new Process
+ {
+ StartInfo = processStartInfo,
+ EnableRaisingEvents = true
+ };
using (var processWrapper = new ProcessWrapper(process, this))
{
try
@@ -732,7 +730,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
while (isResponsive)
{
- if (await process.WaitForExitAsync(30000).ConfigureAwait(false))
+ if (await process.WaitForExitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false))
{
ranToCompletion = true;
break;
@@ -849,14 +847,92 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ /// <inheritdoc />
public Task ConvertImage(string inputPath, string outputPath)
{
throw new NotImplementedException();
}
+ /// <inheritdoc />
public IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber)
{
- throw new NotImplementedException();
+ // min size 300 mb
+ const long MinPlayableSize = 314572800;
+
+ var root = isoMount != null ? isoMount.MountedPath : path;
+
+ // Try to eliminate menus and intros by skipping all files at the front of the list that are less than the minimum size
+ // Once we reach a file that is at least the minimum, return all subsequent ones
+ var allVobs = _fileSystem.GetFiles(root, true)
+ .Where(file => string.Equals(file.Extension, ".vob", StringComparison.OrdinalIgnoreCase))
+ .OrderBy(i => i.FullName)
+ .ToList();
+
+ // If we didn't find any satisfying the min length, just take them all
+ if (allVobs.Count == 0)
+ {
+ _logger.LogWarning("No vobs found in dvd structure.");
+ return Enumerable.Empty<string>();
+ }
+
+ if (titleNumber.HasValue)
+ {
+ var prefix = string.Format(
+ CultureInfo.InvariantCulture,
+ titleNumber.Value >= 10 ? "VTS_{0}_" : "VTS_0{0}_",
+ titleNumber.Value);
+ var vobs = allVobs.Where(i => i.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)).ToList();
+
+ if (vobs.Count > 0)
+ {
+ var minSizeVobs = vobs
+ .SkipWhile(f => f.Length < MinPlayableSize)
+ .ToList();
+
+ return minSizeVobs.Count == 0 ? vobs.Select(i => i.FullName) : minSizeVobs.Select(i => i.FullName);
+ }
+
+ _logger.LogWarning("Could not determine vob file list for {Path} using DvdLib. Will scan using file sizes.", path);
+ }
+
+ var files = allVobs
+ .SkipWhile(f => f.Length < MinPlayableSize)
+ .ToList();
+
+ // If we didn't find any satisfying the min length, just take them all
+ if (files.Count == 0)
+ {
+ _logger.LogWarning("Vob size filter resulted in zero matches. Taking all vobs.");
+ files = allVobs;
+ }
+
+ // Assuming they're named "vts_05_01", take all files whose second part matches that of the first file
+ if (files.Count > 0)
+ {
+ var parts = _fileSystem.GetFileNameWithoutExtension(files[0]).Split('_');
+
+ if (parts.Length == 3)
+ {
+ var title = parts[1];
+
+ files = files.TakeWhile(f =>
+ {
+ var fileParts = _fileSystem.GetFileNameWithoutExtension(f).Split('_');
+
+ return fileParts.Length == 3 && string.Equals(title, fileParts[1], StringComparison.OrdinalIgnoreCase);
+
+ }).ToList();
+
+ // If this resulted in not getting any vobs, just take them all
+ if (files.Count == 0)
+ {
+ _logger.LogWarning("Vob filename filter resulted in zero matches. Taking all vobs.");
+ files = allVobs;
+ }
+ }
+ }
+
+ return files.Select(i => i.FullName);
}
public bool CanExtractSubtitles(string codec)
@@ -871,22 +947,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
private bool _disposed = false;
- public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder)
+ public ProcessWrapper(Process process, MediaEncoder mediaEncoder)
{
Process = process;
_mediaEncoder = mediaEncoder;
Process.Exited += OnProcessExited;
}
- public IProcess Process { get; }
+ public Process Process { get; }
public bool HasExited { get; private set; }
public int? ExitCode { get; private set; }
- void OnProcessExited(object sender, EventArgs e)
+ private void OnProcessExited(object sender, EventArgs e)
{
- var process = (IProcess)sender;
+ var process = (Process)sender;
HasExited = true;
@@ -901,7 +977,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
DisposeProcess(process);
}
- private void DisposeProcess(IProcess process)
+ private void DisposeProcess(Process process)
{
lock (_mediaEncoder._runningProcessesLock)
{
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 783457bda3..af8bee301c 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -1,5 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
+ <!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
+ <PropertyGroup>
+ <ProjectGuid>{960295EE-4AF4-4440-A525-B4C295B01A61}</ProjectGuid>
+ </PropertyGroup>
+
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -18,8 +23,8 @@
<ItemGroup>
<PackageReference Include="BDInfo" Version="0.7.6.1" />
- <PackageReference Include="System.Text.Encoding.CodePages" Version="4.6.0" />
- <PackageReference Include="UTF.Unknown" Version="2.2.0" />
+ <PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" />
+ <PackageReference Include="UTF.Unknown" Version="2.3.0" />
</ItemGroup>
</Project>
diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs
index 7fa7afa5b3..0b2f1d231e 100644
--- a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs
+++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs
@@ -225,7 +225,7 @@ namespace MediaBrowser.MediaEncoding.Probing
/// </summary>
/// <value>The start_pts.</value>
[JsonPropertyName("start_pts")]
- public int StartPts { get; set; }
+ public long StartPts { get; set; }
/// <summary>
/// Gets or sets the is_avc.
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index bd89c6cae9..b24d97f4ef 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -9,7 +9,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
@@ -19,13 +18,11 @@ namespace MediaBrowser.MediaEncoding.Probing
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
private readonly ILocalizationManager _localization;
- public ProbeResultNormalizer(ILogger logger, IFileSystem fileSystem, ILocalizationManager localization)
+ public ProbeResultNormalizer(ILogger logger, ILocalizationManager localization)
{
_logger = logger;
- _fileSystem = fileSystem;
_localization = localization;
}
@@ -40,7 +37,7 @@ namespace MediaBrowser.MediaEncoding.Probing
FFProbeHelpers.NormalizeFFProbeResult(data);
SetSize(data, info);
- var internalStreams = data.Streams ?? new MediaStreamInfo[] { };
+ var internalStreams = data.Streams ?? Array.Empty<MediaStreamInfo>();
info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.Format))
.Where(i => i != null)
@@ -112,6 +109,9 @@ namespace MediaBrowser.MediaEncoding.Probing
info.Name = title;
}
+ info.IndexNumber = FFProbeHelpers.GetDictionaryNumericValue(tags, "episode_sort");
+ info.ParentIndexNumber = FFProbeHelpers.GetDictionaryNumericValue(tags, "season_number");
+ info.ShowName = FFProbeHelpers.GetDictionaryValue(tags, "show_name");
info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
// Several different forms of retaildate
@@ -536,7 +536,7 @@ namespace MediaBrowser.MediaEncoding.Probing
if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString))
{
- attachment.CodecTag = streamInfo.CodecTagString;
+ attachment.CodecTag = streamInfo.CodecTagString;
}
if (streamInfo.Tags != null)
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
index 605504418b..293cf5ea5b 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.MediaEncoding.Subtitles
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
index 0606dbdb29..c98dd15024 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
@@ -4,7 +4,6 @@ using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
index 0d696b9064..b94d451653 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.MediaEncoding.Subtitles
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 99bb368b26..ba171295ea 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Concurrent;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -12,7 +13,6 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -31,7 +31,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private readonly IMediaEncoder _mediaEncoder;
private readonly IHttpClient _httpClient;
private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IProcessFactory _processFactory;
public SubtitleEncoder(
ILibraryManager libraryManager,
@@ -40,8 +39,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
IFileSystem fileSystem,
IMediaEncoder mediaEncoder,
IHttpClient httpClient,
- IMediaSourceManager mediaSourceManager,
- IProcessFactory processFactory)
+ IMediaSourceManager mediaSourceManager)
{
_libraryManager = libraryManager;
_logger = logger;
@@ -50,7 +48,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_mediaEncoder = mediaEncoder;
_httpClient = httpClient;
_mediaSourceManager = mediaSourceManager;
- _processFactory = processFactory;
}
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
@@ -188,6 +185,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
using (var stream = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
{
var result = CharsetDetector.DetectFromStream(stream).Detected;
+ stream.Position = 0;
if (result != null)
{
@@ -428,49 +426,53 @@ namespace MediaBrowser.MediaEncoding.Subtitles
encodingParam = " -sub_charenc " + encodingParam;
}
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = _mediaEncoder.EncoderPath,
- Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
- EnableRaisingEvents = true,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error starting ffmpeg");
+ int exitCode;
- throw;
- }
-
- var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _mediaEncoder.EncoderPath,
+ Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- if (!ranToCompletion)
- {
try
{
- _logger.LogInformation("Killing ffmpeg subtitle conversion process");
-
- process.Kill();
+ process.Start();
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error killing subtitle conversion process");
+ _logger.LogError(ex, "Error starting ffmpeg");
+
+ throw;
}
- }
- var exitCode = ranToCompletion ? process.ExitCode : -1;
+ var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
+
+ if (!ranToCompletion)
+ {
+ try
+ {
+ _logger.LogInformation("Killing ffmpeg subtitle conversion process");
+
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing subtitle conversion process");
+ }
+ }
- process.Dispose();
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
var failed = false;
@@ -577,49 +579,53 @@ namespace MediaBrowser.MediaEncoding.Subtitles
outputCodec,
outputPath);
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- EnableRaisingEvents = true,
- FileName = _mediaEncoder.EncoderPath,
- Arguments = processArgs,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ int exitCode;
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error starting ffmpeg");
-
- throw;
- }
-
- var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ FileName = _mediaEncoder.EncoderPath,
+ Arguments = processArgs,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
- if (!ranToCompletion)
- {
try
{
- _logger.LogWarning("Killing ffmpeg subtitle extraction process");
-
- process.Kill();
+ process.Start();
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error killing subtitle extraction process");
+ _logger.LogError(ex, "Error starting ffmpeg");
+
+ throw;
}
- }
- var exitCode = ranToCompletion ? process.ExitCode : -1;
+ var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
- process.Dispose();
+ if (!ranToCompletion)
+ {
+ try
+ {
+ _logger.LogWarning("Killing ffmpeg subtitle extraction process");
+
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing subtitle extraction process");
+ }
+ }
+
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
var failed = false;
@@ -691,7 +697,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (!string.Equals(text, newText))
{
- using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+ using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var writer = new StreamWriter(fileStream, encoding))
{
writer.Write(newText);
@@ -730,6 +736,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName;
+ // UTF16 is automatically converted to UTF8 by FFmpeg, do not specify a character encoding
+ if ((path.EndsWith(".ass") || path.EndsWith(".ssa"))
+ && (string.Equals(charset, "utf-16le", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(charset, "utf-16be", StringComparison.OrdinalIgnoreCase)))
+ {
+ charset = "";
+ }
+
_logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path);
return charset;
@@ -745,15 +759,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
Url = path,
CancellationToken = cancellationToken,
+
+ // Needed for seeking
BufferContent = true
};
return _httpClient.Get(opts);
- case MediaProtocol.File:
- return Task.FromResult<Stream>(File.OpenRead(path));
- default:
- throw new ArgumentOutOfRangeException(nameof(protocol));
+ case MediaProtocol.File:
+ return Task.FromResult<Stream>(File.OpenRead(path));
+ default:
+ throw new ArgumentOutOfRangeException(nameof(protocol));
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
index 4f15bac496..7d3e185784 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
@@ -1,4 +1,3 @@
-using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;