tracksperanto 1.8.1 → 1.8.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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