mediakit 0.0.12 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: {}