class Castaway::Production

Attributes

current_scene[R]
fps[R]
options[R]
resolution[R]
scenes[R]

Public Class Methods

new(options = {}) click to toggle source
# File lib/castaway/production.rb, line 21
def initialize(options = {})
  @options = options
  @resolution = _translate_resolution(options[:resolution] || '480p')
  @deliverable = options[:deliverable]
  @fps = options[:fps] || 30

  _build_scenes
end

Public Instance Methods

_construct_scene(scene, definition) click to toggle source
# File lib/castaway/production.rb, line 93
def _construct_scene(scene, definition)
  instance_exec(scene, &definition)
ensure
  @current_scene = nil
end
_construct_timeline() click to toggle source
# File lib/castaway/production.rb, line 52
def _construct_timeline
  Castaway::Timeline.new(resolution, fps).tap do |timeline|
    @scenes.each { |scene| scene.construct(timeline) }
  end
end
_hd_resolution(rows) click to toggle source
# File lib/castaway/production.rb, line 112
def _hd_resolution(rows)
  rows = rows.to_i
  cols = rows * 16 / 9.0
  Castaway::Size.new(cols.ceil, rows)
end
_next_filename(ext = nil) click to toggle source
# File lib/castaway/production.rb, line 118
def _next_filename(ext = nil)
  @next_filename ||= 0
  File.join(self.class.output_path,
            format('__%04d%s', @next_filename += 1, ext))
end
_produce_frames(timeline, range) click to toggle source
# File lib/castaway/production.rb, line 62
def _produce_frames(timeline, range)
  template = _template

  start_frame = range.start_frame
  end_frame   = range.end_frame

  progress_end = end_frame - start_frame + 1
  progress = ProgressBar.create(starting_at: 0, total: progress_end)

  start_frame.upto(end_frame) do |f|
    timeline.render_frame(f, name: format(template, f - start_frame))
    progress.increment
  end
end
_produce_movie(soundtrack) click to toggle source
# File lib/castaway/production.rb, line 77
def _produce_movie(soundtrack)
  FileUtils.rm_f(deliverable)

  ffmpeg = Chaussettes::Tool.new('ffmpeg')
  ffmpeg << '-thread_queue_size' << 8192
  ffmpeg << '-r' << fps << '-s' << resolution.to_resolution
  ffmpeg << '-i' << _template('.png') << '-i' << soundtrack
  ffmpeg << '-vcodec' << 'libx264'
  ffmpeg << '-preset' << 'veryslow' << '-tune' << 'stillimage'
  ffmpeg << '-crf' << 23 << '-pix_fmt' << 'yuv420p' << '-acodec' << 'aac'
  ffmpeg << deliverable

  puts ffmpeg.to_s
  system(ffmpeg.to_s)
end
_template(ext = nil) click to toggle source
# File lib/castaway/production.rb, line 58
def _template(ext = nil)
  File.join(self.class.output_path, format('frame-%s%s', '%05d', ext))
end
_translate_resolution(res) click to toggle source
# File lib/castaway/production.rb, line 99
def _translate_resolution(res)
  case res
  when Castaway::Size then res
  when Array then Castaway::Size.new(res.first.to_i, res.last.to_i)
  when /^(\d+)p$/ then _hd_resolution(Regexp.last_match(1))
  when Integer then _hd_resolution(res)
  when /^(\d+)x(\d+)$/ then
    Castaway::Size.new(Regexp.last_match(1).to_i, Regexp.last_match(2).to_i)
  else raise ArgumentError,
             "don't know how to turn #{res.inspect} into resolution"
  end
end
deliverable() click to toggle source
# File lib/castaway/production.rb, line 39
def deliverable
  @deliverable ||= begin
    if self.class.name
      self.class.name.split(/::/).last.
        gsub(/([^A-Z]+)([A-Z]+)/) { "#{$1}-#{$2.downcase}" }.
        gsub(/([^0-9]+)([0-9]+)/) { "#{$1}-#{$2}" }.
        downcase + '.mp4'
    else
      'production.mp4'
    end
  end
end
produce(range = Castaway::Range.new(self)) click to toggle source
# File lib/castaway/production.rb, line 30
def produce(range = Castaway::Range.new(self))
  FileUtils.mkdir_p(self.class.output_path)

  timeline = _construct_timeline
  _produce_frames(timeline, range)
  soundtrack = _produce_soundtrack(range)
  _produce_movie(soundtrack)
end