diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-11-29 14:13:20 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-11-29 14:13:20 -0500 |
| commit | c30b82ab44401cf86f6723834d8d5b1ea8aac66c (patch) | |
| tree | db57790754327657d88dfac23884842bf56ed531 | |
| parent | c80ac9b823d4f128c232d4a69e051af1fd4ea3f4 (diff) | |
update recording encoder
6 files changed, 88 insertions, 73 deletions
diff --git a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs index ebd596dc4..6cc4626ea 100644 --- a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs +++ b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs @@ -110,5 +110,10 @@ namespace Emby.Common.Implementations.EnvironmentInfo { get { return Environment.StackTrace; } } + + public void SetProcessEnvironmentVariable(string name, string value) + { + Environment.SetEnvironmentVariable(name, value); + } } } diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 90848d930..f7fe02fba 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -789,7 +789,8 @@ namespace Emby.Server.Core MemoryStreamFactory, ProcessFactory, (Environment.ProcessorCount > 2 ? 14000 : 40000), - EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows); + EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows, + EnvironmentInfo); MediaEncoder = mediaEncoder; RegisterSingleInstance(MediaEncoder); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 5e55b893f..5bb65b650 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -31,7 +31,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly IServerApplicationPaths _appPaths; private readonly LiveTvOptions _liveTvOptions; private bool _hasExited; - private Stream _logFileStream; private string _targetPath; private IProcess _process; private readonly IProcessFactory _processFactory; @@ -85,22 +84,26 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _targetPath = targetFile; _fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile)); + var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid().ToString("N") + ".txt"); + _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, - UseShellExecute = false, + UseShellExecute = true, // Must consume both stdout and stderr or deadlocks may occur //RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, + RedirectStandardError = false, + RedirectStandardInput = false, FileName = _mediaEncoder.EncoderPath, Arguments = GetCommandLineArgs(mediaSource, inputFile, targetFile, duration), IsHidden = true, ErrorDialog = false, - EnableRaisingEvents = true + EnableRaisingEvents = true, + WorkingDirectory = Path.GetDirectoryName(logFilePath) }); _process = process; @@ -108,14 +111,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; _logger.Info(commandLineLogMessage); - var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + _mediaEncoder.SetLogFilename(Path.GetFileName(logFilePath)); - // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); - - var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); - _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length); + //var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile); @@ -128,10 +126,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV onStarted(); - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - StartStreamingLog(process.StandardError.BaseStream, _logFileStream); - _logger.Info("ffmpeg recording process started for {0}", _targetPath); + _mediaEncoder.ClearLogFilename(); return _taskCompletionSource.Task; } @@ -154,7 +150,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks); var inputModifiers = "-fflags +genpts -async 1 -vsync -1"; - var commandLineArgs = "-i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\""; + var commandLineArgs = "-i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -loglevel info -y \"{1}\""; long startTimeTicks = 0; //if (mediaSource.DateLiveStreamOpened.HasValue) @@ -234,16 +230,19 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return output; } + private bool _isCancelled; private void Stop() { if (!_hasExited) { try { + _isCancelled = true; + _logger.Info("Killing ffmpeg recording process for {0}", _targetPath); - //process.Kill(); - _process.StandardInput.WriteLine("q"); + _process.Kill(); + //_process.StandardInput.WriteLine("q"); } catch (Exception ex) { @@ -259,11 +258,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { _hasExited = true; - DisposeLogStream(); - try { - var exitCode = process.ExitCode; + var exitCode = _isCancelled ? 0 : process.ExitCode; _logger.Info("FFMpeg recording exited with code {0} for {1}", exitCode, _targetPath); @@ -282,49 +279,5 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _taskCompletionSource.TrySetException(new Exception(string.Format("Recording for {0} failed", _targetPath))); } } - - private void DisposeLogStream() - { - if (_logFileStream != null) - { - try - { - _logFileStream.Dispose(); - } - catch (Exception ex) - { - _logger.ErrorException("Error disposing recording log stream", ex); - } - - _logFileStream = null; - } - } - - private async void 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 recording log", ex); - } - } } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 866a08aa1..45aaa8e8e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -135,5 +135,8 @@ namespace MediaBrowser.Controller.MediaEncoding Task UpdateEncoderPath(string path, string pathType); bool SupportsEncoder(string encoder); bool IsDefaultEncoderPath { get; } + + void SetLogFilename(string name); + void ClearLogFilename(); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 719083e73..a8ab1a4c0 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -24,6 +24,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Model.Diagnostics; +using MediaBrowser.Model.System; namespace MediaBrowser.MediaEncoding.Encoder { @@ -88,9 +89,11 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly int DefaultImageExtractionTimeoutMs; private readonly bool EnableEncoderFontFile; + private readonly IEnvironmentInfo _environmentInfo; + 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, IMemoryStreamFactory memoryStreamProvider, IProcessFactory processFactory, int defaultImageExtractionTimeoutMs, - bool enableEncoderFontFile) + bool enableEncoderFontFile, IEnvironmentInfo environmentInfo) { _logger = logger; _jsonSerializer = jsonSerializer; @@ -109,12 +112,66 @@ namespace MediaBrowser.MediaEncoding.Encoder _processFactory = processFactory; DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs; EnableEncoderFontFile = enableEncoderFontFile; + _environmentInfo = environmentInfo; FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; _originalFFProbePath = ffProbePath; _originalFFMpegPath = ffMpegPath; _hasExternalEncoder = hasExternalEncoder; + + SetEnvironmentVariable(); + } + + private readonly object _logLock = new object(); + public void SetLogFilename(string name) + { + lock (_logLock) + { + try + { + _environmentInfo.SetProcessEnvironmentVariable("FFREPORT", "file=" + name + ":level=32"); + } + catch (Exception ex) + { + _logger.ErrorException("Error setting FFREPORT environment variable", ex); + } + } + } + + public void ClearLogFilename() + { + lock (_logLock) + { + try + { + _environmentInfo.SetProcessEnvironmentVariable("FFREPORT", null); + } + catch (Exception ex) + { + //_logger.ErrorException("Error setting FFREPORT environment variable", ex); + } + } + } + + private void SetEnvironmentVariable() + { + try + { + //_environmentInfo.SetProcessEnvironmentVariable("FFREPORT", "file=program-YYYYMMDD-HHMMSS.txt:level=32"); + } + catch (Exception ex) + { + _logger.ErrorException("Error setting FFREPORT environment variable", ex); + } + try + { + //_environmentInfo.SetUserEnvironmentVariable("FFREPORT", "file=program-YYYYMMDD-HHMMSS.txt:level=32"); + } + catch (Exception ex) + { + _logger.ErrorException("Error setting FFREPORT environment variable", ex); + } } public string EncoderLocationType diff --git a/MediaBrowser.Model/System/IEnvironmentInfo.cs b/MediaBrowser.Model/System/IEnvironmentInfo.cs index f9795a568..abe39fa03 100644 --- a/MediaBrowser.Model/System/IEnvironmentInfo.cs +++ b/MediaBrowser.Model/System/IEnvironmentInfo.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - + namespace MediaBrowser.Model.System { public interface IEnvironmentInfo @@ -13,6 +8,7 @@ namespace MediaBrowser.Model.System string OperatingSystemVersion { get; } Architecture SystemArchitecture { get; } string GetEnvironmentVariable(string name); + void SetProcessEnvironmentVariable(string name, string value); string GetUserId(); string StackTrace { get; } } |
