예제 #1
0
        private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
        {
            _targetPath = targetFile;
            _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile));

            var process = _processFactory.Create(new ProcessOptions
            {
                CreateNoWindow  = true,
                UseShellExecute = false,

                // Must consume both stdout and stderr or deadlocks may occur
                //RedirectStandardOutput = true,
                RedirectStandardError = true,
                RedirectStandardInput = true,

                FileName  = _mediaEncoder.EncoderPath,
                Arguments = GetCommandLineArgs(mediaSource, inputFile, targetFile, duration),

                IsHidden            = true,
                ErrorDialog         = false,
                EnableRaisingEvents = true
            });

            _process = process;

            var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;

            _logger.LogInformation(commandLineLogMessage);

            var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt");

            _fileSystem.CreateDirectory(_fileSystem.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, 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);

            process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile);

            process.Start();

            cancellationToken.Register(Stop);

            // MUST read both stdout and stderr asynchronously or a deadlock may occurr
            //process.BeginOutputReadLine();

            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.LogInformation("ffmpeg recording process started for {0}", _targetPath);

            return(_taskCompletionSource.Task);
        }
예제 #2
0
        private bool ExecuteCommand(string cmdFilename, string cmdArguments)
        {
            bool processFailed = false;

            var process = ProcessFactory.Create(
                new ProcessOptions
            {
                CreateNoWindow         = true,
                RedirectStandardOutput = true,
                RedirectStandardError  = true,
                UseShellExecute        = false,
                FileName            = cmdFilename,
                Arguments           = cmdArguments,
                IsHidden            = true,
                ErrorDialog         = false,
                EnableRaisingEvents = true
            }
                );

            try
            {
                process.Start();

                //StreamReader outputReader = process.StandardOutput.;
                //StreamReader errorReader = process.StandardError;

                Logger.Debug(
                    "[{0}] Standard output from process is [{1}].",
                    Name,
                    process.StandardOutput.ReadToEnd()
                    );

                Logger.Debug(
                    "[{0}] Standard error from process is [{1}].",
                    Name,
                    process.StandardError.ReadToEnd()
                    );
            }
            catch (Exception ex)
            {
                processFailed = true;

                Logger.Debug(
                    "[{0}] Unhandled exception executing command, exception is [{1}].",
                    Name,
                    ex.Message
                    );
            }

            if (!processFailed && process.ExitCode == 0)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #3
0
        public void  Setup()
        {
            IProcessFactory factory = Substitute.For <IProcessFactory>();

            process   = CreateTestProbe();
            processId = Guid.NewGuid();
            factory.Create(Arg.Any <IActorRefFactory>(), Arg.Any <SupervisorStrategy>()).Returns(process);
            manager = Sys.ActorOf(Props.Create(() => new Manager(factory)));
        }
예제 #4
0
        private static IProcess Create(this IProcessFactory factory, ProcessArguments?args = null)
        {
            if (factory == null)
            {
                throw new ArgumentNullException(nameof(factory));
            }

            return(factory.Create(args));
        }
 public void ProcessSimulationForStrategies(SingleProcessSimulation simulation, List <IStrategyFactory> strategyFactories)
 {
     foreach (var strategyFactory in strategyFactories)
     {
         simulation.PageList  = _pageListPrototype.Clone();
         simulation.FrameList = _frameListPrototype.Clone();
         simulation.Process   = _processFactory.Create(strategyFactory, _pageReferencesListPrototype.Clone());
         simulation.ProcessAll();
     }
 }
        public void Execute(string program, string arguments)
        {
            var instructions = new ProcessInstructions
            {
                Program   = program,
                Arguments = arguments
            };

            if (_executor.ProcessInstance == null)
            {
                _executor.ProcessInstance = _processFactory.Create(instructions);
            }

            _executor.Execute();
        }
예제 #7
0
 public async Task Shutdown()
 {
     try
     {
         using var process = _processFactory.Create(
                   new ProcessStartInfo(_dotNetCommandPathProvider.Path, $"build-server shutdown"));
         using var error = process.Output.Concat(process.Error)
                           .Subscribe(x => _logger.Information(x));
         await process.Run().ConfigureAwait(false);
     }
     catch (Exception e)
     {
         _logger.Error(e, "Error shutting down build server");
     }
 }
예제 #8
0
        private void Ready()
        {
            Receive <StartProcessCommand>(cmd =>
            {
                logger.Info($"Creating process with Id: {cmd.Id}.");
                if (processes.ContainsKey(cmd.Id))
                {
                    logger.Error($"Process exists with Id: {cmd.Id}.");
                    return;
                }

                var process = processFactory.Create(Context, Akka.Actor.SupervisorStrategy.StoppingStrategy);
                Context.Watch(process);
                processes.Add(cmd.Id, process);
                logger.Info($"Created process with Id: {cmd.Id}.");
                process.Forward(cmd);
            });

            Receive <DomainEvent>(evnt =>
            {
                if (!processes.ContainsKey(evnt.Id))
                {
                    logger.Error($"Could not delagate event to process with Id: {evnt.Id}.");
                    return;
                }
                logger.Info($"Delegating event to process with Id: {evnt.Id}.");
                processes[evnt.Id].Tell(evnt);
            });

            Receive <Terminated>(msg =>
            {
                logger.Info("Removing process.");

                Guid key = (from actorRef in processes
                            where Equals(actorRef.Value, msg.ActorRef)
                            select actorRef.Key).DefaultIfEmpty(Guid.Empty).FirstOrDefault();

                if (key == Guid.Empty)
                {
                    logger.Warning("Could not remove process.");
                    return;
                }

                logger.Info($"Removing process with Id: {key}.");
                processes.Remove(key);
            });
        }
예제 #9
0
        public BuildResult Execute(DotnetBuildInfo info)
        {
            if (!_toolResolver.TryResolve(Tool.Dotnet, out var dotnet))
            {
                throw new InvalidOperationException($"Cannot find {Tool.Dotnet}.");
            }

            var process = _processFactory.Create(
                new ProcessInfo(
                    dotnet,
                    _workingDirectory,
                    GetArgs().Concat(info.Arguments),
                    Enumerable.Empty <EnvironmentVariable>()));

            process.Run(_processListener);
            return(_processListener.Result);
        }
예제 #10
0
        public Task StartAsync(CancellationToken cancellationToken = default)
        {
            _logger.StartInvoked(GetType());

            var process = _processFactory.Create(startInfo => {
                startInfo.FileName  = _process;
                startInfo.Arguments = string.Join(' ', _args);
            });

            _logger.ProcessCreated(process.Id);

            var result = process.Start();

            _logger.ProcessStarted(process.Id, result);

            return(Task.FromResult(result ? 0 : 1));
        }
예제 #11
0
        public void Execute(TemplatePlanContext context)
        {
            var gitProcess = _processFactory
                             .Create(p =>
            {
                p.UseShellExecute = false;
                p.FileName        = "git";
                p.Arguments       = "clone {0} {1}".ToFormat(context.Input.GitFlag, context.TempDir);
            });

            gitProcess.Start();
            gitProcess.WaitForExit();
            if (gitProcess.ExitCode != 0)
            {
                throw new FubuException(gitProcess.ExitCode, "Command finished with a non-zero exit code");
            }
        }
예제 #12
0
        public IProcess Create(ProcessInfo info)
        {
            IProcessWrapper[] wrappers;
            lock (_wrappers)
            {
                wrappers = _wrappers.Reverse().ToArray();
            }

            info = wrappers.Aggregate(info, (currentInfo, wrapper) =>
            {
                LogInfo(currentInfo, "Before wrapping");
                var result = wrapper.Wrap(currentInfo);
                LogInfo(result, "After wrapping");
                return(result);
            });

            return(_processFactory.Create(info));
        }
예제 #13
0
        private string GetProcessOutput(string path, string arguments)
        {
            IProcess process = _processFactory.Create(new ProcessOptions
            {
                CreateNoWindow         = true,
                UseShellExecute        = false,
                FileName               = path,
                Arguments              = arguments,
                IsHidden               = true,
                ErrorDialog            = false,
                RedirectStandardOutput = true,
                // ffmpeg uses stderr to log info, don't show this
                RedirectStandardError = true
            });

            _logger.LogDebug("Running {Path} {Arguments}", path, arguments);

            using (process)
            {
                process.Start();

                try
                {
                    return(process.StandardOutput.ReadToEnd());
                }
                catch
                {
                    _logger.LogWarning("Killing process {Path} {Arguments}", path, arguments);

                    // Hate having to do this
                    try
                    {
                        process.Kill();
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error killing process");
                    }

                    throw;
                }
            }
        }
예제 #14
0
파일: Locator.cs 프로젝트: DevTeam/flow
        public bool TryFind(Path path, out Path fullPath)
        {
            var processInfo = new ProcessInfo(SearchTool, _workingDirectory, new[] { new CommandLineArgument(path.Value) }, Enumerable.Empty <EnvironmentVariable>());
            var process     = _processFactory.Create(processInfo);

            if (process.Run(this).Value != 0)
            {
                throw new InvalidOperationException($"Cannot run {SearchTool}.");
            }

            if (!string.IsNullOrWhiteSpace(_firstLine))
            {
                fullPath = new Path(_firstLine);
                return(true);
            }

            fullPath = default(Path);
            return(false);
        }
예제 #15
0
        private string GetProcessOutput(string path, string arguments)
        {
            var process = _processFactory.Create(new ProcessOptions
            {
                CreateNoWindow         = true,
                UseShellExecute        = false,
                FileName               = path,
                Arguments              = arguments,
                IsHidden               = true,
                ErrorDialog            = false,
                RedirectStandardOutput = true
            });

            _logger.Info("Running {0} {1}", path, arguments);

            using (process)
            {
                process.Start();

                try
                {
                    return(process.StandardOutput.ReadToEnd());
                }
                catch
                {
                    _logger.Info("Killing process {0} {1}", path, arguments);

                    // Hate having to do this
                    try
                    {
                        process.Kill();
                    }
                    catch (Exception ex1)
                    {
                        _logger.ErrorException("Error killing process", ex1);
                    }

                    throw;
                }
            }
        }
예제 #16
0
        public void Run(TemplatePlanContext context, string rakeFile)
        {
            var tempFile = FileSystem.Combine(context.TempDir, "{0}.rb".ToFormat(Guid.NewGuid()));

            using (var runner = GetType().Assembly.GetManifestResourceStream(GetType(), "rakerunner.rb"))
            {
                using (var fileStream = File.Create(tempFile))
                {
                    runner.CopyTo(fileStream);
                    using (var writer = new StreamWriter(fileStream))
                    {
                        writer.WriteLine("FUBU_PROJECT_NAME = \"{0}\"".ToFormat(context.Input.ProjectName));
                        writer.WriteLine("Rake.application.run");
                        writer.Close();
                    }
                }
            }

            var rakeProcess = _processFactory
                              .Create(s =>
            {
                s.FileName         = "ruby";
                s.UseShellExecute  = false;
                s.WorkingDirectory = context.TargetPath;
                s.Arguments        = "{0} --rakefile {1}".ToFormat(tempFile, rakeFile);
            });

            rakeProcess.Start();
            rakeProcess.WaitForExit();

            _fileSystem.DeleteFile(tempFile);

            if (rakeProcess.ExitCode != 0)
            {
                var message = new StringBuilder()
                              .AppendLine("Command finished with a non-zero exit code")
                              .AppendLine(rakeProcess.GetErrors());
                throw new FubuException(rakeProcess.ExitCode, message.ToString());
            }
        }
예제 #17
0
        private void OnIntegrationFilesDropped(object sender, FileSystemEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(e.FullPath))
            {
                return;
            }

            try
            {
                // help prevent duplicate event calls
                _watcher.EnableRaisingEvents = false;

                IProcess process = _processFactory.Create();
                process.Execute(e.FullPath);

                _watcher.EnableRaisingEvents = true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
        }
예제 #18
0
        /// <summary>
        /// Converts the text subtitle to SRT internal.
        /// </summary>
        /// <param name="inputPath">The input path.</param>
        /// <param name="inputProtocol">The input protocol.</param>
        /// <param name="outputPath">The output path.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// inputPath
        /// or
        /// outputPath
        /// </exception>
        private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(inputPath))
            {
                throw new ArgumentNullException("inputPath");
            }

            if (string.IsNullOrEmpty(outputPath))
            {
                throw new ArgumentNullException("outputPath");
            }

            _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));

            var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false);

            if (!string.IsNullOrEmpty(encodingParam))
            {
                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),

                IsHidden    = true,
                ErrorDialog = false
            });

            _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);

            try
            {
                process.Start();
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Error starting ffmpeg", ex);

                throw;
            }

            var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);

            if (!ranToCompletion)
            {
                try
                {
                    _logger.Info("Killing ffmpeg subtitle conversion process");

                    process.Kill();
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error killing subtitle conversion process", ex);
                }
            }

            var exitCode = ranToCompletion ? process.ExitCode : -1;

            process.Dispose();

            var failed = false;

            if (exitCode == -1)
            {
                failed = true;

                if (_fileSystem.FileExists(outputPath))
                {
                    try
                    {
                        _logger.Info("Deleting converted subtitle due to failure: ", outputPath);
                        _fileSystem.DeleteFile(outputPath);
                    }
                    catch (IOException ex)
                    {
                        _logger.ErrorException("Error deleting converted subtitle {0}", ex, outputPath);
                    }
                }
            }
            else if (!_fileSystem.FileExists(outputPath))
            {
                failed = true;
            }

            if (failed)
            {
                var msg = string.Format("ffmpeg subtitle conversion failed for {0}", inputPath);

                _logger.Error(msg);

                throw new Exception(msg);
            }
            await SetAssFont(outputPath).ConfigureAwait(false);

            _logger.Info("ffmpeg subtitle conversion succeeded for {0}", inputPath);
        }
예제 #19
0
        /// <summary>
        /// Converts the text subtitle to SRT internal.
        /// </summary>
        /// <param name="inputPath">The input path.</param>
        /// <param name="inputProtocol">The input protocol.</param>
        /// <param name="outputPath">The output path.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task.</returns>
        /// <exception cref="ArgumentNullException">
        /// inputPath
        /// or
        /// outputPath
        /// </exception>
        private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(inputPath))
            {
                throw new ArgumentNullException(nameof(inputPath));
            }

            if (string.IsNullOrEmpty(outputPath))
            {
                throw new ArgumentNullException(nameof(outputPath));
            }

            Directory.CreateDirectory(Path.GetDirectoryName(outputPath));

            var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false);

            // FFmpeg automatically convert character encoding when it is UTF-16
            // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event"
            if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && (encodingParam == "UTF-16BE" || encodingParam == "UTF-16LE"))
            {
                encodingParam = "";
            }
            else if (!string.IsNullOrEmpty(encodingParam))
            {
                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");

                throw;
            }

            var ranToCompletion = await process.WaitForExitAsync(300000).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");
                }
            }

            var exitCode = ranToCompletion ? process.ExitCode : -1;

            process.Dispose();

            var failed = false;

            if (exitCode == -1)
            {
                failed = true;

                if (File.Exists(outputPath))
                {
                    try
                    {
                        _logger.LogInformation("Deleting converted subtitle due to failure: ", outputPath);
                        _fileSystem.DeleteFile(outputPath);
                    }
                    catch (IOException ex)
                    {
                        _logger.LogError(ex, "Error deleting converted subtitle {Path}", outputPath);
                    }
                }
            }
            else if (!File.Exists(outputPath))
            {
                failed = true;
            }

            if (failed)
            {
                _logger.LogError("ffmpeg subtitle conversion failed for {Path}", inputPath);

                throw new Exception(
                          string.Format(CultureInfo.InvariantCulture, "ffmpeg subtitle conversion failed for {0}", inputPath));
            }

            await SetAssFont(outputPath).ConfigureAwait(false);

            _logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath);
        }
예제 #20
0
        /// <summary>
        /// Runs specified process with specified arguments.
        /// </summary>
        /// <param name="fileName">The process to start.</param>
        /// <param name="arguments">The set of arguments to use when starting the process.</param>
        /// <returns>The process completion status.</returns>
        /// <exception cref="System.IO.FileNotFoundException">Occurs when the file to run is not found.</exception>
        /// <exception cref="InvalidOperationException">Occurs when this class instance is already running another process.</exception>
        public virtual CompletionStatus Run(string fileName, string arguments)
        {
            fileName.CheckNotNullOrEmpty(nameof(fileName));

            IProcess p;

            lock (LockToken)
            {
                if (WorkProcess != null)
                {
                    throw new InvalidOperationException(Resources.ProcessWorkerBusy);
                }
                p           = _factory.Create();
                WorkProcess = p;
            }
            _output.Clear();
            _cancelWork = new CancellationTokenSource();
            if (Options == null)
            {
                Options = new ProcessOptions();
            }

            p.StartInfo.FileName  = fileName;
            p.StartInfo.Arguments = arguments;
            CommandWithArgs       = $@"""{fileName}"" {arguments}".TrimEnd();

            if (OutputType == ProcessOutput.Output)
            {
                p.OutputDataReceived += OnDataReceived;
            }
            else if (OutputType == ProcessOutput.Error)
            {
                p.ErrorDataReceived += OnDataReceived;
            }

            if (Options.DisplayMode != ProcessDisplayMode.Native)
            {
                //if (Options.DisplayMode == ProcessDisplayMode.Interface && Config.UserInterfaceManager != null)
                //{
                //    Config.UserInterfaceManager.Display(Owner, this);
                //}

                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.WindowStyle    = ProcessWindowStyle.Hidden;
                if (OutputType == ProcessOutput.Output)
                {
                    p.StartInfo.RedirectStandardOutput = true;
                }
                else if (OutputType == ProcessOutput.Error)
                {
                    p.StartInfo.RedirectStandardError = true;
                }

                p.StartInfo.UseShellExecute = false;
            }

            ProcessStarted?.Invoke(this, new ProcessStartedEventArgs(this));

            p.Start();
            try
            {
                if (!p.HasExited)
                {
                    p.PriorityClass = Options.Priority;
                }
            }
            catch (System.ComponentModel.Win32Exception) { }
            catch (InvalidOperationException) { }

            if (Options.DisplayMode != ProcessDisplayMode.Native)
            {
                if (OutputType == ProcessOutput.Output)
                {
                    p.BeginOutputReadLine();
                }
                else if (OutputType == ProcessOutput.Error)
                {
                    p.BeginErrorReadLine();
                }
            }

            var timeout = Wait();

            // ExitCode is 0 for normal exit. Different value when closing the console.
            var result = timeout ? CompletionStatus.Timeout : _cancelWork.IsCancellationRequested ? CompletionStatus.Cancelled : p.ExitCode == 0 ? CompletionStatus.Success : CompletionStatus.Failed;

            _cancelWork = null;
            // Allow changing CompletionStatus in ProcessCompleted.
            var completedArgs = new ProcessCompletedEventArgs(result);

            ProcessCompleted?.Invoke(this, completedArgs);
            result = completedArgs.Status;
            LastCompletionStatus = result;
            //if ((result == CompletionStatus.Failed || result == CompletionStatus.Timeout) && Options.DisplayMode == ProcessDisplayMode.ErrorOnly)
            //{
            //    Config.UserInterfaceManager?.DisplayError(Owner, this);
            //}

            WorkProcess = null;
            return(result);
        }
예제 #21
0
        public async Task <EncodingJob> Start(EncodingJobOptions options,
                                              IProgress <double> progress,
                                              CancellationToken cancellationToken)
        {
            var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager, ConfigurationManager, MediaEncoder)
                              .CreateJob(options, EncodingHelper, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);

            encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
            FileSystem.CreateDirectory(FileSystem.GetDirectoryName(encodingJob.OutputFilePath));

            encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate;

            await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false);

            var commandLineArgs = GetCommandLineArguments(encodingJob);

            var process = ProcessFactory.Create(new ProcessOptions
            {
                CreateNoWindow  = true,
                UseShellExecute = false,

                // Must consume both stdout and stderr or deadlocks may occur
                //RedirectStandardOutput = true,
                RedirectStandardError = true,
                RedirectStandardInput = true,

                FileName  = MediaEncoder.EncoderPath,
                Arguments = commandLineArgs,

                IsHidden            = true,
                ErrorDialog         = false,
                EnableRaisingEvents = true
            });

            var workingDirectory = GetWorkingDirectory(options);

            if (!string.IsNullOrWhiteSpace(workingDirectory))
            {
                process.StartInfo.WorkingDirectory = workingDirectory;
            }

            OnTranscodeBeginning(encodingJob);

            var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;

            Logger.LogInformation(commandLineLogMessage);

            var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt");

            FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath));

            // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
            encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true);

            var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine);
            await encodingJob.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationToken).ConfigureAwait(false);

            process.Exited += (sender, args) => OnFfMpegProcessExited(process, encodingJob);

            try
            {
                process.Start();
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Error starting ffmpeg");

                OnTranscodeFailedToStart(encodingJob.OutputFilePath, encodingJob);

                throw;
            }

            cancellationToken.Register(() => Cancel(process, encodingJob));

            // MUST read both stdout and stderr asynchronously or a deadlock may occurr
            //process.BeginOutputReadLine();

            // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
            new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream);

            // Wait for the file to exist before proceeeding
            while (!FileSystem.FileExists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
            {
                await Task.Delay(100, cancellationToken).ConfigureAwait(false);
            }

            return(encodingJob);
        }
예제 #22
0
        /// <summary>
        /// Runs specified application with specified arguments.
        /// </summary>
        /// <param name="fileName">The application to start.</param>
        /// <param name="arguments">The set of arguments to use when starting the application.</param>
        /// <returns>The process completion status.</returns>
        /// <exception cref="System.IO.FileNotFoundException">Occurs when the file to run is not found.</exception>
        /// <exception cref="InvalidOperationException">Occurs when this class instance is already running another process.</exception>
        public virtual CompletionStatus Run(string fileName, string arguments)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("Filename cannot be null or empty.", nameof(fileName));
            }
            if (!fileSystem.Exists(fileName))
            {
                throw new System.IO.FileNotFoundException(string.Format(@"File ""{0}"" is not found.", fileName));
            }
            IProcess P;

            lock (lockToken) {
                if (WorkProcess != null)
                {
                    throw new InvalidOperationException("This instance of FFmpegProcess is busy. You can run concurrent commands by creating other class instances.");
                }
                P           = factory.Create();
                WorkProcess = P;
            }
            output.Clear();
            cancelWork = new CancellationTokenSource();
            if (Options == null)
            {
                Options = new ProcessOptions();
            }

            P.StartInfo.FileName  = fileName;
            P.StartInfo.Arguments = arguments;
            CommandWithArgs       = string.Format(@"""{0}"" {1}", fileName, arguments).TrimEnd();

            if (OutputType == ProcessOutput.Output)
            {
                P.OutputDataReceived += OnDataReceived;
            }
            else if (OutputType == ProcessOutput.Error)
            {
                P.ErrorDataReceived += OnDataReceived;
            }

            if (Options.DisplayMode != FFmpegDisplayMode.Native)
            {
                if (Options.DisplayMode == FFmpegDisplayMode.Interface && Config.UserInterfaceManager != null)
                {
                    Config.UserInterfaceManager.Display(this);
                }
                P.StartInfo.CreateNoWindow = true;
                P.StartInfo.WindowStyle    = ProcessWindowStyle.Hidden;
                if (OutputType == ProcessOutput.Output)
                {
                    P.StartInfo.RedirectStandardOutput = true;
                }
                else if (OutputType == ProcessOutput.Error)
                {
                    P.StartInfo.RedirectStandardError = true;
                }
                P.StartInfo.UseShellExecute = false;
            }

            ProcessStarted?.Invoke(this, new ProcessStartedEventArgs(this));

            P.Start();
            try {
                if (!P.HasExited)
                {
                    P.PriorityClass = Options.Priority;
                }
            } catch { }
            if (Options.DisplayMode != FFmpegDisplayMode.Native)
            {
                if (OutputType == ProcessOutput.Output)
                {
                    P.BeginOutputReadLine();
                }
                else if (OutputType == ProcessOutput.Error)
                {
                    P.BeginErrorReadLine();
                }
            }

            bool Timeout = Wait();

            // ExitCode is 0 for normal exit. Different value when closing the console.
            CompletionStatus Result = Timeout ? CompletionStatus.Timeout : cancelWork.IsCancellationRequested ? CompletionStatus.Cancelled : P.ExitCode == 0 ? CompletionStatus.Success : CompletionStatus.Failed;

            cancelWork           = null;
            LastCompletionStatus = Result;
            ProcessCompleted?.Invoke(this, new ProcessCompletedEventArgs(Result));
            if ((Result == CompletionStatus.Failed || Result == CompletionStatus.Timeout) && Options.DisplayMode == FFmpegDisplayMode.ErrorOnly)
            {
                Config.UserInterfaceManager?.DisplayError(this);
            }

            WorkProcess = null;
            return(Result);
        }