rvideo-tecnobrat 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/ENV +100 -0
- data/ENV2 +129 -0
- data/History.txt +30 -0
- data/License.txt +20 -0
- data/Manifest.txt +47 -0
- data/README.txt +91 -0
- data/RULES +11 -0
- data/Rakefile +184 -0
- data/config/boot.rb +16 -0
- data/lib/rvideo.rb +17 -0
- data/lib/rvideo/errors.rb +24 -0
- data/lib/rvideo/float.rb +7 -0
- data/lib/rvideo/inspector.rb +486 -0
- data/lib/rvideo/reporter.rb +176 -0
- data/lib/rvideo/reporter/views/index.html.erb +27 -0
- data/lib/rvideo/reporter/views/report.css +27 -0
- data/lib/rvideo/reporter/views/report.html.erb +81 -0
- data/lib/rvideo/reporter/views/report.js +9 -0
- data/lib/rvideo/tools/abstract_tool.rb +79 -0
- data/lib/rvideo/tools/ffmpeg.rb +128 -0
- data/lib/rvideo/tools/flvtool2.rb +45 -0
- data/lib/rvideo/tools/mencoder.rb +65 -0
- data/lib/rvideo/transcoder.rb +122 -0
- data/lib/rvideo/version.rb +9 -0
- data/scripts/txt2html +67 -0
- data/setup.rb +1585 -0
- data/spec/files/kites.mp4 +0 -0
- data/spec/fixtures/ffmpeg_builds.yml +28 -0
- data/spec/fixtures/files.yml +385 -0
- data/spec/fixtures/recipes.yml +57 -0
- data/spec/integrations/files/files.yml +361 -0
- data/spec/integrations/formats_spec.rb +295 -0
- data/spec/integrations/inspection_spec.rb +15 -0
- data/spec/integrations/recipes_spec.rb +0 -0
- data/spec/integrations/rvideo_spec.rb +17 -0
- data/spec/integrations/transcoding_spec.rb +9 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/units/abstract_tool_spec.rb +112 -0
- data/spec/units/ffmpeg_spec.rb +703 -0
- data/spec/units/flvtool2_spec.rb +314 -0
- data/spec/units/inspector_spec.rb +49 -0
- data/spec/units/mencoder_spec.rb +4986 -0
- data/spec/units/transcoder_spec.rb +140 -0
- data/website/index.html +219 -0
- data/website/index.txt +142 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- 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,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
|