Class: Tracksperanto::Pipeline::Base
- Inherits:
-
Object
- Object
- Tracksperanto::Pipeline::Base
- Includes:
- BlockInit
- Defined in:
- lib/pipeline/base.rb
Overview
The base pipeline is the whole process of track conversion from start to finish. The pipeline object organizes the import formats, scans them, applies the tools. Here’s how a calling sequence for a pipeline looks like:
pipe = Tracksperanto::Pipeline::Base.new
pipe.tool_tuples = ["Shift", {:x => 10}]
pipe.progress_block = lambda{|percent, msg| puts("#{msg}..#{percent.to_i}%") }
pipe.run("/tmp/shakescript.shk", :width => 720, :height => 576)
The pipeline will also automatically allocate output files with the right extensions at the same place where the original file resides, and setup outputs for all supported export formats.
Constant Summary collapse
- EXTENSION =
:nodoc:
/\.([^\.]+)$/
- PERMITTED_OPTIONS =
[:importer, :width, :height]
Instance Attribute Summary collapse
-
#converted_keyframes ⇒ Object
readonly
How many keyframes have been converted.
-
#converted_points ⇒ Object
readonly
How many points have been converted.
-
#exporters ⇒ Object
Assign an array of exporter classes to use them instead of the default “All”.
-
#progress_block ⇒ Object
A block acepting percent and message vars can be assigned here.
-
#tool_tuples ⇒ Object
Contains arrays of the form [“MiddewareName”, => value].
Instance Method Summary collapse
-
#initialize(*any) ⇒ Base
constructor
A new instance of Base.
- #initialize_importer_with_path_and_options(from_input_file_path, options) ⇒ Object
-
#open_owned_export_file(path_to_file) ⇒ Object
Open the file for writing and register it to be closed automatically.
- #report_progress(percent_complete, message) ⇒ Object
- #require_dimensions_in!(opts) ⇒ Object
-
#run(from_input_file_path, passed_options = {}) ⇒ Object
Runs the whole pipeline.
-
#run_export(tracker_data_io, importer, exporter) ⇒ Object
Runs the export and returns the number of points and keyframes processed.
-
#setup_outputs_for(input_file_path) ⇒ Object
Setup output files and return a single output that replays to all of them.
-
#wrap_output_with_tools(output) ⇒ Object
Will scan the tool_tuples attribute and create a processing chain.
Constructor Details
#initialize(*any) ⇒ Base
Returns a new instance of Base.
72 73 74 75 |
# File 'lib/pipeline/base.rb', line 72 def initialize(*any) super @ios = [] end |
Instance Attribute Details
#converted_keyframes ⇒ Object (readonly)
How many keyframes have been converted
57 58 59 |
# File 'lib/pipeline/base.rb', line 57 def converted_keyframes @converted_keyframes end |
#converted_points ⇒ Object (readonly)
How many points have been converted
54 55 56 |
# File 'lib/pipeline/base.rb', line 54 def converted_points @converted_points end |
#exporters ⇒ Object
Assign an array of exporter classes to use them instead of the default “All”
66 67 68 |
# File 'lib/pipeline/base.rb', line 66 def exporters @exporters end |
#progress_block ⇒ Object
A block acepting percent and message vars can be assigned here. When it’s assigned, the pipeline will pass the status reports of all the importers and exporters to the block, together with percent complete
63 64 65 |
# File 'lib/pipeline/base.rb', line 63 def progress_block @progress_block end |
#tool_tuples ⇒ Object
Contains arrays of the form [“MiddewareName”, => value]
69 70 71 |
# File 'lib/pipeline/base.rb', line 69 def tool_tuples @tool_tuples end |
Instance Method Details
#initialize_importer_with_path_and_options(from_input_file_path, options) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/pipeline/base.rb', line 125 def (from_input_file_path, ) d = Tracksperanto::FormatDetector.new(from_input_file_path) if [:importer] imp = Tracksperanto.get_importer([:importer]) require_dimensions_in!() unless imp.autodetects_size? imp.new(:width => [:width], :height => [:height]) elsif d.match? && d.auto_size? d.importer_klass.new elsif d.match? require_dimensions_in!() d.importer_klass.new(:width => [:width], :height => [:height]) else raise UnknownFormatError end end |
#open_owned_export_file(path_to_file) ⇒ Object
Open the file for writing and register it to be closed automatically
232 233 234 |
# File 'lib/pipeline/base.rb', line 232 def open_owned_export_file(path_to_file) @ios.push(File.open(path_to_file, "wb"))[-1] end |
#report_progress(percent_complete, message) ⇒ Object
120 121 122 123 |
# File 'lib/pipeline/base.rb', line 120 def report_progress(percent_complete, ) int_pct = percent_complete.to_f.floor # Prevent float overflow above 100 percent @progress_block.call(int_pct, ) if @progress_block end |
#require_dimensions_in!(opts) ⇒ Object
143 144 145 |
# File 'lib/pipeline/base.rb', line 143 def require_dimensions_in!(opts) raise DimensionsRequiredError unless (opts[:width] && opts[:height]) end |
#run(from_input_file_path, passed_options = {}) ⇒ Object
Runs the whole pipeline. Accepts the following options
-
width - The comp width, for the case that the format does not support auto size
-
height - The comp height, for the case that the format does not support auto size
-
parser - The parser class, for the case that it can’t be autodetected from the file name
Returns the number of trackers and the number of keyframes processed during the run
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/pipeline/base.rb', line 92 def run(from_input_file_path, = {}) # Prevent formats that we do not support Tracksperanto::Blacklist.raise_if_format_unsupported(from_input_file_path) # Check for empty files raise EmptySourceFileError if File.stat(from_input_file_path).size.zero? # Reset stats @converted_keyframes, @converted_points = 0, 0 # Assign the parser importer = (from_input_file_path, ) # Open the file read_data = File.open(from_input_file_path, "rb") # Setup a multiplexer mux = setup_outputs_for(from_input_file_path) # Wrap it into a module that will prevent us from exporting invalid trackers lint = Tracksperanto::Tool::Lint.new(mux) # Setup tools endpoint = wrap_output_with_tools(lint) @converted_points, @converted_keyframes = run_export(read_data, importer, endpoint) end |
#run_export(tracker_data_io, importer, exporter) ⇒ Object
Runs the export and returns the number of points and keyframes processed. If a block is passed, the block will receive the percent complete and the last status message that you can pass back to the UI
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/pipeline/base.rb', line 150 def run_export(tracker_data_io, importer, exporter) points, keyframes, percent_complete = 0, 0, 0.0 last_reported_percentage = 0.0 report_progress(percent_complete, "Starting the parser") progress_lambda = lambda do | m | last_reported_percentage = percent_complete report_progress(percent_complete, m) end # Report progress from the parser importer.progress_block = progress_lambda # Wrap the input in a progressive IO, setup a lambda that will spy on the reader and # update the percentage. We will only broadcast messages that come from the parser # though (complementing it with a percentage) io_with_progress = ProgressiveIO.new(tracker_data_io) do | offset, of_total | percent_complete = (50.0 / of_total) * offset # Some importers do not signal where they are and do not send nice reports. The way we can help that in the interim # would be just to indicate where we are in the input, but outside of the exporter. We do not want to flood # the logs though so what we WILL do instead is report some progress going on every 2-3 percent progress_lambda.call("Parsing the file") if (percent_complete - last_reported_percentage) > 3 end @ios.push(io_with_progress) importer.io = io_with_progress obuf = Obuf.new(Tracksperanto::YieldNonEmpty.new(importer)) report_progress(percent_complete = 50.0, "Validating #{obuf.size} imported trackers") raise NoTrackersRecoveredError.new(importer) if obuf.size.zero? report_progress(percent_complete, "Starting export") percent_per_tracker = (100.0 - percent_complete) / obuf.size # Use the width and height provided by the parser itself exporter.start_export(importer.width, importer.height) # Now send each tracker through the tool chain obuf.each_with_index do | t, tracker_idx | kf_weight = percent_per_tracker / t.keyframes.length points += 1 exporter.start_tracker_segment(t.name) t.each_with_index do | kf, idx | keyframes += 1 exporter.export_point(kf.frame, kf.abs_x, kf.abs_y, kf.residual) report_progress( percent_complete += kf_weight, "Writing keyframe #{idx+1} of #{t.name.inspect}, #{obuf.size - tracker_idx} trackers to go" ) end exporter.end_tracker_segment end exporter.end_export report_progress(100.0, "Wrote #{points} points and #{keyframes} keyframes") obuf.clear @ios.map!{|e| e.close! rescue e.close } @ios.clear return [points, keyframes] end |
#setup_outputs_for(input_file_path) ⇒ Object
Setup output files and return a single output that replays to all of them
220 221 222 223 224 225 226 227 228 229 |
# File 'lib/pipeline/base.rb', line 220 def setup_outputs_for(input_file_path) file_name_without_extension = File.basename(input_file_path, '.*') outputs = (exporters || Tracksperanto.exporters).map do | exporter_class | export_name = [file_name_without_extension, exporter_class.desc_and_extension].join("_") export_path = File.join(File.dirname(input_file_path), export_name) exporter_class.new(open_owned_export_file(export_path)) end Tracksperanto::Export::Mux.new(outputs) end |
#wrap_output_with_tools(output) ⇒ Object
Will scan the tool_tuples attribute and create a processing chain. Tools will be instantiated and wrap each other, starting with the first one
79 80 81 82 83 84 85 |
# File 'lib/pipeline/base.rb', line 79 def wrap_output_with_tools(output) return output unless (tool_tuples && tool_tuples.any?) tool_tuples.reverse.inject(output) do | wrapped, (tool_name, ) | Tracksperanto.get_tool(tool_name).new(wrapped, || {}) end end |