mediakit 0.0.12 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee3e85010075e5c0cc67eb59f16716b958a69d72
4
- data.tar.gz: 51f35a2e74284eff387a63e51970626d8b56272b
3
+ metadata.gz: 00fe5dc8bf1a3f9d14614c1ae42ccdccf3f7941b
4
+ data.tar.gz: 660ba4fe4cae816c0c30e05e340dbdd8a299dd4f
5
5
  SHA512:
6
- metadata.gz: 40389b44e91057cba2e806a69aa4b361c7b8d7758b9d4217cb985c6047d4b2db0eaf6acaa0e3ae84971a15f4d926a7623beb1a034f2d0556b452aa8a5d119682
7
- data.tar.gz: 21c2f0a2a669050440b07a83cfef0aef310b3d520e2b5e5315bf9f91bebd402d18062cc3a74e651233c6c103bf82cf62fc887cb8b108dd7ddf33da7a174460d5
6
+ metadata.gz: 19923e14f8f23410b9b6a202c53287f8ad6dbd70d93f695ddd74e5f612382d8353a15a0c8ec0bab49665367213ef502ab5ef32d59eeec7849357ea0d265ae4cd
7
+ data.tar.gz: 4779b3998cac878a698f9d3885df1e9ff00aef8de93c7fbd37f7ba7a40f37c26ece71059d22ca464b01409ee8ac6c7a177fe9367009d2767ffda1c770a967306
data/.codeclimate.yml ADDED
@@ -0,0 +1,8 @@
1
+ # Save as .codeclimate.yml (note leading .) in project root directory
2
+ languages:
3
+ Ruby: true
4
+ JavaScript: true
5
+ PHP: true
6
+ Python: true
7
+ # exclude_paths:
8
+ # - "foo/bar.rb"
data/.gitignore CHANGED
@@ -8,4 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /.idea
11
- out.mp4
11
+ out.*
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mediakit
2
2
 
3
- [![Circle CI](https://circleci.com/gh/ainame/mediakit/tree/master.svg?style=svg)](https://circleci.com/gh/ainame/mediakit/tree/master)
3
+ [![Circle CI](https://circleci.com/gh/ainame/mediakit/tree/master.svg?style=svg)](https://circleci.com/gh/ainame/mediakit/tree/master) [![Code Climate](https://codeclimate.com/github/ainame/mediakit/badges/gpa.svg)](https://codeclimate.com/github/ainame/mediakit)
4
4
 
5
5
  mediakit is the libraries for ffmpeg and sox backed media manipulation something.
6
6
  I've design this library for following purpose.
@@ -13,13 +13,14 @@ I've design this library for following purpose.
13
13
  Currently you can use low-level inteface of mediakit!
14
14
 
15
15
  * [x] low-level interface
16
- * [x] execute command for ffmpeg
16
+ * [x] execute command for ffmpeg as a code
17
17
  * [x] unit testing supports (fake driver)
18
18
  * [x] nice command setting
19
19
  * [x] read timeout setting
20
20
  * [x] shell escape for security
21
21
  * [x] ffmpeg instropection (retrive supported formats, codecs, encoders and decoders)
22
22
  * [x] logger support
23
+ * [x] formats, codecs, encoders and decoders representation as a code
23
24
  * [ ] low-level ffprobe interface
24
25
  * [ ] high-level interface for ffmpeg
25
26
  * [ ] low-level interface for sox
@@ -124,7 +125,25 @@ assert_equal(exit_status, true)
124
125
  fake_driver.reset
125
126
  ```
126
127
 
128
+ ### Formats/Codecs/Decoders/Encoders
127
129
 
130
+ FFmpeg has so many formats, codecs, decoders and encoders.
131
+ So, mediakit provide constant values for presenting those resources as a code.
132
+
133
+ ```rb
134
+ ffmpeg = Mediakit::FFmpeg.create
135
+ ffmpeg.init
136
+
137
+ # can use after call Mediakit::FFmpeg#init
138
+ Mediakit::FFmpeg::AudioCodec::CODEC_MP3 #=> #<Mediakit::FFmpeg::AudioCodec:0x007fb514040ad0>
139
+ Mediakit::FFmpeg::AudioCodec::CODEC_MP3.name #=> "mp3"
140
+ Mediakit::FFmpeg::AudioCodec::CODEC_MP3.desc #=> "MP3 (MPEG audio layer 3)"
141
+ ...
142
+
143
+ ```
144
+
145
+ These values reflect your ffmpeg binary build conditions by automate.
146
+ `Mediakit::FFmpeg::AudioCodec::CODEC_MP3` is just a instance of Mediakit::FFmpeg::AudioCodec class.
128
147
  ### High Level Interface
129
148
 
130
149
  TBD
data/bin/console CHANGED
@@ -10,5 +10,7 @@ require "mediakit"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
+ ffmpeg = Mediakit::FFmpeg.create
14
+ ffmpeg.init
13
15
  require "pry"
14
16
  Pry.start
@@ -1,5 +1,4 @@
1
- require 'shellwords'
2
- require 'mediakit/utils/process_runner'
1
+ require 'mediakit/process/runner'
3
2
 
4
3
  module Mediakit
5
4
  module Drivers
@@ -34,12 +33,12 @@ module Mediakit
34
33
  # @return [String] stdout output
35
34
  def run(*args)
36
35
  options, rest_args = parse_options(args.dup)
37
- runner = Mediakit::Utils::ProcessRunner.new(options)
36
+ runner = Mediakit::Process::Runner.new(options)
38
37
  begin
39
38
  stdout, stderr, exit_status = runner.run(bin, *rest_args)
40
39
  raise(FailError, stderr) unless exit_status
41
40
  stdout
42
- rescue Mediakit::Utils::ProcessRunner::CommandNotFoundError => e
41
+ rescue Mediakit::Process::Runner::CommandNotFoundError => e
43
42
  raise(ConfigurationError, "cant' find bin in #{bin}.")
44
43
  end
45
44
  end
@@ -53,7 +52,7 @@ module Mediakit
53
52
  # @return [String] command
54
53
  def command(*args)
55
54
  options, rest_args = parse_options(args.dup)
56
- runner = Mediakit::Utils::ProcessRunner.new(options)
55
+ runner = Mediakit::Process::Runner.new(options)
57
56
  runner.build_command(bin, *rest_args)
58
57
  end
59
58
 
@@ -24,10 +24,12 @@ module Mediakit
24
24
  return if option.nil?
25
25
  case option
26
26
  when GlobalOption
27
+ raise(ArgumentError, 'you can give only a GlobalOption.') if @global
27
28
  set_global(option)
28
29
  when InputFileOption
29
30
  add_input(option)
30
31
  when OutputFileOption
32
+ raise(ArgumentError, 'you can give only a OutputFileOption.') if @output
31
33
  set_output(option)
32
34
  else
33
35
  raise(ArgumentError)
@@ -96,6 +98,12 @@ module Mediakit
96
98
  end
97
99
 
98
100
  class GlobalOption < OrderedHash
101
+ def initialize(options = {})
102
+ if options.values.any? { |x| x.kind_of?(Hash) }
103
+ raise(ArgumentError, 'you can\'t give nested Hash in GlobalOption')
104
+ end
105
+ super
106
+ end
99
107
  end
100
108
 
101
109
  class OptionPathPair
@@ -1,17 +1,27 @@
1
1
  require 'mediakit/drivers'
2
2
  require 'mediakit/ffmpeg/options'
3
+ require 'mediakit/utils/constant_factory'
3
4
 
4
5
  module Mediakit
5
6
  class FFmpeg
6
- class FFmpegError < StandardError; end
7
+ class FFmpegError < StandardError;
8
+ end
9
+
10
+ attr_reader(:codecs, :formats, :decoders, :encoders)
7
11
 
8
- attr_accessor(:codecs, :formats, :decoders, :encoders)
12
+ def self.create(driver = Mediakit::Drivers::FFmpeg.new)
13
+ @ffmpeg ||= new(driver)
14
+ end
9
15
 
10
16
  def initialize(driver)
11
- @driver = driver
17
+ @driver = driver
12
18
  @codecs, @formats, @decoders, @encoders = [], [], [], []
13
19
  end
14
20
 
21
+ def init
22
+ Mediakit::Initializers::FFmpeg.setup(self)
23
+ end
24
+
15
25
  # execute runners with options object
16
26
  #
17
27
  # @param [Mediakit::Runners::FFmpeg::Options] options options to create CLI argument
@@ -25,20 +35,74 @@ module Mediakit
25
35
  @driver.command(args, driver_options)
26
36
  end
27
37
 
28
- Codec = Struct.new(:name, :desc, :type, :decode, :encode, :decoders, :encoders, :intra_frame, :lossy, :lossless) do |klass|
29
- def to_s; name; end
38
+ module BaseTypeMatcher
39
+ def self.included(included_class)
40
+ define_method(:===) do |other|
41
+ return true if included_class::Base >= other
42
+ false
43
+ end
44
+
45
+ included_class.send(:module_function, :===)
46
+ end
47
+ end
48
+
49
+ class Format
50
+ def self.using_attributes
51
+ [:name, :desc, :demuxing, :muxing]
52
+ end
53
+
54
+ include Utils::ConstantFactory
55
+ end
56
+
57
+ class Codec
58
+ def self.using_attributes
59
+ [:name, :desc, :type, :decode, :encode, :decoders, :encoders, :intra_frame, :lossy, :lossless]
60
+ end
61
+
62
+ include Utils::ConstantFactory
63
+ end
64
+
65
+ class AudioCodec < Codec
66
+ end
67
+
68
+ class VideoCodec < Codec
69
+ end
70
+
71
+ class SubtitleCodec < Codec
72
+ end
73
+
74
+ class Encoder
75
+ def self.using_attributes
76
+ [:name, :desc, :type, :frame_level, :slice_level, :experimental, :horizon_band, :direct_rendering_method]
77
+ end
78
+
79
+ include Utils::ConstantFactory
80
+ end
81
+
82
+ class AudioEncoder < Encoder
83
+ end
84
+
85
+ class VideoEncoder < Encoder
86
+ end
87
+
88
+ class SubtitleEncoder < Encoder
89
+ end
90
+
91
+ class Decoder
92
+ def self.using_attributes
93
+ [:name, :desc, :type, :frame_level, :slice_level, :experimental, :horizon_band, :direct_rendering_method]
94
+ end
95
+
96
+ include Utils::ConstantFactory
30
97
  end
31
98
 
32
- Format = Struct.new(:name, :desc, :demuxing, :muxing) do |klass|
33
- def to_s; name; end
99
+ class AudioDecoder < Decoder
34
100
  end
35
101
 
36
- Encoder = Struct.new(:name, :desc, :type, :frame_level, :slice_level, :experimental, :horizon_band, :direct_rendering_method) do |klass|
37
- def to_s; name; end
102
+ class VideoDecoder < Decoder
38
103
  end
39
104
 
40
- Decoder = Struct.new(:name, :desc, :type, :frame_level, :slice_level, :experimental, :horizon_band, :direct_rendering_method) do |klass|
41
- def to_s; name; end
105
+ class SubtitleDecoder < Decoder
42
106
  end
43
107
  end
44
108
  end
@@ -3,6 +3,16 @@ require 'active_support/core_ext/string/inflections'
3
3
  module Mediakit
4
4
  module Initializers
5
5
  class FFmpeg
6
+ def self.setup(ffmpeg)
7
+ Mediakit::Initializers::FFmpeg::FormatInitializer.new(ffmpeg).call
8
+ Mediakit::Initializers::FFmpeg::DecoderInitializer.new(ffmpeg).call
9
+ Mediakit::Initializers::FFmpeg::EncoderInitializer.new(ffmpeg).call
10
+ Mediakit::Initializers::FFmpeg::CodecInitializer.new(ffmpeg).call
11
+ end
12
+
13
+ class UnknownTypeError < StandardError
14
+ end
15
+
6
16
  class Base
7
17
  attr_reader :items
8
18
 
@@ -12,6 +22,7 @@ module Mediakit
12
22
 
13
23
  def call
14
24
  @command.send(item_type).concat(parse_items)
25
+ @command.send(item_type).freeze
15
26
  end
16
27
 
17
28
  def item_type
@@ -37,49 +48,6 @@ module Mediakit
37
48
  end
38
49
  end
39
50
 
40
- class CodecInitializer < Base
41
- DELIMITER_FOR_CODECS = "\n -------\n".freeze
42
- SUPPORT_PATTERN = /(?<support>(?<decode>[D.])(?<encode>[E.])(?<type>[VAS.])(?<intra_frame>[I.])(?<lossy>[L.])(?<lossless>[S.]))/.freeze
43
- DESCRIPTION_PATTERN = /.*?( \(decoders: (?<decoders>.+?) \)| \(encoders: (?<encoders>.+?) \))*/.freeze
44
- PATTERN = /\A\s*#{SUPPORT_PATTERN}\s+(?<name>\w+)\s+(?<desc>(#{DESCRIPTION_PATTERN}))\z/.freeze
45
-
46
- def item_type
47
- 'codecs'
48
- end
49
-
50
- def raw_items
51
- options = Mediakit::FFmpeg::Options.new(Mediakit::FFmpeg::Options::GlobalOption.new('codecs' => true))
52
- output, _, _ = @command.run(options)
53
- return [] if output.nil? || output.empty?
54
- output.split(DELIMITER_FOR_CODECS)[1].each_line.to_a
55
- end
56
-
57
- def create_item(line)
58
- match = line.match(PATTERN)
59
- if match
60
- type = case match[:type]
61
- when "A"
62
- :audio
63
- when "V"
64
- :video
65
- when "S"
66
- :subtitle
67
- else
68
- :unknown
69
- end
70
- decode = match[:decode] != '.'
71
- encode = match[:encode] != '.'
72
- decoders = match[:decoders] ? match[:decoders].split(' ') : (decode ? [match[:name]] : nil)
73
- encoders = match[:encoders] ? match[:encoders].split(' ') : (encode ? [match[:name]] : nil)
74
- intra_frame = match[:intra_frame] != '.'
75
- lossy = match[:lossy] != '.'
76
- lossless = match[:lossless] != '.'
77
-
78
- Mediakit::FFmpeg::Codec.new(match[:name], match[:desc], type, decode, encode, decoders, encoders, intra_frame, lossy, lossless)
79
- end
80
- end
81
- end
82
-
83
51
  class FormatInitializer < Base
84
52
  DELIMITER_FOR_FORMATS = "\n --\n".freeze
85
53
  SUPPORT_PATTERN = /(?<support>(?<demuxing>[D.\s])(?<muxing>[E.\s]))/.freeze
@@ -91,7 +59,7 @@ module Mediakit
91
59
 
92
60
  def raw_items
93
61
  options = Mediakit::FFmpeg::Options.new(Mediakit::FFmpeg::Options::GlobalOption.new('formats' => true))
94
- output, _, _ = @command.run(options)
62
+ output, _, _ = @command.run(options, logger: nil)
95
63
  return [] if output.nil? || output.empty?
96
64
  output.split(DELIMITER_FOR_FORMATS)[1].each_line.to_a
97
65
  end
@@ -99,10 +67,15 @@ module Mediakit
99
67
  def create_item(line)
100
68
  match = line.match(PATTERN)
101
69
  if match
102
- demuxing = match[:demuxing] == 'D'
103
- muxing = match[:muxing] == 'E'
104
-
105
- Mediakit::FFmpeg::Format.new(match[:name], match[:desc], demuxing, muxing)
70
+ attributes = {
71
+ name: match[:name],
72
+ desc: match[:desc],
73
+ demuxing: match[:demuxing] == 'D',
74
+ muxing: match[:muxing] == 'E'
75
+ }
76
+ Mediakit::FFmpeg::Format.create_constant(
77
+ "FORMAT_#{attributes[:name].underscore.upcase}", attributes
78
+ )
106
79
  end
107
80
  end
108
81
  end
@@ -128,7 +101,7 @@ module Mediakit
128
101
 
129
102
  def raw_items
130
103
  options = Mediakit::FFmpeg::Options.new(Mediakit::FFmpeg::Options::GlobalOption.new('decoders' => true))
131
- output, _, _ = @command.run(options)
104
+ output, _, _ = @command.run(options, logger: nil)
132
105
  return [] if output.nil? || output.empty?
133
106
  output.split(DELIMITER_FOR_CODER)[1].each_line.to_a
134
107
  end
@@ -136,23 +109,31 @@ module Mediakit
136
109
  def create_item(line)
137
110
  match = line.match(PATTERN)
138
111
  if match
139
- type = case match[:type]
140
- when 'V'
141
- :video
142
- when 'A'
143
- :audio
144
- when 'S'
145
- :subtitle
146
- else
147
- :unknown
148
- end
149
- frame_leval = match[:frame_level] != '.'
150
- slice_leval = match[:slice_level] != '.'
151
- experimental = match[:experimental] != '.'
152
- horizon_band = match[:horizon_band] != '.'
153
- direct_rendering_method = match[:direct_rendering_method] != '.'
154
-
155
- Mediakit::FFmpeg::Decoder.new(match[:name], match[:desc], type, frame_leval, slice_leval, experimental, horizon_band, direct_rendering_method)
112
+ attributes = {
113
+ name: match[:name],
114
+ desc: match[:desc],
115
+ frame_level: match[:frame_level] != '.',
116
+ slice_level: match[:slice_level] != '.',
117
+ experimental: match[:experimental] != '.',
118
+ horizon_band: match[:horizon_band] != '.',
119
+ direct_rendering_method: match[:direct_rendering_method] != '.'
120
+ }
121
+ case match[:type]
122
+ when 'V'
123
+ Mediakit::FFmpeg::VideoDecoder.create_constant(
124
+ "DECODER_#{attributes[:name].underscore.upcase}", attributes.merge(type: :video)
125
+ )
126
+ when 'A'
127
+ Mediakit::FFmpeg::AudioDecoder.create_constant(
128
+ "DECODER_#{attributes[:name].underscore.upcase}", attributes.merge(type: :audio)
129
+ )
130
+ when 'S'
131
+ Mediakit::FFmpeg::SubtitleDecoder.create_constant(
132
+ "DECODER_#{attributes[:name].underscore.upcase}", attributes.merge(type: :subtitle)
133
+ )
134
+ else
135
+ raise(UnknownTypeError)
136
+ end
156
137
  end
157
138
  end
158
139
  end
@@ -178,7 +159,7 @@ module Mediakit
178
159
 
179
160
  def raw_items
180
161
  options = Mediakit::FFmpeg::Options.new(Mediakit::FFmpeg::Options::GlobalOption.new('encoders' => true))
181
- output, _, _ = @command.run(options)
162
+ output, _, _ = @command.run(options, logger: nil)
182
163
  return [] if output.nil? || output.empty?
183
164
  output.split(DELIMITER_FOR_CODER)[1].each_line.to_a
184
165
  end
@@ -186,23 +167,95 @@ module Mediakit
186
167
  def create_item(line)
187
168
  match = line.match(PATTERN)
188
169
  if match
189
- type = case match[:type]
190
- when 'V'
191
- :video
192
- when 'A'
193
- :audio
194
- when 'S'
195
- :subtitle
196
- else
197
- :unknown
198
- end
199
- frame_level = match[:frame_level] != '.'
200
- slice_level = match[:slice_level] != '.'
201
- experimental = match[:experimental] != '.'
202
- horizon_band = match[:horizon_band] != '.'
203
- direct_rendering_method = match[:direct_rendering_method] != '.'
204
-
205
- Mediakit::FFmpeg::Encoder.new(match[:name], match[:desc], type, frame_level, slice_level, experimental, horizon_band, direct_rendering_method)
170
+ attributes = {
171
+ name: match[:name],
172
+ desc: match[:desc],
173
+ frame_level: match[:frame_level] != '.',
174
+ slice_level: match[:slice_level] != '.',
175
+ experimental: match[:experimental] != '.',
176
+ horizon_band: match[:horizon_band] != '.',
177
+ direct_rendering_method: match[:direct_rendering_method] != '.'
178
+ }
179
+
180
+ case match[:type]
181
+ when 'V'
182
+ Mediakit::FFmpeg::VideoEncoder.create_constant(
183
+ "ENCODER_#{attributes[:name].underscore.upcase}", attributes.merge(type: :video)
184
+ )
185
+ when 'A'
186
+ Mediakit::FFmpeg::AudioEncoder.create_constant(
187
+ "ENCODER_#{attributes[:name].underscore.upcase}", attributes.merge(type: :audio)
188
+ )
189
+ when 'S'
190
+ Mediakit::FFmpeg::SubtitleEncoder.create_constant(
191
+ "ENCODER_#{attributes[:name].underscore.upcase}", attributes.merge(type: :subtitle)
192
+ )
193
+ else
194
+ raise(UnknownTypeError)
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ class CodecInitializer < Base
201
+ DELIMITER_FOR_CODECS = "\n -------\n".freeze
202
+ SUPPORT_PATTERN = /(?<support>(?<decode>[D.])(?<encode>[E.])(?<type>[VAS.])(?<intra_frame>[I.])(?<lossy>[L.])(?<lossless>[S.]))/.freeze
203
+ DESCRIPTION_PATTERN = /.*?( \(decoders: (?<decoders>.+?) \)| \(encoders: (?<encoders>.+?) \))*/.freeze
204
+ PATTERN = /\A\s*#{SUPPORT_PATTERN}\s+(?<name>\w+)\s+(?<desc>(#{DESCRIPTION_PATTERN}))\z/.freeze
205
+
206
+ def item_type
207
+ 'codecs'
208
+ end
209
+
210
+ def raw_items
211
+ options = Mediakit::FFmpeg::Options.new(Mediakit::FFmpeg::Options::GlobalOption.new('codecs' => true))
212
+ output, _, _ = @command.run(options, logger: nil)
213
+ return [] if output.nil? || output.empty?
214
+ output.split(DELIMITER_FOR_CODECS)[1].each_line.to_a
215
+ end
216
+
217
+ def find_decoders(decoders)
218
+ return unless decoders
219
+ decoders.map { |name| @command.decoders.find { |decoder| decoder.name == name } }
220
+ end
221
+
222
+ def find_encoders(encoders)
223
+ return unless encoders
224
+ encoders.map { |name| @command.encoders.find { |encoder| encoder.name == name } }
225
+ end
226
+
227
+ def create_item(line)
228
+ match = line.match(PATTERN)
229
+ if match
230
+ decode = match[:decode] != '.'
231
+ encode = match[:encode] != '.'
232
+ attributes = {
233
+ name: match[:name],
234
+ desc: match[:desc],
235
+ decode: decode,
236
+ encode: encode,
237
+ decoders: find_decoders(match[:decoders] ? match[:decoders].split(' ') : (decode ? [match[:name]] : nil)),
238
+ encoders: find_encoders(match[:encoders] ? match[:encoders].split(' ') : (encode ? [match[:name]] : nil)),
239
+ intra_frame: match[:intra_frame] != '.',
240
+ lossy: match[:lossy] != '.',
241
+ lossless: match[:lossless] != '.'
242
+ }
243
+ case match[:type]
244
+ when 'V'
245
+ Mediakit::FFmpeg::VideoCodec.create_constant(
246
+ "CODEC_#{attributes[:name].underscore.upcase}", attributes.merge(type: :video)
247
+ )
248
+ when 'A'
249
+ Mediakit::FFmpeg::AudioCodec.create_constant(
250
+ "CODEC_#{attributes[:name].underscore.upcase}", attributes.merge(type: :audio)
251
+ )
252
+ when 'S'
253
+ Mediakit::FFmpeg::SubtitleCodec.create_constant(
254
+ "CODEC_#{attributes[:name].underscore.upcase}", attributes.merge(type: :subtitle)
255
+ )
256
+ else
257
+ raise(UnknownTypeError)
258
+ end
206
259
  end
207
260
  end
208
261
  end
@@ -1,13 +1,13 @@
1
1
  require 'open3'
2
- require 'thread'
3
2
  require 'timeout'
4
3
  require 'cool.io'
5
4
  require 'logger'
6
- require 'mediakit/utils/shell_escape'
5
+ require 'mediakit/process/shell_escape'
6
+ require 'mediakit/utils/null_logger'
7
7
 
8
8
  module Mediakit
9
- module Utils
10
- class ProcessRunner
9
+ module Process
10
+ class Runner
11
11
  class CommandNotFoundError < StandardError;
12
12
  end
13
13
  class TimeoutError < StandardError;
@@ -17,10 +17,10 @@ module Mediakit
17
17
 
18
18
  attr_reader(:logger)
19
19
 
20
- def initialize(timeout: nil, nice: 0, logger: nil)
20
+ def initialize(timeout: nil, nice: 0, logger: Logger.new(STDOUT))
21
21
  @timeout = timeout
22
22
  @nice = nice
23
- @logger = logger || Logger.new(STDOUT)
23
+ @logger = logger || Mediakit::Utils::NullLogger.new
24
24
  end
25
25
 
26
26
  # @overload run(command, *args)
@@ -37,11 +37,7 @@ module Mediakit
37
37
  begin
38
38
  stdin, stdout, stderr, wait_thread = Open3.popen3(command)
39
39
  stdin.close
40
- output, error_output, exit_status = if @timeout
41
- wait_with_timeout(stdout, stderr, wait_thread)
42
- else
43
- wait_without_timeout(stdout, stderr, wait_thread)
44
- end
40
+ output, error_output, exit_status = wait(stdout, stderr, wait_thread)
45
41
  rescue Errno::ENOENT => e
46
42
  raise(CommandNotFoundError, "Can't find command - #{command}, #{e.meessage}")
47
43
  end
@@ -49,13 +45,7 @@ module Mediakit
49
45
  [output, error_output, exit_status]
50
46
  end
51
47
 
52
- def wait_without_timeout(stdout, stderr, wait_thread)
53
- wait_thread.join
54
- exit_status = (wait_thread.value.exitstatus == 0)
55
- [stdout.read, stderr.read, exit_status]
56
- end
57
-
58
- def wait_with_timeout(stdout, stderr, wait_thread)
48
+ def wait(stdout, stderr, wait_thread)
59
49
  begin
60
50
  setup_watchers(stdout, stderr)
61
51
  loop_thread = Thread.new { run_loop }
@@ -87,13 +77,13 @@ module Mediakit
87
77
  end
88
78
 
89
79
  def setup_watchers(stdout, stderr)
90
- @timer = TimeoutTimer.new(@timeout, Thread.current)
91
- @out_watcher = IOWatcher.new(stdout) { |data| @timer.update; logger.info(data) }
92
- @err_watcher = IOWatcher.new(stderr) { |data| @timer.update; logger.error(data) }
80
+ @timer = @timeout ? TimeoutTimer.new(@timeout, Thread.current) : nil
81
+ @out_watcher = IOWatcher.new(stdout) { |data| @timer.update if @timer; logger.info(data) }
82
+ @err_watcher = IOWatcher.new(stderr) { |data| @timer.update if @timer; logger.error(data) }
93
83
  @loop = Coolio::Loop.new
94
84
  @out_watcher.attach(@loop)
95
85
  @err_watcher.attach(@loop)
96
- @timer.attach(@loop)
86
+ @timer.attach(@loop) if @timer
97
87
  end
98
88
 
99
89
  def run_loop
@@ -116,7 +106,7 @@ module Mediakit
116
106
  end
117
107
 
118
108
  def force_kill_process(pid)
119
- Process.kill('SIGKILL', pid)
109
+ ::Process.kill('SIGKILL', pid)
120
110
  rescue Errno::ESRCH => e
121
111
  logger.warn("fail SIGKILL pid=#{pid} - #{e.message}, #{e.backtrace.join("\n")}")
122
112
  end
@@ -131,8 +121,8 @@ module Mediakit
131
121
  end
132
122
 
133
123
  def on_read(data)
134
- @data << data
135
124
  @block.call(data)
125
+ @data << data
136
126
  end
137
127
 
138
128
  def on_close
@@ -144,7 +134,6 @@ module Mediakit
144
134
  DEFAULT_CHECK_INTERVAL = 0.1
145
135
 
146
136
  def initialize(duration, current_thread)
147
- @mutex = Mutex.new
148
137
  @duration = duration
149
138
  @watched_at = Time.now
150
139
  @current_thread = current_thread
@@ -158,9 +147,7 @@ module Mediakit
158
147
  end
159
148
 
160
149
  def update
161
- @mutex.synchronize do
162
- @watched_at = Time.now
163
- end
150
+ @watched_at = Time.now
164
151
  end
165
152
 
166
153
  private
@@ -1,7 +1,7 @@
1
1
  require 'shellwords'
2
2
 
3
3
  module Mediakit
4
- module Utils
4
+ module Process
5
5
  module ShellEscape
6
6
  def escape(*args)
7
7
  case args.size
@@ -0,0 +1,8 @@
1
+ module Mediakit
2
+ module Railtie < ::Rails::Railtie
3
+ initializer('mediakit.initialize_ffmpeg') do
4
+ ffmpeg = Mediakit::FFmpeg.create
5
+ Mediakit::Initializers.setup(ffmpeg)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,35 @@
1
+ module Mediakit
2
+ module Utils
3
+ module ConstantFactory
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ base.class_eval do
7
+ attr_reader(*(base.using_attributes))
8
+
9
+ def initialize(attributes)
10
+ self.class.using_attributes.each do |key|
11
+ instance_variable_set("@#{key}", attributes[key])
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ def using_attributes
19
+ raise(NotImplementedError)
20
+ end
21
+
22
+ def create_constant(name, attributes)
23
+ raise(
24
+ ArgumentError,
25
+ <<EOS
26
+ you can give attribute keys which only defined by `using_attributes` and that is satisfied all keys.'
27
+ EOS
28
+ ) unless Set.new(using_attributes) == Set.new(attributes.keys)
29
+ return self.const_get(name) if self.const_defined?(name)
30
+ self.const_set(name, new(attributes).freeze)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ module Mediakit
2
+ module Utils
3
+ class NullLogger
4
+ attr_accessor(:formatter, :level)
5
+
6
+ def debug(*); end
7
+ def info(*); end
8
+ def warn(*); end
9
+ def error(*); end
10
+ def fatal(*); end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Mediakit
2
- VERSION = "0.0.12"
2
+ VERSION = '0.1.1'
3
3
  end
data/lib/mediakit.rb CHANGED
@@ -5,4 +5,6 @@ module Mediakit
5
5
  require 'mediakit/ffmpeg'
6
6
  require 'mediakit/ffprobe'
7
7
  require 'mediakit/initializers'
8
+
9
+ require 'mediakit/railtie' if defined?(Rails)
8
10
  end
data/mediakit.gemspec CHANGED
@@ -29,4 +29,5 @@ EOS
29
29
  spec.add_development_dependency "ruby-debug-ide", "~> 0.4"
30
30
  spec.add_development_dependency "yard", "> 0.8"
31
31
  spec.add_development_dependency "rubocop", ">= 0.31"
32
+ spec.add_development_dependency "minitest-power_assert", ">= 0.2"
32
33
  end
File without changes
data/sample/encode.rb ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mediakit"
5
+ require 'pry'
6
+
7
+ input_file = ARGV[0]
8
+ exit(1) unless input_file
9
+
10
+ output_file = ARGV[1] || 'out.mov'
11
+
12
+ def transcode_option(input, output)
13
+ options = Mediakit::FFmpeg::Options.new(
14
+ Mediakit::FFmpeg::Options::GlobalOption.new(
15
+ 'y' => true,
16
+ 'threads' => 4,
17
+ 't' => 10
18
+ ),
19
+ Mediakit::FFmpeg::Options::InputFileOption.new(
20
+ options: nil,
21
+ path: input,
22
+ ),
23
+ Mediakit::FFmpeg::Options::OutputFileOption.new(
24
+ options: {
25
+ 'acodec' => 'mp3',
26
+ 'vcodec' => 'libx264',
27
+ #'vf' => 'crop=240:240:0:0',
28
+ 'ar' => '44100',
29
+ 'ab' => '128k',
30
+ },
31
+ path: output,
32
+ ),
33
+ )
34
+ end
35
+
36
+ root = File.expand_path(File.join(File.dirname(__FILE__), '../'))
37
+ input_path = File.expand_path(input_file)
38
+ output_path = File.expand_path(File.join(root, 'out.mov'))
39
+ ffmpeg = Mediakit::FFmpeg.create
40
+ options = transcode_option(input_path, output_path)
41
+ puts "$ #{ffmpeg.command(options, nice: 10)}"
42
+ puts ffmpeg.run(options, nice: 10, timeout: 30)
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mediakit"
5
+ require 'pry'
6
+
7
+ ffmpeg = Mediakit::FFmpeg.new(Mediakit::Drivers::FFmpeg.new)
8
+ Mediakit::Initializers.setup(ffmpeg)
9
+
10
+ binding.pry
11
+
12
+ # ffmpeg.codecs.select {|c| c.name =~ /264/ } ...
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mediakit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ainame
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-05-27 00:00:00.000000000 Z
11
+ date: 2015-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0.31'
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest-power_assert
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0.2'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0.2'
111
125
  description: |
112
126
  mediakit is the libraries for ffmpeg and sox backed media manipulation something.
113
127
  you can create complex manipulation for media as a ruby code.
@@ -117,6 +131,7 @@ executables: []
117
131
  extensions: []
118
132
  extra_rdoc_files: []
119
133
  files:
134
+ - ".codeclimate.yml"
120
135
  - ".gitignore"
121
136
  - Gemfile
122
137
  - README.md
@@ -131,12 +146,17 @@ files:
131
146
  - lib/mediakit/ffprobe.rb
132
147
  - lib/mediakit/initializers.rb
133
148
  - lib/mediakit/initializers/ffmpeg.rb
134
- - lib/mediakit/utils/process_runner.rb
135
- - lib/mediakit/utils/shell_escape.rb
149
+ - lib/mediakit/process/runner.rb
150
+ - lib/mediakit/process/shell_escape.rb
151
+ - lib/mediakit/railtie.rb
152
+ - lib/mediakit/utils/constant_factory.rb
153
+ - lib/mediakit/utils/null_logger.rb
136
154
  - lib/mediakit/version.rb
137
155
  - mediakit.gemspec
138
156
  - sample/configure.rb
139
- - sample/raw_crop.rb
157
+ - sample/crop.rb
158
+ - sample/encode.rb
159
+ - sample/instropections.rb
140
160
  homepage: https://github.com/ainame/mediakit
141
161
  licenses: []
142
162
  metadata: {}