puremotion 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.yardopts +1 -0
  2. data/README.md +69 -0
  3. data/Rakefile +23 -11
  4. data/examples/progress_reporting.rb +26 -0
  5. data/examples/simple.rb +22 -0
  6. data/ext/puremotion/audio.c +38 -0
  7. data/ext/puremotion/extconf.rb +34 -0
  8. data/ext/puremotion/frame.c +176 -0
  9. data/ext/puremotion/media.c +175 -0
  10. data/ext/puremotion/puremotion.c +26 -0
  11. data/ext/puremotion/puremotion.h +38 -0
  12. data/ext/puremotion/stream.c +128 -0
  13. data/ext/puremotion/stream_collection.c +44 -0
  14. data/ext/puremotion/utils.c +81 -0
  15. data/ext/puremotion/utils.h +6 -0
  16. data/ext/puremotion/video.c +141 -0
  17. data/lib/{puremotion/events → events}/event.rb +0 -0
  18. data/lib/{puremotion/events → events}/generator.rb +0 -0
  19. data/lib/media.rb +89 -0
  20. data/lib/preset/audio/audio.rb +42 -0
  21. data/lib/preset/file.rb +19 -0
  22. data/lib/preset/general.rb +28 -0
  23. data/lib/preset/metadata.rb +41 -0
  24. data/lib/preset/preset.rb +120 -0
  25. data/lib/preset/video/crop.rb +29 -0
  26. data/lib/preset/video/pad.rb +31 -0
  27. data/lib/preset/video/video.rb +130 -0
  28. data/lib/puremotion.rb +20 -12
  29. data/lib/puremotion_native.so +0 -0
  30. data/lib/threading.rb +54 -0
  31. data/lib/{puremotion/tools → tools}/ffmpeg.rb +12 -50
  32. data/lib/transcode/transcode.rb +142 -0
  33. data/spec/spec_helper.rb +7 -0
  34. data/spec/units/media_spec.rb +13 -0
  35. data/spec/units/preset_spec.rb +91 -0
  36. metadata +52 -44
  37. data/.document +0 -5
  38. data/.gitignore +0 -21
  39. data/README.rdoc +0 -18
  40. data/VERSION +0 -1
  41. data/lib/puremotion/codecs.rb +0 -59
  42. data/lib/puremotion/media.rb +0 -490
  43. data/lib/puremotion/media/stream.rb +0 -4
  44. data/lib/puremotion/media/stream/audio.rb +0 -0
  45. data/lib/puremotion/media/stream/base.rb +0 -7
  46. data/lib/puremotion/media/stream/collection.rb +0 -5
  47. data/lib/puremotion/media/stream/video.rb +0 -61
  48. data/lib/puremotion/recipes/ipod.yml +0 -12
  49. data/lib/puremotion/thread.rb +0 -153
  50. data/lib/puremotion/transcode/recipe.rb +0 -250
  51. data/lib/puremotion/transcode/transcode.rb +0 -153
  52. data/puremotion.gemspec +0 -68
  53. data/test/helper.rb +0 -10
  54. data/test/test_puremotion.rb +0 -7
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puremotion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Ominiom
@@ -9,53 +14,51 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-11-14 00:00:00 +00:00
17
+ date: 2010-03-25 00:00:00 +00:00
13
18
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: thoughtbot-shoulda
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- version:
25
- description: A Ruby wrapper for analysis and conversion of media using FFmpeg
26
- email: iain.iw.wilson@googlemail.com
27
- executables: []
19
+ dependencies: []
28
20
 
29
- extensions: []
21
+ description: A Ruby wrapper for FFmpeg
22
+ email: iain@ominiom.com
23
+ executables: []
30
24
 
25
+ extensions:
26
+ - ext/puremotion/extconf.rb
31
27
  extra_rdoc_files:
32
28
  - LICENSE
33
- - README.rdoc
29
+ - README.md
34
30
  files:
35
- - .document
36
- - .gitignore
31
+ - .yardopts
37
32
  - LICENSE
38
- - README.rdoc
33
+ - README.md
39
34
  - Rakefile
40
- - VERSION
35
+ - ext/puremotion/audio.c
36
+ - ext/puremotion/extconf.rb
37
+ - ext/puremotion/frame.c
38
+ - ext/puremotion/media.c
39
+ - ext/puremotion/puremotion.c
40
+ - ext/puremotion/puremotion.h
41
+ - ext/puremotion/stream.c
42
+ - ext/puremotion/stream_collection.c
43
+ - ext/puremotion/utils.c
44
+ - ext/puremotion/utils.h
45
+ - ext/puremotion/video.c
46
+ - lib/events/event.rb
47
+ - lib/events/generator.rb
48
+ - lib/media.rb
49
+ - lib/preset/audio/audio.rb
50
+ - lib/preset/file.rb
51
+ - lib/preset/general.rb
52
+ - lib/preset/metadata.rb
53
+ - lib/preset/preset.rb
54
+ - lib/preset/video/crop.rb
55
+ - lib/preset/video/pad.rb
56
+ - lib/preset/video/video.rb
41
57
  - lib/puremotion.rb
42
- - lib/puremotion/codecs.rb
43
- - lib/puremotion/events/event.rb
44
- - lib/puremotion/events/generator.rb
45
- - lib/puremotion/media.rb
46
- - lib/puremotion/media/stream.rb
47
- - lib/puremotion/media/stream/audio.rb
48
- - lib/puremotion/media/stream/base.rb
49
- - lib/puremotion/media/stream/collection.rb
50
- - lib/puremotion/media/stream/video.rb
51
- - lib/puremotion/recipes/ipod.yml
52
- - lib/puremotion/thread.rb
53
- - lib/puremotion/tools/ffmpeg.rb
54
- - lib/puremotion/transcode/recipe.rb
55
- - lib/puremotion/transcode/transcode.rb
56
- - puremotion.gemspec
57
- - test/helper.rb
58
- - test/test_puremotion.rb
58
+ - lib/puremotion_native.so
59
+ - lib/threading.rb
60
+ - lib/tools/ffmpeg.rb
61
+ - lib/transcode/transcode.rb
59
62
  has_rdoc: true
60
63
  homepage: http://github.com/ominiom/puremotion
61
64
  licenses: []
@@ -69,21 +72,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
72
  requirements:
70
73
  - - ">="
71
74
  - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
72
77
  version: "0"
73
- version:
74
78
  required_rubygems_version: !ruby/object:Gem::Requirement
75
79
  requirements:
76
80
  - - ">="
77
81
  - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
78
84
  version: "0"
79
- version:
80
85
  requirements: []
81
86
 
82
87
  rubyforge_project:
83
- rubygems_version: 1.3.5
88
+ rubygems_version: 1.3.6
84
89
  signing_key:
85
90
  specification_version: 3
86
91
  summary: PureMotion
87
92
  test_files:
88
- - test/helper.rb
89
- - test/test_puremotion.rb
93
+ - spec/units/media_spec.rb
94
+ - spec/units/preset_spec.rb
95
+ - spec/spec_helper.rb
96
+ - examples/progress_reporting.rb
97
+ - examples/simple.rb
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
@@ -1,18 +0,0 @@
1
- = puremotion
2
-
3
- Description goes here.
4
-
5
- == Note on Patches/Pull Requests
6
-
7
- * Fork the project.
8
- * Make your feature addition or bug fix.
9
- * Add tests for it. This is important so I don't break it in a
10
- future version unintentionally.
11
- * Commit, do not mess with rakefile, version, or history.
12
- (if you want to have your own version, that is fine but
13
- bump version in a commit by itself I can ignore when I pull)
14
- * Send me a pull request. Bonus points for topic branches.
15
-
16
- == Copyright
17
-
18
- Copyright (c) 2009 Ominiom. See LICENSE for details.
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.0.1
@@ -1,59 +0,0 @@
1
- module PureMotion::Codecs
2
-
3
- @@Codec = Struct.new(:audio, :video, :ffmpeg_name)
4
-
5
- @@codecs = {
6
- 'aac' => {
7
- :ffmpeg_name => 'libfaac',
8
- :audio => true
9
- },
10
- 'mp3' => {
11
- :ffmpeg_name => 'libmp3lame',
12
- :audio => true
13
- },
14
- 'vorbis' => {
15
- :ffmpeg_name => 'libvorbis',
16
- :audio => true
17
- },
18
- 'theora' => {
19
- :ffmpeg_name => 'libtheora',
20
- :video => true
21
- },
22
- 'divx' => {
23
- :ffmpeg_name => 'libxvid',
24
- :video => true
25
- },
26
- 'h264' => {
27
- :ffmpeg_name => 'libx264',
28
- :video => true
29
- },
30
- 'flv' => {
31
- :ffmpeg_name => 'flv',
32
- :video => true
33
- }
34
- }
35
-
36
- def self.find name, type = nil
37
- codec = @@codecs[name]
38
- if not type.nil? and not codec.nil? then
39
- if not codec[type] then return false end
40
- end
41
- return build(codec) unless codec.nil?
42
- nil
43
- end
44
-
45
- def self.valid? name, type = nil
46
- codec = find name, type
47
- return false if codec.nil?
48
- true
49
- end
50
-
51
- def self.build codec
52
- c = @@Codec.new
53
- codec.each_pair do |key, value|
54
- c[key] = value
55
- end
56
- c
57
- end
58
-
59
- end
@@ -1,490 +0,0 @@
1
- module PureMotion
2
-
3
- class Media
4
-
5
- event :analysed
6
-
7
- attr_accessor :file
8
-
9
- @analysed = false
10
-
11
- @unknown_format = false
12
- @invalid_file = false
13
-
14
- @streams = nil
15
-
16
- def self.analyse(input, options = {})
17
- return self.new(input)
18
- end
19
-
20
- def analysed?
21
- @analysed
22
- end
23
-
24
- def initialize(file)
25
- @file = file
26
-
27
- @output = ''
28
- raise ArgumentError, "File does not exist" unless File.exists? @file
29
-
30
- @ffmpeg = Tools::FFmpeg.new :options => "-i #{file}"
31
-
32
- @ffmpeg.line + lambda do |ffmpeg, line|
33
-
34
- end
35
-
36
- @ffmpeg.complete + lambda do | ffmpeg, out |
37
- @output = @ffmpeg.output.join("\n")
38
-
39
- metadata = /(Input \#.*)\n.+\n\Z/m.match(@output)
40
-
41
- @unknown_format = has(/Unknown format/i)
42
- @invalid_file = has(/Duration: N\/A|bitrate: N\/A/im)
43
-
44
- @analysed = true
45
- analysed(true)
46
- end
47
-
48
- end
49
-
50
- # Raw output of FFmpeg
51
- #
52
- # Returns:
53
- #
54
- # * Nil: If the video is still being analysed - unless the parameter :so_far is passed
55
- # * String: Raw output
56
- def output(opt)
57
-
58
- return nil unless valid?
59
-
60
- if status(:analysing) then return nil unless opt == :so_far end
61
-
62
- return output.join('\n')
63
-
64
- end
65
-
66
- def transcode(params)
67
- return Transcode::Transcode.new(self, params)
68
- end
69
-
70
- # Returns:
71
- # * nil if not yet analysed
72
- # * false if the media is an unknown format
73
- # * false if the file is not media or is corrupt
74
- # * true otherwise
75
- def valid?
76
- return nil unless @analysed
77
- return false if @unknown_format || @invalid_file
78
- has /Input #\d*.\d*/
79
- end
80
-
81
- def invalid?
82
- !valid?
83
- end
84
-
85
-
86
- def unknown_format?
87
- @unknown_format
88
- end
89
-
90
- # If true then either:
91
- # * The media is a valid format but corrupted and cannot be read
92
- # or
93
- # * The file isn't media!
94
- def invalid_file?
95
- @invalid_file
96
- end
97
-
98
- # Container bitrate:
99
- #
100
- # Returns:
101
- # * Nil: If the bitrate could not be detected
102
- # * String: "xxx kb/s" if _fmt_ is :raw
103
- # * Integer: bitrate in kb/s otherwise
104
- def bitrate(fmt = nil)
105
- br = bitrate_match
106
- return nil if br.nil?
107
-
108
- mbr = {
109
- :value => br[1].to_i,
110
- :unit => br[2]
111
- }
112
-
113
- return mbr[:value] unless fmt == :raw
114
-
115
- br
116
-
117
- end
118
-
119
- # Boolean: Whether media has a video stream or not
120
- def video?
121
- return nil if not @analysed
122
- return false if not valid?
123
- !video_match.nil?
124
- end
125
-
126
- # Boolean: Whether media has an audio stream or not
127
- def audio?
128
- return nil if not @analysed
129
- has /Stream\s*(.*?)[,|:|\(|\[].*?\s*Video:\s*(.*?),\s*(.*?),\s*(\d*)x(\d*)/
130
- end
131
-
132
- # Returns a hash with all sorts of details about the first video stream
133
- # Nil if no video stream
134
- def video
135
- return nil unless video?
136
- {
137
- :codec => detail(:video, :codec),
138
- :colorspace => detail(:video, :colorspace),
139
- :resolution => {
140
- :width => detail(:video, :resolution, :width),
141
- :height => detail(:video, :resolution, :height)
142
- },
143
- :fps => detail(:video, :fps),
144
- :bitrate => detail(:video, :bitrate, :raw),
145
- :duration => detail(:duration, :seconds)
146
- }
147
- end
148
-
149
- def audio
150
- return nil unless audio?
151
- {
152
- :codec => detail(:audio, :codec),
153
- :sample_rate => detail(:audio, :sample, :rate),
154
- :sample_size => detail(:audio, :sample, :size),
155
- :channels => detail(:audio, :channels),
156
- :bitrate => detail(:audio, :bitrate)
157
- }
158
- end
159
-
160
- # Big messy function that allows things like:
161
- # * detail :video, :resolution, :height
162
- # * detail :video, :fps
163
- # * detail :video, :duration
164
- def detail(*args)
165
-
166
- return nil unless valid?
167
-
168
- case args[0]
169
- when :video
170
-
171
- # Main Video handler
172
-
173
- case args[1]
174
- when :codec
175
-
176
- # Find video codec
177
- return video_match[2]
178
-
179
- when :colorspace
180
-
181
- # Find colorspace
182
- return video_match[3]
183
-
184
- when :resolution
185
-
186
- # Handle resolution
187
-
188
- case args[2]
189
- when :width
190
-
191
- # Frame width
192
- return video_match[4]
193
-
194
- when :height
195
-
196
- # Frame height
197
- return video_match[5]
198
-
199
- end
200
-
201
- # Default resolution output format
202
- return video_match[4] + "x" + video_match[5]
203
-
204
- when :fps
205
-
206
- # Frame Rate
207
- fps = video_frame_rate_match[1].to_f
208
-
209
- # Handle undected frame rates
210
- if fps == 0 then fps = nil end
211
-
212
- return fps
213
-
214
- when :bitrate
215
-
216
- # Captue bitrate via regex
217
- br = video_bitrate_match[1].to_i
218
-
219
- # Decide if bitrate is in kb/s or b/s
220
- case video_bitrate_match[2]
221
- when 'b/s'
222
-
223
- # If in b/s divide to get kb/s
224
- return (br / 1024).to_i
225
-
226
- end
227
-
228
- # Otherwise send raw bitrate
229
- return br
230
-
231
- when :duration
232
-
233
- # Redirect to overall file duration
234
- return detail(:duration, args[1])
235
-
236
- end
237
-
238
- # End video section
239
-
240
- return nil
241
-
242
- when :audio
243
-
244
- # Audio section
245
-
246
- case args[1]
247
- when :codec
248
-
249
- # Find the codec
250
- codec = audio_match[2]
251
-
252
- if codec =~ /\dx[\d a-f]*/ then
253
- codec = :unidentifed
254
- end
255
-
256
- return codec
257
-
258
- when :sample
259
-
260
- case args[2]
261
- when :rate
262
- return audio_match[3].to_i
263
- end
264
-
265
- return nil
266
-
267
- when :channels
268
-
269
- case audio_match[5]
270
- when 'stereo'
271
- return 2
272
- when 'mono'
273
- return 1
274
- end
275
-
276
- return nil
277
- when :bitrate
278
- return audio_bitrate_match[1].to_i
279
- end
280
-
281
- return nil
282
-
283
- when :duration
284
-
285
- d = dur
286
- secs = (d[:h] * 60 * 60) + (d[:m] * 60) + (d[:s]) * 1.00
287
-
288
- case args[1]
289
- when :seconds
290
- return secs
291
- when :frames
292
- return (secs * video_frame_rate_match[1].to_f).to_i
293
- end
294
-
295
- return d[:raw]
296
-
297
- end
298
-
299
- nil
300
- end
301
-
302
- # * Float: Frame rate of video stream
303
- # * Nil: If no video stream, undectable or invalid media
304
- def fps
305
- return nil unless valid?
306
- return nil unless video?
307
- begin
308
- return video_frame_rate_match[1].to_f
309
- rescue
310
- return nil
311
- end
312
- end
313
-
314
- private
315
-
316
- def bitrate_match
317
- /bitrate: ([0-9\.]+)\s*(.*)\s+/.match(@raw_metadata)
318
- end
319
-
320
- def audio_match
321
- return nil unless valid?
322
-
323
- match = /Stream\s*(.*?)[,|:|\(|\[].*?\s*Audio:\s*(.*?),\s*([0-9\.]*) (\w*),\s*([a-zA-Z:]*)/.match(@output)
324
-
325
- match
326
- end
327
-
328
- def audio_bitrate_match
329
- return nil if not valid?
330
-
331
- match = /Stream\s*.*?[,|:|\(|\[].*?\s*Audio:\s*.*?,\s*[0-9\.]* \w*,\s*[a-zA-Z:]*,[^,]*,\s*(\d*)\s*([a-zA-Z]*\/s)/.match(@output)
332
-
333
- match
334
- end
335
-
336
- def video_match
337
- return nil unless valid?
338
-
339
- match = /Stream\s*(.*?)[,|:|\(|\[].*?\s*Video:\s*(.*?),\s*(.*?),\s*(\d*)x(\d*)/.match(@output)
340
-
341
- /#
342
-
343
- 1 => stream id
344
- 2 => codec
345
- 3 => colorspace
346
- 4 => width
347
- 5 => height
348
-
349
-
350
- /
351
-
352
- match
353
- end
354
-
355
- def video_bitrate_match
356
- match = /Stream\s*.*?[,|:|\(|\[].*?\s*Video:\s*.*?,\s*.*?,\s*\d*x\d*[^,]*,\s*([0-9\.]+)\s*(.*\/.),/.match(@output)
357
- match
358
- end
359
-
360
- def video_frame_rate_match
361
- match = /Stream\s*.*?[,|:|\(|\[].*?\s*Video:\s\S*,\s\S*,\s\d+x\d+[^,]+,\s\S*\s\S*,\s([^,\s]*)/.match(@output)
362
-
363
- match
364
- end
365
-
366
- def raw_duration
367
- return nil unless valid?
368
-
369
- /Duration:\s*([0-9\:\.]+),/.match(@output)[1]
370
- end
371
-
372
- def dur
373
- return nil unless valid?
374
-
375
- bits = /(\d*):(\d{2}):(\d{2}.\d*)/.match(raw_duration)
376
- {
377
- :raw => bits[0],
378
- :h => bits[1].to_i,
379
- :m => bits[2].to_i,
380
- :s => bits[3].to_f
381
- }
382
- end
383
-
384
- def has(regexp)
385
- if @output =~ regexp then
386
- true
387
- else
388
- false
389
- end
390
- end
391
-
392
- def find(regexp)
393
- m = regexp.match(@output)
394
- return m[1] if m
395
- nil
396
- end
397
-
398
- end
399
-
400
- class Stream
401
-
402
- def initialize(raw)
403
- @raw = raw
404
- end
405
-
406
- def kind
407
- m = /:\s*(\S*):/.match(@raw)
408
- m[1]
409
- end
410
-
411
- end
412
-
413
- class Input
414
-
415
- attr_accessor :streams
416
-
417
- def initialize(raw)
418
- @raw = raw
419
- @streams = []
420
- detect_streams
421
- end
422
-
423
- def container
424
- /Input \#\d+\,\s*(\S+),\s*from/.match(@raw)[1]
425
- end
426
-
427
- def file
428
- /from '(\S+)'/.match(@raw)[1]
429
- end
430
-
431
- protected
432
-
433
- def detect_streams
434
- @raw.each_line do |line|
435
- @streams << Stream.new(line) if line =~ /\s*Stream/
436
- end
437
- end
438
-
439
- end
440
-
441
- class Analysis
442
-
443
- attr_accessor :info, :inputs
444
-
445
- def initialize(options = {})
446
- analyse
447
- @inputs[0] unless @inputs.empty?
448
- end
449
-
450
- def analyse
451
- @inputs = []
452
- @fio = IO.popen('ffmpeg -i C:/ffmpeg/test.wmv 2>&1')
453
-
454
- prev_indent = -1
455
- indent = 0
456
- lines = []
457
-
458
- begin
459
- f = @fio.gets
460
-
461
- indent = f.length - f.lstrip.length
462
-
463
- if indent < prev_indent then
464
- add(lines.join)
465
- lines = []
466
- end
467
-
468
- prev_indent = indent
469
-
470
- #puts "Indent: " + indent.to_s + " - " + f
471
-
472
- if f =~ /Input #\d*/ then
473
-
474
- end
475
-
476
- lines << f
477
-
478
- end while not @fio.eof?
479
-
480
- end
481
-
482
- def add(block)
483
- if m = /^Input #(\d+),/.match(block) then
484
- @inputs[m[0].to_i] = Input.new block
485
- end
486
- end
487
-
488
- end
489
-
490
- end