tracksperanto 1.8.1 → 1.8.2

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.
@@ -1,3 +1,8 @@
1
+ === 1.8.2 / 2010-03-04
2
+
3
+ * Fix the bug in the Flame exporter that was convincing Flame that there is only one tracker in the setup
4
+ * Buffer temporary outputs to String buffers until they reach a certain size. Helps with tempfile pollution and IO speed
5
+
1
6
  === 1.8.1 / 2010-02-18
2
7
 
3
8
  * Add Flame stabilizer export support
@@ -42,6 +42,7 @@ lib/middleware/slipper.rb
42
42
  lib/pipeline/base.rb
43
43
  lib/tracksperanto.rb
44
44
  lib/tracksperanto/block_init.rb
45
+ lib/tracksperanto/buffer_io.rb
45
46
  lib/tracksperanto/casts.rb
46
47
  lib/tracksperanto/const_name.rb
47
48
  lib/tracksperanto/ext_io.rb
@@ -49,6 +50,7 @@ lib/tracksperanto/flame_builder.rb
49
50
  lib/tracksperanto/format_detector.rb
50
51
  lib/tracksperanto/keyframe.rb
51
52
  lib/tracksperanto/progressive_io.rb
53
+ lib/tracksperanto/returning.rb
52
54
  lib/tracksperanto/safety.rb
53
55
  lib/tracksperanto/simple_export.rb
54
56
  lib/tracksperanto/tracker.rb
@@ -130,6 +132,7 @@ test/middleware/test_reformat_middleware.rb
130
132
  test/middleware/test_scaler_middleware.rb
131
133
  test/middleware/test_shift_middleware.rb
132
134
  test/middleware/test_slip_middleware.rb
135
+ test/test_buffer_io.rb
133
136
  test/test_const_name.rb
134
137
  test/test_extio.rb
135
138
  test/test_flame_builder.rb
data/README.txt CHANGED
@@ -69,7 +69,7 @@ Import and export support:
69
69
  * Syntheyes 2D tracking data exports
70
70
  * 3DE point exports (as output by the default script) - versions 3 and 4
71
71
  * MatchMover Pro .rz2
72
- * MayaLive track export (square pixel aspect only)
72
+ * MayaLive track export (square pixel aspect only, you will need to write some extra code to convert that)
73
73
  * Flame .stabilizer file
74
74
 
75
75
  Import only:
@@ -98,6 +98,11 @@ are themselves arrays of Tracksperanto::Keyframe objects.
98
98
 
99
99
  You can easily write an exporter. Refer to the Tracksperanto::Export::Base docs.
100
100
 
101
+ == Ading your own processing steps
102
+
103
+ You probably want to write a Middleware (consult the Tracksperanto::Middleware::Base docs). A Middleware is just like
104
+ an exporter, except that it wraps another exporter instead (so you can intercept export calls and massage the data as it is moving through).
105
+
101
106
  == Limitations
102
107
 
103
108
  Information about the search area, reference area and offset is not passed along (outside
data/Rakefile CHANGED
@@ -8,6 +8,7 @@ begin
8
8
  (Hoe::RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
9
9
 
10
10
  Hoe.spec('tracksperanto') do | p |
11
+ p.clean_globs = %w( **/.DS_Store )
11
12
  p.version = Tracksperanto::VERSION
12
13
  p.extra_dev_deps = {"flexmock" => ">=0"}
13
14
  p.rubyforge_name = 'guerilla-di'
@@ -14,7 +14,7 @@ class Tracksperanto::Export::Equalizer3 < Tracksperanto::Export::Base
14
14
  def start_export( img_width, img_height)
15
15
  @w, @h = img_width, img_height
16
16
  # 3DE needs to know the number of keyframes in advance
17
- @buffer = Tempfile.new("ts3dex")
17
+ @buffer = Tracksperanto::BufferIO.new
18
18
  @highest_keyframe = 0
19
19
  end
20
20
 
@@ -12,13 +12,13 @@ class Tracksperanto::Export::Equalizer4 < Tracksperanto::Export::Base
12
12
  def start_export( img_width, img_height)
13
13
  # 3DE needs to know the number of points in advance,
14
14
  # so we will just buffer to a StringIO
15
- @internal_io, @num_of_trackers = Tempfile.new("teq4x"), 0
15
+ @internal_io, @num_of_trackers = Tracksperanto::BufferIO.new, 0
16
16
  end
17
17
 
18
18
  def start_tracker_segment(tracker_name)
19
19
  @internal_io.puts(tracker_name)
20
20
  @num_of_trackers += 1
21
- @tracker_buffer, @num_of_kfs = Tempfile.new("teq4x_p"), 0
21
+ @tracker_buffer, @num_of_kfs = Tracksperanto::BufferIO.new, 0
22
22
  end
23
23
 
24
24
  def export_point(frame, abs_float_x, abs_float_y, float_residual)
@@ -1,6 +1,9 @@
1
+ # TODO: this exporter is MAJORLY slow now
1
2
  class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
2
3
 
3
4
  COLOR = "50 50 50"
5
+ DATETIME_FORMAT = '%a %b %d %H:%M:%S %Y'
6
+
4
7
  def self.desc_and_extension
5
8
  "flame.stabilizer"
6
9
  end
@@ -12,22 +15,27 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
12
15
  def start_export( img_width, img_height)
13
16
  @counter = 0
14
17
  @width, @height = img_width, img_height
15
- @temp = Tempfile.new("flamexp")
18
+ @temp = Tracksperanto::BufferIO.new
16
19
  @writer = Tracksperanto::FlameBuilder.new(@temp)
17
20
  end
18
21
 
19
22
  def end_export
23
+ # Now make another writer, this time for our main IO
20
24
  @writer = Tracksperanto::FlameBuilder.new(@io)
21
- write_header
25
+
26
+ # Now we know how many trackers we have so we can write the header
27
+ # data along with NbTrackers
28
+ write_header_with_number_of_trackers(@counter)
22
29
 
23
30
  # Now write everything that we accumulated earlier into the base IO
24
31
  @temp.rewind
25
32
  @io.write(@temp.read) until @temp.eof?
26
33
  @temp.close!
27
34
 
35
+ # Send the ChannelEnd command and list the trackers
28
36
  @writer.channel_end
29
37
  @counter.times do |i|
30
- @writer.tracker(i) do |t|
38
+ @writer.write_unterminated_block!("tracker", i) do |t|
31
39
  t.active true
32
40
  t.color_hash!("colour", 0, 100, 0)
33
41
  t.fixed_ref true
@@ -40,30 +48,39 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
40
48
 
41
49
  def start_tracker_segment(tracker_name)
42
50
  @counter += 1
43
- @tracker_name = tracker_name
44
- @x_values, @y_values = [], []
45
51
  @write_first_frame = true
46
52
  end
47
53
 
48
54
  def export_point(frame, abs_float_x, abs_float_y, float_residual)
55
+ flame_frame = frame + 1
49
56
  if @write_first_frame
50
- write_first_frame(abs_float_x, abs_float_y, frame)
51
- @x_values << [frame, 0]
52
- @y_values << [frame, 0]
57
+ @base_x, @base_y = abs_float_x, abs_float_y
58
+ write_first_frame(abs_float_x, abs_float_y)
59
+ # For Flame to recognize the reference frame of the Shift channel
60
+ # we need it to contain zero as an int, not as a float. The shift proceeds
61
+ # from there.
62
+ @x_shift_values = [[flame_frame, 0]]
63
+ @y_shift_values = [[flame_frame, 0]]
64
+ @write_first_frame = false
53
65
  else
54
- @x_values << [frame, (@base_x - abs_float_x)]
55
- @y_values << [frame, (@base_y - abs_float_y)]
66
+ # Just continue buffering the upcoming shift keyframes and flush them in the end
67
+ shift_x, shift_y = @base_x - abs_float_x, @base_y - abs_float_y
68
+ @x_shift_values.push([flame_frame, shift_x])
69
+ @y_shift_values.push([flame_frame, shift_y])
56
70
  end
57
71
  end
58
72
 
59
73
  def end_tracker_segment
60
- write_shift_channel("shift/x", @x_values, @base_x)
61
- write_shift_channel("shift/y", @y_values, @base_y)
74
+ # We write these at tracker end since we need to know in advance
75
+ # how many keyframes they should contain
76
+ write_shift_channel("shift/x", @x_shift_values)
77
+ write_shift_channel("shift/y", @y_shift_values)
62
78
  end
63
79
 
64
80
  private
65
81
 
66
- def write_shift_channel(name_without_prefix, values, base)
82
+ # The shift channel is what determines how the tracking point moves.
83
+ def write_shift_channel(name_without_prefix, values)
67
84
  @writer.channel(prefix(name_without_prefix)) do | c |
68
85
  c.extrapolation :constant
69
86
  c.value values[0][1]
@@ -71,8 +88,8 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
71
88
  c.size values.length
72
89
  values.each_with_index do | (f, v), i |
73
90
  c.key(i) do | k |
74
- k.frame(f + 1)
75
- k.value(v)
91
+ k.frame f
92
+ k.value v
76
93
  k.interpolation :linear
77
94
  k.left_slope 2.4
78
95
  k.right_slope 2.4
@@ -85,12 +102,12 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
85
102
  ["tracker#{@counter}", tracker_channel].join("/")
86
103
  end
87
104
 
88
- def write_header
105
+ def write_header_with_number_of_trackers(number_of_trackers)
89
106
  @writer.stabilizer_file_version "5.0"
90
- @writer.creation_date(Time.now.strftime('%a %b %d %H:%M:%S %Y'))
107
+ @writer.creation_date(Time.now.strftime(DATETIME_FORMAT))
91
108
  @writer.linebreak!(2)
92
109
 
93
- @writer.nb_trackers(@counter)
110
+ @writer.nb_trackers number_of_trackers
94
111
  @writer.selected 0
95
112
  @writer.frame_width @width
96
113
  @writer.frame_height @height
@@ -109,19 +126,31 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
109
126
  @writer.anim
110
127
  end
111
128
 
112
- def write_first_frame(x, y, f)
113
- @write_first_frame = false
114
- @base_x, @base_y = x, y
129
+ def write_first_frame(x, y)
130
+ write_track_channels
131
+ write_track_width_and_height
132
+ write_ref_width_and_height
133
+ write_ref_channels(x, y)
134
+ write_deltax_and_deltay_channels
135
+ write_offset_channels
136
+ end
137
+
138
+ def write_track_channels
139
+ ctr_x, ctr_y = @width / 2, @height / 2
115
140
 
116
- tx, ty = @width / 2, @height / 2
117
- %w( track/x track/y).map(&method(:prefix)).zip([tx, ty]).each do | cname, default |
141
+ # track determines where the tracking box is, and should be in the center
142
+ # of the image for Flame to compute all other shifts properly
143
+ %w( track/x track/y).map(&method(:prefix)).zip([ctr_x, ctr_y]).each do | cname, default |
118
144
  @writer.channel(cname) do | c |
119
145
  c.extrapolation("constant")
120
146
  c.value(default.to_i)
121
147
  c.colour(COLOR)
122
148
  end
123
149
  end
124
-
150
+ end
151
+
152
+ # The size of the tracking area
153
+ def write_track_width_and_height
125
154
  %w( track/width track/height ).map(&method(:prefix)).each do | channel_name |
126
155
  @writer.channel(channel_name) do | c |
127
156
  c.extrapolation :linear
@@ -129,7 +158,10 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
129
158
  c.colour COLOR
130
159
  end
131
160
  end
132
-
161
+ end
162
+
163
+ # The size of the reference area
164
+ def write_ref_width_and_height
133
165
  %w( ref/width ref/height).map(&method(:prefix)).each do | channel_name |
134
166
  @writer.channel(channel_name) do | c |
135
167
  c.extrapolation :linear
@@ -137,8 +169,14 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
137
169
  c.colour COLOR
138
170
  end
139
171
  end
140
-
141
- %w( ref/x ref/y).map(&method(:prefix)).zip([x, y]).each do | cname, default |
172
+ end
173
+
174
+ # The Ref channel contains the reference for the shift channel in absolute
175
+ # coordinates, and is set as float. Since we do not "snap" the tracker in
176
+ # the process it's enough for us to make one keyframe in the ref channels
177
+ # at the same frame as the first shift keyframe
178
+ def write_ref_channels(ref_x, ref_y)
179
+ %w( ref/x ref/y).map(&method(:prefix)).zip([ref_x, ref_y]).each do | cname, default |
142
180
  @writer.channel(cname) do | c |
143
181
  c.extrapolation("constant")
144
182
  c.value(default)
@@ -154,7 +192,11 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
154
192
  end
155
193
  end
156
194
  end
157
-
195
+ end
196
+
197
+ def write_deltax_and_deltay_channels
198
+ # This is used for deltax and deltay (offset tracking).
199
+ # We set it to zero and lock
158
200
  %w( ref/dx ref/dy).map(&method(:prefix)).each do | chan, v |
159
201
  @writer.channel(chan) do | c |
160
202
  c.extrapolation("constant")
@@ -177,14 +219,16 @@ class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
177
219
  k.interpolation :constant
178
220
  end
179
221
  end # Chan block
180
-
181
- %w(offset/x offset/y).map(&method(:prefix)).each do | c |
182
- @writer.channel(c) do | chan |
183
- chan.extrapolation :constant
184
- chan.value 0
185
- end
222
+ end
223
+ end
224
+
225
+ def write_offset_channels
226
+ %w(offset/x offset/y).map(&method(:prefix)).each do | c |
227
+ @writer.channel(c) do | chan |
228
+ chan.extrapolation :constant
229
+ chan.value 0
186
230
  end
187
- end #Iter
188
- end # Meth
231
+ end
232
+ end
189
233
 
190
234
  end
@@ -45,7 +45,7 @@ Constant {
45
45
  # We allocate an IO for the file being output that will contain all the trackers,
46
46
  # and then write that one into the script preceded by the preamble that sets length
47
47
  # based on the last frame position in time
48
- @trackers_io = Tempfile.new("nukex")
48
+ @trackers_io = Tracksperanto::BufferIO.new
49
49
  end
50
50
 
51
51
  # We accumulate a tracker and on end dump it out in one piece
@@ -13,20 +13,24 @@ class Tracksperanto::Export::PFTrack4 < Tracksperanto::Export::Base
13
13
 
14
14
  def start_tracker_segment(tracker_name)
15
15
  # Setup for the next tracker
16
- @prev_tracker = []
16
+ @frame_count = 0
17
17
  @tracker_name = tracker_name
18
+ @tracker_io = Tracksperanto::BufferIO.new
18
19
  end
19
20
 
20
21
  def end_tracker_segment
21
- block = [ "\n",
22
- @tracker_name.inspect, # "autoquotes"
23
- @prev_tracker.length,
24
- @prev_tracker.join("\n") ]
25
- @io.puts block.join("\n")
22
+ @io.write("\n\n")
23
+ @io.puts(@tracker_name.inspect) # autoquotes
24
+ @io.puts(@frame_count)
25
+
26
+ @tracker_io.rewind
27
+ @io.write(@tracker_io.read) until @tracker_io.eof?
28
+ @tracker_io.close!
26
29
  end
27
30
 
28
31
  def export_point(frame, abs_float_x, abs_float_y, float_residual)
32
+ @frame_count += 1
29
33
  line = KEYFRAME_TEMPLATE % [frame, abs_float_x, abs_float_y, float_residual / 8]
30
- @prev_tracker << line
34
+ @tracker_io.puts(line)
31
35
  end
32
36
  end
@@ -10,11 +10,13 @@ class Tracksperanto::Export::PFTrack5 < Tracksperanto::Export::PFTrack4
10
10
  end
11
11
 
12
12
  def end_tracker_segment
13
- block = [ "\n",
14
- @tracker_name.inspect, # "autoquotes"
15
- "Primary".inspect, # For primary/secondary cam in stereo pair
16
- @prev_tracker.length,
17
- @prev_tracker.join("\n") ]
18
- @io.puts block.join("\n")
13
+ @io.write("\n\n")
14
+ @io.puts(@tracker_name.inspect) # autoquotes
15
+ @io.puts("Primary".inspect) # For primary/secondary cam in stereo pair
16
+ @io.puts(@frame_count)
17
+
18
+ @tracker_io.rewind
19
+ @io.write(@tracker_io.read) until @tracker_io.eof?
20
+ @tracker_io.close!
19
21
  end
20
22
  end
@@ -21,6 +21,7 @@ class Tracksperanto::Import::MatchMover < Tracksperanto::Import::Base
21
21
  private
22
22
 
23
23
  def detect_format(io)
24
+ report_progress("Detecting width and height")
24
25
  lines = (0..2).map{ io.gets }
25
26
  last_line = lines[-1]
26
27
  w, h, _ = last_line.scan(/(\d+)/).flatten
@@ -37,10 +38,12 @@ class Tracksperanto::Import::MatchMover < Tracksperanto::Import::Base
37
38
 
38
39
  def extract_track(start_line, io)
39
40
  tracker_name = start_line.scan(/\"([^\"]+)\"/).flatten[0]
41
+ report_progress("Extracting tracker #{tracker_name}")
40
42
  t = Tracksperanto::Tracker.new(:name => tracker_name)
41
43
  while(line = io.gets) do
42
44
  return t if line =~ /\}/
43
45
  t.keyframes.push(extract_key(line.strip)) if line =~ /^(\s+?)(\d)/
46
+ report_progress("Extracting keyframe")
44
47
  end
45
48
  raise "Track didn't close"
46
49
  end
@@ -59,9 +59,11 @@ class Tracksperanto::Pipeline::Base
59
59
  # Yield middlewares to the block
60
60
  yield(*middlewares) if block_given?
61
61
 
62
- @converted_points, @converted_keyframes = run_export(read_data, importer, middlewares[-1]) do | p, m |
63
- @progress_block.call(p, m) if @progress_block
64
- end
62
+ @converted_points, @converted_keyframes = run_export(read_data, importer, middlewares[-1])
63
+ end
64
+
65
+ def report_progress(percent_complete, message)
66
+ @progress_block.call(percent_complete, message) if @progress_block
65
67
  end
66
68
 
67
69
  def detect_importer_or_use_options(path, opts)
@@ -87,31 +89,26 @@ class Tracksperanto::Pipeline::Base
87
89
  def run_export(tracker_data_io, parser, processor)
88
90
  points, keyframes, percent_complete = 0, 0, 0.0
89
91
 
90
- yield(percent_complete, "Starting the parser") if block_given?
92
+ report_progress(percent_complete, "Starting the parser")
91
93
 
92
94
  # Report progress from the parser
93
- parser.progress_block = lambda do | message |
94
- yield(percent_complete, message) if block_given?
95
- end
95
+ parser.progress_block = lambda { | m | report_progress(percent_complete, m) }
96
96
 
97
- # Wrap the input in a progressive IO
98
- io_with_progress = Tracksperanto::ProgressiveIO.new(tracker_data_io)
99
- @ios << io_with_progress
100
-
101
- # Setup a lambda that will spy on the reader and update the percentage.
102
- # We will only broadcast messages that come from the parser though (complementing it
103
- # with a percentage)
104
- io_with_progress.progress_block = lambda do | offset, of_total |
97
+ # Wrap the input in a progressive IO, setup a lambda that will spy on the reader and
98
+ # update the percentage. We will only broadcast messages that come from the parser
99
+ # though (complementing it with a percentage)
100
+ io_with_progress = Tracksperanto::ProgressiveIO.new(tracker_data_io) do | offset, of_total |
105
101
  percent_complete = (50.0 / of_total) * offset
106
102
  end
103
+ @ios << io_with_progress
107
104
 
108
105
  trackers = parser.parse(io_with_progress)
109
106
 
110
- yield(percent_complete = 50.0, "Validating #{trackers.length} imported trackers") if block_given?
107
+ report_progress(percent_complete = 50.0, "Validating #{trackers.length} imported trackers")
111
108
 
112
109
  validate_trackers!(trackers)
113
110
 
114
- yield(percent_complete, "Starting export") if block_given?
111
+ report_progress(percent_complete, "Starting export")
115
112
 
116
113
  percent_per_tracker = (100.0 - percent_complete) / trackers.length
117
114
 
@@ -124,13 +121,13 @@ class Tracksperanto::Pipeline::Base
124
121
  t.each_with_index do | kf, idx |
125
122
  keyframes += 1
126
123
  processor.export_point(kf.frame, kf.abs_x, kf.abs_y, kf.residual)
127
- yield(percent_complete += kf_weight, "Writing keyframe #{idx+1} of #{t.name.inspect}") if block_given?
124
+ report_progress(percent_complete += kf_weight, "Writing keyframe #{idx+1} of #{t.name.inspect}, #{trackers.length - idx + 1} trackers to go")
128
125
  end
129
126
  processor.end_tracker_segment
130
127
  end
131
128
  processor.end_export
132
129
 
133
- yield(100.0, "Wrote #{points} points and #{keyframes} keyframes") if block_given?
130
+ report_progress(100.0, "Wrote #{points} points and #{keyframes} keyframes")
134
131
 
135
132
  [points, keyframes]
136
133
  ensure
@@ -176,7 +173,7 @@ class Tracksperanto::Pipeline::Base
176
173
 
177
174
  # Check that the trackers made by the parser are A-OK
178
175
  def validate_trackers!(trackers)
179
- trackers.reject!{|t| t.length < 2 }
176
+ trackers.reject!{|t| t.empty? }
180
177
  raise "Could not recover any non-empty trackers from this file. Wrong import format maybe?" if trackers.empty?
181
178
  end
182
179
  end
@@ -4,7 +4,7 @@ require 'tempfile'
4
4
 
5
5
  module Tracksperanto
6
6
  PATH = File.expand_path(File.dirname(__FILE__))
7
- VERSION = '1.8.1'
7
+ VERSION = '1.8.2'
8
8
 
9
9
  module Import; end
10
10
  module Export; end
@@ -59,6 +59,7 @@ module Tracksperanto
59
59
  end
60
60
 
61
61
  %w(
62
+ returning
62
63
  const_name
63
64
  casts
64
65
  block_init
@@ -69,6 +70,7 @@ end
69
70
  format_detector
70
71
  ext_io
71
72
  progressive_io
73
+ buffer_io
72
74
  simple_export
73
75
  uv_coordinates
74
76
  flame_builder
@@ -0,0 +1,48 @@
1
+ require "tempfile"
2
+
3
+ # BufferIO is used for writing big segments of text. When the segment is bigger than a certain number of bytes,
4
+ # the underlying memory buffer will be swapped with a tempfile
5
+ class Tracksperanto::BufferIO < DelegateClass(IO)
6
+ include Tracksperanto::Returning
7
+
8
+ IN_MEMORY_SIZE_LIMIT = 100_000
9
+
10
+ def initialize
11
+ __setobj__(StringIO.new)
12
+ end
13
+
14
+ def write(s)
15
+ returning(super) { replace_with_tempfile_if_needed }
16
+ end
17
+
18
+ def puts(s)
19
+ returning(super) { replace_with_tempfile_if_needed }
20
+ end
21
+
22
+ def <<(s)
23
+ returning(super) { replace_with_tempfile_if_needed }
24
+ end
25
+
26
+ def putc(c)
27
+ returning(super) { replace_with_tempfile_if_needed }
28
+ end
29
+
30
+ def close!
31
+ __getobj__.close! if @tempfile_in
32
+ __setobj__(nil)
33
+ end
34
+
35
+ private
36
+
37
+ def replace_with_tempfile_if_needed
38
+ return if @tempfile_in
39
+ io = __getobj__
40
+ if io.pos > IN_MEMORY_SIZE_LIMIT
41
+ @tempfile_in = true
42
+ tf = Tempfile.new("tracksperanto-xbuf")
43
+ io.rewind
44
+ tf.write(io.read) until io.eof?
45
+ __setobj__(tf)
46
+ end
47
+ end
48
+ end
@@ -12,6 +12,11 @@ class Tracksperanto::FlameBuilder
12
12
  @io.puts(INDENT * (@indent + 1) + "End")
13
13
  end
14
14
 
15
+ def write_unterminated_block!(name, value = nil, &blk)
16
+ value.nil? ? write_loose!(name) : write_tuple!(name, value)
17
+ yield(self.class.new(@io, @indent + 1))
18
+ end
19
+
15
20
  def write_tuple!(key, value)
16
21
  @io.puts("%s%s %s" % [INDENT * @indent, __camelize(key), __flameize(value)])
17
22
  end
@@ -25,34 +30,36 @@ class Tracksperanto::FlameBuilder
25
30
  end
26
31
 
27
32
  def color_hash!(name, red, green, blue)
28
- write_loose!(name)
29
- n = self.class.new(@io, @indent + 1)
30
- n.red(red)
31
- n.green(green)
32
- n.blue(blue)
33
+ write_unterminated_block!(name) do | b |
34
+ b.red(red)
35
+ b.green(green)
36
+ b.blue(blue)
37
+ end
33
38
  end
34
39
 
35
- private
36
-
37
- def method_missing(meth, arg = nil)
38
- self.class.send(:alias_method, meth, :__generic)
39
- if block_given?
40
- __generic(meth, arg) {|*a| yield(*a) if block_given? }
41
- else
42
- __generic(meth, arg)
40
+ def <<(some_verbatim_string)
41
+ some_verbatim_string.split("\n").each do | line |
42
+ @io.puts(["\t" * @indent, line].join)
43
43
  end
44
44
  end
45
45
 
46
- def __generic(meth, arg = nil)
46
+ private
47
+
48
+ def method_missing(meth, arg = nil)
47
49
  if block_given?
48
- write_block!(meth, arg) { |c| yield(c) }
50
+ write_block!(meth, arg) {|c| yield(c) }
49
51
  else
50
- arg.nil? ? write_loose!(meth) : write_tuple!(meth, arg)
52
+ if arg.nil?
53
+ write_loose!(meth)
54
+ else
55
+ write_tuple!(meth, arg)
56
+ end
51
57
  end
52
58
  end
53
59
 
54
60
  def __camelize(s)
55
- s.to_s.gsub(/(^|_)(.)/) { $2.upcase }
61
+ @@camelizations ||= {}
62
+ @@camelizations[s] ||= s.to_s.gsub(/(^|_)(.)/) { $2.upcase }
56
63
  end
57
64
 
58
65
  def __flameize(v)
@@ -1,17 +1,17 @@
1
1
  # Used for IO objects that need to report the current offset at each operation that changes the said offset
2
2
  # (useful for building progress bars that report on a file read operation)
3
3
  class Tracksperanto::ProgressiveIO < DelegateClass(IO)
4
-
5
- # Should contain a block that accepts the current offset in bytes and the total size
6
- attr_accessor :progress_block
4
+ include Tracksperanto::Returning
7
5
 
8
6
  # Get or set the total size of the contained IO. If the passed IO is a File object
9
7
  # the size will be preset automatically
10
8
  attr_accessor :total_size
9
+ attr_accessor :progress_block
11
10
 
12
- def initialize(with_file)
11
+ def initialize(with_file, &blk)
13
12
  __setobj__(with_file)
14
13
  @total_size = with_file.stat.size if with_file.respond_to?(:stat)
14
+ @progress_block = blk.to_proc if blk
15
15
  end
16
16
 
17
17
  def each(sep_string = $/, &blk)
@@ -69,9 +69,6 @@ class Tracksperanto::ProgressiveIO < DelegateClass(IO)
69
69
  end
70
70
 
71
71
  private
72
- def returning(r)
73
- yield; r
74
- end
75
72
 
76
73
  def notify_read
77
74
  @progress_block.call(pos, @total_size) if @progress_block
@@ -0,0 +1,6 @@
1
+ module Tracksperanto::Returning
2
+ # The "returning" idiomn copied from ActiveSupport
3
+ def returning(r)
4
+ yield(r); r
5
+ end
6
+ end
@@ -101,14 +101,6 @@ Channel tracker1/ref/dx
101
101
  Interpolation constant
102
102
  End
103
103
  End
104
- Channel tracker1/offset/x
105
- Extrapolation constant
106
- Value 0
107
- End
108
- Channel tracker1/offset/y
109
- Extrapolation constant
110
- Value 0
111
- End
112
104
  Channel tracker1/ref/dy
113
105
  Extrapolation constant
114
106
  Value 0
@@ -495,14 +487,6 @@ Channel tracker2/ref/dx
495
487
  Interpolation constant
496
488
  End
497
489
  End
498
- Channel tracker2/offset/x
499
- Extrapolation constant
500
- Value 0
501
- End
502
- Channel tracker2/offset/y
503
- Extrapolation constant
504
- Value 0
505
- End
506
490
  Channel tracker2/ref/dy
507
491
  Extrapolation constant
508
492
  Value 0
@@ -821,7 +805,6 @@ Tracker 0
821
805
  FixedX no
822
806
  FixedY no
823
807
  Tolerance 100
824
- End
825
808
  Tracker 1
826
809
  Active yes
827
810
  Colour
@@ -832,4 +815,3 @@ Tracker 1
832
815
  FixedX no
833
816
  FixedY no
834
817
  Tolerance 100
835
- End
@@ -7,7 +7,7 @@ class FlameStabilizerExportTestTest < Test::Unit::TestCase
7
7
  def test_export_output_written
8
8
  t = Time.local(2010, "Feb", 18, 17, 22, 12)
9
9
  flexmock(Time).should_receive(:now).once.and_return(t)
10
- ensure_same_output Tracksperanto::Export::FlameStabilizer, P
10
+ ensure_same_output Tracksperanto::Export::FlameStabilizer, P
11
11
  end
12
12
 
13
13
  def test_exporter_meta
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestBufferIO < Test::Unit::TestCase
4
+
5
+ def test_write_in_mem_has_a_stringio
6
+ io = Tracksperanto::BufferIO.new
7
+ 9000.times { io.write("a") }
8
+ assert_kind_of StringIO, io.__getobj__
9
+ assert_nothing_raised { io.close! }
10
+ end
11
+
12
+ def test_write_larger_than_max_swaps_tempfile
13
+ io = Tracksperanto::BufferIO.new
14
+ 110_000.times { io.write("a") }
15
+ f = io.__getobj__
16
+ assert_kind_of Tempfile, f
17
+ f.rewind
18
+ assert_equal 110_000, f.read.length
19
+ flexmock(f).should_receive(:close!).once
20
+ io.close!
21
+ end
22
+ end
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
+ require "benchmark"
2
3
 
3
4
  class FlameBuilderTest < Test::Unit::TestCase
4
5
  def setup
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tracksperanto
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 1.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-18 00:00:00 +01:00
12
+ date: 2010-03-04 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -89,6 +89,7 @@ files:
89
89
  - lib/pipeline/base.rb
90
90
  - lib/tracksperanto.rb
91
91
  - lib/tracksperanto/block_init.rb
92
+ - lib/tracksperanto/buffer_io.rb
92
93
  - lib/tracksperanto/casts.rb
93
94
  - lib/tracksperanto/const_name.rb
94
95
  - lib/tracksperanto/ext_io.rb
@@ -96,6 +97,7 @@ files:
96
97
  - lib/tracksperanto/format_detector.rb
97
98
  - lib/tracksperanto/keyframe.rb
98
99
  - lib/tracksperanto/progressive_io.rb
100
+ - lib/tracksperanto/returning.rb
99
101
  - lib/tracksperanto/safety.rb
100
102
  - lib/tracksperanto/simple_export.rb
101
103
  - lib/tracksperanto/tracker.rb
@@ -177,6 +179,7 @@ files:
177
179
  - test/middleware/test_scaler_middleware.rb
178
180
  - test/middleware/test_shift_middleware.rb
179
181
  - test/middleware/test_slip_middleware.rb
182
+ - test/test_buffer_io.rb
180
183
  - test/test_const_name.rb
181
184
  - test/test_extio.rb
182
185
  - test/test_flame_builder.rb
@@ -248,6 +251,7 @@ test_files:
248
251
  - test/middleware/test_scaler_middleware.rb
249
252
  - test/middleware/test_shift_middleware.rb
250
253
  - test/middleware/test_slip_middleware.rb
254
+ - test/test_buffer_io.rb
251
255
  - test/test_const_name.rb
252
256
  - test/test_extio.rb
253
257
  - test/test_flame_builder.rb