Class: FFMPEG::Transcoder

Inherits:
Object
  • Object
show all
Includes:
FFMPEG::Transcoders::Autorotator, FFMPEG::Transcoders::Scaler
Defined in:
lib/ffmpeg/transcoder.rb

Overview

transcoder options:

  • preserve_aspect_ration: [:width|:height]

  • scale_and_enlarge: boolean, default: true

  • autorotate: boolean

Constant Summary collapse

@@timeout =
200

Class Method Summary collapse

Instance Method Summary collapse

Methods included from FFMPEG::Transcoders::Autorotator

#apply_autorotate, #autorotate?, #changes_orientation?

Constructor Details

#initialize(movie, output_file, options = EncodingOptions.new, transcoder_options = {:enlarge => true}) ⇒ Transcoder

Returns a new instance of Transcoder.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ffmpeg/transcoder.rb', line 27

def initialize(movie, output_file, options = EncodingOptions.new, transcoder_options = {:enlarge => true})
  @movie = movie
  @output_file = output_file
  
  if options.is_a?(String) || 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."
  end
  
  @transcoder_options = transcoder_options
  @errors = []
  
  apply_transcoder_options
end

Class Method Details

.timeoutObject



23
24
25
# File 'lib/ffmpeg/transcoder.rb', line 23

def self.timeout
  @@timeout
end

.timeout=(time) ⇒ Object



19
20
21
# File 'lib/ffmpeg/transcoder.rb', line 19

def self.timeout=(time)
  @@timeout = time
end

Instance Method Details

#encodedObject



105
106
107
# File 'lib/ffmpeg/transcoder.rb', line 105

def encoded
  @encoded ||= Movie.new(@output_file)
end

#encoding_succeeded?Boolean

Returns:

  • (Boolean)


99
100
101
102
103
# File 'lib/ffmpeg/transcoder.rb', line 99

def encoding_succeeded?
  @errors << "no output file created" and return false unless File.exists?(@output_file)
  @errors << "encoded file is invalid" and return false unless encoded.valid?
  true
end

#runObject

ffmpeg < 0.8: frame= 413 fps= 48 q=31.0 size= 2139kB time=16.52 bitrate=1060.6kbits/s ffmpeg >= 0.8: frame= 4855 fps= 46 q=31.0 size= 45306kB time=00:02:42.28 bitrate=2287.0kbits/



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
# File 'lib/ffmpeg/transcoder.rb', line 47

def run
  command = "#{FFMPEG.ffmpeg_binary} -y -i #{Shellwords.escape(@movie.path)} #{@raw_options} #{Shellwords.escape(@output_file)}"
  FFMPEG.logger.info("Running transcoding...\n#{command}\n")
  output = ""
  last_output = nil
  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
        if line.include?("time=")
          if line =~ /time=(\d+):(\d+):(\d+.\d+)/ # ffmpeg 0.8 and above style
            time = ($1.to_i * 3600) + ($2.to_i * 60) + $3.to_f
          elsif line =~ /time=(\d+.\d+)/ # ffmpeg 0.7 and below style
            time = $1.to_f
          else # better make sure it wont blow up in case of unexpected output
            time = 0.0
          end
          progress = time / @movie.duration
          yield(progress) if block_given?
        end
        if line =~ /Unsupported codec/
          FFMPEG.logger.error "Failed encoding...\nCommand\n#{command}\nOutput\n#{output}\n"
          raise "Failed encoding: #{line}"
        end
      end
      
      if @@timeout
        stderr.each_with_timeout(wait_thr.pid, @@timeout, "r", &next_line)
      else
        stderr.each("r", &next_line)
      end
        
    rescue Timeout::Error => e
      FFMPEG.logger.error "Process hung...\nCommand\n#{command}\nOutput\n#{output}\n"
      raise FFMPEG::Error, "Process hung. Full output: #{output}"
    end
  end

  if encoding_succeeded?
    yield(1.0) if block_given?
    FFMPEG.logger.info "Transcoding of #{@movie.path} to #{@output_file} succeeded\n"
  else
    errors = "Errors: #{@errors.join(", ")}. "
    FFMPEG.logger.error "Failed encoding...\n#{command}\n\n#{output}\n#{errors}\n"
    raise FFMPEG::Error, "Failed encoding.#{errors}Full output: #{output}"
  end
  
  encoded
end