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,176 @@
1
+ require 'erb'
2
+
3
+ module RVideo
4
+ class Reporter
5
+ include ERB::Util
6
+
7
+ def self.run
8
+ Reporter.new.run
9
+ end
10
+
11
+ def run
12
+ @current_report_path = Reporter.next_available_report_path(File.join(REPORT_PATH, 'generated_reports'))
13
+ files = available_files
14
+ recipes = available_recipes
15
+
16
+ puts "\nInput files:\n--#{files.collect { |file| File.basename(file) }.join("\n--")}"
17
+ puts "\nInput recipes:\n--#{recipes.map {|name, recipe| name }.join("\n--")}"
18
+ combinations = calculate_combinations_using recipes, files
19
+ results = mass_transcode combinations
20
+ build_report_from results
21
+ puts "Done! Report available at #{@current_report_path}"
22
+ puts "Launching report in browser..."
23
+ exec "open #{@current_report_path}/index.html"
24
+ end
25
+
26
+ private
27
+
28
+ def self.next_available_report_path(base_path)
29
+ ordered_reports = Dir[File.join(base_path, "*")].sort_by {|name| File.basename(name).to_i }
30
+ ordered_reports = ["0"] if ordered_reports.empty?
31
+ last_report = File.basename(ordered_reports.last)
32
+ new_report_name = (last_report.to_i + 1).to_s
33
+ new_dir = File.join(base_path, new_report_name)
34
+ FileUtils.mkdir_p(new_dir)
35
+ new_dir
36
+ end
37
+
38
+ def available_recipes
39
+ recipes = []
40
+ recipe_files = Dir[File.join(REPORT_PATH, "*.yml")]
41
+ recipe_files.each do |recipe_file|
42
+ YAML.load_file(recipe_file).each { |recipe| recipes << recipe }
43
+ end
44
+ if recipes.empty?
45
+ puts "No recipes found. Add recipe YAML files to report/."
46
+ exit
47
+ else
48
+ recipes
49
+ end
50
+ end
51
+
52
+ def available_files
53
+ files = Dir[File.join(REPORT_PATH, "files/input/*.*")]
54
+ if files.empty?
55
+ puts "No input files. Add files to report/files/input to test."
56
+ exit
57
+ else
58
+ files
59
+ end
60
+ end
61
+
62
+ def calculate_combinations_using(recipes, files)
63
+ @combinations = {}
64
+ files.each { |file| @combinations[file] = recipes }
65
+ @combinations
66
+ end
67
+
68
+ def build_report_from(results, options = nil)
69
+ @results = results
70
+ #build main report
71
+ report = load_view 'index'
72
+ full_report_path = File.join(@current_report_path, "index.html")
73
+ File.open(full_report_path, "w+") do |file|
74
+ file.write report
75
+ end
76
+ #build individual reports
77
+ @results.each do |input_file, recipes|
78
+ recipes.each do |recipe_name, result|
79
+ build_individual_report(input_file, recipe_name, result)
80
+ end
81
+ end
82
+ end
83
+
84
+ def build_individual_report(input_file, recipe_name, result)
85
+ #instance variables may no longer be necessary...
86
+ @input_file = input_file
87
+ @recipe_name = recipe_name
88
+ @result = result
89
+ individual_report = load_view 'report'
90
+ individual_report_name = "#{underscoreize_file_basename(input_file)}_#{recipe_name}.html"
91
+ File.makedirs(File.join(@current_report_path, "individual_reports"))
92
+ full_report_path = File.join(@current_report_path, "individual_reports", individual_report_name)
93
+ File.open(full_report_path, "w+") do |file|
94
+ file.write individual_report
95
+ end
96
+ end
97
+
98
+
99
+ def load_view(template_name)
100
+ template_file = "#{File.dirname(__FILE__)}/reporter/views/#{template_name}.html.erb"
101
+ template = File.read(template_file).gsub(/^ /, '')
102
+ ERB.new(template).result(binding)
103
+ end
104
+
105
+ def mass_transcode(combinations)
106
+ results = {}
107
+ combinations.each do |file, recipes|
108
+ results[file] = {}
109
+ recipes.each do |recipe_name, recipe|
110
+ puts "Transcoding #{File.basename(file)} using recipe #{recipe_name}"
111
+
112
+ #generate input/output file paths
113
+ input_file = File.expand_path(file)
114
+ output_file = generate_output_file_using input_file, recipe_name, recipe
115
+ #raise output_file
116
+ #input_file.gsub!(" ","\\ ")
117
+ input_file = "#{File.dirname(input_file)}/\"#{File.basename(input_file)}\""
118
+
119
+ #create logfile
120
+ log_file_name = underscoreize_file_basename(input_file) + "_" + recipe_name + ".log"
121
+ log_file = create_log_file(log_file_name)
122
+ RVideo::Transcoder.logger = Logger.new(log_file)
123
+
124
+ transcoder, errors = transcode(recipe, input_file, output_file)
125
+
126
+ #build the results object for the views
127
+ results[file][recipe_name] = {}
128
+ results[file][recipe_name]['output_file'] = output_file
129
+ results[file][recipe_name]['transcoder'] = transcoder
130
+ results[file][recipe_name]['errors'] = errors
131
+ results[file][recipe_name]['recipe'] = recipe
132
+ results[file][recipe_name]['log'] = log_file
133
+ end
134
+ end
135
+ return results
136
+ end
137
+
138
+ def generate_output_file_using(selected_file, recipe_name, recipe)
139
+ #File.join(@current_report_path, 'output_files')
140
+ output_path = File.join(@current_report_path, 'output_files' + underscoreize_file_basename(selected_file))
141
+ File.makedirs output_path
142
+ output_filename = "#{recipe_name}.#{recipe['extension']}"
143
+ output_file = File.join(output_path, output_filename)
144
+ #output_file.gsub(" ","_")
145
+ end
146
+
147
+ def underscoreize_file_basename(file)
148
+ File.basename(file).gsub(".","_").gsub(" ","_")
149
+ end
150
+
151
+ def transcode(recipe, input_file, output_file)
152
+ command = recipe['command']
153
+ errors = nil
154
+
155
+ #RVideo::Transcoder.logger = Logger.new(STDOUT)
156
+ begin
157
+ transcoder = RVideo::Transcoder.new
158
+ transcoder.execute(command, {:input_file => input_file,
159
+ :output_file => output_file})
160
+ #rescue => errors
161
+ end
162
+
163
+ return transcoder, errors
164
+ end
165
+
166
+ def create_log_file(log_file_name)
167
+ log_path = File.join(@current_report_path, "logs")
168
+ File.makedirs log_path
169
+ logfile = File.join(log_path, log_file_name)
170
+ File.open(logfile, "w+") { |file| }
171
+ logfile
172
+ end
173
+
174
+ end
175
+
176
+ end
@@ -0,0 +1,27 @@
1
+ <html>
2
+ <head>
3
+ <title>RVideo Reports Index</title>
4
+ <link rel="stylesheet" href="report.css" type="text/css" media="screen" />
5
+ <script type="text/javascript" src="report.js"></script>
6
+ </head>
7
+ <body>
8
+ <% @results.each do |input_file, recipes| %>
9
+ <h1>
10
+ <a href="<%= input_file %>"><%= File.basename(input_file) %> (launch file)</a>
11
+ </h1>
12
+ <ol>
13
+ <% recipes.each do |recipe_name, result| %>
14
+ <li>
15
+ <% css_class = 'warning' unless result['transcoder'].errors.empty? %>
16
+ <% css_class = 'critical' if result['errors'] %>
17
+ <% css_class = 'passed' if css_class.nil? %>
18
+ <div class="<%= css_class %>">
19
+ <% individual_report_url = "individual_reports/" + underscoreize_file_basename(input_file) + "_" + recipe_name + ".html" %>
20
+ <h2><a href="<%= result['output_file'] %>">Launch <%= recipe_name %></a> <a class="view-report" href="<%= individual_report_url %>" >view full report</a></h2>
21
+ </div>
22
+ </li>
23
+ <% end %>
24
+ </ol>
25
+ <% end %>
26
+ </body>
27
+ </html>
@@ -0,0 +1,27 @@
1
+ /* a { color: black; margin-left: 20px;}
2
+ a:visited { color: #111; }
3
+ .critical { background-color: #E6E6E6; border-left: 20px solid #F00; }
4
+ .warning { background-color: #E6E6E6; border-left: 20px solid orange; }
5
+ .passed { background-color: #E6E6E6; border-left: 20px solid #0F0; }
6
+
7
+ div { margin: 10px; border: 1px solid #ccc; padding: 5px; }
8
+ li { margin: 20px; padding: 5px; list-style-type: none; }
9
+ span { background-color: #ccc; padding: 5px; width: 500px;}
10
+ span:hover { cursor: pointer; text-decoration: underline; }
11
+ */
12
+
13
+ html { font-size: .75em;}
14
+ div { font-size: 1.2em;}
15
+ h1, h2, h3, h4, h5, ul { margin: .5em; }
16
+ a { color: black; margin-left: 2em; padding: 1em;}
17
+ a:visited { color: #111; }
18
+ .critical, .warning, .passed { background-color: #E6E6E6; border-left: 5em solid; }
19
+ .critical { border-left-color: #F00; }
20
+ .warning { border-left-color: orange; }
21
+ .passed { border-left-color: #0F0; }
22
+
23
+ div { margin: 1em; border: 1px solid #ccc; padding: .5em; }
24
+ ol li { margin: .01em; padding: 0; margin-left: 5em; }
25
+ ul li { margin: 1em; padding: 1em; list-style-type: none; }
26
+ span { background-color: #ccc; padding: 1em; width: 500px;}
27
+ span:hover { cursor: pointer; text-decoration: underline; }
@@ -0,0 +1,81 @@
1
+ <html>
2
+ <head>
3
+ <title>RVideo Reports</title>
4
+ <link rel="stylesheet" href="<%= report.css %>" type="text/css" media="screen" />
5
+ <script type="text/javascript" src="<%= report.js %>"></script>
6
+ </head>
7
+ <body>
8
+ <div>
9
+ <h2><a href="<%= @result['output_file'] %>">Launch output file</a></h2>
10
+ <ul>
11
+ <li>
12
+ <div>
13
+ <h2>Recipe: <%= @recipe_name %></h2>
14
+ <p>
15
+ <% @result['recipe'].each do |key, value|%>
16
+ <%= key %>: <%= value %><br />
17
+ <% end %>
18
+ </p>
19
+ </div>
20
+ </li>
21
+ <% unless @result['errors'].nil? %>
22
+ <li>
23
+ <span onclick="toggle('rescued-errors');">Hide/Show Rescued Errors</span>
24
+ <div id='rescued-errors' style="display: none;">
25
+ <h2>Rescued Error Backtrace</h2>
26
+ <h4><%= h(@result['errors'].class.name) %></h4>
27
+ <p><%= h(@result['errors'].message)%>
28
+ <p><%= h(@result['errors'].backtrace) %></p>
29
+ </div>
30
+ </li>
31
+ <% end %>
32
+ <li>
33
+ <span onclick="toggle('transcoder');">Hide/Show Transcoder</span>
34
+ <div id='transcoder' style="display: none;">
35
+ <h2>Transcoder</h2>
36
+ <% unless @result['transcoder'].errors.empty? %>
37
+ <h3>Transcoder Errors</h3>
38
+ <p><%= h(@result['transcoder'].errors.inspect) %></p>
39
+ <% end %>
40
+ <h3>Executed Commands</h3>
41
+ <p><%= h(@result['transcoder'].executed_commands.map(&:command)) %></p>
42
+ <h3>Raw Meta</h3>
43
+ <p><%= h(@result['transcoder'].metadata) %></p>
44
+ </div>
45
+ <li>
46
+ <span onclick="toggle('input-file');">Hide/Show Input File</span>
47
+ <div id='input-file' style="display: none;">
48
+ <h2>Original Input File</h2>
49
+ <h3>Raw Metadata</h3>
50
+ <p><%= h(@result['transcoder'].original.raw_metadata) %></p>
51
+ <h3>Raw Response</h3>
52
+ <p><%= h(@result['transcoder'].original.raw_response) %></p>
53
+ </div>
54
+ </li>
55
+ <% if @result['transcoder'].processed %>
56
+ <li>
57
+ <span onclick="toggle('output-file');">Hide/Show Output File</span>
58
+ <div id='output-file' style="display: none;">
59
+ <h2>Processed Output File</h2>
60
+ <h3>Raw Metadata</h3>
61
+ <p><%= h(@result['transcoder'].processed.raw_metadata) %></p>
62
+ <h3>Raw Response</h3>
63
+ <p><%= h(@result['transcoder'].processed.raw_response) %></p>
64
+ </div>
65
+ </li>
66
+ <% end %>
67
+ <li>
68
+ <span onclick="toggle('log');">Hide/Show Log</span>
69
+ <div id='log' style="display: none;">
70
+ <h2>Log</h2>
71
+ <p>
72
+ <% File.readlines(@result['log']).each do |line| %>
73
+ <%= line %> <br />
74
+ <% end %>
75
+ </p>
76
+ </div>
77
+ </li>
78
+ </ul>
79
+ </div>
80
+ </body>
81
+ </html>
@@ -0,0 +1,9 @@
1
+ function toggle(obj) {
2
+ var el = document.getElementById(obj);
3
+ if ( el.style.display != 'none' ) {
4
+ el.style.display = 'none';
5
+ }
6
+ else {
7
+ el.style.display = '';
8
+ }
9
+ }
@@ -0,0 +1,79 @@
1
+ module RVideo # :nodoc:
2
+ module Tools # :nodoc:
3
+ class AbstractTool
4
+
5
+ #
6
+ # AbstractTool is an interface to every transcoder tool class (e.g.
7
+ # ffmpeg, flvtool2). Called by the Transcoder class.
8
+ #
9
+
10
+ def self.assign(cmd, options = {})
11
+ tool_name = cmd.split(" ").first
12
+ tool = "RVideo::Tools::#{tool_name.classify}".constantize.send(:new, cmd, options)
13
+ end
14
+
15
+
16
+ module InstanceMethods
17
+ attr_reader :options, :command, :raw_result
18
+
19
+ def initialize(raw_command, options = {})
20
+ @raw_command = raw_command
21
+ @options = HashWithIndifferentAccess.new(options)
22
+ @command = interpolate_variables(raw_command)
23
+ end
24
+
25
+ #
26
+ # Look for variables surrounded by $, and interpolate with either
27
+ # variables passed in the options hash, or special methods provided by
28
+ # the tool class (e.g. "$original_fps$" with ffmpeg).
29
+ #
30
+ # $foo$ should match
31
+ # \$foo or $foo\$ or \$foo\$ should not
32
+
33
+ def interpolate_variables(raw_command)
34
+ raw_command.scan(/[^\\]\$[-_a-zA-Z]+\$/).each do |match|
35
+ match.strip!
36
+ raw_command.gsub!(match, matched_variable(match))
37
+ end
38
+ raw_command.gsub("\\$", "$")
39
+ end
40
+
41
+ #
42
+ # Strip the $s. First, look for a supplied option that matches the
43
+ # variable name. If one is not found, look for a method that matches.
44
+ # If not found, raise ParameterError exception.
45
+ #
46
+
47
+ def matched_variable(match)
48
+ variable_name = match.gsub("$","")
49
+ if @options.key?(variable_name)
50
+ @options[variable_name] || ""
51
+ elsif self.respond_to? variable_name
52
+ self.send(variable_name)
53
+ else
54
+ raise TranscoderError::ParameterError, "command is looking for the #{variable_name} parameter, but it was not provided. (Command: #{@raw_command})"
55
+ end
56
+ end
57
+
58
+ #
59
+ # Execute the command and parse the result.
60
+ #
61
+
62
+ def execute
63
+ final_command = "#{@command} 2>&1"
64
+ Transcoder.logger.info("\nExecuting Command: #{final_command}\n")
65
+ @raw_result = `#{final_command}`
66
+ Transcoder.logger.info("Result: \n#{@raw_result}")
67
+ parse_result(@raw_result)
68
+ end
69
+
70
+ private
71
+
72
+ def inspect_original
73
+ @original = Inspector.new(:file => options[:input_file])
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,128 @@
1
+ module RVideo
2
+ module Tools
3
+ class Ffmpeg
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :frame, :q, :size, :time, :bitrate, :video_size, :audio_size, :header_size, :overhead, :psnr, :fps
7
+
8
+ # Not sure if this is needed anymore...
9
+ def tool_command
10
+ 'ffmpeg'
11
+ end
12
+
13
+ #
14
+ # Return -r and the frame rate of the original file. E.g.:
15
+ #
16
+ # -r 29.97
17
+ #
18
+ # If the original frame rate can't be determined, return an empty
19
+ # string.
20
+ def original_fps
21
+ inspect_original if @original.nil?
22
+ if @original.fps
23
+ "-r #{@original.fps}"
24
+ else
25
+ ""
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def parse_result(result)
32
+
33
+ if m = /Unable for find a suitable output format for.*$/.match(result)
34
+ raise TranscoderError::InvalidCommand, m[0]
35
+ end
36
+
37
+ if m = /could not find codec parameters/.match(result)
38
+ raise TranscoderError::InvalidFile, "Codec not supported by this build of ffmpeg"
39
+ end
40
+
41
+ if m = /I\/O error occured\n(.*)$/.match(result)
42
+ raise TranscoderError::InvalidFile, "I/O error: #{m[1].strip}"
43
+ end
44
+
45
+ if m = /\n(.*)Unknown Format$/.match(result)
46
+ raise TranscoderError::InvalidFile, "unknown format (#{m[1]})"
47
+ end
48
+
49
+ if m = /\nERROR.*/m.match(result)
50
+ raise TranscoderError::InvalidFile, m[0]
51
+ end
52
+
53
+ if result =~ /usage: ffmpeg/
54
+ raise TranscoderError::InvalidCommand, "must pass a command to ffmpeg"
55
+ end
56
+
57
+ # Could not open './spec/../config/../tmp/processed/1/kites-1.avi'
58
+ if result =~ /Could not open .#{@output_file}.\Z/
59
+ raise TranscoderError, "Could not write output file to #{@output_file}"
60
+ end
61
+
62
+ full_details = /Press .* to stop encoding\n(.*)/m.match(result)
63
+ raise TranscoderError, "Unexpected result details (#{result})" if full_details.nil?
64
+ details = full_details[1].strip.gsub(/\s*\n\s*/," - ")
65
+
66
+ if details =~ /Could not write header/
67
+ raise TranscoderError, details
68
+ end
69
+
70
+ #frame= 584 q=6.0 Lsize= 708kB time=19.5 bitrate= 297.8kbits/s
71
+ #video:49kB audio:153kB global headers:0kB muxing overhead 250.444444%
72
+
73
+ #frame= 4126 q=31.0 Lsize= 5917kB time=69.1 bitrate= 702.0kbits/s
74
+ #video:2417kB audio:540kB global headers:0kB muxing overhead 100.140277%
75
+
76
+ #frame= 273 fps= 31 q=10.0 Lsize= 398kB time=5.9 bitrate= 551.8kbits/s
77
+ #video:284kB audio:92kB global headers:0kB muxing overhead 5.723981%
78
+
79
+ #mdb:94, lastbuf:0 skipping granule 0
80
+ #size= 1080kB time=69.1 bitrate= 128.0kbits /s
81
+ #video:0kB audio:1080kB global headers:0kB muxing overhead 0.002893%
82
+
83
+ #size= 80kB time=5.1 bitrate= 128.0kbits/s ^Msize= 162kB time=10.3 bitrate= 128.0kbits/s ^Msize= 241kB time=15.4 bitrate= 128.0kbits/s ^Msize= 329kB time=21.1 bitrate= 128.0kbits/s ^Msize= 413kB time=26.4 bitrate= 128.0kbits/s ^Msize= 506kB time=32.4 bitrate= 128.0kbits/s ^Msize= 591kB time=37.8 bitrate= 128.0kbits/s ^Msize= 674kB time=43.2 bitrate= 128.0kbits/s ^Msize= 771kB time=49.4 bitrate= 128.0kbits/s ^Msize= 851kB time=54.5 bitrate= 128.0kbits/s ^Msize= 932kB time=59.6 bitrate= 128.0kbits/s ^Msize= 1015kB time=64.9 bitrate= 128.0kbits/s ^Msize= 1094kB time=70.0 bitrate= 128.0kbits/s ^Msize= 1175kB time=75.2 bitrate= 128.0kbits/s ^Msize= 1244kB time=79.6 bitrate= 128.0kbits/s ^Msize= 1335kB time=85.4 bitrate= 128.0kbits/s ^Msize= 1417kB time=90.7 bitrate= 128.0kbits/s ^Msize= 1508kB time=96.5 bitrate= 128.0kbits/s ^Msize= 1589kB time=101.7 bitrate= 128.0kbits/s ^Msize= 1671kB time=106.9 bitrate= 128.0kbits/s ^Msize= 1711kB time=109.5 bitrate= 128.0kbits/s - video:0kB audio:1711kB global headers:0kB muxing overhead 0.001826%
84
+
85
+ #mdb:14, lastbuf:0 skipping granule 0 - overread, skip -5 enddists: -2 -2 - overread, skip -5 enddists: -2 -2 - size= 90kB time=5.7 bitrate= 128.0kbits/s \nsize= 189kB time=12.1 bitrate= 128.0kbits/s
86
+
87
+ #size= 59kB time=20.2 bitrate= 24.0kbits/s \nsize= 139kB time=47.4 bitrate= 24.0kbits/s \nsize= 224kB time=76.5 bitrate= 24.0kbits/s \nsize= 304kB time=103.7 bitrate= 24.0kbits/s \nsi
88
+
89
+ #mdb:14, lastbuf:0 skipping granule 0 - overread, skip -5 enddists: -2 -2 - overread, skip -5 enddists: -2 -2 - size= 81kB time=10.3 bitrate= 64.0kbits/s \nsize= 153kB time=19.6 bitrate= 64.0kbits/s
90
+
91
+ #size= 65kB time=4.1 bitrate= 128.1kbits/s \nsize= 119kB time=7.6 bitrate= 128.0kbits/s \nsize= 188kB time=12.0 bitrate= 128.0kbits/s \nsize= 268kB time=17.1 bitrate= 128.0kbits/s \nsize=
92
+
93
+ #Error while decoding stream #0.1 [mpeg4aac @ 0xb7d089f0]faac: frame decoding failed: Gain control not yet implementedError while decoding stream #0.1frame= 2143 fps= 83 q=4.0 size= 4476kB time=71.3 bitrate= 514.5kbits/s ^M[mpeg4aac @ 0xb7d089f0]faac: frame decoding failed: Gain control not yet implementedError while decoding stream #0.1
94
+
95
+ # NOTE: had to remove "\s" from "\s.*L.*size=" from this regexp below.
96
+ # Not sure why. Unit tests were succeeding, but hand tests weren't.
97
+ if details =~ /video:/
98
+ #success = /^frame=\s*(\S*)\s*q=(\S*).*L.*size=\s*(\S*)\s*time=\s*(\S*)\s*bitrate=\s*(\S*)\s*/m.match(details)
99
+ @frame = sanitary_match(/frame=\s*(\S*)/, details)
100
+ @fps = sanitary_match(/fps=\s*(\S*)/, details)
101
+ @q = sanitary_match(/\s+q=\s*(\S*)/, details)
102
+ @size = sanitary_match(/size=\s*(\S*)/, details)
103
+ @time = sanitary_match(/time=\s*(\S*)/, details)
104
+ @bitrate = sanitary_match(/bitrate=\s*(\S*)/, details)
105
+
106
+ @video_size = /video:\s*(\S*)/.match(details)[1]
107
+ @audio_size = /audio:\s*(\S*)/.match(details)[1]
108
+ @header_size = /headers:\s*(\S*)/.match(details)[1]
109
+ @overhead = /overhead[:]*\s*(\S*)/.match(details)[1]
110
+ psnr_match = /PSNR=(.*)\s*size=/.match(details)
111
+ @psnr = psnr_match[1].strip if psnr_match
112
+ return true
113
+ end
114
+
115
+ #[mp3 @ 0x54340c]flv doesnt support that sample rate, choose from (44100, 22050, 11025)
116
+ #Could not write header for output file #0 (incorrect codec parameters ?)
117
+
118
+ raise TranscoderError::UnexpectedResult, details
119
+ end
120
+
121
+ def sanitary_match(regexp, string)
122
+ match = regexp.match(string)
123
+ return match[1] if match
124
+ end
125
+
126
+ end
127
+ end
128
+ end