class FFmpegProgress::FFmpeg

The class that does the actual work.

Constants

DEFAULT_DIR

The directory for the default output file.

DEFAULT_EXT

The extension for the default output file.

LOG_FILE

The log file for ffmpeg. Progress data will be read from here.

Attributes

duration[R]

Returns the duration (in seconds) of the input file. @return [Integer]

duration_ff[R]

Returns the duration of the input file as a ffmpeg format string +(HH:MM:SS.ms)+.

@return [Integer]

input[R]

The input file. @return [String]

options[RW]

The options to pass to ffmpeg. Any occurrences of the string +_INPUT_+ will be converted to the value of the {#input} attribute. @return [String]

output[RW]

The output file. Directories will be auto-created on execution. @return [String]

pid[R]

The PID of the last spawned ffmpeg process, or nil if none spawned yet. @return [Integer]

theme[RW]

The theme for the progress bar. See {Theme::DEFAULT_THEME} for details. @return [Hash]

Public Class Methods

new(input_file, option_hash = {}) click to toggle source

Creates a new {FFmpeg} instance.

@param [String] input_file the source file name. @param [Hash] option_hash @option option_hash [String] :output the output file to write to. @option option_hash [String] :options the options to pass to ffmpeg.

See {#options} for details and {Presets} for examples.

@option option_hash [Hash, Theme] :theme either a theme hash or a {Theme}

object.

@option option_hash [Boolean] :bell whether to play a bell sound upon

finishing the task. (See {Utils} for details.)

@return [FFmpeg]

# File lib/ffmpeg_progress/ffmpeg.rb, line 60
def initialize(input_file, option_hash = {})
  self.input = input_file

  @options = option_hash.fetch :options, DEFAULT_OPTIONS
  @theme = Theme.from(option_hash.fetch :theme, Theme.new)
  @bell = option_hash.fetch :bell, false

  @output = option_hash.fetch :output, @output
  @duration_ff ||= nil
  @duration ||= nil

  @block = nil

  @pid = nil

  @last_bar = nil
end

Public Instance Methods

command() click to toggle source

Returns the current ffmpeg command that will be executed by {#run}.

@return [String]

# File lib/ffmpeg_progress/ffmpeg.rb, line 98
def command
  "ffmpeg -i \'#{@input}\' #{@options} \'#{@output}\' &> #{LOG_FILE}"
    .gsub('_INPUT_', "'#{@input}'")
end
input=(string) click to toggle source

Set the input file.

@param [String] string @return [String]

# File lib/ffmpeg_progress/ffmpeg.rb, line 82
def input=(string)
  @input = string

  return @input unless @input

  @duration_ff = `ffmpeg -i \'#{@input}\' 2>&1`.scan(/..:..:..\.../).first
  @duration = parse_ffmpeg_time(@duration_ff)

  @output ||= "#{DEFAULT_DIR}#{@input.rpartition('.').first}.#{DEFAULT_EXT}"

  @input
end
run(&block) click to toggle source

Run ffmpeg while printing a progress bar to the terminal. If a block is passed, its return value will be attached to the progress bar. The current {FFmpeg} instance will be passed to the block.

@return [0]

# File lib/ffmpeg_progress/ffmpeg.rb, line 109
def run(&block)
  File.delete(LOG_FILE) if File.exist?(LOG_FILE)

  FileUtils.mkpath(@output.rpartition('/').first) if output.include?('/')

  @pid = spawn command
  @block = block

  sleep 1 until current_time
  monitor_progress

  cleanup

  0
end

Private Instance Methods

cleanup() click to toggle source

Kill ffmpeg if still running, and delete the log file.

# File lib/ffmpeg_progress/ffmpeg.rb, line 161
def cleanup
  Process.detach(@pid)

  ffmpeg_alive =
    begin
      Process.kill(0, @pid)
      true
    rescue Errno::ESRCH
      false
    end

  Process.kill('TERM', @pid) if ffmpeg_alive

  File.delete(LOG_FILE) if File.exist?(LOG_FILE)
end
current_time() click to toggle source

Get the current time (in ffmpeg format) from the log file. Returns nil if the actual transcoding process has not started yet.

@return [String]

# File lib/ffmpeg_progress/ffmpeg.rb, line 152
def current_time
  return nil unless File.exist?(LOG_FILE)
  match = File.read(LOG_FILE).scan(/time=..:..:..\.../).last

  return '00:00:00.00' unless match
  match.delete('time=')
end
monitor_progress() click to toggle source

Display the progress bar while waiting for ffmpeg to finish.

# File lib/ffmpeg_progress/ffmpeg.rb, line 128
def monitor_progress
  until Process.waitpid(@pid, Process::WNOHANG)
    print "\r#{progress_bar}"
    sleep 1
  end

  puts "\r#{progress_bar(@duration_ff, finished: true)}"
  bell if @bell
rescue Interrupt, IRB::Abort
  puts "\r#{progress_bar(current_time, interrupted: true)}"
end
progress_bar(time = current_time, option_hash = {}) click to toggle source

Display the progress bar.

# File lib/ffmpeg_progress/ffmpeg.rb, line 141
def progress_bar(time = current_time, option_hash = {})
  position = parse_ffmpeg_time(time).to_f / @duration
  option_hash.merge!(block_output: (@block ? @block.call(self) : nil))

  @theme.bar(position, time, option_hash)
end