ffmprb 0.11.3 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +5 -5
  2. data/Dockerfile +18 -0
  3. data/Gemfile +8 -1
  4. data/Gemfile.lock +121 -0
  5. data/README.md +65 -21
  6. data/TODO.md +0 -0
  7. data/bin/dev +12 -0
  8. data/bin/test +13 -0
  9. data/coverage/assets/0.10.0/application.css +799 -0
  10. data/coverage/assets/0.10.0/application.js +1707 -0
  11. data/coverage/assets/0.10.0/colorbox/border.png +0 -0
  12. data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  13. data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  14. data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  15. data/coverage/assets/0.10.0/favicon_green.png +0 -0
  16. data/coverage/assets/0.10.0/favicon_red.png +0 -0
  17. data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  18. data/coverage/assets/0.10.0/loading.gif +0 -0
  19. data/coverage/assets/0.10.0/magnify.png +0 -0
  20. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  21. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  22. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  23. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  24. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  25. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  26. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  27. data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  28. data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  29. data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  30. data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  31. data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  32. data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  33. data/coverage/assets/0.10.2/application.css +799 -0
  34. data/coverage/assets/0.10.2/application.js +1707 -0
  35. data/coverage/assets/0.10.2/colorbox/border.png +0 -0
  36. data/coverage/assets/0.10.2/colorbox/controls.png +0 -0
  37. data/coverage/assets/0.10.2/colorbox/loading.gif +0 -0
  38. data/coverage/assets/0.10.2/colorbox/loading_background.png +0 -0
  39. data/coverage/assets/0.10.2/favicon_green.png +0 -0
  40. data/coverage/assets/0.10.2/favicon_red.png +0 -0
  41. data/coverage/assets/0.10.2/favicon_yellow.png +0 -0
  42. data/coverage/assets/0.10.2/loading.gif +0 -0
  43. data/coverage/assets/0.10.2/magnify.png +0 -0
  44. data/coverage/assets/0.10.2/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  45. data/coverage/assets/0.10.2/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  46. data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  47. data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  48. data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  49. data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  50. data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  51. data/coverage/assets/0.10.2/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  52. data/coverage/assets/0.10.2/smoothness/images/ui-icons_222222_256x240.png +0 -0
  53. data/coverage/assets/0.10.2/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  54. data/coverage/assets/0.10.2/smoothness/images/ui-icons_454545_256x240.png +0 -0
  55. data/coverage/assets/0.10.2/smoothness/images/ui-icons_888888_256x240.png +0 -0
  56. data/coverage/assets/0.10.2/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  57. data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc.png +0 -0
  58. data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  59. data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_both.png +0 -0
  60. data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc.png +0 -0
  61. data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  62. data/coverage/assets/0.12.2/application.css +1 -0
  63. data/coverage/assets/0.12.2/application.js +7 -0
  64. data/coverage/assets/0.12.2/colorbox/border.png +0 -0
  65. data/coverage/assets/0.12.2/colorbox/controls.png +0 -0
  66. data/coverage/assets/0.12.2/colorbox/loading.gif +0 -0
  67. data/coverage/assets/0.12.2/colorbox/loading_background.png +0 -0
  68. data/coverage/assets/0.12.2/favicon_green.png +0 -0
  69. data/coverage/assets/0.12.2/favicon_red.png +0 -0
  70. data/coverage/assets/0.12.2/favicon_yellow.png +0 -0
  71. data/coverage/assets/0.12.2/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  72. data/coverage/assets/0.12.2/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  73. data/coverage/assets/0.12.2/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  74. data/coverage/assets/0.12.2/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  75. data/coverage/assets/0.12.2/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  76. data/coverage/assets/0.12.2/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  77. data/coverage/assets/0.12.2/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  78. data/coverage/assets/0.12.2/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  79. data/coverage/assets/0.12.2/images/ui-icons_222222_256x240.png +0 -0
  80. data/coverage/assets/0.12.2/images/ui-icons_2e83ff_256x240.png +0 -0
  81. data/coverage/assets/0.12.2/images/ui-icons_454545_256x240.png +0 -0
  82. data/coverage/assets/0.12.2/images/ui-icons_888888_256x240.png +0 -0
  83. data/coverage/assets/0.12.2/images/ui-icons_cd0a0a_256x240.png +0 -0
  84. data/coverage/assets/0.12.2/loading.gif +0 -0
  85. data/coverage/assets/0.12.2/magnify.png +0 -0
  86. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc.png +0 -0
  87. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  88. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_both.png +0 -0
  89. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc.png +0 -0
  90. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  91. data/coverage/assets/0.12.3/application.css +1 -0
  92. data/coverage/assets/0.12.3/application.js +7 -0
  93. data/coverage/assets/0.12.3/colorbox/border.png +0 -0
  94. data/coverage/assets/0.12.3/colorbox/controls.png +0 -0
  95. data/coverage/assets/0.12.3/colorbox/loading.gif +0 -0
  96. data/coverage/assets/0.12.3/colorbox/loading_background.png +0 -0
  97. data/coverage/assets/0.12.3/favicon_green.png +0 -0
  98. data/coverage/assets/0.12.3/favicon_red.png +0 -0
  99. data/coverage/assets/0.12.3/favicon_yellow.png +0 -0
  100. data/coverage/assets/0.12.3/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  101. data/coverage/assets/0.12.3/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  102. data/coverage/assets/0.12.3/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  103. data/coverage/assets/0.12.3/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  104. data/coverage/assets/0.12.3/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  105. data/coverage/assets/0.12.3/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  106. data/coverage/assets/0.12.3/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  107. data/coverage/assets/0.12.3/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  108. data/coverage/assets/0.12.3/images/ui-icons_222222_256x240.png +0 -0
  109. data/coverage/assets/0.12.3/images/ui-icons_2e83ff_256x240.png +0 -0
  110. data/coverage/assets/0.12.3/images/ui-icons_454545_256x240.png +0 -0
  111. data/coverage/assets/0.12.3/images/ui-icons_888888_256x240.png +0 -0
  112. data/coverage/assets/0.12.3/images/ui-icons_cd0a0a_256x240.png +0 -0
  113. data/coverage/assets/0.12.3/loading.gif +0 -0
  114. data/coverage/assets/0.12.3/magnify.png +0 -0
  115. data/coverage/index.html +47324 -0
  116. data/exp/EXP +7 -0
  117. data/exp/av-cut-mp4you60.ffmprb +10 -0
  118. data/exp/docker-compose.yml +9 -0
  119. data/exp/gop-cut-cat-you60 +141 -0
  120. data/exp/present/Dockerfile +13 -0
  121. data/exp/present/Gemfile +3 -0
  122. data/exp/present/Gemfile.lock +22 -0
  123. data/exp/present/bin/up-deps +8 -0
  124. data/exp/present/docker-compose.yml +21 -0
  125. data/exp/present/exp/present +10 -0
  126. data/exp/present/exp/present.rb +37 -0
  127. data/exp/run +9 -0
  128. data/exp/stitch2.ffmprb +5 -0
  129. data/exp/unzip-mp4you60 +58 -0
  130. data/exp/youtubby/Dockerfile +13 -0
  131. data/exp/youtubby/Gemfile +7 -0
  132. data/exp/youtubby/Gemfile.lock +73 -0
  133. data/exp/youtubby/README.md +21 -0
  134. data/exp/youtubby/bin/up-deps +8 -0
  135. data/exp/youtubby/docker-compose.yml +20 -0
  136. data/exp/youtubby/exp/gop-raw-cut-you-HD60 +13 -0
  137. data/exp/youtubby/exp/gop-raw-cut-you-HD60.rb +230 -0
  138. data/exp/youtubby/exp/media-upload +13 -0
  139. data/exp/youtubby/exp/tmp/CURRENT +2 -0
  140. data/exp/youtubby/google_youtube.rb +39 -0
  141. data/exp/youtubby/old-ul.py +181 -0
  142. data/exp/youtubby/old-ul.rb +87 -0
  143. data/exp/youtubby/py-Dockerfile +11 -0
  144. data/exp/youtubby/py-docker-compose.yml +13 -0
  145. data/exp/youtubby/requirements.txt +19 -0
  146. data/exp/youtubby/upload.rb +38 -0
  147. data/exp/zip-cut-mp4you60 +42 -0
  148. data/exp/zip2mp4k60 +27 -0
  149. data/ffmprb.gemspec +34 -14
  150. data/lib/defaults.rb +6 -6
  151. data/lib/ffmprb/execution.rb +1 -1
  152. data/lib/ffmprb/file/sample.rb +2 -2
  153. data/lib/ffmprb/file/threaded_buffered.rb +4 -4
  154. data/lib/ffmprb/file.rb +20 -20
  155. data/lib/ffmprb/filter.rb +100 -61
  156. data/lib/ffmprb/find_silence.rb +5 -2
  157. data/lib/ffmprb/process/input/chain_base.rb +6 -4
  158. data/lib/ffmprb/process/input/channeled.rb +1 -1
  159. data/lib/ffmprb/process/input/cropped.rb +4 -1
  160. data/lib/ffmprb/process/input/cut.rb +2 -2
  161. data/lib/ffmprb/process/input/looping.rb +11 -16
  162. data/lib/ffmprb/process/input/loud.rb +1 -1
  163. data/lib/ffmprb/process/input/paced.rb +35 -0
  164. data/lib/ffmprb/process/input/postprocessed.rb +29 -0
  165. data/lib/ffmprb/process/input/reversed.rb +29 -0
  166. data/lib/ffmprb/process/input.rb +7 -3
  167. data/lib/ffmprb/process/output.rb +45 -29
  168. data/lib/ffmprb/process.rb +8 -9
  169. data/lib/ffmprb/util/proc_vis.rb +5 -4
  170. data/lib/ffmprb/util/thread.rb +13 -11
  171. data/lib/ffmprb/util/threaded_io_buffer.rb +25 -22
  172. data/lib/ffmprb/util.rb +38 -13
  173. data/lib/ffmprb/version.rb +2 -2
  174. data/lib/ffmprb.rb +8 -5
  175. data/tmp/exp/docker-compose.yml +9 -0
  176. data/tmp/exp/src/SAM_3132.MP4 +0 -0
  177. data/tmp/ffmprb-0.11.4.gem +0 -0
  178. data/tmp/output.rb +383 -0
  179. metadata +159 -139
  180. data/.gitignore +0 -10
  181. data/.rspec +0 -4
  182. data/.ruby-version +0 -1
  183. data/.travis.yml +0 -3
  184. data/circle.yml +0 -7
@@ -6,7 +6,7 @@ module Ffmprb
6
6
 
7
7
  # TODO the events mechanism is currently unused (and commented out) => synchro mechanism not needed
8
8
  class ThreadedIoBuffer
9
- # XXX include Synchro
9
+ # TODO? include Synchro
10
10
  include ProcVis::Node
11
11
 
12
12
  class << self
@@ -29,7 +29,7 @@ module Ffmprb
29
29
  def initialize(input, *outputs, keep_outputs_open_on_input_idle_limit: nil)
30
30
  super() # NOTE for the monitor, apparently
31
31
 
32
- Ffmprb.logger.debug "ThreadedIoBuffer initializing with (#{ThreadedIoBuffer.blocks_max}x#{ThreadedIoBuffer.block_size})"
32
+ Ffmprb.logger.debug{"ThreadedIoBuffer initializing with (#{ThreadedIoBuffer.blocks_max}x#{ThreadedIoBuffer.block_size})"}
33
33
 
34
34
  @input = input
35
35
  @outputs = outputs.map do |outp|
@@ -47,10 +47,11 @@ module Ffmprb
47
47
  end
48
48
 
49
49
  Thread.join_children!.tap do
50
- Ffmprb.logger.debug "ThreadedIoBuffer (#{@input.path}->#{@outputs.map(&:io).map(&:path)}) terminated successfully (#{stats})"
50
+ Ffmprb.logger.debug{"ThreadedIoBuffer (#{@input.path}->#{@outputs.map(&:io).map(&:path)}) terminated successfully (#{stats})"}
51
51
  end
52
52
  end
53
53
  end
54
+ # TODO?
54
55
  #
55
56
  # def once(event, &blk)
56
57
  # event = event.to_sym
@@ -58,17 +59,17 @@ module Ffmprb
58
59
  # if @events[event].respond_to? :call
59
60
  # fail Error, "Once upon a time (one #once(event) at a time) please"
60
61
  # elsif @events[event]
61
- # Ffmprb.logger.debug "ThreadedIoBuffer (post-)reacting to #{event}"
62
+ # Ffmprb.logger.debug{"ThreadedIoBuffer (post-)reacting to #{event}"}
62
63
  # @handler_thr = Util::Thread.new "#{event} handler", &blk
63
64
  # else
64
- # Ffmprb.logger.debug "ThreadedIoBuffer subscribing to #{event}"
65
+ # Ffmprb.logger.debug{"ThreadedIoBuffer subscribing to #{event}"}
65
66
  # @events[event] = blk
66
67
  # end
67
68
  # end
68
69
  # handle_synchronously :once
69
70
  #
70
71
  # def reader_done!
71
- # Ffmprb.logger.debug "ThreadedIoBuffer reader terminated (#{stats})"
72
+ # Ffmprb.logger.debug{"ThreadedIoBuffer reader terminated (#{stats})"}
72
73
  # fire! :reader_done
73
74
  # end
74
75
  #
@@ -84,7 +85,7 @@ module Ffmprb
84
85
  #
85
86
  # def fire!(event)
86
87
  # wait_for_handler!
87
- # Ffmprb.logger.debug "ThreadedIoBuffer firing #{event}"
88
+ # Ffmprb.logger.debug{"ThreadedIoBuffer firing #{event}"}
88
89
  # if blk = @events.to_h[event.to_sym]
89
90
  # @handler_thr = Util::Thread.new "#{event} handler", &blk
90
91
  # end
@@ -104,9 +105,9 @@ module Ffmprb
104
105
 
105
106
  def reader_input! # NOTE just for reader thread
106
107
  if @input.respond_to?(:call)
107
- Ffmprb.logger.debug "Opening buffer input"
108
+ Ffmprb.logger.debug{"Opening buffer input"}
108
109
  @input = @input.call
109
- Ffmprb.logger.debug "Opened buffer input: #{@input.path}"
110
+ Ffmprb.logger.debug{"Opened buffer input: #{@input.path}"}
110
111
  end
111
112
  @input
112
113
  end
@@ -137,17 +138,17 @@ module Ffmprb
137
138
  rescue IO::WaitReadable
138
139
  if @keep_outputs_open_on_input_idle_limit && stats.bytes_in > 0 && stats.blocks_buff == 0 && timeouts * ThreadedIoBuffer.io_wait_timeout > @keep_outputs_open_on_input_idle_limit
139
140
  if s.length > 0 # NOTE let's see if it helps outputting an incomplete block
140
- Ffmprb.logger.debug "ThreadedIoBuffer reader (from #{input_io.path}) giving a chance to write #{s.length}/#{ThreadedIoBuffer.block_size}b after waiting >#{@keep_outputs_open_on_input_idle_limit}s, after reading #{stats.bytes_in}b"
141
+ Ffmprb.logger.debug{"ThreadedIoBuffer reader (from #{input_io.path}) giving a chance to write #{s.length}/#{ThreadedIoBuffer.block_size}b after waiting >#{@keep_outputs_open_on_input_idle_limit}s, after reading #{stats.bytes_in}b"}
141
142
  break
142
143
  else
143
- Ffmprb.logger.debug "ThreadedIoBuffer reader (from #{input_io.path}) giving up after waiting >#{@keep_outputs_open_on_input_idle_limit}s, after reading #{stats.bytes_in}b, closing outputs"
144
+ Ffmprb.logger.debug{"ThreadedIoBuffer reader (from #{input_io.path}) giving up after waiting >#{@keep_outputs_open_on_input_idle_limit}s, after reading #{stats.bytes_in}b, closing outputs"}
144
145
  raise EOFError
145
146
  end
146
147
  else
147
148
  Thread.current.live!
148
149
  timeouts += 1
149
150
  if timeouts > 2 * logged_timeouts
150
- Ffmprb.logger.debug "ThreadedIoBuffer reader (from #{input_io.path}) retrying... (#{timeouts} reads): #{$!.class}"
151
+ Ffmprb.logger.debug{"ThreadedIoBuffer reader (from #{input_io.path}) retrying... (#{timeouts} reads): #{$!.class}"}
151
152
  logged_timeouts = timeouts
152
153
  end
153
154
  IO.select [input_io], nil, nil, ThreadedIoBuffer.io_wait_timeout
@@ -165,7 +166,7 @@ module Ffmprb
165
166
  output_enq! s
166
167
  end
167
168
  rescue EOFError
168
- Ffmprb.logger.debug "ThreadedIoBuffer reader (from #{input_io.path}) breaking off"
169
+ Ffmprb.logger.debug{"ThreadedIoBuffer reader (from #{input_io.path}) breaking off"}
169
170
  rescue AllOutputsBrokenError
170
171
  Ffmprb.logger.info "All outputs broken"
171
172
  rescue Exception
@@ -182,7 +183,7 @@ module Ffmprb
182
183
  Ffmprb.logger.error "#{$!.class.name} closing ThreadedIoBuffer input: #{$!.message}"
183
184
  end
184
185
  # reader_done!
185
- Ffmprb.logger.debug "ThreadedIoBuffer reader terminated (#{stats})"
186
+ Ffmprb.logger.debug{"ThreadedIoBuffer reader terminated (#{stats})"}
186
187
  end
187
188
  end
188
189
  end
@@ -191,13 +192,13 @@ module Ffmprb
191
192
  return output.io = output._io unless output._io.respond_to?(:call)
192
193
 
193
194
  output.thr = Thread.new("buffer writer output helper") do
194
- Ffmprb.logger.debug "Opening buffer output"
195
+ Ffmprb.logger.debug{"Opening buffer output"}
195
196
  output.io =
196
197
  Thread.timeout_or_live nil, log: "in the buffer writer helper thread", timeout: ThreadedIoBuffer.timeout do |time|
197
198
  fail Error, "giving up buffer writer init since the reader has failed (#{@reader_failed.message})" if @reader_failed
198
199
  output._io.call
199
200
  end
200
- Ffmprb.logger.debug "Opened buffer output: #{output.io.path}"
201
+ Ffmprb.logger.debug{"Opened buffer output: #{output.io.path}"}
201
202
  end
202
203
  end
203
204
 
@@ -223,7 +224,7 @@ module Ffmprb
223
224
  Thread.current.live!
224
225
  timeouts += 1
225
226
  if timeouts > 2 * logged_timeouts
226
- Ffmprb.logger.debug "ThreadedIoBuffer writer (to #{output_io.path}) retrying... (#{timeouts} writes): #{$!.class}"
227
+ Ffmprb.logger.debug{"ThreadedIoBuffer writer (to #{output_io.path}) retrying... (#{timeouts} writes): #{$!.class}"}
227
228
  logged_timeouts = timeouts
228
229
  end
229
230
  IO.select nil, [output_io], nil, ThreadedIoBuffer.io_wait_timeout
@@ -234,9 +235,9 @@ module Ffmprb
234
235
  retry
235
236
  end
236
237
  end
237
- Ffmprb.logger.debug "ThreadedIoBuffer writer (to #{output_io.path}) breaking off"
238
+ Ffmprb.logger.debug{"ThreadedIoBuffer writer (to #{output_io.path}) breaking off"}
238
239
  rescue Errno::EPIPE
239
- Ffmprb.logger.debug "ThreadedIoBuffer writer (to #{output_io.path}) broken"
240
+ Ffmprb.logger.debug{"ThreadedIoBuffer writer (to #{output_io.path}) broken"}
240
241
  output.broken = true
241
242
  ensure
242
243
  # terminated!
@@ -246,7 +247,7 @@ module Ffmprb
246
247
  Ffmprb.logger.error "#{$!.class.name} closing ThreadedIoBuffer output: #{$!.message}"
247
248
  end
248
249
  output.broken = true
249
- Ffmprb.logger.debug "ThreadedIoBuffer writer (to #{output_io && output_io.path}) terminated (#{stats})"
250
+ Ffmprb.logger.debug{"ThreadedIoBuffer writer (to #{output_io && output_io.path}) terminated (#{stats})"}
250
251
  end
251
252
  end
252
253
  end
@@ -279,9 +280,11 @@ module Ffmprb
279
280
  logged_timeouts = timeouts
280
281
  end
281
282
 
282
- retry unless timeouts >= ThreadedIoBuffer.timeout_limit # NOTE the queue has probably overflown
283
+ retry unless # NOTE the queue has probably overflown
284
+ timeouts >= ThreadedIoBuffer.timeout_limit
283
285
 
284
- @reader_failed ||= Error.new("the writer has failed with timeout limit while queuing") # NOTE screw the race condition
286
+ @reader_failed ||= # NOTE screw the race condition
287
+ Error.new("the writer has failed with timeout limit while queuing")
285
288
  # timeout!
286
289
  fail Error, "Looks like we're stuck (>#{ThreadedIoBuffer.timeout_limit*ThreadedIoBuffer.timeout}s idle) with #{ThreadedIoBuffer.blocks_max}x#{ThreadedIoBuffer.block_size}b blocks (buffering #{reader_input!.path}->...)..."
287
290
  end
data/lib/ffmprb/util.rb CHANGED
@@ -9,6 +9,8 @@ module Ffmprb
9
9
  class BrokenPipeError < Error; end
10
10
  class TimeLimitError < Error; end
11
11
 
12
+ FFMPEG_BROKEN_PIPE_ERROR_RE = /^.*\berror\b.*:.*\bbroken pipe\b.*$/i
13
+
12
14
  class << self
13
15
 
14
16
  attr_accessor :ffmpeg_cmd, :ffmpeg_inputs_max, :ffprobe_cmd
@@ -18,17 +20,25 @@ module Ffmprb
18
20
  sh *ffprobe_cmd, *args, limit: limit, timeout: timeout
19
21
  end
20
22
 
23
+ # TODO un-colorise ffmpeg output for logging, also, convert ^M into something
21
24
  def ffmpeg(*args, limit: nil, timeout: cmd_timeout, ignore_broken_pipes: true)
22
- args = ['-loglevel', 'debug'] + args if Ffmprb.ffmpeg_debug
23
- sh *ffmpeg_cmd, *args, output: :stderr, limit: limit, timeout: timeout, ignore_broken_pipes: ignore_broken_pipes
25
+ args = %w[-loglevel debug] + args if
26
+ Ffmprb.ffmpeg_debug
27
+ sh *ffmpeg_cmd, *args,
28
+ output: :stderr,
29
+ limit: limit,
30
+ timeout: timeout,
31
+ ignore_broken_pipes: ignore_broken_pipes,
32
+ broken_pipe_error_re: FFMPEG_BROKEN_PIPE_ERROR_RE
24
33
  end
25
34
 
26
- def sh(*cmd, input: nil, output: :stdout, limit: nil, timeout: cmd_timeout, ignore_broken_pipes: false)
35
+ def sh(*cmd, input: nil, output: :stdout, limit: nil, timeout: cmd_timeout, ignore_broken_pipes: false, broken_pipe_error_re: nil)
27
36
  cmd = cmd.map &:to_s unless cmd.size == 1
28
37
  cmd_str = cmd.size != 1 ? cmd.map{|c| sh_escape c}.join(' ') : cmd.first
38
+ cmd_log_line = "#{log_hash cmd_str}: `#{cmd_str}`"
29
39
  timeout = [timeout, limit].compact.min
30
- thr = Thread.new "`#{cmd_str}`" do
31
- Ffmprb.logger.info "Popening `#{cmd_str}`..."
40
+ thr = Thread.new cmd_log_line do
41
+ Ffmprb.logger.info "Popening #{cmd_log_line}..."
32
42
  Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
33
43
  begin
34
44
  stdin.write input if input
@@ -37,29 +47,33 @@ module Ffmprb
37
47
  log_cmd = cmd.first.upcase
38
48
  stdout_r = Reader.new(stdout, store: output == :stdout, log_with: log_cmd)
39
49
  stderr_r = Reader.new(stderr, store: true, log_with: log_cmd, log_as: output == :stderr && Logger::DEBUG || Logger::INFO)
50
+ stderr_s = nil
40
51
 
41
- Thread.timeout_or_live(limit, log: "while waiting for `#{cmd_str}`", timeout: timeout) do |time|
52
+ Thread.timeout_or_live(limit, log: "while waiting for #{cmd_log_line}", timeout: timeout) do |time|
42
53
  value = wait_thr.value
43
54
  status = value.exitstatus # NOTE blocking
44
55
  if status != 0
45
- if value.signaled? && value.termsig == Signal.list['PIPE']
56
+ stderr_s = stderr_r.read
57
+ if (value.signaled? && value.termsig == Signal.list['PIPE']) ||
58
+ # NOTE this doesn't seem to work for ffmpeg 4.x (it ignores SIGPIPEs)
59
+ (broken_pipe_error_re && status == 1 && stderr_s =~ broken_pipe_error_re)
46
60
  if ignore_broken_pipes
47
- Ffmprb.logger.info "Ignoring broken pipe: #{cmd_str}"
61
+ Ffmprb.logger.info "Ignoring broken pipe: #{cmd_log_line}"
48
62
  else
49
- fail BrokenPipeError, cmd_str
63
+ fail BrokenPipeError, cmd_log_line
50
64
  end
51
65
  else
52
66
  status ||= "sig##{value.termsig}"
53
- fail Error, "#{cmd_str} (#{status}):\n#{stderr_r.read}"
67
+ fail Error, "#{cmd_log_line} (#{status}):\n#{stderr_s}"
54
68
  end
55
69
  end
56
70
  end
57
- Ffmprb.logger.debug "FINISHED: #{cmd_str}"
71
+ Ffmprb.logger.debug{"FINISHED: #{cmd_log_line}"}
58
72
 
59
73
  Thread.join_children! limit, timeout: timeout
60
74
 
61
75
  # NOTE only one of them will return non-nil, see above
62
- stdout_r.read || stderr_r.read
76
+ stdout_r.read || stderr_s || stderr_r.read
63
77
  ensure
64
78
  process_dead! wait_thr, cmd_str, limit
65
79
  end
@@ -71,7 +85,18 @@ module Ffmprb
71
85
  def assert_options_empty!(opts)
72
86
  fail ArgumentError, "Unknown options: #{opts}" unless opts.empty?
73
87
  end
74
- protected
88
+
89
+ private
90
+
91
+ def log_hash(s)
92
+ n = s.hash
93
+ %w[bcdfghk aeiuy mnprqstvwxz].reduce '' do |hash, chars|
94
+ hash + chars[n % chars.length]
95
+ end
96
+ end
97
+
98
+ def broken_pipe_error_printed?(s)
99
+ end
75
100
 
76
101
  # NOTE a best guess kinda method
77
102
  def sh_escape(str)
@@ -1,8 +1,8 @@
1
1
  module Ffmprb
2
2
 
3
- VERSION = '0.11.3'
3
+ VERSION = '0.12.1'
4
4
 
5
- GEM_GITHUB_URL = 'https://github.com/showbox-oss/ffmprb'
5
+ GEM_GITHUB_URL = 'https://github.com/costa/ffmprb'
6
6
 
7
7
  FIREBASE_AVAILABLE =
8
8
  begin
data/lib/ffmprb.rb CHANGED
@@ -13,8 +13,10 @@ module Ffmprb
13
13
 
14
14
  CGA = '320x200'
15
15
  QVGA = '320x240'
16
+ HD_480p = '854x480'
16
17
  HD_720p = '1280x720'
17
18
  HD_1080p = '1920x1080'
19
+ HD_4K = '3840x2160'
18
20
 
19
21
  class << self
20
22
 
@@ -22,16 +24,17 @@ module Ffmprb
22
24
  def process(*args, name: nil, **opts, &blk)
23
25
  fail Error, "process: nothing ;( gimme a block!" unless blk
24
26
 
25
- name ||= blk.source_location.map(&:to_s).map{ |s| ::File.basename s.to_s, ::File.extname(s) }.join(':')
27
+ name ||= blk.source_location.map(&:to_s).map{ |s| File.basename s.to_s, File.extname(s) }.join(':')
26
28
  process = Process.new(name: name, **opts)
27
- proc_vis_node process if respond_to? :proc_vis_node # XXX simply include the ProcVis if it makes into a gem
28
- logger.debug "Starting process with #{args} #{opts} in #{blk.source_location}"
29
+ # TODO simply include the ProcVis if it makes into a gem
30
+ proc_vis_node process if respond_to? :proc_vis_node
31
+ logger.debug{"Starting process with #{args} #{opts} in #{blk.source_location}"}
29
32
 
30
33
  process.instance_exec *args, &blk
31
- logger.debug "Initialized process with #{args} #{opts} in #{blk.source_location}"
34
+ logger.debug{"Initialized process with #{args} #{opts} in #{blk.source_location}"}
32
35
 
33
36
  process.run.tap do
34
- logger.debug "Finished process with #{args} #{opts} in #{blk.source_location}"
37
+ logger.debug{"Finished process with #{args} #{opts} in #{blk.source_location}"}
35
38
  end
36
39
  end
37
40
  alias :action! :process # ;)
@@ -0,0 +1,9 @@
1
+ version: '2.1'
2
+ services:
3
+ tester:
4
+ build: ../..
5
+ volumes:
6
+ - ../..:/ffmprb
7
+ environment:
8
+ - FFMPRB_DEBUG=1
9
+ command: tmp/exp/src
Binary file
Binary file