Class: VideoConverter::Ffmpeg
Class Attribute Summary collapse
-
.aliases ⇒ Object
Returns the value of attribute aliases.
-
.bin ⇒ Object
Returns the value of attribute bin.
-
.concat_command ⇒ Object
Returns the value of attribute concat_command.
-
.crop_detect_command ⇒ Object
Returns the value of attribute crop_detect_command.
-
.defaults ⇒ Object
Returns the value of attribute defaults.
-
.ffprobe_bin ⇒ Object
Returns the value of attribute ffprobe_bin.
-
.first_pass_command ⇒ Object
Returns the value of attribute first_pass_command.
-
.key_frames_command ⇒ Object
Returns the value of attribute key_frames_command.
-
.mux_command ⇒ Object
Returns the value of attribute mux_command.
-
.one_pass_command ⇒ Object
Returns the value of attribute one_pass_command.
-
.second_pass_command ⇒ Object
Returns the value of attribute second_pass_command.
-
.split_command ⇒ Object
Returns the value of attribute split_command.
-
.volume_detect_command ⇒ Object
Returns the value of attribute volume_detect_command.
Instance Attribute Summary collapse
-
#input ⇒ Object
Returns the value of attribute input.
-
#outputs ⇒ Object
Returns the value of attribute outputs.
Class Method Summary collapse
- .concat(inputs, output, method = nil) ⇒ Object
- .mux(inputs, output) ⇒ Object
- .split(input, output) ⇒ Object
Instance Method Summary collapse
-
#initialize(input, outputs) ⇒ Ffmpeg
constructor
A new instance of Ffmpeg.
- #run ⇒ Object
Constructor Details
#initialize(input, outputs) ⇒ Ffmpeg
Returns a new instance of Ffmpeg.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/video_converter/ffmpeg.rb', line 71 def initialize input, outputs self.input = input self.outputs = input.select_outputs(outputs) self.outputs.each do |output| # volume output.[:audio_filter] = "volume=#{volume(output.volume)}" if output.volume unless output.[:vn] # autorotate if output.type != 'playlist' && output.rotate == true output.rotate = input.[:rotate] ? 360 - input.[:rotate] : nil end # autocrop output.crop = input.crop_detect if output.type != 'playlist' && output.crop == true # autodeinterlace output.[:deinterlace] = input.[:interlaced] if output.[:deinterlace].nil? # filter_complex filter_complex = [] filter_complex << "crop=#{output.crop.shellescape}" if output.crop if output.width || output.height output.width = (output.height * aspect(input, output)).ceil / 2 * 2 if output.height && !output.width output.height = (output.width / aspect(input, output)).ceil / 2 * 2 if output.width && !output.height filter_complex << "scale=#{scale(output.width, :w)}:#{scale(output.height, :h)}" if output.[:aspect] filter_complex << "setdar=#{output..delete(:aspect).to_s.shellescape}" elsif input.video_stream[:dar_width] && input.video_stream[:dar_height] filter_complex << "setdar=#{aspect(input, output)}" end end if output.watermarks && (output.watermarks[:width] || output.watermarks[:height]) filter_complex = ["[0:v] #{filter_complex.join(',')} [main]"] filter_complex << "[1:v] scale=#{scale(output.watermarks[:width], :w, output.width)}:#{scale(output.watermarks[:height], :h, output.height)} [overlay]" filter_complex << "[main] [overlay] overlay=#{(output.watermarks[:x], :w)}:#{(output.watermarks[:y], :h)}" if output.rotate filter_complex[filter_complex.count-1] += ' [overlayed]' filter_complex << '[overlayed] ' + rotate(output.rotate) end output.[:filter_complex] = "'#{filter_complex.join(';')}'" else filter_complex << "overlay=#{(output.watermarks[:x], :w)}:#{(output.watermarks[:y], :h)}" if output.watermarks filter_complex << rotate(output.rotate) if output.rotate output.[:filter_complex] = filter_complex.join(',') if filter_complex.any? end else output..delete(:deinterlace) output..delete(:filter_complex) end output.[:format] ||= File.extname(output.filename).delete('.') output.[:format] = 'mpegts' if output.[:format] == 'ts' output.[:movflags] = '+faststart' if output.faststart || (output.faststart.nil? && %w(mov mp4).include?(output.[:format].downcase)) unless output.type == 'playlist' output. = self.class.defaults.merge(output.) output.[:keyint_min] ||= output.[:frame_rate] output.[:keyframe_interval] = output.[:keyint_min] * Output.keyframe_interval_in_seconds end end end |
Class Attribute Details
.aliases ⇒ Object
Returns the value of attribute aliases.
6 7 8 |
# File 'lib/video_converter/ffmpeg.rb', line 6 def aliases @aliases end |
.bin ⇒ Object
Returns the value of attribute bin.
6 7 8 |
# File 'lib/video_converter/ffmpeg.rb', line 6 def bin @bin end |
.concat_command ⇒ Object
Returns the value of attribute concat_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def concat_command @concat_command end |
.crop_detect_command ⇒ Object
Returns the value of attribute crop_detect_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def crop_detect_command @crop_detect_command end |
.defaults ⇒ Object
Returns the value of attribute defaults.
6 7 8 |
# File 'lib/video_converter/ffmpeg.rb', line 6 def defaults @defaults end |
.ffprobe_bin ⇒ Object
Returns the value of attribute ffprobe_bin.
6 7 8 |
# File 'lib/video_converter/ffmpeg.rb', line 6 def ffprobe_bin @ffprobe_bin end |
.first_pass_command ⇒ Object
Returns the value of attribute first_pass_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def first_pass_command @first_pass_command end |
.key_frames_command ⇒ Object
Returns the value of attribute key_frames_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def key_frames_command @key_frames_command end |
.mux_command ⇒ Object
Returns the value of attribute mux_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def mux_command @mux_command end |
.one_pass_command ⇒ Object
Returns the value of attribute one_pass_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def one_pass_command @one_pass_command end |
.second_pass_command ⇒ Object
Returns the value of attribute second_pass_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def second_pass_command @second_pass_command end |
.split_command ⇒ Object
Returns the value of attribute split_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def split_command @split_command end |
.volume_detect_command ⇒ Object
Returns the value of attribute volume_detect_command.
7 8 9 |
# File 'lib/video_converter/ffmpeg.rb', line 7 def volume_detect_command @volume_detect_command end |
Instance Attribute Details
#input ⇒ Object
Returns the value of attribute input.
69 70 71 |
# File 'lib/video_converter/ffmpeg.rb', line 69 def input @input end |
#outputs ⇒ Object
Returns the value of attribute outputs.
69 70 71 |
# File 'lib/video_converter/ffmpeg.rb', line 69 def outputs @outputs end |
Class Method Details
.concat(inputs, output, method = nil) ⇒ Object
55 56 57 58 59 |
# File 'lib/video_converter/ffmpeg.rb', line 55 def self.concat(inputs, output, method = nil) method = %w(ts mpg mpeg).include?(File.extname(inputs.first.to_s).delete('.')) ? :protocol : :muxer unless method output. = { :codec => 'copy' }.merge(output.) send("concat_#{method}", inputs, output) end |
.mux(inputs, output) ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/video_converter/ffmpeg.rb', line 61 def self.mux(inputs, output) output. = { :codec => 'copy' }.merge(output.) Command.new(mux_command, prepare_params(nil, output).merge({ :inputs => { '-i' => inputs }, :maps => { '-map' => inputs.each_with_index.map { |_,i| "#{i}:0" }.join(' ') } })).execute end |
Instance Method Details
#run ⇒ Object
129 130 131 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 |
# File 'lib/video_converter/ffmpeg.rb', line 129 def run success = true threads = [] input.output_groups(outputs).each_with_index do |group, group_index| qualities = group.select { |output| output.type != 'playlist' } # common first pass if !one_pass?(qualities) && common_first_pass?(qualities) qualities.each do |output| output.[:passlogfile] = File.join(output.work_dir, "group#{group_index}.log") end best_quality = qualities.sort do |q1, q2| res = q1.[:video_bitrate].to_i <=> q2.[:video_bitrate].to_i res = q1.height.to_i <=> q2.height.to_i if res == 0 res = q1.width.to_i <=> q2.width.to_i if res == 0 # TODO compare by size res end.last success &&= Command.new(self.class.first_pass_command, self.class.prepare_params(input, best_quality), ['-filter_complex']).execute end qualities.each_with_index do |output, output_index| command = if one_pass?(qualities) Command.new(self.class.one_pass_command, self.class.prepare_params(input, output), ['-filter_complex']) elsif common_first_pass?(qualities) Command.new(self.class.second_pass_command, self.class.prepare_params(input, output), ['-filter_complex']) else output.[:passlogfile] = File.join(output.work_dir, "group#{group_index}_#{output_index}.log") output.[:force_key_frames] = input.[:video_start_time].step(input.[:duration_in_ms] / 1000.0, Output.keyframe_interval_in_seconds).map(&:floor).join(',') output.[:sc_threshold] = 0 output.[:keyint_min] = output.[:keyframe_interval] = nil Command.new(self.class.first_pass_command, self.class.prepare_params(input, output), ['-filter_complex']).append( Command.new(self.class.second_pass_command, self.class.prepare_params(input, output), ['-filter_complex']) ) end # run ffmpeg if VideoConverter.paral threads << Thread.new { success &&= command.execute } else success &&= command.execute end end end threads.each { |t| t.join } if VideoConverter.paral success end |