lib/ffmpeg/transcoder.rb in streamio-ffmpeg-2.0.0 vs lib/ffmpeg/transcoder.rb in streamio-ffmpeg-2.1.0
- old
+ new
@@ -1,25 +1,25 @@
require 'open3'
-require 'shellwords'
module FFMPEG
class Transcoder
+ attr_reader :command, :input
+
@@timeout = 30
- def self.timeout=(time)
- @@timeout = time
+ class << self
+ attr_accessor :timeout
end
- def self.timeout
- @@timeout
- end
-
- def initialize(movie, output_file, options = EncodingOptions.new, transcoder_options = {})
- @movie = movie
+ def initialize(input, output_file, options = EncodingOptions.new, transcoder_options = {})
+ if input.is_a?(FFMPEG::Movie)
+ @movie = input
+ @input = input.path
+ end
@output_file = output_file
- if options.is_a?(String) || options.is_a?(EncodingOptions)
+ if options.is_a?(Array) || options.is_a?(EncodingOptions)
@raw_options = options
elsif options.is_a?(Hash)
@raw_options = EncodingOptions.new(options)
else
raise ArgumentError, "Unknown options format '#{options.class}', should be either EncodingOptions, Hash or String."
@@ -27,10 +27,18 @@
@transcoder_options = transcoder_options
@errors = []
apply_transcoder_options
+
+ @input = @transcoder_options[:input] unless @transcoder_options[:input].nil?
+
+ input_options = @transcoder_options[:input_options] || []
+ iopts = []
+ input_options.each { |k, v| iopts += ['-' + k.to_s, v] }
+
+ @command = [FFMPEG.ffmpeg_binary, '-y', *iopts, '-i', @input, *@raw_options.to_a, @output_file]
end
def run(&block)
transcode_movie(&block)
if @transcoder_options[:validate]
@@ -49,18 +57,21 @@
def encoded
@encoded ||= Movie.new(@output_file)
end
+ def timeout
+ self.class.timeout
+ end
+
private
# frame= 4855 fps= 46 q=31.0 size= 45306kB time=00:02:42.28 bitrate=2287.0kbits/
def transcode_movie
- @command = "#{FFMPEG.ffmpeg_binary} -y -i #{Shellwords.escape(@movie.path)} #{@raw_options} #{Shellwords.escape(@output_file)}"
- FFMPEG.logger.info("Running transcoding...\n#{@command}\n")
+ FFMPEG.logger.info("Running transcoding...\n#{command}\n")
@output = ""
- Open3.popen3(@command) do |_stdin, _stdout, stderr, wait_thr|
+ Open3.popen3(*command) do |_stdin, _stdout, stderr, wait_thr|
begin
yield(0.0) if block_given?
next_line = Proc.new do |line|
fix_encoding(line)
@output << line
@@ -73,38 +84,38 @@
progress = time / @movie.duration
yield(progress) if block_given?
end
end
- if @@timeout
- stderr.each_with_timeout(wait_thr.pid, @@timeout, 'size=', &next_line)
+ if timeout
+ stderr.each_with_timeout(wait_thr.pid, timeout, 'size=', &next_line)
else
stderr.each('size=', &next_line)
end
rescue Timeout::Error => e
- FFMPEG.logger.error "Process hung...\n@command\n#{@command}\nOutput\n#{@output}\n"
+ FFMPEG.logger.error "Process hung...\n@command\n#{command}\nOutput\n#{@output}\n"
raise Error, "Process hung. Full output: #{@output}"
end
end
end
def validate_output_file(&block)
if encoding_succeeded?
yield(1.0) if block_given?
- FFMPEG.logger.info "Transcoding of #{@movie.path} to #{@output_file} succeeded\n"
+ FFMPEG.logger.info "Transcoding of #{input} to #{@output_file} succeeded\n"
else
errors = "Errors: #{@errors.join(", ")}. "
- FFMPEG.logger.error "Failed encoding...\n#{@command}\n\n#{@output}\n#{errors}\n"
+ FFMPEG.logger.error "Failed encoding...\n#{command}\n\n#{@output}\n#{errors}\n"
raise Error, "Failed encoding.#{errors}Full output: #{@output}"
end
end
def apply_transcoder_options
# if true runs #validate_output_file
@transcoder_options[:validate] = @transcoder_options.fetch(:validate) { true }
- return if @movie.calculated_aspect_ratio.nil?
+ return if @movie.nil? || @movie.calculated_aspect_ratio.nil?
case @transcoder_options[:preserve_aspect_ratio].to_s
when "width"
new_height = @raw_options.width / @movie.calculated_aspect_ratio
new_height = new_height.ceil.even? ? new_height.ceil : new_height.floor
new_height += 1 if new_height.odd? # needed if new_height ended up with no decimals in the first place