update image & subtitle extraction

This commit is contained in:
Luke Pulverenti 2016-11-14 01:44:21 -05:00
parent ceaf0e2098
commit 9b5a4c22e3
8 changed files with 97 additions and 151 deletions

View File

@ -59,6 +59,7 @@
<Compile Include="EntryPoints\RecordingNotifier.cs" /> <Compile Include="EntryPoints\RecordingNotifier.cs" />
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" /> <Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
<Compile Include="EntryPoints\ServerEventNotifier.cs" /> <Compile Include="EntryPoints\ServerEventNotifier.cs" />
<Compile Include="EntryPoints\SystemEvents.cs" />
<Compile Include="EntryPoints\UdpServerEntryPoint.cs" /> <Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
<Compile Include="EntryPoints\UsageEntryPoint.cs" /> <Compile Include="EntryPoints\UsageEntryPoint.cs" />
<Compile Include="EntryPoints\UsageReporter.cs" /> <Compile Include="EntryPoints\UsageReporter.cs" />

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.System;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Common;
namespace Emby.Server.Implementations.EntryPoints
{
public class SystemEvents : IServerEntryPoint
{
private readonly ISystemEvents _systemEvents;
private readonly IApplicationHost _appHost;
public SystemEvents(ISystemEvents systemEvents, IApplicationHost appHost)
{
_systemEvents = systemEvents;
_appHost = appHost;
}
public void Run()
{
_systemEvents.SessionLogoff += _systemEvents_SessionLogoff;
_systemEvents.SystemShutdown += _systemEvents_SystemShutdown;
}
private void _systemEvents_SessionLogoff(object sender, EventArgs e)
{
if (!_appHost.IsRunningAsService)
{
_appHost.Shutdown();
}
}
private void _systemEvents_SystemShutdown(object sender, EventArgs e)
{
_appHost.Shutdown();
}
public void Dispose()
{
_systemEvents.SystemShutdown -= _systemEvents_SystemShutdown;
}
}
}

View File

@ -542,8 +542,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
// 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,
RedirectStandardInput = false,
FileName = FFProbePath, FileName = FFProbePath,
Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(), Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(),
@ -554,7 +552,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
using (var processWrapper = new ProcessWrapper(process, this, _logger, false)) using (var processWrapper = new ProcessWrapper(process, this, _logger))
{ {
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
@ -616,7 +614,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
catch catch
{ {
StopProcess(processWrapper, 100, true); StopProcess(processWrapper, 100);
throw; throw;
} }
@ -671,9 +669,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
UseShellExecute = false, 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,
RedirectStandardError = true, RedirectStandardError = true,
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(),
@ -685,7 +681,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_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;
using (var processWrapper = new ProcessWrapper(process, this, _logger, false)) using (var processWrapper = new ProcessWrapper(process, this, _logger))
{ {
try try
{ {
@ -728,7 +724,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
catch catch
{ {
StopProcess(processWrapper, 100, true); StopProcess(processWrapper, 100);
throw; throw;
} }
@ -945,7 +941,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
using (var processWrapper = new ProcessWrapper(process, this, _logger, false)) using (var processWrapper = new ProcessWrapper(process, this, _logger))
{ {
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
@ -965,7 +961,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!ranToCompletion) if (!ranToCompletion)
{ {
StopProcess(processWrapper, 1000, false); StopProcess(processWrapper, 1000);
} }
} }
@ -1043,8 +1039,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
FileName = FFMpegPath, FileName = FFMpegPath,
Arguments = args, Arguments = args,
IsHidden = true, IsHidden = true,
ErrorDialog = false, ErrorDialog = false
RedirectStandardInput = true
}); });
_logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
@ -1053,7 +1048,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
bool ranToCompletion = false; bool ranToCompletion = false;
using (var processWrapper = new ProcessWrapper(process, this, _logger, true)) using (var processWrapper = new ProcessWrapper(process, this, _logger))
{ {
try try
{ {
@ -1085,7 +1080,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!ranToCompletion) if (!ranToCompletion)
{ {
StopProcess(processWrapper, 1000, false); StopProcess(processWrapper, 1000);
} }
} }
finally finally
@ -1157,40 +1152,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
_runningProcesses.Add(process); _runningProcesses.Add(process);
} }
} }
private void StopProcess(ProcessWrapper process, int waitTimeMs, bool enableForceKill) private void StopProcess(ProcessWrapper process, int waitTimeMs)
{ {
try
{
if (process.Process.WaitForExit(waitTimeMs))
{
return;
}
}
catch (Exception ex)
{
_logger.Error("Error in WaitForExit", ex);
}
try try
{ {
_logger.Info("Killing ffmpeg process"); _logger.Info("Killing ffmpeg process");
if (process.IsRedirectingStdin) process.Process.Kill();
{
try
{
process.Process.StandardInput.WriteLine("q");
}
catch (Exception)
{
_logger.Error("Error sending q command to process");
}
}
try
{
if (process.Process.WaitForExit(waitTimeMs))
{
return;
}
}
catch (Exception ex)
{
_logger.Error("Error in WaitForExit", ex);
}
if (enableForceKill)
{
process.Process.Kill();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1211,7 +1191,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
if (!process.HasExited) if (!process.HasExited)
{ {
StopProcess(process, 500, true); StopProcess(process, 500);
} }
} }
} }
@ -1252,15 +1232,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
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 ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger, bool isRedirectingStdin) public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger)
{ {
Process = process; Process = process;
_mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
_logger = logger; _logger = logger;
Process.Exited += Process_Exited; Process.Exited += Process_Exited;
IsRedirectingStdin = isRedirectingStdin;
} }
void Process_Exited(object sender, EventArgs e) void Process_Exited(object sender, EventArgs e)

View File

@ -444,10 +444,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var process = _processFactory.Create(new ProcessOptions var process = _processFactory.Create(new ProcessOptions
{ {
RedirectStandardOutput = false,
RedirectStandardError = true,
RedirectStandardInput = true,
CreateNoWindow = true, CreateNoWindow = true,
UseShellExecute = false, UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath, FileName = _mediaEncoder.EncoderPath,
@ -459,26 +455,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _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));
var logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read,
true);
try try
{ {
process.Start(); process.Start();
} }
catch (Exception ex) catch (Exception ex)
{ {
logFileStream.Dispose();
_logger.ErrorException("Error starting ffmpeg", ex); _logger.ErrorException("Error starting ffmpeg", ex);
throw; throw;
} }
var logTask = process.StandardError.BaseStream.CopyToAsync(logFileStream);
var ranToCompletion = process.WaitForExit(60000); var ranToCompletion = process.WaitForExit(60000);
@ -488,19 +474,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{ {
_logger.Info("Killing ffmpeg subtitle conversion process"); _logger.Info("Killing ffmpeg subtitle conversion process");
process.StandardInput.WriteLine("q"); process.Kill();
process.WaitForExit(1000);
await logTask.ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.ErrorException("Error killing subtitle conversion process", ex); _logger.ErrorException("Error killing subtitle conversion process", ex);
} }
finally
{
logFileStream.Dispose();
}
} }
var exitCode = ranToCompletion ? process.ExitCode : -1; var exitCode = ranToCompletion ? process.ExitCode : -1;
@ -533,13 +512,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (failed) if (failed)
{ {
var msg = string.Format("ffmpeg subtitle converted failed for {0}", inputPath); var msg = string.Format("ffmpeg subtitle conversion failed for {0}", inputPath);
_logger.Error(msg); _logger.Error(msg);
throw new Exception(msg); throw new Exception(msg);
} }
await SetAssFont(outputPath).ConfigureAwait(false); await SetAssFont(outputPath).ConfigureAwait(false);
_logger.Info("ffmpeg subtitle conversion succeeded for {0}", inputPath);
} }
/// <summary> /// <summary>
@ -597,10 +578,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
CreateNoWindow = true, CreateNoWindow = true,
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = true,
RedirectStandardInput = true,
FileName = _mediaEncoder.EncoderPath, FileName = _mediaEncoder.EncoderPath,
Arguments = processArgs, Arguments = processArgs,
IsHidden = true, IsHidden = true,
@ -609,28 +586,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); _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));
var logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read,
true);
try try
{ {
process.Start(); process.Start();
} }
catch (Exception ex) catch (Exception ex)
{ {
logFileStream.Dispose();
_logger.ErrorException("Error starting ffmpeg", ex); _logger.ErrorException("Error starting ffmpeg", ex);
throw; throw;
} }
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
Task.Run(() => StartStreamingLog(process.StandardError.BaseStream, logFileStream));
var ranToCompletion = process.WaitForExit(300000); var ranToCompletion = process.WaitForExit(300000);
if (!ranToCompletion) if (!ranToCompletion)
@ -639,17 +605,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{ {
_logger.Info("Killing ffmpeg subtitle extraction process"); _logger.Info("Killing ffmpeg subtitle extraction process");
process.StandardInput.WriteLine("q"); process.Kill();
process.WaitForExit(1000);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.ErrorException("Error killing subtitle extraction process", ex); _logger.ErrorException("Error killing subtitle extraction process", ex);
} }
finally
{
logFileStream.Dispose();
}
} }
var exitCode = ranToCompletion ? process.ExitCode : -1; var exitCode = ranToCompletion ? process.ExitCode : -1;
@ -702,33 +663,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
} }
} }
private async Task StartStreamingLog(Stream source, Stream target)
{
try
{
using (var reader = new StreamReader(source))
{
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync().ConfigureAwait(false);
var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
await target.FlushAsync().ConfigureAwait(false);
}
}
}
catch (ObjectDisposedException)
{
// Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
}
catch (Exception ex)
{
_logger.ErrorException("Error reading ffmpeg log", ex);
}
}
/// <summary> /// <summary>
/// Sets the ass font. /// Sets the ass font.
/// </summary> /// </summary>

View File

@ -6,5 +6,7 @@ namespace MediaBrowser.Model.System
{ {
event EventHandler Resume; event EventHandler Resume;
event EventHandler Suspend; event EventHandler Suspend;
event EventHandler SessionLogoff;
event EventHandler SystemShutdown;
} }
} }

View File

@ -1,8 +1,6 @@
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations;
using MediaBrowser.Server.Mono.Native; using MediaBrowser.Server.Mono.Native;
using MediaBrowser.Server.Startup.Common; using MediaBrowser.Server.Startup.Common;
using Microsoft.Win32;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
@ -14,7 +12,6 @@ using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Common.Implementations.EnvironmentInfo; using Emby.Common.Implementations.EnvironmentInfo;
using Emby.Common.Implementations.IO;
using Emby.Common.Implementations.Logging; using Emby.Common.Implementations.Logging;
using Emby.Common.Implementations.Networking; using Emby.Common.Implementations.Networking;
using Emby.Common.Implementations.Security; using Emby.Common.Implementations.Security;
@ -84,8 +81,6 @@ namespace MediaBrowser.Server.Mono
private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options) private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options)
{ {
Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding;
// Allow all https requests // Allow all https requests
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
@ -108,7 +103,7 @@ namespace MediaBrowser.Server.Mono
new MemoryStreamProvider(), new MemoryStreamProvider(),
new NetworkManager(logManager.GetLogger("NetworkManager")), new NetworkManager(logManager.GetLogger("NetworkManager")),
GenerateCertificate, GenerateCertificate,
() => Environment.UserDomainName); () => Environment.UserName);
if (options.ContainsOption("-v")) if (options.ContainsOption("-v"))
{ {
@ -219,19 +214,6 @@ namespace MediaBrowser.Server.Mono
public string machine = string.Empty; public string machine = string.Empty;
} }
/// <summary>
/// Handles the SessionEnding event of the SystemEvents control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SessionEndingEventArgs"/> instance containing the event data.</param>
static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
if (e.Reason == SessionEndReasons.SystemShutdown)
{
Shutdown();
}
}
/// <summary> /// <summary>
/// Handles the UnhandledException event of the CurrentDomain control. /// Handles the UnhandledException event of the CurrentDomain control.
/// </summary> /// </summary>

View File

@ -9,6 +9,8 @@ namespace MediaBrowser.Server.Startup.Common
{ {
public event EventHandler Resume; public event EventHandler Resume;
public event EventHandler Suspend; public event EventHandler Suspend;
public event EventHandler SessionLogoff;
public event EventHandler SystemShutdown;
private readonly ILogger _logger; private readonly ILogger _logger;
@ -16,6 +18,20 @@ namespace MediaBrowser.Server.Startup.Common
{ {
_logger = logger; _logger = logger;
Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding;
}
private void SystemEvents_SessionEnding(object sender, Microsoft.Win32.SessionEndingEventArgs e)
{
switch (e.Reason)
{
case Microsoft.Win32.SessionEndReasons.Logoff:
EventHelper.FireEventIfNotNull(SessionLogoff, this, EventArgs.Empty, _logger);
break;
case Microsoft.Win32.SessionEndReasons.SystemShutdown:
EventHelper.FireEventIfNotNull(SystemShutdown, this, EventArgs.Empty, _logger);
break;
}
} }
private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e) private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e)

View File

@ -368,7 +368,6 @@ namespace MediaBrowser.ServerApplication
task = InstallVcredist2013IfNeeded(_appHost, _logger); task = InstallVcredist2013IfNeeded(_appHost, _logger);
Task.WaitAll(task); Task.WaitAll(task);
Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding;
Microsoft.Win32.SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; Microsoft.Win32.SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
HideSplashScreen(); HideSplashScreen();
@ -569,19 +568,6 @@ namespace MediaBrowser.ServerApplication
} }
} }
/// <summary>
/// Handles the SessionEnding event of the SystemEvents control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SessionEndingEventArgs"/> instance containing the event data.</param>
static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
if (e.Reason == SessionEndReasons.SystemShutdown || !IsRunningAsService)
{
Shutdown();
}
}
/// <summary> /// <summary>
/// Handles the UnhandledException event of the CurrentDomain control. /// Handles the UnhandledException event of the CurrentDomain control.
/// </summary> /// </summary>