Class: FfmpegWrapper::FFmpeg

Inherits:
Object
  • Object
show all
Defined in:
lib/ffmpeg_wrapper/ffmpeg.rb,
lib/ffmpeg_wrapper/filters/concat.rb,
lib/ffmpeg_wrapper/filters/blackdetect.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFFmpeg

Returns a new instance of FFmpeg.


3
4
5
6
7
8
9
10
11
12
13
# File 'lib/ffmpeg_wrapper/ffmpeg.rb', line 3

def initialize
  @command = 'ffmpeg -y -hide_banner'
  @inputs = []
  @audios = []
  @videos = []
  @mappings = []
  @filters = []
  @n = 0
  @result = {}
  @post_exec_hooks = []
end

Class Method Details

.and_write_to(filename) ⇒ Object

Singleton method defined on FFmpeg after calling #filter_blackdetect. Writes info about black intervals as a plain text to a file.

Parameters:

  • filename (String)

27
28
29
30
31
32
33
34
35
# File 'lib/ffmpeg_wrapper/filters/blackdetect.rb', line 27

def self.and_write_to(filename)
  @post_exec_hooks << proc do
    File.open(filename, 'w') do |f|
      @result[:blacks].each do |black|
        f.puts 'black_interval start: %f end: %f duration: %f' % [black[:start], black[:end], black[:duration]]
      end
    end
  end
end

.run(*flags, &block) ⇒ FFmpeg

Construct ffmpeg command using that function, then execute. All opts hashe's option meant to be axactly the same as according ffmpeg flags. That is -pix_fmt => :pix_fmt

Examples:

FFmpeg.run do
  media 'somefile.mp4'
  map(0,1).applying acodec: 'libmp3lame',
                       ac: 2, ar: '44.1k'
  # .applying is a dynamic method of a
  # String returned from #map
  output 'out.mp3'
end

Returns:


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

def self.run(*flags, &block)
  lo = Logger.new(STDOUT) if flags.include?(:debug)
  ff = FFmpeg.new
  ff.instance_eval do
    instance_eval(&block)
    @command << ' ' << @inputs.join(' ')
    @command << ' ' << @filters.join(' ') if @filters.any?
    @command << ' ' << @mappings.join(' ') if @mappings.any?
    @command << ' ' << @output if @output
    lo.info @command if lo
    @out = IO.popen(@command, err: [:child, :out]) do |io|
      io.read
    end
    @post_exec_hooks.each { |h| instance_eval(&h) }
    fail @out.to_s unless $?.success?
  end
  ff.instance_variable_get(:@result)
end

Instance Method Details

#audio(filename, opts = {}) ⇒ Object

Adds input audio file (no video will be extracted anyway)

Parameters:

  • filename (String)
  • opts (Hash) (defaults to: {})

    options for this input file


84
85
86
87
88
# File 'lib/ffmpeg_wrapper/ffmpeg.rb', line 84

def audio(filename, opts = {})
  n = input(filename, opts)
  @audios << n
  n
end

#filter_blackdetect(opts = {}) ⇒ Object Also known as: detect_black

Find intervals of blackness in a video file. This info then can be found in a hash, returned from FFmpeg.run by key :blacks. TODO: add argument support

Examples:

FFmpeg.run do
  media 'video.mp4'
  detect_black.and_write_to 'black_intervals.txt'
end # => { ... :blacks => [ { :start => x, :end => y, :duration => z}, ... ] }

Parameters:

  • opts (Hash) (defaults to: {})

Returns:

  • FFmpeg self. Chainable, see example.


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/ffmpeg_wrapper/filters/blackdetect.rb', line 16

def filter_blackdetect(opts = {})
  @filters << '-vf blackdetect'
  @output = ' -f null /dev/null '
  @redirection = [:child, :out]
  @result[:blacks] = []

  # Singleton method defined on FFmpeg
  # after calling #filter_blackdetect.
  # Writes info about black intervals as a plain text to
  # a file.
  # @param (String) filename
  def self.and_write_to(filename)
    @post_exec_hooks << proc do
      File.open(filename, 'w') do |f|
        @result[:blacks].each do |black|
          f.puts 'black_interval start: %f end: %f duration: %f' % [black[:start], black[:end], black[:duration]]
        end
      end
    end
  end
  @post_exec_hooks << proc do
    bdlines = @out.lines.grep(/blackdetect/)
    bdlines.map do |l|
      /black_start:(?<st>\S+).*
        black_end:(?<en>\S+).*
        black_duration:(?<du>\S+)/x =~ l
      @result[:blacks] << { start: st.to_f, end: en.to_f, duration: du.to_f }
    end
  end
  self
end

#filter_concat(_mappings = {}) ⇒ Object

This function extends basic FfmpegWrapper::FFmpeg functionality providing filter command. TODO: non-trivial mappings(i.e. multi-streamed inputs)


6
7
8
9
10
11
12
13
14
15
# File 'lib/ffmpeg_wrapper/filters/concat.rb', line 6

def filter_concat(_mappings = {})
  line = ''
  line << filter_complex(:audio)
  line << filter_complex(:video)
  @filters << line
  mappings = []
  mappings << (@videos.size > 1 ? '[v]' : @videos.first)
  mappings << (@audios.size > 1 ? '[a]' : @audios.first)
  mappings
end

#map(file, index = nil) ⇒ String

Specify mapping: what input stream or alias (from format, e. g. [a])

Parameters:

  • file (String, Int)

    file number or alias

  • index (Int) (defaults to: nil)

    stream specifier

Returns:

  • (String)

See Also:


103
104
105
106
107
108
109
110
111
112
# File 'lib/ffmpeg_wrapper/ffmpeg.rb', line 103

def map(file, index = nil)
  line =  "-map #{file}#{':' + index.to_s if index}"
  @mappings << line
  def line.applying(opts = {})
    opts.each do |k, v|
      self << " -#{k} #{v}"
    end
  end
  line
end

#media(filename, opts = {}) ⇒ Object

Adds input file, containing audio and video. of options below. If input file is a media container,

    1. mpeg4 or avi you don't need to explicitly specify any.

If file is raw video or audio, specify V for video and A for audio

Parameters:

  • filename (String)
  • opts (Hash) (defaults to: {})

    options for this input file. See list

Options Hash (opts):

  • :f (String)

    V format 'rawvideo'

  • :s (String)

    V geometry WxH(+X,Y)

  • :pix_fmt (String)

    V pixel format bgr8, rgba, etc…

  • :r (Int)

    V fps

  • :f (String)

    A format 'alaw', etc…

  • :ar (String)

    A sample rate, e.g. '44.1k'

  • :ac (Int)

    A channels

See Also:


63
64
65
66
67
68
# File 'lib/ffmpeg_wrapper/ffmpeg.rb', line 63

def media(filename, opts = {})
  n = input(filename, opts)
  @videos << n
  @audios << n
  n
end

#output(filename) ⇒ Object

Specify filename for output file

Parameters:

  • filename (String)

92
93
94
# File 'lib/ffmpeg_wrapper/ffmpeg.rb', line 92

def output(filename)
  @output = " #{filename}"
end

#video(filename, opts = {}) ⇒ Object

Adds input video file (no audio will be extracted anyway)

Parameters:

  • filename (String)
  • opts (Hash) (defaults to: {})

    options for this input file


74
75
76
77
78
# File 'lib/ffmpeg_wrapper/ffmpeg.rb', line 74

def video(filename, opts = {})
  n = input(filename, opts)
  @videos << n
  n
end