require 'streamio-ffmpeg' require 'os' require_relative 'recorder_errors' require_relative 'recorder_options' require_relative 'recording_regions' module FFMPEG # @since 1.0.0-beta class ScreenRecorder attr_reader :options, :video def initialize(options = {}) @options = RecorderOptions.new(options) @video = nil @process = nil initialize_logger(@options.log_level || Logger::ERROR) end # # Starts the recording # def start @video = nil # New file start_time = Time.now @process = start_ffmpeg elapsed = Time.now - start_time FFMPEG.logger.debug "Process started in #{elapsed}s" FFMPEG.logger.info 'Recording...' end # # Stops the recording # def stop FFMPEG.logger.debug 'Stopping ffmpeg.exe...' elapsed = kill_ffmpeg FFMPEG.logger.debug "Stopped ffmpeg.exe in #{elapsed}s" FFMPEG.logger.info 'Recording complete.' @video = Movie.new(options.output) end private # # Launches the ffmpeg binary using a generated command based on # the given options. # def start_ffmpeg raise RecorderErrors::DependencyNotFound, 'ffmpeg binary not found.' unless ffmpeg_exists? FFMPEG.logger.debug "Command: #{command}" puts "Command: #{command}" # @todo Remove this after debugging process = IO.popen(command, 'r+') sleep(1.5) # Takes ~1.5s on average to initialize process end # # Sends 'q' to the ffmpeg binary to gracefully stop the process. # def kill_ffmpeg @process.puts 'q' # Gracefully exit ffmpeg elapsed = wait_for_io_eof(5) @process.close_write # Close IO elapsed end # # Initializes the logger with the given log level. # def initialize_logger(level) FFMPEG.logger.progname = 'FFmpeg' FFMPEG.logger.level = level FFMPEG.logger.formatter = proc do |severity, time, progname, msg| "#{time.strftime('%F %T')} #{progname} - #{severity} - #{msg}\n" end FFMPEG.logger.debug 'Logger initialized.' end # # Generates the command line arguments based on the given # options. # def command cmd = "#{FFMPEG.ffmpeg_binary} -y " cmd << @options.parsed end # # Waits for IO#eof? to return true # after 'q' is sent to the ffmpeg process. # def wait_for_io_eof(timeout) start = Time.now Timeout.timeout(timeout) do sleep(0.1) until @process.eof? end FFMPEG.logger.debug "IO#eof? #{@process.eof?}" Time.now - start end # # Returns true if ffmpeg binary is found. # def ffmpeg_exists? return !`which ffmpeg`.empty? if OS.linux? # "" if not found return !`where ffmpeg`.empty? if OS.windows? true # @todo Check on windows end end # class Recorder end # module FFMPEG