123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- using MediaBrowser.Common.Configuration;
- using MediaBrowser.Common.IO;
- using MediaBrowser.Controller.LiveTv;
- using MediaBrowser.Model.Entities;
- using MediaBrowser.Model.IO;
- using MediaBrowser.Model.Logging;
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Threading;
- using System.Threading.Tasks;
- namespace MediaBrowser.MediaEncoding.Encoder
- {
- public class FFMpegProcess : IDisposable
- {
- private readonly string _ffmpegPath;
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly IApplicationPaths _appPaths;
- private readonly IIsoManager _isoManager;
- private readonly ILiveTvManager _liveTvManager;
- private Stream _logFileStream;
- private InternalEncodingTask _task;
- private IIsoMount _isoMount;
- public FFMpegProcess(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths, IIsoManager isoManager, ILiveTvManager liveTvManager)
- {
- _ffmpegPath = ffmpegPath;
- _logger = logger;
- _fileSystem = fileSystem;
- _appPaths = appPaths;
- _isoManager = isoManager;
- _liveTvManager = liveTvManager;
- }
- public async Task Start(InternalEncodingTask task, Func<InternalEncodingTask,string,string> argumentsFactory)
- {
- _task = task;
- if (!File.Exists(_ffmpegPath))
- {
- throw new InvalidOperationException("ffmpeg was not found at " + _ffmpegPath);
- }
- Directory.CreateDirectory(Path.GetDirectoryName(task.Request.OutputPath));
- string mountedPath = null;
- if (task.InputVideoType.HasValue && task.InputVideoType == VideoType.Iso && task.IsoType.HasValue)
- {
- if (_isoManager.CanMount(task.MediaPath))
- {
- _isoMount = await _isoManager.Mount(task.MediaPath, CancellationToken.None).ConfigureAwait(false);
- mountedPath = _isoMount.MountedPath;
- }
- }
-
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- // Must consume both stdout and stderr or deadlocks may occur
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- FileName = _ffmpegPath,
- WorkingDirectory = Path.GetDirectoryName(_ffmpegPath),
- Arguments = argumentsFactory(task, mountedPath),
- WindowStyle = ProcessWindowStyle.Hidden,
- ErrorDialog = false
- },
- EnableRaisingEvents = true
- };
- _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
- var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-" + task.Id + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(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, FileMode.Create, FileAccess.Write, FileShare.Read, true);
- process.Exited += process_Exited;
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error starting ffmpeg", ex);
- task.OnError();
- DisposeLogFileStream();
- process.Dispose();
- throw;
- }
- task.OnBegin();
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- process.BeginOutputReadLine();
- #pragma warning disable 4014
- // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- process.StandardError.BaseStream.CopyToAsync(_logFileStream);
- #pragma warning restore 4014
- }
- async void process_Exited(object sender, EventArgs e)
- {
- var process = (Process)sender;
- if (_isoMount != null)
- {
- _isoMount.Dispose();
- _isoMount = null;
- }
- DisposeLogFileStream();
- try
- {
- _logger.Info("FFMpeg exited with code {0} for {1}", process.ExitCode, _task.Request.OutputPath);
- }
- catch
- {
- _logger.Info("FFMpeg exited with an error for {0}", _task.Request.OutputPath);
- }
- _task.OnCompleted();
-
- if (!string.IsNullOrEmpty(_task.LiveTvStreamId))
- {
- try
- {
- await _liveTvManager.CloseLiveStream(_task.LiveTvStreamId, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing live tv stream", ex);
- }
- }
- }
- public void Dispose()
- {
- DisposeLogFileStream();
- }
- private void DisposeLogFileStream()
- {
- if (_logFileStream != null)
- {
- _logFileStream.Dispose();
- _logFileStream = null;
- }
- }
- }
- }
|