rvideo 0.8.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.
- data/ENV +100 -0
- data/ENV2 +129 -0
- data/History.txt +3 -0
- data/License.txt +20 -0
- data/Manifest.txt +44 -0
- data/README.txt +91 -0
- data/RULES +11 -0
- data/Rakefile +163 -0
- data/config/boot.rb +16 -0
- data/lib/rvideo.rb +19 -0
- data/lib/rvideo/errors.rb +21 -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 +111 -0
- data/lib/rvideo/tools/flvtool2.rb +45 -0
- data/lib/rvideo/transcoder.rb +113 -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 +374 -0
- data/spec/fixtures/recipes.yml +6 -0
- data/spec/integrations/files/files.yml +361 -0
- data/spec/integrations/formats_spec.rb +287 -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 +41 -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 +94 -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
|
+
@options = HashWithIndifferentAccess.new(options)
|
21
|
+
@command = interpolate_variables(raw_command)
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Look for variables surrounded by $, and interpolate with either (1)
|
26
|
+
# variables passed in the options hash, or special methods provided by
|
27
|
+
# the tool class (e.g. "$original_fps$" with ffmpeg).
|
28
|
+
#
|
29
|
+
# $foo$ should match
|
30
|
+
# \$foo or $foo\$ or \$foo\$ should not
|
31
|
+
|
32
|
+
def interpolate_variables(raw_command)
|
33
|
+
|
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, "recipe is expecting a value for the #{variable_name} parameter, but it was not provided."
|
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("Executing: #{final_command}")
|
65
|
+
@raw_result = `#{final_command}`
|
66
|
+
Transcoder.logger.info("Result: #{@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,111 @@
|
|
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
|
+
if m = /Unable for find a suitable output format for.*$/.match(result)
|
33
|
+
raise TranscoderError::InvalidCommand, m[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
if m = /I\/O error occured\n(.*)$/.match(result)
|
37
|
+
raise TranscoderError::InvalidFile, "I/O error: #{m[1].strip}"
|
38
|
+
end
|
39
|
+
|
40
|
+
if m = /\n(.*)Unknown Format$/.match(result)
|
41
|
+
raise TranscoderError::InvalidFile, "unknown format (#{m[1]})"
|
42
|
+
end
|
43
|
+
|
44
|
+
if m = /\nERROR.*/m.match(result)
|
45
|
+
raise TranscoderError::InvalidFile, m[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
if result =~ /usage: ffmpeg/
|
49
|
+
raise TranscoderError::InvalidCommand, "must pass a command to ffmpeg"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Could not open './spec/../config/../tmp/processed/1/kites-1.avi'
|
53
|
+
if result =~ /Could not open .#{@output_file}.\Z/
|
54
|
+
raise TranscoderError, "Could not write output file to #{@output_file}"
|
55
|
+
end
|
56
|
+
|
57
|
+
full_details = /Press .* to stop encoding\n(.*)/m.match(result)
|
58
|
+
raise TranscoderError, "Unexpected result details (#{result})" if full_details.nil?
|
59
|
+
details = full_details[1].strip.gsub(/\s*\n\s*/," - ")
|
60
|
+
|
61
|
+
if details =~ /Could not write header/
|
62
|
+
raise TranscoderError, details
|
63
|
+
end
|
64
|
+
|
65
|
+
#frame= 584 q=6.0 Lsize= 708kB time=19.5 bitrate= 297.8kbits/s
|
66
|
+
#video:49kB audio:153kB global headers:0kB muxing overhead 250.444444%
|
67
|
+
|
68
|
+
#frame= 4126 q=31.0 Lsize= 5917kB time=69.1 bitrate= 702.0kbits/s
|
69
|
+
#video:2417kB audio:540kB global headers:0kB muxing overhead 100.140277%
|
70
|
+
|
71
|
+
#frame= 273 fps= 31 q=10.0 Lsize= 398kB time=5.9 bitrate= 551.8kbits/s
|
72
|
+
#video:284kB audio:92kB global headers:0kB muxing overhead 5.723981%
|
73
|
+
|
74
|
+
#mdb:94, lastbuf:0 skipping granule 0
|
75
|
+
#size= 1080kB time=69.1 bitrate= 128.0kbits /s
|
76
|
+
#video:0kB audio:1080kB global headers:0kB muxing overhead 0.002893%
|
77
|
+
|
78
|
+
# NOTE: had to remove "\s" from "\s.*L.*size=" from this regexp below. Not sure why.
|
79
|
+
# Unit tests were succeeding, but hand tests weren't.
|
80
|
+
if details =~ /video:/
|
81
|
+
#success = /^frame=\s*(\S*)\s*q=(\S*).*L.*size=\s*(\S*)\s*time=\s*(\S*)\s*bitrate=\s*(\S*)\s*/m.match(details)
|
82
|
+
@frame = sanitary_match(/frame=\s*(\S*)/, details)
|
83
|
+
@fps = sanitary_match(/fps=\s*(\S*)/, details)
|
84
|
+
@q = sanitary_match(/\s+q=\s*(\S*)/, details)
|
85
|
+
@size = sanitary_match(/size=\s*(\S*)/, details)
|
86
|
+
@time = sanitary_match(/time=\s*(\S*)/, details)
|
87
|
+
@bitrate = sanitary_match(/bitrate=\s*(\S*)/, details)
|
88
|
+
|
89
|
+
@video_size = /video:\s*(\S*)/.match(details)[1]
|
90
|
+
@audio_size = /audio:\s*(\S*)/.match(details)[1]
|
91
|
+
@header_size = /headers:\s*(\S*)/.match(details)[1]
|
92
|
+
@overhead = /overhead[:]*\s*(\S*)/.match(details)[1]
|
93
|
+
psnr_match = /PSNR=(.*)\s*size=/.match(details)
|
94
|
+
@psnr = psnr_match[1].strip if psnr_match
|
95
|
+
return true
|
96
|
+
end
|
97
|
+
|
98
|
+
#[mp3 @ 0x54340c]flv doesnt support that sample rate, choose from (44100, 22050, 11025)
|
99
|
+
#Could not write header for output file #0 (incorrect codec parameters ?)
|
100
|
+
|
101
|
+
raise TranscoderError::UnexpectedResult, details
|
102
|
+
end
|
103
|
+
|
104
|
+
def sanitary_match(regexp, string)
|
105
|
+
match = regexp.match(string)
|
106
|
+
return match[1] if match
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|