Class: RVideo::Tools::Ffmpeg

Inherits:
Object
  • Object
show all
Includes:
AbstractTool::InstanceMethods
Defined in:
lib/rvideo/tools/ffmpeg.rb

Constant Summary collapse

RESOLUTION_ABBREVIATIONS =
{
  "sqcif"  => "128x96",
  "qcif"   => "176x144",
  "cif"    => "352x288",
  "4cif"   => "704x576",
  "qqvga"  => "160x120",
  "qvga"   => "320x240",
  "vga"    => "640x480",
  "svga"   => "800x600",
  "xga"    => "1024x768",
  "uxga"   => "1600x1200",
  "qxga"   => "2048x1536",
  "sxga"   => "1280x1024",
  "qsxga"  => "2560x2048",
  "hsxga"  => "5120x4096",
  "wvga"   => "852x480",
  "wxga"   => "1366x768",
  "wsxga"  => "1600x1024",
  "wuxga"  => "1920x1200",
  "woxga"  => "2560x1600",
  "wqsxga" => "3200x2048",
  "wquxga" => "3840x2400",
  "whsxga" => "6400x4096",
  "whuxga" => "7680x4800",
  "cga"    => "320x200",
  "ega"    => "640x350",
  "hd480"  => "852x480",
  "hd720"  => "1280x720",
  "hd1080" => "1920x1080"
}
VALID_ASPECT_STRINGS =
["4:3", "16:9"]
VALID_ASPECT_FLOATS =
[1.3333, 1.7777]
DEFAULT_VIDEO_BIT_RATE_PARAMETER =

The flag used to set video bitrate has apparently changed between different ffmpeg versions. In the latest builds -b is used. In older builds it was -v which is now used to set verbosity of logging.

"b"

Instance Attribute Summary collapse

Attributes included from AbstractTool::InstanceMethods

#command, #options, #original, #progress, #raw_result

Instance Method Summary collapse

Methods included from AbstractTool::InstanceMethods

abstract_attribute_formatter, #audio_bit_rate, #audio_channels, #audio_sample_rate, #calculate_height, #calculate_width, #deinterlace, #do_execute, #execute, #fps, #get_audio_bit_rate, #get_audio_channels, #get_audio_sample_rate, #get_deinterlace, #get_fit_to_height_resolution, #get_fit_to_width_resolution, #get_fps, #get_letterbox_resolution, #get_mono_audio, #get_original_fps, #get_original_resolution, #get_resolution, #get_specific_audio_bit_rate, #get_specific_audio_sample_rate, #get_specific_fps, #get_specific_resolution, #get_stereo_audio, #get_video_bit_rate, #get_video_bit_rate_max, #get_video_bit_rate_min, #get_video_bit_rate_tolerance, #get_video_quality, #resolution, #temp_dir, #valid_dimension?, #video_bit_rate, #video_bit_rate_max, #video_bit_rate_min, #video_bit_rate_tolerance, #video_quality

Constructor Details

#initialize(raw_command, options = {}) ⇒ Ffmpeg

Returns a new instance of Ffmpeg.



49
50
51
52
53
54
55
56
# File 'lib/rvideo/tools/ffmpeg.rb', line 49

def initialize(raw_command, options = {})
  @progress_sample_rate = options.delete(:progress_sample_rate)
  @progress_timeout = options.delete(:progress_timeout)
  
  @raw_command = raw_command
  @options = HashWithIndifferentAccess.new(options)
  @command = interpolate_variables(raw_command)
end

Instance Attribute Details

#audio_sizeObject (readonly)

Returns the value of attribute audio_size.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def audio_size
  @audio_size
end

#frameObject (readonly)

Returns the value of attribute frame.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def frame
  @frame
end

#header_sizeObject (readonly)

Returns the value of attribute header_size.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def header_size
  @header_size
end

#output_bitrateObject (readonly)

Returns the value of attribute output_bitrate.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def output_bitrate
  @output_bitrate
end

#output_fpsObject (readonly)

Returns the value of attribute output_fps.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def output_fps
  @output_fps
end

#overheadObject (readonly)

Returns the value of attribute overhead.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def overhead
  @overhead
end

#pidObject (readonly)

Returns the value of attribute pid.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def pid
  @pid
end

#psnrObject (readonly)

Returns the value of attribute psnr.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def psnr
  @psnr
end

#qObject (readonly)

Returns the value of attribute q.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def q
  @q
end

#sizeObject (readonly)

Returns the value of attribute size.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def size
  @size
end

#timeObject (readonly)

Returns the value of attribute time.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def time
  @time
end

#video_sizeObject (readonly)

Returns the value of attribute video_size.



47
48
49
# File 'lib/rvideo/tools/ffmpeg.rb', line 47

def video_size
  @video_size
end

Instance Method Details

#execute_with_progressObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rvideo/tools/ffmpeg.rb', line 132

def execute_with_progress
  # TODO put progress_counter stuff back in because long videos might not update their progress for some time and we wouldn't want to accidently kill them!
  final_command = @command
  RVideo.logger.info("\nExecuting Command: #{final_command}\n")
  @raw_result = ''
  duration = 0
  previous_line = nil
  mutex = Mutex.new
  
  command_thread = Thread.new do 
    @pid, stdin, stdout, stderr = Open4::popen4(final_command)
    stderr.each("\r") do |line|
      if line != previous_line
        previous_line = line
        new_progress, duration = parse_progress(line, duration)
          mutex.synchronize do
            @progress = new_progress
          end
        $defout.flush
      end
      # WARNING: we may need to set a limit to how many lines are appended to @raw_result as ffmpeg can spit out a massive amount of info if things go pear shaped
      @raw_result += line + "\r"
    end
  end
  
  # Yield the progress and monitor the process
  current_timeout = 0
  progress_to_yeild = nil
  
  loop do
    # Exit when the command is done
    break unless command_thread.alive?
    # Yield the progress
    mutex.synchronize do
      # First check if we're actually making progress! We should kill the command if it's not, as it's probably because ffmpeg has frozen
      if progress_to_yeild == @progress
        current_timeout += @progress_sample_rate
      end
      progress_to_yeild = @progress
    end
    
    unless @progress_timeout == false
      self.kill if current_timeout >= @progress_timeout
    end
    
    yield progress_to_yeild
    sleep @progress_sample_rate
  end
end

#format_audio_bit_rate(params = {}) ⇒ Object



124
125
126
# File 'lib/rvideo/tools/ffmpeg.rb', line 124

def format_audio_bit_rate(params={})
  "-ab #{params[:bit_rate]}k"
end

#format_audio_channels(params = {}) ⇒ Object



120
121
122
# File 'lib/rvideo/tools/ffmpeg.rb', line 120

def format_audio_channels(params={})
  "-ac #{params[:channels]}"
end

#format_audio_sample_rate(params = {}) ⇒ Object



128
129
130
# File 'lib/rvideo/tools/ffmpeg.rb', line 128

def format_audio_sample_rate(params={})
  "-ar #{params[:sample_rate]}"
end

#format_deinterlace(params = {}) ⇒ Object



63
64
65
# File 'lib/rvideo/tools/ffmpeg.rb', line 63

def format_deinterlace(params={})
  params[:deinterlace] ? "-deinterlace" : ""
end

#format_fps(params = {}) ⇒ Object



67
68
69
# File 'lib/rvideo/tools/ffmpeg.rb', line 67

def format_fps(params={})
  "-r #{params[:fps]}"
end

#format_resolution(params = {}) ⇒ Object



110
111
112
113
114
115
116
117
118
# File 'lib/rvideo/tools/ffmpeg.rb', line 110

def format_resolution(params={})
  p = "-s #{params[:scale][:width]}x#{params[:scale][:height]}"
  if params[:letterbox]
    plr = ((params[:letterbox][:width] - params[:scale][:width]) / 2).to_i
    ptb = ((params[:letterbox][:height] - params[:scale][:height]) / 2).to_i
    p += " -padtop #{ptb} -padbottom #{ptb} -padleft #{plr} -padright #{plr} "
  end
  p
end

#format_video_bit_rate(params = {}) ⇒ Object



71
72
73
# File 'lib/rvideo/tools/ffmpeg.rb', line 71

def format_video_bit_rate(params = {})
  "-#{video_bit_rate_parameter} #{params[:video_bit_rate]}k"
end

#format_video_bit_rate_max(params = {}) ⇒ Object



83
84
85
# File 'lib/rvideo/tools/ffmpeg.rb', line 83

def format_video_bit_rate_max(params = {})
  "-maxrate #{params[:video_bit_rate_max]}k"
end

#format_video_bit_rate_min(params = {}) ⇒ Object



79
80
81
# File 'lib/rvideo/tools/ffmpeg.rb', line 79

def format_video_bit_rate_min(params = {})
  "-minrate #{params[:video_bit_rate_min]}k"
end

#format_video_bit_rate_tolerance(params = {}) ⇒ Object



75
76
77
# File 'lib/rvideo/tools/ffmpeg.rb', line 75

def format_video_bit_rate_tolerance(params = {})
  "-bt #{params[:video_bit_rate_tolerance]}k"
end

#format_video_quality(params = {}) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rvideo/tools/ffmpeg.rb', line 87

def format_video_quality(params={})
  bitrate = params[:video_bit_rate].blank? ? nil : params[:video_bit_rate]
  
  params.merge! get_original_fps unless params[:fps]
  
  factor  = params[:scale][:width].to_f * params[:scale][:height].to_f * params[:fps].to_f
  
  case params[:video_quality]
  when 'low'
    bitrate ||= (factor / 12000).to_i
    params[:video_bit_rate] = bitrate
    "#{format_video_bit_rate params} -crf 30 -me zero -subq 1 -refs 1 -threads auto"
  when 'medium'
    bitrate ||= (factor / 9000).to_i
    params[:video_bit_rate] = bitrate
    "#{format_video_bit_rate params} -crf 22 -flags +loop -cmp +sad -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me hex -subq 3 -trellis 1 -refs 2 -bf 3 -b_strategy 1 -coder 1 -me_range 16 -g 250"
  when 'high'
    bitrate ||= (factor / 3600).to_i
    params[:video_bit_rate] = bitrate
    "#{format_video_bit_rate params} -crf 18 -flags +loop -cmp +sad -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me full -subq 6 -trellis 1 -refs 3 -bf 3 -b_strategy 1 -coder 1 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71"
  end
end

#killObject

Raises:



182
183
184
185
# File 'lib/rvideo/tools/ffmpeg.rb', line 182

def kill
  Process.kill("SIGKILL", @pid)
  raise TranscoderError, "Transcoder hung."
end

#tool_commandObject

Not sure if this is needed anymore…



59
60
61
# File 'lib/rvideo/tools/ffmpeg.rb', line 59

def tool_command
  'ffmpeg'
end