Module: Ffmprb::Util

Defined in:
lib/ffmprb/util.rb,
lib/ffmprb/util/thread.rb,
lib/ffmprb/util/threaded_io_buffer.rb

Defined Under Namespace

Classes: Reader, Thread, ThreadedIoBuffer, TimeLimitError

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.cmd_timeoutObject

Returns the value of attribute cmd_timeout.



16
17
18
# File 'lib/ffmprb/util.rb', line 16

def cmd_timeout
  @cmd_timeout
end

.ffmpeg_cmdObject

Returns the value of attribute ffmpeg_cmd.



15
16
17
# File 'lib/ffmprb/util.rb', line 15

def ffmpeg_cmd
  @ffmpeg_cmd
end

.ffprobe_cmdObject

Returns the value of attribute ffprobe_cmd.



15
16
17
# File 'lib/ffmprb/util.rb', line 15

def ffprobe_cmd
  @ffprobe_cmd
end

Class Method Details

.ffmpeg(*args, limit: nil, timeout: cmd_timeout, ignore_broken_pipe: false) ⇒ Object



22
23
24
25
# File 'lib/ffmprb/util.rb', line 22

def ffmpeg(*args, limit: nil, timeout: cmd_timeout, ignore_broken_pipe: false)
  args = ['-loglevel', 'debug'] + args  if Ffmprb.debug
  sh *ffmpeg_cmd, *args, output: :stderr, limit: limit, timeout: timeout, ignore_broken_pipe: ignore_broken_pipe
end

.ffprobe(*args, limit: nil, timeout: cmd_timeout) ⇒ Object



18
19
20
# File 'lib/ffmprb/util.rb', line 18

def ffprobe(*args, limit: nil, timeout: cmd_timeout)
  sh *ffprobe_cmd, *args, limit: limit, timeout: timeout
end

.sh(*cmd, output: :stdout, log: :stderr, limit: nil, timeout: cmd_timeout, ignore_broken_pipe: false) ⇒ Object



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
64
# File 'lib/ffmprb/util.rb', line 27

def sh(*cmd, output: :stdout, log: :stderr, limit: nil, timeout: cmd_timeout, ignore_broken_pipe: false)
  cmd = cmd.map &:to_s  unless cmd.size == 1
  cmd_str = cmd.size != 1 ? cmd.map{|c| "\"#{c}\""}.join(' ') : cmd.first
  timeout = [timeout, limit].compact.min
  thr = Thread.new "`#{cmd_str}`" do
    Ffmprb.logger.info "Popening `#{cmd_str}`..."
    Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
      begin
        stdin.close

        log_cmd = cmd.first.upcase  if log
        stdout_r = Reader.new(stdout, output == :stdout, log == :stdout && log_cmd)
        stderr_r = Reader.new(stderr, true, log == :stderr && log_cmd)

        Thread.timeout_or_live(limit, log: "while waiting for `#{cmd_str}`", timeout: timeout) do |time|
          value = wait_thr.value
          status = value.exitstatus  # NOTE blocking
          if status != 0
            if ignore_broken_pipe && value.signaled? && value.termsig == Signal.list['PIPE']
              Ffmprb.logger.debug "Ignoring broken pipe: #{cmd_str}"
            else
              fail Error, "#{cmd_str} (#{status || "sig##{value.termsig}"}):\n#{stderr_r.read}"
            end
          end
        end
        Ffmprb.logger.debug "FINISHED: #{cmd_str}"

        Thread.join_children! limit, timeout: timeout

        # NOTE only one of them will return non-nil, see above
        stdout_r.read || stderr_r.read
      ensure
        process_dead! wait_thr, cmd_str, limit
      end
    end
  end
  thr.value
end