newbamboo-rvideo 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGELOG +70 -0
  2. data/ENV +100 -0
  3. data/ENV2 +129 -0
  4. data/LICENSE +20 -0
  5. data/Manifest +68 -0
  6. data/README +106 -0
  7. data/RULES +11 -0
  8. data/Rakefile +63 -0
  9. data/config/boot.rb +25 -0
  10. data/lib/rvideo.rb +46 -0
  11. data/lib/rvideo/errors.rb +24 -0
  12. data/lib/rvideo/float.rb +7 -0
  13. data/lib/rvideo/frame_capturer.rb +127 -0
  14. data/lib/rvideo/inspector.rb +482 -0
  15. data/lib/rvideo/reporter.rb +176 -0
  16. data/lib/rvideo/reporter/views/index.html.erb +27 -0
  17. data/lib/rvideo/reporter/views/report.css +27 -0
  18. data/lib/rvideo/reporter/views/report.html.erb +81 -0
  19. data/lib/rvideo/reporter/views/report.js +9 -0
  20. data/lib/rvideo/string.rb +5 -0
  21. data/lib/rvideo/tools/abstract_tool.rb +406 -0
  22. data/lib/rvideo/tools/ffmpeg.rb +356 -0
  23. data/lib/rvideo/tools/ffmpeg2theora.rb +42 -0
  24. data/lib/rvideo/tools/flvtool2.rb +50 -0
  25. data/lib/rvideo/tools/mencoder.rb +103 -0
  26. data/lib/rvideo/tools/mp4box.rb +21 -0
  27. data/lib/rvideo/tools/mp4creator.rb +35 -0
  28. data/lib/rvideo/tools/mplayer.rb +31 -0
  29. data/lib/rvideo/tools/qtfaststart.rb +37 -0
  30. data/lib/rvideo/tools/segmenter.rb +21 -0
  31. data/lib/rvideo/tools/yamdi.rb +44 -0
  32. data/lib/rvideo/transcoder.rb +139 -0
  33. data/lib/rvideo/version.rb +9 -0
  34. data/rvideo.gemspec +36 -0
  35. data/scripts/txt2html +67 -0
  36. data/setup.rb +1585 -0
  37. data/spec/files/boat.avi +0 -0
  38. data/spec/files/kites.mp4 +0 -0
  39. data/spec/fixtures/ffmpeg_builds.yml +28 -0
  40. data/spec/fixtures/ffmpeg_results.yml +608 -0
  41. data/spec/fixtures/files.yml +398 -0
  42. data/spec/fixtures/recipes.yml +58 -0
  43. data/spec/integrations/formats_spec.rb +315 -0
  44. data/spec/integrations/frame_capturer_spec.rb +26 -0
  45. data/spec/integrations/inspection_spec.rb +112 -0
  46. data/spec/integrations/recipes_spec.rb +0 -0
  47. data/spec/integrations/rvideo_spec.rb +17 -0
  48. data/spec/integrations/transcoder_integration_spec.rb +29 -0
  49. data/spec/integrations/transcoding_spec.rb +9 -0
  50. data/spec/spec.opts +1 -0
  51. data/spec/spec_helper.rb +16 -0
  52. data/spec/support.rb +36 -0
  53. data/spec/units/abstract_tool_spec.rb +111 -0
  54. data/spec/units/ffmpeg_spec.rb +323 -0
  55. data/spec/units/flvtool2_spec.rb +324 -0
  56. data/spec/units/frame_capturer_spec.rb +72 -0
  57. data/spec/units/inspector_spec.rb +59 -0
  58. data/spec/units/mencoder_spec.rb +4994 -0
  59. data/spec/units/mp4box_spec.rb +34 -0
  60. data/spec/units/mp4creator_spec.rb +34 -0
  61. data/spec/units/mplayer_spec.rb +34 -0
  62. data/spec/units/qtfaststart_spec.rb +35 -0
  63. data/spec/units/string_spec.rb +8 -0
  64. data/spec/units/transcoder_spec.rb +156 -0
  65. data/tasks/deployment.rake +5 -0
  66. data/tasks/testing.rake +27 -0
  67. data/tasks/transcoding.rake +40 -0
  68. data/tasks/website.rake +8 -0
  69. metadata +179 -0
@@ -0,0 +1,21 @@
1
+ module RVideo
2
+ module Tools
3
+ class Mp4box
4
+ include AbstractTool::InstanceMethods
5
+ attr_reader :raw_metadata
6
+
7
+ def tool_command
8
+ 'MP4Box'
9
+ end
10
+
11
+ private
12
+
13
+ def parse_result(result)
14
+ #currently, no useful info returned in result to determine if successful or not
15
+ @raw_metadata = result.empty? ? "No Results" : result
16
+ return true
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module RVideo
2
+ module Tools
3
+ class Mp4creator
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :raw_metadata
7
+
8
+ def tool_command
9
+ 'mp4creator'
10
+ end
11
+
12
+ def format_fps(params={})
13
+ " -rate=#{params[:fps]}"
14
+ end
15
+
16
+ def parse_result(result)
17
+ if m = /can't open file/.match(result)
18
+ raise TranscoderError::InvalidFile, "I/O error"
19
+ end
20
+
21
+ if m = /unknown file type/.match(result)
22
+ raise TranscoderError::InvalidFile, "I/O error"
23
+ end
24
+
25
+ if @options['output_file'] && !File.exist?(@options['output_file'])
26
+ raise TranscoderError::UnexpectedResult, "An unknown error has occured with mp4creator:#{result}"
27
+ end
28
+
29
+ @raw_metadata = result.empty? ? "No Results" : result
30
+ return true
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ module RVideo
2
+ module Tools
3
+ class Mplayer
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :raw_metadata
7
+
8
+ def tool_command
9
+ 'mplayer'
10
+ end
11
+
12
+ def parse_result(result)
13
+ if m = /This will likely crash/.match(result)
14
+ raise TranscoderError::InvalidFile, "unknown format"
15
+ end
16
+
17
+ if m = /Failed to open/.match(result)
18
+ raise TranscoderError::InvalidFile, "I/O error"
19
+ end
20
+
21
+ if m = /File not found/.match(result)
22
+ raise TranscoderError::InvalidFile, "I/O error"
23
+ end
24
+
25
+ @raw_metadata = result.empty? ? "No Results" : result
26
+ return true
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ module RVideo
2
+ module Tools
3
+ class QtFaststart
4
+ include AbstractTool::InstanceMethods
5
+ attr_reader :raw_metadata
6
+
7
+ def tool_command
8
+ 'qt-faststart'
9
+ end
10
+
11
+ private
12
+
13
+ def parse_result(result)
14
+
15
+ if m = /Usage: qt-faststart <infile.mov> <outfile.mov>/.match(result)
16
+ raise TranscoderError::InvalidCommand, "Usage: qt-faststart <infile.mov> <outfile.mov>"
17
+ end
18
+
19
+ if m = /last atom in file was not a moov atom/.match(result)
20
+ raise TranscoderError::InvalidFile, "Could not find moov atom"
21
+ end
22
+
23
+ if m = /No such file or directory/.match(result)
24
+ raise TranscoderError::InvalidFile, "No such file or directory"
25
+ end
26
+
27
+ if m = /Undefined error:/.match(result)
28
+ raise TranscoderError::UnexpectedResult, "Undefined error"
29
+ end
30
+
31
+ @raw_metadata = result.empty? ? "No Results" : result
32
+ return true
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module RVideo
2
+ module Tools
3
+ class Segmenter
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :raw_metadata
7
+
8
+ def tool_command
9
+ 'segmenter'
10
+ end
11
+
12
+ private
13
+
14
+ def parse_result(result)
15
+ # TODO: parse segmenter results
16
+ return true
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ module RVideo
2
+ module Tools
3
+ class Yamdi
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :raw_metadata
7
+
8
+ def tool_command
9
+ 'yamdi'
10
+ end
11
+
12
+ private
13
+
14
+ def parse_result(result)
15
+ if result.empty?
16
+ return true
17
+ end
18
+
19
+ if m = /Couldn't stat on (.*)/.match(result)
20
+ raise TranscoderError::InputFileNotFound, m[0]
21
+ end
22
+
23
+ if m = /The input file is not a FLV./.match(result)
24
+ raise TranscoderError::InvalidFile, "input must be a valid FLV file"
25
+ end
26
+
27
+ if m = /\(c\) \d{4} Ingo Oppermann/i.match(result)
28
+ raise TranscoderError::InvalidCommand, "command printed yamdi help text (and presumably didn't execute)"
29
+ end
30
+
31
+ if m = /Please provide at least one output file/i.match(result)
32
+ raise TranscoderError::InvalidCommand, "command did not contain a valid output file. Yamdi expects a -o switch."
33
+ end
34
+
35
+ if m = /ERROR: undefined method .?timestamp.? for nil/.match(result)
36
+ raise TranscoderError::InvalidFile, "Output file was empty (presumably)"
37
+ end
38
+
39
+ raise TranscoderError::UnexpectedResult, result
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,139 @@
1
+ module RVideo # :nodoc:
2
+ class Transcoder
3
+
4
+ attr_reader :executed_commands, :processed, :errors, :warnings, :total_time
5
+
6
+ #
7
+ # To transcode a video, initialize a Transcoder object:
8
+ #
9
+ # transcoder = RVideo::Transcoder.new("/path/to/input.mov")
10
+ #
11
+ # Then pass a recipe and valid options to the execute method
12
+ #
13
+ # recipe = "ffmpeg -i $input_file$ -ar 22050 -ab 64 -f flv -r 29.97 -s"
14
+ # recipe += " $resolution$ -y $output_file$"
15
+ # recipe += "\nflvtool2 -U $output_file$"
16
+ # begin
17
+ # transcoder.execute(recipe, {:output_file => "/path/to/output.flv",
18
+ # :resolution => "640x360"})
19
+ # rescue TranscoderError => e
20
+ # puts "Unable to transcode file: #{e.class} - #{e.message}"
21
+ # end
22
+ #
23
+ # If the job succeeds, you can access the metadata of the input and output
24
+ # files with:
25
+ #
26
+ # transcoder.original # RVideo::Inspector object
27
+ # transcoder.processed # RVideo::Inspector object
28
+ #
29
+ # If the transcoding succeeds, the file may still have problems. RVideo
30
+ # will populate an errors array if the duration of the processed video
31
+ # differs from the duration of the original video, or if the processed
32
+ # file is unreadable.
33
+ #
34
+
35
+ def initialize(input_file = nil)
36
+ # Allow a nil input_file for backwards compatibility. (Change at 1.0?)
37
+ check_input_file(input_file)
38
+
39
+ @input_file = input_file
40
+ @executed_commands = []
41
+ @errors = []
42
+ @warnings = []
43
+ end
44
+
45
+ def original
46
+ @original ||= Inspector.new(:file => @input_file)
47
+ end
48
+
49
+ #
50
+ # Requires a command and a hash of various interpolated options. The
51
+ # command should be one or more lines of transcoder tool commands (e.g.
52
+ # ffmpeg, flvtool2). Interpolate options by adding $option_key$ to the
53
+ # recipe, and passing :option_key => "value" in the options hash.
54
+ #
55
+ # recipe = "ffmpeg -i $input_file$ -ar 22050 -ab 64 -f flv -r 29.97
56
+ # recipe += "-s $resolution$ -y $output_file$"
57
+ # recipe += "\nflvtool2 -U $output_file$"
58
+ #
59
+ # transcoder = RVideo::Transcoder.new("/path/to/input.mov")
60
+ # begin
61
+ # transcoder.execute(recipe, {:output_file => "/path/to/output.flv", :resolution => "320x240"})
62
+ # rescue TranscoderError => e
63
+ # puts "Unable to transcode file: #{e.class} - #{e.message}"
64
+ # end
65
+ #
66
+
67
+ def execute(task, options = {})
68
+ options[:progress_sample_rate] ||= 5
69
+ options[:progress_timeout] ||= false
70
+
71
+ t1 = Time.now
72
+
73
+ if @input_file.nil?
74
+ @input_file = options[:input_file]
75
+ end
76
+
77
+ RVideo.logger.info("\nNew transcoder job\n================\nTask: #{task}\nOptions: #{options.inspect}")
78
+
79
+ if block_given?
80
+ parse_and_execute(task, options) do |tool, progress|
81
+ yield(tool, progress)
82
+ end
83
+ else
84
+ parse_and_execute(task, options)
85
+ end
86
+
87
+ @processed = Inspector.new(:file => options[:output_file])
88
+ result = check_integrity
89
+ RVideo.logger.info("\nFinished task. Total errors: #{@errors.size}\n")
90
+ @total_time = Time.now - t1
91
+ result
92
+ rescue TranscoderError => e
93
+ raise e
94
+ rescue Exception => e
95
+ RVideo.logger.error "[ERROR] Unhandled RVideo exception: #{e.class} - #{e.message}"
96
+ RVideo.logger.error e.backtrace.join("\n\t")
97
+ raise TranscoderError::UnknownError, "Unexpected RVideo error: #{e.message} (#{e.class})"
98
+ end
99
+
100
+ private
101
+
102
+ def check_input_file(input_file)
103
+ if input_file and !FileTest.exist?(input_file.gsub("\"",""))
104
+ raise TranscoderError::InputFileNotFound, "File not found (#{input_file})"
105
+ end
106
+ end
107
+
108
+ def check_integrity
109
+ precision = 1.1
110
+ if @processed.invalid?
111
+ @errors << "Output file invalid"
112
+ elsif (@processed.duration >= (original.duration * precision) or @processed.duration <= (original.duration / precision))
113
+ @errors << "Original file has a duration of #{original.duration}, but processed file has a duration of #{@processed.duration}"
114
+ end
115
+ return @errors.size == 0
116
+ end
117
+
118
+ def parse_and_execute(task, options = {})
119
+ raise TranscoderError::ParameterError, "Expected a recipe class (as a string), but got a #{task.class.to_s} (#{task})" unless task.is_a? String
120
+ options = options.merge(:input_file => @input_file)
121
+
122
+ commands = task.split("\n").compact
123
+ commands.each do |c|
124
+ tool = Tools::AbstractTool.assign(c, options)
125
+ tool.original = original
126
+
127
+ if block_given?
128
+ tool.execute do |progress|
129
+ yield(tool, progress)
130
+ end
131
+ else
132
+ tool.execute
133
+ end
134
+
135
+ executed_commands << tool
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,9 @@
1
+ module RVideo #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 9
5
+ TINY = 6
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{newbamboo-rvideo}
5
+ s.version = "0.9.6"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Peter Boling, Jonathan Dahl (Slantwise Design), Seth Thomas Rasmussen"]
9
+ s.date = %q{2010-01-29}
10
+ s.description = %q{Inspect and transcode video and audio files.}
11
+ s.email = %q{sethrasmussen@gmail.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/rvideo/errors.rb", "lib/rvideo/float.rb", "lib/rvideo/frame_capturer.rb", "lib/rvideo/inspector.rb", "lib/rvideo/reporter/views/index.html.erb", "lib/rvideo/reporter/views/report.css", "lib/rvideo/reporter/views/report.html.erb", "lib/rvideo/reporter/views/report.js", "lib/rvideo/reporter.rb", "lib/rvideo/string.rb", "lib/rvideo/tools/abstract_tool.rb", "lib/rvideo/tools/ffmpeg.rb", "lib/rvideo/tools/ffmpeg2theora.rb", "lib/rvideo/tools/flvtool2.rb", "lib/rvideo/tools/mencoder.rb", "lib/rvideo/tools/mp4box.rb", "lib/rvideo/tools/mp4creator.rb", "lib/rvideo/tools/mplayer.rb", "lib/rvideo/tools/qtfaststart.rb", "lib/rvideo/tools/yamdi.rb", "lib/rvideo/tools/segmenter.rb", "lib/rvideo/transcoder.rb", "lib/rvideo/version.rb", "lib/rvideo.rb", "LICENSE", "README", "tasks/deployment.rake", "tasks/testing.rake", "tasks/transcoding.rake", "tasks/website.rake"]
13
+ s.files = ["CHANGELOG", "config/boot.rb", "ENV", "ENV2", "lib/rvideo/errors.rb", "lib/rvideo/float.rb", "lib/rvideo/frame_capturer.rb", "lib/rvideo/inspector.rb", "lib/rvideo/reporter/views/index.html.erb", "lib/rvideo/reporter/views/report.css", "lib/rvideo/reporter/views/report.html.erb", "lib/rvideo/reporter/views/report.js", "lib/rvideo/reporter.rb", "lib/rvideo/string.rb", "lib/rvideo/tools/abstract_tool.rb", "lib/rvideo/tools/ffmpeg.rb", "lib/rvideo/tools/ffmpeg2theora.rb", "lib/rvideo/tools/flvtool2.rb", "lib/rvideo/tools/mencoder.rb", "lib/rvideo/tools/mp4box.rb", "lib/rvideo/tools/mp4creator.rb", "lib/rvideo/tools/mplayer.rb", "lib/rvideo/tools/qtfaststart.rb", "lib/rvideo/tools/yamdi.rb", "lib/rvideo/tools/segmenter.rb", "lib/rvideo/transcoder.rb", "lib/rvideo/version.rb", "lib/rvideo.rb", "LICENSE", "Manifest", "Rakefile", "README", "RULES", "rvideo.gemspec", "scripts/txt2html", "setup.rb", "spec/files/boat.avi", "spec/files/kites.mp4", "spec/fixtures/ffmpeg_builds.yml", "spec/fixtures/ffmpeg_results.yml", "spec/fixtures/files.yml", "spec/fixtures/recipes.yml", "spec/integrations/formats_spec.rb", "spec/integrations/frame_capturer_spec.rb", "spec/integrations/inspection_spec.rb", "spec/integrations/recipes_spec.rb", "spec/integrations/rvideo_spec.rb", "spec/integrations/transcoder_integration_spec.rb", "spec/integrations/transcoding_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/support.rb", "spec/units/abstract_tool_spec.rb", "spec/units/ffmpeg_spec.rb", "spec/units/flvtool2_spec.rb", "spec/units/frame_capturer_spec.rb", "spec/units/inspector_spec.rb", "spec/units/mencoder_spec.rb", "spec/units/mp4box_spec.rb", "spec/units/mp4creator_spec.rb", "spec/units/mplayer_spec.rb", "spec/units/qtfaststart_spec.rb", "spec/units/string_spec.rb", "spec/units/transcoder_spec.rb", "tasks/deployment.rake", "tasks/testing.rake", "tasks/transcoding.rake", "tasks/website.rake"]
14
+ s.homepage = %q{http://github.com/newbamboo/rvideo}
15
+ s.rdoc_options = ["--quiet", "--title", "rvideo documentation", "--opname", "index.html", "--line-numbers", "--main", "README", "--inline-source"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{newbamboo-rvideo}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{Inspect and transcode video and audio files.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
27
+ s.add_development_dependency(%q<rspec>, [">= 0"])
28
+ else
29
+ s.add_dependency(%q<activesupport>, [">= 0"])
30
+ s.add_dependency(%q<rspec>, [">= 0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<activesupport>, [">= 0"])
34
+ s.add_dependency(%q<rspec>, [">= 0"])
35
+ end
36
+ end
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'redcloth'
5
+ require 'syntax/convertors/html'
6
+ require 'erb'
7
+ require File.dirname(__FILE__) + '/../lib/rvideo/version.rb'
8
+
9
+ version = Rvideo::VERSION::STRING
10
+ download = 'http://rubyforge.org/projects/rvideo'
11
+
12
+ class Fixnum
13
+ def ordinal
14
+ # teens
15
+ return 'th' if (10..19).include?(self % 100)
16
+ # others
17
+ case self % 10
18
+ when 1: return 'st'
19
+ when 2: return 'nd'
20
+ when 3: return 'rd'
21
+ else return 'th'
22
+ end
23
+ end
24
+ end
25
+
26
+ class Time
27
+ def pretty
28
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
29
+ end
30
+ end
31
+
32
+ def convert_syntax(syntax, source)
33
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
34
+ end
35
+
36
+ if ARGV.length >= 1
37
+ src, template = ARGV
38
+ template ||= File.dirname(__FILE__) + '/../website/template.rhtml'
39
+
40
+ else
41
+ puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
42
+ exit!
43
+ end
44
+
45
+ template = ERB.new(File.open(template).read)
46
+
47
+ title = nil
48
+ body = nil
49
+ File.open(src) do |fsrc|
50
+ title_text = fsrc.readline
51
+ body_text = fsrc.read
52
+ syntax_items = []
53
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</>!m){
54
+ ident = syntax_items.length
55
+ element, syntax, source = $1, $2, $3
56
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
57
+ "syntax-temp-#{ident}"
58
+ }
59
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
60
+ body = RedCloth.new(body_text).to_html
61
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
62
+ end
63
+ stat = File.stat(src)
64
+ created = stat.ctime
65
+ modified = stat.mtime
66
+
67
+ $stdout << template.result(binding)