make media encoding project portable

This commit is contained in:
Luke Pulverenti 2016-11-01 00:07:12 -04:00
parent 13d8110ce2
commit b1276dc208
23 changed files with 444 additions and 214 deletions

View File

@ -27,11 +27,16 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using Emby.Common.Implementations.Cryptography; using Emby.Common.Implementations.Cryptography;
using Emby.Common.Implementations.Diagnostics;
using Emby.Common.Implementations.Threading;
using MediaBrowser.Common; using MediaBrowser.Common;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.System; using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
#if NETSTANDARD1_6 #if NETSTANDARD1_6
using System.Runtime.Loader; using System.Runtime.Loader;
#endif #endif
@ -146,6 +151,9 @@ namespace Emby.Common.Implementations
protected ISystemEvents SystemEvents { get; private set; } protected ISystemEvents SystemEvents { get; private set; }
protected IProcessFactory ProcessFactory { get; private set; }
protected ITimerFactory TimerFactory { get; private set; }
/// <summary> /// <summary>
/// Gets the name. /// Gets the name.
/// </summary> /// </summary>
@ -535,6 +543,12 @@ return null;
IsoManager = new IsoManager(); IsoManager = new IsoManager();
RegisterSingleInstance(IsoManager); RegisterSingleInstance(IsoManager);
ProcessFactory = new ProcessFactory();
RegisterSingleInstance(ProcessFactory);
TimerFactory = new TimerFactory();
RegisterSingleInstance(TimerFactory);
return Task.FromResult(true); return Task.FromResult(true);
} }

View File

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Diagnostics;
namespace Emby.Common.Implementations.Diagnostics
{
public class CommonProcess : IProcess
{
public event EventHandler Exited;
private readonly ProcessOptions _options;
private readonly Process _process;
public CommonProcess(ProcessOptions options)
{
_options = options;
var startInfo = new ProcessStartInfo
{
Arguments = options.Arguments,
FileName = options.FileName,
WorkingDirectory = options.WorkingDirectory,
UseShellExecute = options.UseShellExecute,
CreateNoWindow = options.CreateNoWindow,
RedirectStandardError = options.RedirectStandardError,
RedirectStandardInput = options.RedirectStandardInput,
RedirectStandardOutput = options.RedirectStandardOutput
};
#if NET46
startInfo.ErrorDialog = options.ErrorDialog;
if (options.IsHidden)
{
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
}
#endif
_process = new Process
{
StartInfo = startInfo
};
if (options.EnableRaisingEvents)
{
_process.EnableRaisingEvents = true;
_process.Exited += _process_Exited;
}
}
private void _process_Exited(object sender, EventArgs e)
{
if (Exited != null)
{
Exited(_process, e);
}
}
public ProcessOptions StartInfo
{
get { return _options; }
}
public StreamWriter StandardInput
{
get { return _process.StandardInput; }
}
public StreamReader StandardError
{
get { return _process.StandardError; }
}
public StreamReader StandardOutput
{
get { return _process.StandardOutput; }
}
public int ExitCode
{
get { return _process.ExitCode; }
}
public void Start()
{
_process.Start();
}
public void Kill()
{
_process.Kill();
}
public bool WaitForExit(int timeMs)
{
return _process.WaitForExit(timeMs);
}
public void Dispose()
{
_process.Dispose();
}
}
}

View File

@ -0,0 +1,12 @@
using MediaBrowser.Model.Diagnostics;
namespace Emby.Common.Implementations.Diagnostics
{
public class ProcessFactory : IProcessFactory
{
public IProcess Create(ProcessOptions options)
{
return new CommonProcess(options);
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Threading;
namespace Emby.Common.Implementations.Threading
{
public class CommonTimer : ITimer
{
private readonly Timer _timer;
public CommonTimer(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
{
_timer = new Timer(new TimerCallback(callback), state, dueTime, period);
}
public CommonTimer(Action<object> callback, object state, int dueTimeMs, int periodMs)
{
_timer = new Timer(new TimerCallback(callback), state, dueTimeMs, periodMs);
}
public void Change(TimeSpan dueTime, TimeSpan period)
{
_timer.Change(dueTime, period);
}
public void Change(int dueTimeMs, int periodMs)
{
_timer.Change(dueTimeMs, periodMs);
}
public void Dispose()
{
_timer.Dispose();
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Threading;
namespace Emby.Common.Implementations.Threading
{
public class TimerFactory : ITimerFactory
{
public ITimer Create(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
{
return new CommonTimer(callback, state, dueTime, period);
}
public ITimer Create(Action<object> callback, object state, int dueTimeMs, int periodMs)
{
return new CommonTimer(callback, state, dueTimeMs, periodMs);
}
}
}

View File

@ -44,6 +44,8 @@
"target": "project" "target": "project"
}, },
"System.IO.FileSystem.DriveInfo": "4.0.0", "System.IO.FileSystem.DriveInfo": "4.0.0",
"System.Diagnostics.Process": "4.1.0",
"System.Threading.Timer": "4.0.1",
"System.Net.Requests": "4.0.11", "System.Net.Requests": "4.0.11",
"System.Xml.XmlSerializer": "4.0.11", "System.Xml.XmlSerializer": "4.0.11",
"System.Net.Http": "4.1.0", "System.Net.Http": "4.1.0",

View File

@ -42,6 +42,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Dlna", "Emby.Dlna\Emby
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Photos", "Emby.Photos\Emby.Photos.csproj", "{89AB4548-770D-41FD-A891-8DAFF44F452C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Photos", "Emby.Photos\Emby.Photos.csproj", "{89AB4548-770D-41FD-A891-8DAFF44F452C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -145,6 +149,18 @@ Global
{89AB4548-770D-41FD-A891-8DAFF44F452C}.Release Mono|Any CPU.Build.0 = Release|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release Mono|Any CPU.Build.0 = Release|Any CPU
{89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.ActiveCfg = Release|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.Build.0 = Release|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.Build.0 = Release|Any CPU
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.Build.0 = Release|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -166,5 +182,7 @@ Global
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} {C227ADB7-E256-4E70-A8B9-22B9E0CF4F55} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839}
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} {F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839}
{89AB4548-770D-41FD-A891-8DAFF44F452C} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839} {89AB4548-770D-41FD-A891-8DAFF44F452C} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839}
{4FD51AC5-2C16-4308-A993-C3A84F3B4582} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839}
{0BD82FA6-EB8A-4452-8AF5-74F9C3849451} = {8ADD772F-F0A4-4A53-9B2F-AF4A4C585839}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -7,15 +7,13 @@ using MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO; using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.MediaEncoding.Encoder namespace MediaBrowser.MediaEncoding.Encoder
{ {
public class AudioEncoder : BaseEncoder public class AudioEncoder : BaseEncoder
{ {
public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager) public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory)
{ {
} }
@ -116,5 +114,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
get { return false; } get { return false; }
} }
} }
} }

View File

@ -11,15 +11,12 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO; using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace MediaBrowser.MediaEncoding.Encoder namespace MediaBrowser.MediaEncoding.Encoder
@ -35,6 +32,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected readonly ISessionManager SessionManager; protected readonly ISessionManager SessionManager;
protected readonly ISubtitleEncoder SubtitleEncoder; protected readonly ISubtitleEncoder SubtitleEncoder;
protected readonly IMediaSourceManager MediaSourceManager; protected readonly IMediaSourceManager MediaSourceManager;
protected IProcessFactory ProcessFactory;
protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@ -46,7 +44,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
ILibraryManager libraryManager, ILibraryManager libraryManager,
ISessionManager sessionManager, ISessionManager sessionManager,
ISubtitleEncoder subtitleEncoder, ISubtitleEncoder subtitleEncoder,
IMediaSourceManager mediaSourceManager) IMediaSourceManager mediaSourceManager, IProcessFactory processFactory)
{ {
MediaEncoder = mediaEncoder; MediaEncoder = mediaEncoder;
Logger = logger; Logger = logger;
@ -57,6 +55,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
SessionManager = sessionManager; SessionManager = sessionManager;
SubtitleEncoder = subtitleEncoder; SubtitleEncoder = subtitleEncoder;
MediaSourceManager = mediaSourceManager; MediaSourceManager = mediaSourceManager;
ProcessFactory = processFactory;
} }
public async Task<EncodingJob> Start(EncodingJobOptions options, public async Task<EncodingJob> Start(EncodingJobOptions options,
@ -75,27 +74,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
var commandLineArgs = await GetCommandLineArguments(encodingJob).ConfigureAwait(false); var commandLineArgs = await GetCommandLineArguments(encodingJob).ConfigureAwait(false);
var process = new Process var process = ProcessFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true,
UseShellExecute = false,
// Must consume both stdout and stderr or deadlocks may occur // Must consume both stdout and stderr or deadlocks may occur
//RedirectStandardOutput = true, //RedirectStandardOutput = true,
RedirectStandardError = true, RedirectStandardError = true,
RedirectStandardInput = true, RedirectStandardInput = true,
FileName = MediaEncoder.EncoderPath, FileName = MediaEncoder.EncoderPath,
Arguments = commandLineArgs, Arguments = commandLineArgs,
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
IsHidden = true,
ErrorDialog = false,
EnableRaisingEvents = true EnableRaisingEvents = true
}; });
var workingDirectory = GetWorkingDirectory(options); var workingDirectory = GetWorkingDirectory(options);
if (!string.IsNullOrWhiteSpace(workingDirectory)) if (!string.IsNullOrWhiteSpace(workingDirectory))
@ -149,7 +144,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return encodingJob; return encodingJob;
} }
private void Cancel(Process process, EncodingJob job) private void Cancel(IProcess process, EncodingJob job)
{ {
Logger.Info("Killing ffmpeg process for {0}", job.OutputFilePath); Logger.Info("Killing ffmpeg process for {0}", job.OutputFilePath);
@ -164,7 +159,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary> /// </summary>
/// <param name="process">The process.</param> /// <param name="process">The process.</param>
/// <param name="job">The job.</param> /// <param name="job">The job.</param>
private void OnFfMpegProcessExited(Process process, EncodingJob job) private void OnFfMpegProcessExited(IProcess process, EncodingJob job)
{ {
job.HasExited = true; job.HasExited = true;

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
namespace MediaBrowser.MediaEncoding.Encoder namespace MediaBrowser.MediaEncoding.Encoder
@ -8,10 +9,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
public class EncoderValidator public class EncoderValidator
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProcessFactory _processFactory;
public EncoderValidator(ILogger logger) public EncoderValidator(ILogger logger, IProcessFactory processFactory)
{ {
_logger = logger; _logger = logger;
_processFactory = processFactory;
} }
public Tuple<List<string>, List<string>> Validate(string encoderPath) public Tuple<List<string>, List<string>> Validate(string encoderPath)
@ -145,19 +148,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string GetProcessOutput(string path, string arguments) private string GetProcessOutput(string path, string arguments)
{ {
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true, FileName = path,
UseShellExecute = false, Arguments = arguments,
FileName = path, IsHidden = true,
Arguments = arguments, ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden, RedirectStandardOutput = true
ErrorDialog = false, });
RedirectStandardOutput = true
}
};
_logger.Info("Running {0} {1}", path, arguments); _logger.Info("Running {0} {1}", path, arguments);

View File

@ -88,9 +88,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns>Task.</returns> /// <returns>Task.</returns>
private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress) private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress)
{ {
var existingFile = Directory var existingFile = _fileSystem
.EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories) .GetFilePaths(_appPaths.ProgramDataPath, true)
.FirstOrDefault(); .FirstOrDefault(i => string.Equals(fontFilename, Path.GetFileName(i), StringComparison.OrdinalIgnoreCase));
if (existingFile != null) if (existingFile != null)
{ {

View File

@ -14,19 +14,16 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO; using MediaBrowser.Model.Diagnostics;
namespace MediaBrowser.MediaEncoding.Encoder namespace MediaBrowser.MediaEncoding.Encoder
{ {
@ -81,14 +78,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected readonly Func<IMediaSourceManager> MediaSourceManager; protected readonly Func<IMediaSourceManager> MediaSourceManager;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IZipClient _zipClient; private readonly IZipClient _zipClient;
private readonly IProcessFactory _processFactory;
private readonly IMemoryStreamProvider _memoryStreamProvider; private readonly IMemoryStreamProvider _memoryStreamProvider;
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>(); private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
private readonly bool _hasExternalEncoder; private readonly bool _hasExternalEncoder;
private string _originalFFMpegPath; private readonly string _originalFFMpegPath;
private string _originalFFProbePath; private readonly string _originalFFProbePath;
private readonly int DefaultImageExtractionTimeoutMs;
private readonly bool EnableEncoderFontFile;
public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamProvider memoryStreamProvider) public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamProvider memoryStreamProvider, IProcessFactory processFactory,
int defaultImageExtractionTimeoutMs,
bool enableEncoderFontFile)
{ {
_logger = logger; _logger = logger;
_jsonSerializer = jsonSerializer; _jsonSerializer = jsonSerializer;
@ -104,6 +106,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
_httpClient = httpClient; _httpClient = httpClient;
_zipClient = zipClient; _zipClient = zipClient;
_memoryStreamProvider = memoryStreamProvider; _memoryStreamProvider = memoryStreamProvider;
_processFactory = processFactory;
DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs;
EnableEncoderFontFile = enableEncoderFontFile;
FFProbePath = ffProbePath; FFProbePath = ffProbePath;
FFMpegPath = ffMpegPath; FFMpegPath = ffMpegPath;
_originalFFProbePath = ffProbePath; _originalFFProbePath = ffProbePath;
@ -158,12 +163,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrWhiteSpace(FFMpegPath)) if (!string.IsNullOrWhiteSpace(FFMpegPath))
{ {
var result = new EncoderValidator(_logger).Validate(FFMpegPath); var result = new EncoderValidator(_logger, _processFactory).Validate(FFMpegPath);
SetAvailableDecoders(result.Item1); SetAvailableDecoders(result.Item1);
SetAvailableEncoders(result.Item2); SetAvailableEncoders(result.Item2);
if (Environment.OSVersion.Platform == PlatformID.Win32NT) if (EnableEncoderFontFile)
{ {
var directory = Path.GetDirectoryName(FFMpegPath); var directory = Path.GetDirectoryName(FFMpegPath);
@ -255,7 +260,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private bool ValidateVersion(string path, bool logOutput) private bool ValidateVersion(string path, bool logOutput)
{ {
return new EncoderValidator(_logger).ValidateVersion(path, logOutput); return new EncoderValidator(_logger, _processFactory).ValidateVersion(path, logOutput);
} }
private void ConfigureEncoderPaths() private void ConfigureEncoderPaths()
@ -509,27 +514,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format" ? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format"
: "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format"; : "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format";
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true,
UseShellExecute = false,
// Must consume both or ffmpeg may hang due to deadlocks. See comments below. // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
RedirectStandardOutput = true, RedirectStandardOutput = true,
//RedirectStandardError = true, //RedirectStandardError = true,
RedirectStandardInput = false, RedirectStandardInput = false,
FileName = FFProbePath, FileName = FFProbePath,
Arguments = string.Format(args, Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(),
probeSizeArgument, inputPath).Trim(),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
IsHidden = true,
ErrorDialog = false,
EnableRaisingEvents = true EnableRaisingEvents = true
}; });
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
@ -644,26 +644,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
var args = "{0} -i {1} -map 0:v:{2} -an -filter:v idet -frames:v 500 -an -f null /dev/null"; var args = "{0} -i {1} -map 0:v:{2} -an -filter:v idet -frames:v 500 -an -f null /dev/null";
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true,
UseShellExecute = false,
// Must consume both or ffmpeg may hang due to deadlocks. See comments below. // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
//RedirectStandardOutput = true, //RedirectStandardOutput = true,
RedirectStandardError = true, RedirectStandardError = true,
RedirectStandardInput = false, RedirectStandardInput = false,
FileName = FFMpegPath, FileName = FFMpegPath,
Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(), Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
IsHidden = true,
ErrorDialog = false,
EnableRaisingEvents = true EnableRaisingEvents = true
}; });
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
var idetFoundInterlaced = false; var idetFoundInterlaced = false;
@ -916,18 +912,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args; args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args;
} }
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true, FileName = FFMpegPath,
UseShellExecute = false, Arguments = args,
FileName = FFMpegPath, IsHidden = true,
Arguments = args, ErrorDialog = false
WindowStyle = ProcessWindowStyle.Hidden, });
ErrorDialog = false
}
};
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
@ -944,7 +937,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs; var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
if (timeoutMs <= 0) if (timeoutMs <= 0)
{ {
timeoutMs = Environment.Is64BitOperatingSystem ? (Environment.ProcessorCount > 2 ? 14000 : 20000) : 40000; timeoutMs = DefaultImageExtractionTimeoutMs;
} }
ranToCompletion = process.WaitForExit(timeoutMs); ranToCompletion = process.WaitForExit(timeoutMs);
@ -1022,19 +1015,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
args = probeSize + " " + args; args = probeSize + " " + args;
} }
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true, FileName = FFMpegPath,
UseShellExecute = false, Arguments = args,
FileName = FFMpegPath, IsHidden = true,
Arguments = args, ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden, RedirectStandardInput = true
ErrorDialog = false, });
RedirectStandardInput = true
}
};
_logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
@ -1107,7 +1097,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
LibraryManager, LibraryManager,
SessionManager, SessionManager,
SubtitleEncoder(), SubtitleEncoder(),
MediaSourceManager()) MediaSourceManager(),
_processFactory)
.Start(options, progress, cancellationToken).ConfigureAwait(false); .Start(options, progress, cancellationToken).ConfigureAwait(false);
await job.TaskCompletionSource.Task.ConfigureAwait(false); await job.TaskCompletionSource.Task.ConfigureAwait(false);
@ -1127,7 +1118,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
LibraryManager, LibraryManager,
SessionManager, SessionManager,
SubtitleEncoder(), SubtitleEncoder(),
MediaSourceManager()) MediaSourceManager(),
_processFactory)
.Start(options, progress, cancellationToken).ConfigureAwait(false); .Start(options, progress, cancellationToken).ConfigureAwait(false);
await job.TaskCompletionSource.Task.ConfigureAwait(false); await job.TaskCompletionSource.Task.ConfigureAwait(false);
@ -1231,14 +1223,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
private class ProcessWrapper : IDisposable private class ProcessWrapper : IDisposable
{ {
public readonly Process Process; public readonly IProcess Process;
public bool HasExited; public bool HasExited;
public int? ExitCode; public int? ExitCode;
private readonly MediaEncoder _mediaEncoder; private readonly MediaEncoder _mediaEncoder;
private readonly ILogger _logger; private readonly ILogger _logger;
public bool IsRedirectingStdin { get; private set; } public bool IsRedirectingStdin { get; private set; }
public ProcessWrapper(Process process, MediaEncoder mediaEncoder, ILogger logger, bool isRedirectingStdin) public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger, bool isRedirectingStdin)
{ {
Process = process; Process = process;
_mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
@ -1249,7 +1241,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
void Process_Exited(object sender, EventArgs e) void Process_Exited(object sender, EventArgs e)
{ {
var process = (Process)sender; var process = (IProcess)sender;
HasExited = true; HasExited = true;
@ -1269,7 +1261,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
DisposeProcess(process); DisposeProcess(process);
} }
private void DisposeProcess(Process process) private void DisposeProcess(IProcess process)
{ {
try try
{ {

View File

@ -8,15 +8,13 @@ using MediaBrowser.Model.Logging;
using System; using System;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO; using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.MediaEncoding.Encoder namespace MediaBrowser.MediaEncoding.Encoder
{ {
public class VideoEncoder : BaseEncoder public class VideoEncoder : BaseEncoder
{ {
public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager) public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory)
{ {
} }
@ -193,5 +191,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
get { return true; } get { return true; }
} }
} }
} }

View File

@ -9,10 +9,10 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.MediaEncoding</RootNamespace> <RootNamespace>MediaBrowser.MediaEncoding</RootNamespace>
<AssemblyName>MediaBrowser.MediaEncoding</AssemblyName> <AssemblyName>MediaBrowser.MediaEncoding</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile /> <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -37,13 +37,6 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="UniversalDetector, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="UniversalDetector, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\UniversalDetector.1.0.1\lib\portable-net45+sl4+wp71+win8+wpa81\UniversalDetector.dll</HintPath> <HintPath>..\packages\UniversalDetector.1.0.1\lib\portable-net45+sl4+wp71+win8+wpa81\UniversalDetector.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -108,7 +101,7 @@
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="EmitMSBuildWarning" BeforeTargets="Build">
<Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." />
</Target>
</Project>

View File

@ -14,6 +14,7 @@ using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Providers; using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
@ -31,14 +32,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private readonly IEncryptionManager _encryption; private readonly IEncryptionManager _encryption;
private readonly IJsonSerializer _json; private readonly IJsonSerializer _json;
private readonly IFileSystem _fileSystem;
public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient, IServerConfigurationManager config, IEncryptionManager encryption, IJsonSerializer json) public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient, IServerConfigurationManager config, IEncryptionManager encryption, IJsonSerializer json, IFileSystem fileSystem)
{ {
_logger = logManager.GetLogger(GetType().Name); _logger = logManager.GetLogger(GetType().Name);
_httpClient = httpClient; _httpClient = httpClient;
_config = config; _config = config;
_encryption = encryption; _encryption = encryption;
_json = json; _json = json;
_fileSystem = fileSystem;
_config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating; _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating;
@ -133,7 +136,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if ((DateTime.UtcNow - _lastRateLimitException).TotalHours < 1) if ((DateTime.UtcNow - _lastRateLimitException).TotalHours < 1)
{ {
throw new ApplicationException("OpenSubtitles rate limit reached"); throw new Exception("OpenSubtitles rate limit reached");
} }
var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false); var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false);
@ -141,12 +144,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if ((resultDownLoad.Status ?? string.Empty).IndexOf("407", StringComparison.OrdinalIgnoreCase) != -1) if ((resultDownLoad.Status ?? string.Empty).IndexOf("407", StringComparison.OrdinalIgnoreCase) != -1)
{ {
_lastRateLimitException = DateTime.UtcNow; _lastRateLimitException = DateTime.UtcNow;
throw new ApplicationException("OpenSubtitles rate limit reached"); throw new Exception("OpenSubtitles rate limit reached");
} }
if (!(resultDownLoad is MethodResponseSubtitleDownload)) if (!(resultDownLoad is MethodResponseSubtitleDownload))
{ {
throw new ApplicationException("Invalid response type"); throw new Exception("Invalid response type");
} }
var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results; var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results;
@ -269,11 +272,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var subLanguageId = NormalizeLanguage(request.Language); var subLanguageId = NormalizeLanguage(request.Language);
string hash; string hash;
using (var fileStream = File.OpenRead(request.MediaPath)) using (var fileStream = _fileSystem.OpenRead(request.MediaPath))
{ {
hash = Utilities.ComputeHash(fileStream); hash = Utilities.ComputeHash(fileStream);
} }
var fileInfo = new FileInfo(request.MediaPath); var fileInfo = _fileSystem.GetFileInfo(request.MediaPath);
var movieByteSize = fileInfo.Length; var movieByteSize = fileInfo.Length;
var searchImdbId = request.ContentType == VideoContentType.Movie ? imdbId.ToString(_usCulture) : ""; var searchImdbId = request.ContentType == VideoContentType.Movie ? imdbId.ToString(_usCulture) : "";
var subtitleSearchParameters = request.ContentType == VideoContentType.Episode var subtitleSearchParameters = request.ContentType == VideoContentType.Episode

View File

@ -18,9 +18,8 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Common.IO; using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Controller.IO; using MediaBrowser.Model.TextEncoding;
using MediaBrowser.Model.IO;
using UniversalDetector; using UniversalDetector;
namespace MediaBrowser.MediaEncoding.Subtitles namespace MediaBrowser.MediaEncoding.Subtitles
@ -36,8 +35,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMemoryStreamProvider _memoryStreamProvider; private readonly IMemoryStreamProvider _memoryStreamProvider;
private readonly IProcessFactory _processFactory;
private readonly IEncoding _textEncoding;
public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json, IHttpClient httpClient, IMediaSourceManager mediaSourceManager, IMemoryStreamProvider memoryStreamProvider) public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json, IHttpClient httpClient, IMediaSourceManager mediaSourceManager, IMemoryStreamProvider memoryStreamProvider, IProcessFactory processFactory, IEncoding textEncoding)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
_logger = logger; _logger = logger;
@ -48,6 +49,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_httpClient = httpClient; _httpClient = httpClient;
_mediaSourceManager = mediaSourceManager; _mediaSourceManager = mediaSourceManager;
_memoryStreamProvider = memoryStreamProvider; _memoryStreamProvider = memoryStreamProvider;
_processFactory = processFactory;
_textEncoding = textEncoding;
} }
private string SubtitleCachePath private string SubtitleCachePath
@ -418,7 +421,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// or /// or
/// outputPath /// outputPath
/// </exception> /// </exception>
/// <exception cref="System.ApplicationException"></exception>
private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(inputPath)) if (string.IsNullOrEmpty(inputPath))
@ -440,23 +442,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles
encodingParam = " -sub_charenc " + encodingParam; encodingParam = " -sub_charenc " + encodingParam;
} }
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo RedirectStandardOutput = false,
{ RedirectStandardError = true,
RedirectStandardOutput = false, RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
CreateNoWindow = true, CreateNoWindow = true,
UseShellExecute = false, UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath, FileName = _mediaEncoder.EncoderPath,
Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath), Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
WindowStyle = ProcessWindowStyle.Hidden, IsHidden = true,
ErrorDialog = false ErrorDialog = false
} });
};
_logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
@ -538,7 +537,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.Error(msg); _logger.Error(msg);
throw new ApplicationException(msg); throw new Exception(msg);
} }
await SetAssFont(outputPath).ConfigureAwait(false); await SetAssFont(outputPath).ConfigureAwait(false);
} }
@ -593,23 +592,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath, var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath,
subtitleStreamIndex, outputCodec, outputPath); subtitleStreamIndex, outputCodec, outputPath);
var process = new Process var process = _processFactory.Create(new ProcessOptions
{ {
StartInfo = new ProcessStartInfo CreateNoWindow = true,
{ UseShellExecute = false,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = false, RedirectStandardOutput = false,
RedirectStandardError = true, RedirectStandardError = true,
RedirectStandardInput = true, RedirectStandardInput = true,
FileName = _mediaEncoder.EncoderPath, FileName = _mediaEncoder.EncoderPath,
Arguments = processArgs, Arguments = processArgs,
WindowStyle = ProcessWindowStyle.Hidden, IsHidden = true,
ErrorDialog = false ErrorDialog = false
} });
};
_logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
@ -674,10 +670,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
}
catch (DirectoryNotFoundException)
{
} }
catch (IOException ex) catch (IOException ex)
{ {
@ -695,7 +687,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.Error(msg); _logger.Error(msg);
throw new ApplicationException(msg); throw new Exception(msg);
} }
else else
{ {
@ -749,20 +741,26 @@ namespace MediaBrowser.MediaEncoding.Subtitles
string text; string text;
Encoding encoding; Encoding encoding;
using (var reader = new StreamReader(file, true)) using (var fileStream = _fileSystem.OpenRead(file))
{ {
encoding = reader.CurrentEncoding; using (var reader = new StreamReader(fileStream, true))
{
encoding = reader.CurrentEncoding;
text = await reader.ReadToEndAsync().ConfigureAwait(false); text = await reader.ReadToEndAsync().ConfigureAwait(false);
}
} }
var newText = text.Replace(",Arial,", ",Arial Unicode MS,"); var newText = text.Replace(",Arial,", ",Arial Unicode MS,");
if (!string.Equals(text, newText)) if (!string.Equals(text, newText))
{ {
using (var writer = new StreamWriter(file, false, encoding)) using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
{ {
writer.Write(newText); using (var writer = new StreamWriter(fileStream, encoding))
{
writer.Write(newText);
}
} }
} }
} }
@ -795,7 +793,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{ {
if (protocol == MediaProtocol.File) if (protocol == MediaProtocol.File)
{ {
if (GetFileEncoding(path).Equals(Encoding.UTF8)) if (_textEncoding.GetFileEncoding(path).Equals(Encoding.UTF8))
{ {
return string.Empty; return string.Empty;
} }
@ -902,29 +900,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
return null; return null;
} }
private Encoding GetFileEncoding(string srcFile)
{
// *** Detect byte order mark if any - otherwise assume default
var buffer = new byte[5];
using (var file = _fileSystem.GetFileStream(srcFile, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite))
{
file.Read(buffer, 0, 5);
}
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
return Encoding.UTF8;
if (buffer[0] == 0xfe && buffer[1] == 0xff)
return Encoding.Unicode;
if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
return Encoding.UTF32;
if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
return Encoding.UTF7;
// It's ok - anything aside from utf is ok since that's what we're looking for
return Encoding.Default;
}
private async Task<Stream> GetStream(string path, MediaProtocol protocol, CancellationToken cancellationToken) private async Task<Stream> GetStream(string path, MediaProtocol protocol, CancellationToken cancellationToken)
{ {
if (protocol == MediaProtocol.Http) if (protocol == MediaProtocol.Http)

View File

@ -0,0 +1,17 @@
{
"frameworks":{
"netstandard1.6":{
"dependencies":{
"NETStandard.Library":"1.6.0",
}
},
".NETPortable,Version=v4.5,Profile=Profile7":{
"buildOptions": {
"define": [ ]
},
"frameworkAssemblies":{
}
}
}
}

View File

@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Model.Diagnostics namespace MediaBrowser.Model.Diagnostics
{ {
@ -22,6 +18,7 @@ namespace MediaBrowser.Model.Diagnostics
public bool ErrorDialog { get; set; } public bool ErrorDialog { get; set; }
public bool RedirectStandardError { get; set; } public bool RedirectStandardError { get; set; }
public bool RedirectStandardInput { get; set; } public bool RedirectStandardInput { get; set; }
public bool RedirectStandardOutput { get; set; }
public bool IsHidden { get; set; } public bool IsHidden { get; set; }
} }
} }

View File

@ -1,9 +1,12 @@
 using System.Text;
namespace MediaBrowser.Model.TextEncoding namespace MediaBrowser.Model.TextEncoding
{ {
public interface IEncoding public interface IEncoding
{ {
byte[] GetASCIIBytes(string text); byte[] GetASCIIBytes(string text);
string GetASCIIString(byte[] bytes, int startIndex, int length); string GetASCIIString(byte[] bytes, int startIndex, int length);
Encoding GetFileEncoding(string path);
} }
} }

View File

@ -70,6 +70,9 @@
<Reference Include="ServiceStack.Api.Swagger"> <Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath> <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference> </Reference>
<Reference Include="ServiceStack.Common">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Common.dll</HintPath>
</Reference>
<Reference Include="SharpCompress, Version=0.10.3.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="SharpCompress, Version=0.10.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath> <HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>

View File

@ -1,10 +1,18 @@
using System.Text; using System.Text;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.TextEncoding; using MediaBrowser.Model.TextEncoding;
namespace MediaBrowser.Server.Implementations.TextEncoding namespace MediaBrowser.Server.Implementations.TextEncoding
{ {
public class TextEncoding : IEncoding public class TextEncoding : IEncoding
{ {
private readonly IFileSystem _fileSystem;
public TextEncoding(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public byte[] GetASCIIBytes(string text) public byte[] GetASCIIBytes(string text)
{ {
return Encoding.ASCII.GetBytes(text); return Encoding.ASCII.GetBytes(text);
@ -14,5 +22,28 @@ namespace MediaBrowser.Server.Implementations.TextEncoding
{ {
return Encoding.ASCII.GetString(bytes, 0, bytes.Length); return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
} }
public Encoding GetFileEncoding(string srcFile)
{
// *** Detect byte order mark if any - otherwise assume default
var buffer = new byte[5];
using (var file = _fileSystem.OpenRead(srcFile))
{
file.Read(buffer, 0, 5);
}
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
return Encoding.UTF8;
if (buffer[0] == 0xfe && buffer[1] == 0xff)
return Encoding.Unicode;
if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
return Encoding.UTF32;
if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
return Encoding.UTF7;
// It's ok - anything aside from utf is ok since that's what we're looking for
return Encoding.Default;
}
} }
} }

View File

@ -547,7 +547,7 @@ namespace MediaBrowser.Server.Startup.Common
StringExtensions.LocalizationManager = LocalizationManager; StringExtensions.LocalizationManager = LocalizationManager;
RegisterSingleInstance(LocalizationManager); RegisterSingleInstance(LocalizationManager);
IEncoding textEncoding = new TextEncoding(); IEncoding textEncoding = new TextEncoding(FileSystemManager);
RegisterSingleInstance(textEncoding); RegisterSingleInstance(textEncoding);
Utilities.EncodingHelper = textEncoding; Utilities.EncodingHelper = textEncoding;
RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer(FileSystemManager, textEncoding)); RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer(FileSystemManager, textEncoding));
@ -697,7 +697,7 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager)); RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager)); RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager));
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamProvider); SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamProvider, ProcessFactory, textEncoding);
RegisterSingleInstance(SubtitleEncoder); RegisterSingleInstance(SubtitleEncoder);
await displayPreferencesRepo.Initialize().ConfigureAwait(false); await displayPreferencesRepo.Initialize().ConfigureAwait(false);
@ -789,7 +789,10 @@ namespace MediaBrowser.Server.Startup.Common
() => SubtitleEncoder, () => SubtitleEncoder,
() => MediaSourceManager, () => MediaSourceManager,
HttpClient, HttpClient,
ZipClient, MemoryStreamProvider); ZipClient, MemoryStreamProvider,
ProcessFactory,
Environment.Is64BitOperatingSystem ? (Environment.ProcessorCount > 2 ? 14000 : 20000) : 40000,
Environment.OSVersion.Platform == PlatformID.Win32NT);
MediaEncoder = mediaEncoder; MediaEncoder = mediaEncoder;
RegisterSingleInstance(MediaEncoder); RegisterSingleInstance(MediaEncoder);