Class: Ffmprb::Process

Inherits:
Object
  • Object
show all
Includes:
Util::ProcVis::Node
Defined in:
lib/ffmprb/process.rb,
lib/ffmprb/process/input.rb,
lib/ffmprb/process/output.rb,
lib/ffmprb/process/input/cut.rb,
lib/ffmprb/process/input/loud.rb,
lib/ffmprb/process/input/temp.rb,
lib/ffmprb/process/input/paced.rb,
lib/ffmprb/process/input/cropped.rb,
lib/ffmprb/process/input/looping.rb,
lib/ffmprb/process/input/reversed.rb,
lib/ffmprb/process/input/channeled.rb,
lib/ffmprb/process/input/chain_base.rb,
lib/ffmprb/process/input/postprocessed.rb

Defined Under Namespace

Classes: Input, Output

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes included from Util::ProcVis::Node

#_proc_vis

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::ProcVis::Node

#proc_vis_edge, #proc_vis_name, #proc_vis_node

Constructor Details

#initialize(*args, **opts) ⇒ Process

Returns a new instance of Process.



118
119
120
121
122
123
124
125
126
# File 'lib/ffmprb/process.rb', line 118

def initialize(*args, **opts)
  self.timeout = opts.delete(:timeout) || Process.timeout
  @name = opts.delete(:name)
  @parent = opts.delete(:parent)
  parent.proc_vis_node self  if parent
  self.ignore_broken_pipes = opts.delete(:ignore_broken_pipes)
  Util.assert_options_empty! opts
  @inputs, @outputs = [], []
end

Class Attribute Details

.duck_audio_silent_minObject

Returns the value of attribute duck_audio_silent_min.



10
11
12
# File 'lib/ffmprb/process.rb', line 10

def duck_audio_silent_min
  @duck_audio_silent_min
end

.duck_audio_transition_in_startObject

Returns the value of attribute duck_audio_transition_in_start.



12
13
14
# File 'lib/ffmprb/process.rb', line 12

def duck_audio_transition_in_start
  @duck_audio_transition_in_start
end

.duck_audio_transition_lengthObject

Returns the value of attribute duck_audio_transition_length.



12
13
14
# File 'lib/ffmprb/process.rb', line 12

def duck_audio_transition_length
  @duck_audio_transition_length
end

.duck_audio_transition_out_startObject

Returns the value of attribute duck_audio_transition_out_start.



12
13
14
# File 'lib/ffmprb/process.rb', line 12

def duck_audio_transition_out_start
  @duck_audio_transition_out_start
end

.duck_audio_volume_hiObject

Returns the value of attribute duck_audio_volume_hi.



10
11
12
# File 'lib/ffmprb/process.rb', line 10

def duck_audio_volume_hi
  @duck_audio_volume_hi
end

.duck_audio_volume_loObject

Returns the value of attribute duck_audio_volume_lo.



10
11
12
# File 'lib/ffmprb/process.rb', line 10

def duck_audio_volume_lo
  @duck_audio_volume_lo
end

.input_video_auto_rotateObject

Returns the value of attribute input_video_auto_rotate.



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

def input_video_auto_rotate
  @input_video_auto_rotate
end

.input_video_fpsObject

Returns the value of attribute input_video_fps.



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

def input_video_fps
  @input_video_fps
end

.output_audio_encoderObject

Returns the value of attribute output_audio_encoder.



20
21
22
# File 'lib/ffmprb/process.rb', line 20

def output_audio_encoder
  @output_audio_encoder
end

.output_audio_sampling_freqObject

Returns the value of attribute output_audio_sampling_freq.



21
22
23
# File 'lib/ffmprb/process.rb', line 21

def output_audio_sampling_freq
  @output_audio_sampling_freq
end

.output_video_fpsObject

Returns the value of attribute output_video_fps.



19
20
21
# File 'lib/ffmprb/process.rb', line 19

def output_video_fps
  @output_video_fps
end

.output_video_resolutionObject

Returns the value of attribute output_video_resolution.



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

def output_video_resolution
  @output_video_resolution
end

.timeoutObject

Returns the value of attribute timeout.



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

def timeout
  @timeout
end

Instance Attribute Details

#ignore_broken_pipesObject

Returns the value of attribute ignore_broken_pipes.



116
117
118
# File 'lib/ffmprb/process.rb', line 116

def ignore_broken_pipes
  @ignore_broken_pipes
end

#nameObject

Returns the value of attribute name.



114
115
116
# File 'lib/ffmprb/process.rb', line 114

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



115
116
117
# File 'lib/ffmprb/process.rb', line 115

def parent
  @parent
end

#timeoutObject

Returns the value of attribute timeout.



113
114
115
# File 'lib/ffmprb/process.rb', line 113

def timeout
  @timeout
end

Class Method Details

.duck_audio(av_main_i, a_overlay_i, silence, av_main_o, volume_lo: duck_audio_volume_lo, volume_hi: duck_audio_volume_hi, silent_min: duck_audio_silent_min, process_options: {}, video:, audio:) ⇒ Object

NOTE Temporarily, av_main_i/o and not a_main_i/o



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
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ffmprb/process.rb', line 65

def duck_audio(av_main_i, a_overlay_i, silence, av_main_o,
  volume_lo: duck_audio_volume_lo,
  volume_hi: duck_audio_volume_hi,
  silent_min: duck_audio_silent_min,
  process_options: {},
  video:,  # NOTE Temporarily, video should not be here
  audio:
  )
  Ffmprb.process **process_options do

    in_main = input(av_main_i)
    in_over = input(a_overlay_i)
    output(av_main_o, video: video, audio: audio) do
      roll in_main

      ducked_overlay_volume = {0.0 => volume_lo}
      silence.each do |silent|
        next  if silent.end_at && silent.start_at && (silent.end_at - silent.start_at) < silent_min

        if silent.start_at
          transition_in_start = silent.start_at + Process.duck_audio_transition_in_start
          ducked_overlay_volume.merge!(
            [transition_in_start, 0.0].max => volume_lo,
            (transition_in_start + Process.duck_audio_transition_length) => volume_hi
          )
        end

        if silent.end_at
          transition_out_start = silent.end_at + Process.duck_audio_transition_out_start
          ducked_overlay_volume.merge!(
            [transition_out_start, 0.0].max => volume_hi,
            (transition_out_start + Process.duck_audio_transition_length) => volume_lo
          )
        end
      end
      overlay in_over.volume ducked_overlay_volume

      Ffmprb.logger.debug{
        ducked_overlay_volume_map = ducked_overlay_volume.map{|t,v| "#{t}: #{v}"}
        "Ducking audio with volumes: {#{ducked_overlay_volume_map.join ', '}}"
      }
    end

  end
end

.input_audio_optionsObject



47
48
49
50
# File 'lib/ffmprb/process.rb', line 47

def input_audio_options
  {
  }
end

.input_video_optionsObject



41
42
43
44
45
46
# File 'lib/ffmprb/process.rb', line 41

def input_video_options
  {
    auto_rotate: input_video_auto_rotate,
    fps: input_video_fps  # TODO seen failing on apng (w/ffmpeg v4.x)
  }
end

.intermediate_channel_extname(video:, audio:) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/ffmprb/process.rb', line 25

def intermediate_channel_extname(video:, audio:)
  if video
    if audio
      '.flv'  # TODO optimise this by using http://superuser.com/a/522853 or something
    else
      '.y4m'
    end
  else
    if audio
      '.wav'
    else
      fail Error, "I don't know how to channel [#{media.join ', '}]"
    end
  end
end

.output_audio_optionsObject



57
58
59
60
61
62
# File 'lib/ffmprb/process.rb', line 57

def output_audio_options
  {
    encoder: output_audio_encoder,
    sampling_freq: output_audio_sampling_freq
  }
end

.output_video_optionsObject



51
52
53
54
55
56
# File 'lib/ffmprb/process.rb', line 51

def output_video_options
  {
    fps: output_video_fps,
    resolution: output_video_resolution
  }
end

Instance Method Details

#input(io, video: true, audio: true) ⇒ Object



128
129
130
131
132
133
134
135
136
137
# File 'lib/ffmprb/process.rb', line 128

def input(io, video: true, audio: true)
  Input.new(io, self,
    video: channel_params(video, Process.input_video_options),
    audio: channel_params(audio, Process.input_audio_options)
  ).tap do |inp|
    fail Error, "Too many inputs to the process, try breaking it down somehow"  if @inputs.size > Util.ffmpeg_inputs_max
    @inputs << inp
    proc_vis_edge inp.io, self
  end
end

#input_label(input) ⇒ Object

TODO …or… “output label”! (implement intermediate “outputs” through this)



140
141
142
# File 'lib/ffmprb/process.rb', line 140

def input_label(input)
  @inputs.index input
end

#output(io, video: true, audio: true, &blk) ⇒ Object



144
145
146
147
148
149
150
151
152
153
# File 'lib/ffmprb/process.rb', line 144

def output(io, video: true, audio: true, &blk)
  Output.new(io, self,
    video: channel_params(video, Process.output_video_options),
    audio: channel_params(audio, Process.output_audio_options)
  ).tap do |outp|
    @outputs << outp
    proc_vis_edge self, outp.io
    outp.instance_exec &blk  if blk
  end
end

#output_index(output) ⇒ Object



155
156
157
# File 'lib/ffmprb/process.rb', line 155

def output_index(output)
  @outputs.index output
end

#run(limit: nil) ⇒ Object

NOTE the one and the only entry-point processing function which spawns threads etc



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/ffmprb/process.rb', line 160

def run(limit: nil)  # TODO (async: false)
  # NOTE this is both for the future async: option and according to
  # the threading policy (a parent death will be noticed and handled by children)
  thr = Util::Thread.new main: !parent do
    proc_vis_node Thread.current
    # NOTE yes, an exception can occur anytime, and we'll just die, it's ok, see above
    command do |cmd|
      opts = {limit: limit, timeout: timeout}
      opts[:ignore_broken_pipes] = ignore_broken_pipes  unless ignore_broken_pipes.nil?
      Util.ffmpeg(*cmd, **opts).tap do |res|
        Util::Thread.join_children! limit, timeout: timeout
      end
    end
    proc_vis_node Thread.current, :remove
  end
  thr.value  if thr.join limit  # NOTE should not block for more than limit
end