Class: FFMPEG::Transcoder

Inherits:
Object
  • Object
show all
Defined in:
lib/ffmpeg/transcoder.rb

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Transcoder.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/ffmpeg/transcoder.rb', line 5

def initialize(movie, output_file, options = EncodingOptions.new, transcoder_options = {})
  @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

Instance Method Details

#encodedObject



88
89
90
# File 'lib/ffmpeg/transcoder.rb', line 88

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

#encoding_succeeded?Boolean

Returns:

  • (Boolean)


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ffmpeg/transcoder.rb', line 65

def encoding_succeeded?
  unless File.exists?(@output_file)
    @errors << "no output file created"
    return false
  end
  
  unless encoded.valid?
    @errors << "encoded file is invalid"
    return false
  end
  
  if validate_duration?
    precision = @raw_options[:duration] ? 1.5 : 1.1
    desired_duration = @raw_options[:duration] && @raw_options[:duration] < @movie.duration ? @raw_options[:duration] : @movie.duration
    if (encoded.duration >= (desired_duration * precision) or encoded.duration <= (desired_duration / precision))
      @errors << "encoded file duration differed from original/specified duration (wanted: #{desired_duration}sec, got: #{encoded.duration}sec)"
      return false
    end
  end
  
  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/



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/ffmpeg/transcoder.rb', line 25

def run
  command = "#{FFMPEG.ffmpeg_binary} -y -i '#{@movie.path}' #{@raw_options} '#{@output_file}'"
  FFMPEG.logger.info("Running transcoding...\n#{command}\n")
  output = ""
  last_output = nil
  Open3.popen3(command) do |stdin, stdout, stderr|
    yield(0.0) if block_given?
    stderr.each("r") 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
  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.empty? ? "" : " Errors: #{@errors.join(", ")}. "
    FFMPEG.logger.error "Failed encoding...\n#{command}\n\n#{output}\n#{errors}\n"
    raise "Failed encoding.#{errors}Full output: #{output}"
  end
  
  encoded
end