rvideo-tecnobrat 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/ENV +100 -0
  2. data/ENV2 +129 -0
  3. data/History.txt +30 -0
  4. data/License.txt +20 -0
  5. data/Manifest.txt +47 -0
  6. data/README.txt +91 -0
  7. data/RULES +11 -0
  8. data/Rakefile +184 -0
  9. data/config/boot.rb +16 -0
  10. data/lib/rvideo.rb +17 -0
  11. data/lib/rvideo/errors.rb +24 -0
  12. data/lib/rvideo/float.rb +7 -0
  13. data/lib/rvideo/inspector.rb +486 -0
  14. data/lib/rvideo/reporter.rb +176 -0
  15. data/lib/rvideo/reporter/views/index.html.erb +27 -0
  16. data/lib/rvideo/reporter/views/report.css +27 -0
  17. data/lib/rvideo/reporter/views/report.html.erb +81 -0
  18. data/lib/rvideo/reporter/views/report.js +9 -0
  19. data/lib/rvideo/tools/abstract_tool.rb +79 -0
  20. data/lib/rvideo/tools/ffmpeg.rb +128 -0
  21. data/lib/rvideo/tools/flvtool2.rb +45 -0
  22. data/lib/rvideo/tools/mencoder.rb +65 -0
  23. data/lib/rvideo/transcoder.rb +122 -0
  24. data/lib/rvideo/version.rb +9 -0
  25. data/scripts/txt2html +67 -0
  26. data/setup.rb +1585 -0
  27. data/spec/files/kites.mp4 +0 -0
  28. data/spec/fixtures/ffmpeg_builds.yml +28 -0
  29. data/spec/fixtures/files.yml +385 -0
  30. data/spec/fixtures/recipes.yml +57 -0
  31. data/spec/integrations/files/files.yml +361 -0
  32. data/spec/integrations/formats_spec.rb +295 -0
  33. data/spec/integrations/inspection_spec.rb +15 -0
  34. data/spec/integrations/recipes_spec.rb +0 -0
  35. data/spec/integrations/rvideo_spec.rb +17 -0
  36. data/spec/integrations/transcoding_spec.rb +9 -0
  37. data/spec/spec.opts +1 -0
  38. data/spec/spec_helper.rb +11 -0
  39. data/spec/units/abstract_tool_spec.rb +112 -0
  40. data/spec/units/ffmpeg_spec.rb +703 -0
  41. data/spec/units/flvtool2_spec.rb +314 -0
  42. data/spec/units/inspector_spec.rb +49 -0
  43. data/spec/units/mencoder_spec.rb +4986 -0
  44. data/spec/units/transcoder_spec.rb +140 -0
  45. data/website/index.html +219 -0
  46. data/website/index.txt +142 -0
  47. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  48. metadata +116 -0
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+
3
+ require 'rvideo/inspector'
4
+ require 'rvideo/tools/abstract_tool'
5
+ require 'rvideo/tools/ffmpeg'
6
+ require 'rvideo/tools/flvtool2'
7
+ require 'rvideo/errors'
8
+ require 'rvideo/transcoder'
9
+ require 'yaml'
10
+ require 'rubygems'
11
+ require 'active_support'
12
+
13
+ TEMP_PATH = File.expand_path(File.dirname(__FILE__) + '/../tmp')
14
+ FIXTURE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/fixtures')
15
+ TEST_FILE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/files')
16
+ REPORT_PATH = File.expand_path(File.dirname(__FILE__) + '/../report')
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/rvideo'
2
+
3
+ require 'inspector'
4
+ require 'float'
5
+ require 'tools/abstract_tool'
6
+ require 'tools/ffmpeg'
7
+ require 'tools/mencoder'
8
+ require 'tools/flvtool2'
9
+ require 'errors'
10
+ require 'transcoder'
11
+ require 'active_support'
12
+
13
+ TEMP_PATH = File.expand_path(File.dirname(__FILE__) + '/../tmp')
14
+ FIXTURE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/fixtures')
15
+ TEST_FILE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/files')
16
+ REPORT_PATH = File.expand_path(File.dirname(__FILE__) + '/../report')
17
+
@@ -0,0 +1,24 @@
1
+ module RVideo
2
+ class TranscoderError < RuntimeError
3
+ class RecipeError < TranscoderError
4
+ end
5
+
6
+ class InvalidCommand < TranscoderError
7
+ end
8
+
9
+ class InvalidFile < TranscoderError
10
+ end
11
+
12
+ class InputFileNotFound < TranscoderError
13
+ end
14
+
15
+ class UnexpectedResult < TranscoderError
16
+ end
17
+
18
+ class ParameterError < TranscoderError
19
+ end
20
+
21
+ class UnknownError < TranscoderError
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ # Add a rounding method to the Float class.
2
+ class Float
3
+ def round_to(x)
4
+ (self * 10**x).round.to_f / 10**x
5
+ end
6
+ end
7
+
@@ -0,0 +1,486 @@
1
+ module RVideo # :nodoc:
2
+ class Inspector
3
+
4
+ attr_reader :filename, :path, :full_filename, :raw_response, :raw_metadata
5
+
6
+ attr_accessor :ffmpeg_binary
7
+
8
+ #
9
+ # To inspect a video or audio file, initialize an Inspector object.
10
+ #
11
+ # file = RVideo::Inspector.new(options_hash)
12
+ #
13
+ # Inspector accepts three options: file, raw_response, and ffmpeg_binary.
14
+ # Either raw_response or file is required; ffmpeg binary is optional.
15
+ #
16
+ # :file is a path to a file to be inspected.
17
+ #
18
+ # :raw_response is the full output of "ffmpeg -i [file]". If the
19
+ # :raw_response option is used, RVideo will not actually inspect a file;
20
+ # it will simply parse the provided response. This is useful if your
21
+ # application has already collected the ffmpeg -i response, and you don't
22
+ # want to call it again.
23
+ #
24
+ # :ffmpeg_binary is an optional argument that specifies the path to the
25
+ # ffmpeg binary to be used. If a path is not explicitly declared, RVideo
26
+ # will assume that ffmpeg exists in the Unix path. Type "which ffmpeg" to
27
+ # check if ffmpeg is installed and exists in your operating system's path.
28
+ #
29
+
30
+ def initialize(options = {})
31
+ if options[:raw_response]
32
+ @raw_response = options[:raw_response]
33
+ elsif options[:file]
34
+ if options[:ffmpeg_binary]
35
+ @ffmpeg_binary = options[:ffmpeg_binary]
36
+ raise RuntimeError, "ffmpeg could not be found (trying #{@ffmpeg_binary})" unless FileTest.exist?(@ffmpeg_binary)
37
+ else
38
+ # assume it is in the unix path
39
+ raise RuntimeError, 'ffmpeg could not be found (expected ffmpeg to be found in the Unix path)' unless FileTest.exist?(`which ffmpeg`.chomp)
40
+ @ffmpeg_binary = "ffmpeg"
41
+ end
42
+
43
+ file = options[:file]
44
+ @filename = File.basename(file)
45
+ @path = File.dirname(file)
46
+ @full_filename = file
47
+ raise ArgumentError, "File not found (#{file})" unless FileTest.exist?(file.gsub("\"",""))
48
+ @raw_response = `#{@ffmpeg_binary} -i #{@full_filename} 2>&1`
49
+ else
50
+ raise ArgumentError, "Must supply either an input file or a pregenerated response" if options[:raw_response].nil? and file.nil?
51
+ end
52
+
53
+ metadata = /(Input \#.*)\n(Must|At\sleast)/m.match(@raw_response)
54
+
55
+ if /Unknown format/i.match(@raw_response) || metadata.nil?
56
+ @unknown_format = true
57
+ elsif /Duration: N\/A|bitrate: N\/A/im.match(@raw_response)
58
+ @unreadable_file = true
59
+ @raw_metadata = metadata[1] # in this case, we can at least still get the container type
60
+ else
61
+ @raw_metadata = metadata[1]
62
+ end
63
+ end
64
+
65
+ #
66
+ # Returns true if the file can be read successfully. Returns false otherwise.
67
+ #
68
+
69
+ def valid?
70
+ if @unknown_format or @unreadable_file
71
+ false
72
+ else
73
+ true
74
+ end
75
+ end
76
+
77
+ #
78
+ # Returns false if the file can be read successfully. Returns false otherwise.
79
+ #
80
+
81
+ def invalid?
82
+ !valid?
83
+ end
84
+
85
+ #
86
+ # True if the format is not understood ("Unknown Format")
87
+ #
88
+
89
+ def unknown_format?
90
+ if @unknown_format
91
+ true
92
+ else
93
+ false
94
+ end
95
+ end
96
+
97
+ #
98
+ # True if the file is not readable ("Duration: N/A, bitrate: N/A")
99
+ #
100
+
101
+ def unreadable_file?
102
+ if @unreadable_file
103
+ true
104
+ else
105
+ false
106
+ end
107
+ end
108
+
109
+ #
110
+ # Does the file have an audio stream?
111
+ #
112
+
113
+ def audio?
114
+ if audio_match.nil?
115
+ false
116
+ else
117
+ true
118
+ end
119
+ end
120
+
121
+ #
122
+ # Does the file have a video stream?
123
+ #
124
+
125
+ def video?
126
+ if video_match.nil?
127
+ false
128
+ else
129
+ true
130
+ end
131
+ end
132
+
133
+
134
+ #
135
+ # Returns the version of ffmpeg used, In practice, this may or may not be
136
+ # useful.
137
+ #
138
+ # Examples:
139
+ #
140
+ # SVN-r6399
141
+ # CVS
142
+ #
143
+
144
+ def ffmpeg_version
145
+ @ffmpeg_version = @raw_response.split("\n").first.split("version").last.split(",").first.strip
146
+ end
147
+
148
+ #
149
+ # Returns the configuration options used to build ffmpeg.
150
+ #
151
+ # Example:
152
+ #
153
+ # --enable-mp3lame --enable-gpl --disable-ffplay --disable-ffserver
154
+ # --enable-a52 --enable-xvid
155
+ #
156
+
157
+ def ffmpeg_configuration
158
+ /(\s*configuration:)(.*)\n/.match(@raw_response)[2].strip
159
+ end
160
+
161
+ #
162
+ # Returns the versions of libavutil, libavcodec, and libavformat used by
163
+ # ffmpeg.
164
+ #
165
+ # Example:
166
+ #
167
+ # libavutil version: 49.0.0
168
+ # libavcodec version: 51.9.0
169
+ # libavformat version: 50.4.0
170
+ #
171
+
172
+ def ffmpeg_libav
173
+ /^(\s*lib.*\n)+/.match(@raw_response)[0].split("\n").each {|l| l.strip! }
174
+ end
175
+
176
+ #
177
+ # Returns the build description for ffmpeg.
178
+ #
179
+ # Example:
180
+ #
181
+ # built on Apr 15 2006 04:58:19, gcc: 4.0.1 (Apple Computer, Inc. build
182
+ # 5250)
183
+ #
184
+
185
+ def ffmpeg_build
186
+ /(\n\s*)(built on.*)(\n)/.match(@raw_response)[2]
187
+ end
188
+
189
+ #
190
+ # Returns the container format for the file. Instead of returning a single
191
+ # format, this may return a string of related formats.
192
+ #
193
+ # Examples:
194
+ #
195
+ # "avi"
196
+ #
197
+ # "mov,mp4,m4a,3gp,3g2,mj2"
198
+ #
199
+
200
+ def container
201
+ return nil if @unknown_format
202
+
203
+ /Input \#\d+\,\s*(\S+),\s*from/.match(@raw_metadata)[1]
204
+ end
205
+
206
+ #
207
+ # The duration of the movie, as a string.
208
+ #
209
+ # Example:
210
+ #
211
+ # "00:00:24.4" # 24.4 seconds
212
+ #
213
+ def raw_duration
214
+ return nil unless valid?
215
+
216
+ /Duration:\s*([0-9\:\.]+),/.match(@raw_metadata)[1]
217
+ end
218
+
219
+ #
220
+ # The duration of the movie in milliseconds, as an integer.
221
+ #
222
+ # Example:
223
+ #
224
+ # 24400 # 24.4 seconds
225
+ #
226
+ # Note that the precision of the duration is in tenths of a second, not
227
+ # thousandths, but milliseconds are a more standard unit of time than
228
+ # deciseconds.
229
+ #
230
+
231
+ def duration
232
+ return nil unless valid?
233
+
234
+ units = raw_duration.split(":")
235
+ (units[0].to_i * 60 * 60 * 1000) + (units[1].to_i * 60 * 1000) + (units[2].to_f * 1000).to_i
236
+ end
237
+
238
+ #
239
+ # The bitrate of the movie.
240
+ #
241
+ # Example:
242
+ #
243
+ # 3132
244
+ #
245
+
246
+ def bitrate
247
+ return nil unless valid?
248
+
249
+ bitrate_match[1].to_i
250
+ end
251
+
252
+ #
253
+ # The bitrate units used. In practice, this may always be kb/s.
254
+ #
255
+ # Example:
256
+ #
257
+ # "kb/s"
258
+ #
259
+
260
+ def bitrate_units
261
+ return nil unless valid?
262
+
263
+ bitrate_match[2]
264
+ end
265
+
266
+ def audio_bitrate # :nodoc:
267
+ nil
268
+ end
269
+
270
+ def audio_stream
271
+ return nil unless valid?
272
+
273
+ #/\n\s*Stream.*Audio:.*\n/.match(@raw_response)[0].strip
274
+ match = /\n\s*Stream.*Audio:.*\n/.match(@raw_response)
275
+ return match[0].strip if match
276
+ end
277
+
278
+ #
279
+ # The audio codec used.
280
+ #
281
+ # Example:
282
+ #
283
+ # "aac"
284
+ #
285
+
286
+ def audio_codec
287
+ return nil unless audio?
288
+
289
+ audio_match[2]
290
+ end
291
+
292
+ #
293
+ # The sampling rate of the audio stream.
294
+ #
295
+ # Example:
296
+ #
297
+ # 44100
298
+ #
299
+
300
+ def audio_sample_rate
301
+ return nil unless audio?
302
+
303
+ audio_match[3].to_i
304
+ end
305
+
306
+ #
307
+ # The units used for the sampling rate. May always be Hz.
308
+ #
309
+ # Example:
310
+ #
311
+ # "Hz"
312
+ #
313
+
314
+ def audio_sample_units
315
+ return nil unless audio?
316
+
317
+ audio_match[4]
318
+ end
319
+
320
+ #
321
+ # The channels used in the audio stream.
322
+ #
323
+ # Examples:
324
+ # "stereo"
325
+ # "mono"
326
+ # "5:1"
327
+ #
328
+
329
+ def audio_channels_string
330
+ return nil unless audio?
331
+
332
+ audio_match[5]
333
+ end
334
+
335
+ def audio_channels
336
+ return nil unless audio?
337
+
338
+ case audio_match[5]
339
+ when "mono"
340
+ 1
341
+ when "stereo"
342
+ 2
343
+ else
344
+ raise RuntimeError, "Unknown number of channels: #{audio_channels}"
345
+ end
346
+ end
347
+
348
+ #
349
+ # The ID of the audio stream (useful for troubleshooting).
350
+ #
351
+ # Example:
352
+ # #0.1
353
+ #
354
+
355
+ def audio_stream_id
356
+ return nil unless audio?
357
+
358
+ audio_match[1]
359
+ end
360
+
361
+ def video_stream
362
+ return nil unless valid?
363
+
364
+ match = /\n\s*Stream.*Video:.*\n/.match(@raw_response)
365
+ return match[0].strip unless match.nil?
366
+ nil
367
+ end
368
+
369
+ #
370
+ # The ID of the video stream (useful for troubleshooting).
371
+ #
372
+ # Example:
373
+ # #0.0
374
+ #
375
+
376
+ def video_stream_id
377
+ return nil unless video?
378
+
379
+ video_match[1]
380
+ end
381
+
382
+ #
383
+ # The video codec used.
384
+ #
385
+ # Example:
386
+ #
387
+ # "mpeg4"
388
+ #
389
+
390
+ def video_codec
391
+ return nil unless video?
392
+
393
+ video_match[2]
394
+ end
395
+
396
+ #
397
+ # The colorspace of the video stream.
398
+ #
399
+ # Example:
400
+ #
401
+ # "yuv420p"
402
+ #
403
+
404
+ def video_colorspace
405
+ return nil unless video?
406
+
407
+ video_match[3]
408
+ end
409
+
410
+ #
411
+ # The width of the video in pixels.
412
+ #
413
+
414
+ def width
415
+ return nil unless video?
416
+
417
+ video_match[4].to_i
418
+ end
419
+
420
+ #
421
+ # The height of the video in pixels.
422
+ #
423
+
424
+ def height
425
+ return nil unless video?
426
+
427
+ video_match[5].to_i
428
+ end
429
+
430
+ #
431
+ # width x height, as a string.
432
+ #
433
+ # Examples:
434
+ # 320x240
435
+ # 1280x720
436
+ #
437
+
438
+ def resolution
439
+ return nil unless video?
440
+
441
+ "#{width}x#{height}"
442
+ end
443
+
444
+ #
445
+ # The frame rate of the video in frames per second
446
+ #
447
+ # Example:
448
+ #
449
+ # "29.97"
450
+ #
451
+
452
+ def fps
453
+ return nil unless video?
454
+
455
+ /([0-9\.]+) fps/.match(video_stream)[1]
456
+ end
457
+
458
+ private
459
+
460
+ def bitrate_match
461
+ /bitrate: ([0-9\.]+)\s*(.*)\s+/.match(@raw_metadata)
462
+ end
463
+
464
+ def audio_match
465
+ return nil unless valid?
466
+
467
+ /Stream\s*(.*?)[,|:|\(|\[].*?\s*Audio:\s*(.*?),\s*([0-9\.]*) (\w*),\s*([a-zA-Z:]*)/.match(audio_stream)
468
+ end
469
+
470
+ def video_match
471
+ return nil unless valid?
472
+
473
+ match = /Stream\s*(.*?)[,|:|\(|\[].*?\s*Video:\s*(.*?),\s*(.*?),\s*(\d*)x(\d*)/.match(video_stream)
474
+
475
+ # work-around for Apple Intermediate format, which does not have a color space
476
+ # I fake up a match data object (yea, duck typing!) with an empty spot where
477
+ # the color space would be.
478
+ if match.nil?
479
+ match = /Stream\s*(.*?)[,|:|\(|\[].*?\s*Video:\s*(.*?),\s*(\d*)x(\d*)/.match(video_stream)
480
+ match = [nil, match[1], match[2], nil, match[3], match[4]] unless match.nil?
481
+ end
482
+
483
+ match
484
+ end
485
+ end
486
+ end