puremotion 0.0.1 → 0.1.0

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.
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