aviglitch 0.0.2 → 0.0.3
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/ChangeLog +7 -0
- data/README.rdoc +2 -2
- data/VERSION +1 -1
- data/bin/datamosh +10 -13
- data/lib/aviglitch.rb +8 -4
- data/lib/aviglitch/base.rb +20 -39
- data/lib/aviglitch/frame.rb +3 -3
- data/lib/aviglitch/frames.rb +290 -18
- data/spec/aviglitch_spec.rb +69 -36
- data/spec/datamosh_spec.rb +61 -0
- data/spec/frames_spec.rb +450 -0
- data/spec/spec.opts +2 -1
- metadata +9 -12
data/ChangeLog
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.0.3 / 2010-07-07
|
2
|
+
|
3
|
+
* Changed AviGlitch::Frames allowing to slice and concatenate frames
|
4
|
+
(like Array).
|
5
|
+
* Changed datamosh cli to accept multiple files.
|
6
|
+
* And some tiny fixes.
|
7
|
+
|
1
8
|
== 0.0.2 / 2010-05-17
|
2
9
|
|
3
10
|
* Removed AviGlitch#new. Use AviGlitch#open instead of #new.
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= AviGlitch
|
2
2
|
|
3
|
-
* http://github.com/ucnv/aviglitch
|
3
|
+
* http://github.com/ucnv/aviglitch
|
4
4
|
|
5
5
|
== Description
|
6
6
|
|
@@ -16,7 +16,7 @@ See following urls for details;
|
|
16
16
|
|
17
17
|
* Not supports AVI2 files right now.
|
18
18
|
* Not supports files with interleave.
|
19
|
-
* Parses only container level structure,
|
19
|
+
* Parses only container level structure, doesn't parse codecs.
|
20
20
|
|
21
21
|
== Synopsis
|
22
22
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/bin/datamosh
CHANGED
@@ -7,7 +7,6 @@ require 'aviglitch'
|
|
7
7
|
|
8
8
|
output = './out.avi'
|
9
9
|
all = false
|
10
|
-
force = false
|
11
10
|
|
12
11
|
opts = OptionParser.new do |opts|
|
13
12
|
opts.banner = "datamosh - AviGlitch's datamoshing video generator."
|
@@ -17,9 +16,6 @@ opts = OptionParser.new do |opts|
|
|
17
16
|
"Output the video to OUTPUT (./out.avi by default)") do |f|
|
18
17
|
output = f
|
19
18
|
end
|
20
|
-
opts.on("-f", "--force", "Overwrite an existing output file") do
|
21
|
-
force = true
|
22
|
-
end
|
23
19
|
opts.on("-a", "--all",
|
24
20
|
"Remove all keyframes (It remains a first keyframe by default)") do
|
25
21
|
all = true
|
@@ -29,23 +25,24 @@ opts = OptionParser.new do |opts|
|
|
29
25
|
exit
|
30
26
|
end
|
31
27
|
end
|
28
|
+
|
32
29
|
input = opts.parse!
|
33
30
|
if input.empty?
|
34
31
|
puts opts
|
35
32
|
exit 1
|
36
33
|
end
|
37
|
-
if !force && File.exists?(output)
|
38
|
-
puts "!!! `#{output}' already exists. Use -f option to overwrite."
|
39
|
-
exit 1
|
40
|
-
end
|
41
34
|
|
42
|
-
a = AviGlitch.open input.
|
35
|
+
a = AviGlitch.open input.shift
|
43
36
|
a.glitch_with_index :keyframe do |frame, i|
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
(!all && i == 0) ? frame : "\000" * frame.size # keep the first frame
|
38
|
+
end
|
39
|
+
input.each do |file|
|
40
|
+
b = AviGlitch.open file
|
41
|
+
b.glitch :keyframe do |frame|
|
47
42
|
"\000" * frame.size
|
48
43
|
end
|
44
|
+
a.frames.concat b.frames
|
49
45
|
end
|
50
|
-
|
46
|
+
|
47
|
+
a.output output
|
51
48
|
|
data/lib/aviglitch.rb
CHANGED
@@ -29,14 +29,18 @@ require 'aviglitch/frames'
|
|
29
29
|
#
|
30
30
|
module AviGlitch
|
31
31
|
|
32
|
-
VERSION = '0.0.
|
32
|
+
VERSION = '0.0.3'
|
33
33
|
|
34
34
|
class << self
|
35
35
|
##
|
36
36
|
# Returns AviGlitch::Base instance.
|
37
|
-
# It requires +
|
38
|
-
def AviGlitch.open
|
39
|
-
|
37
|
+
# It requires +path_or_frames+ as String or Pathname, or Frames instance.
|
38
|
+
def AviGlitch.open path_or_frames
|
39
|
+
if path_or_frames.kind_of?(Frames)
|
40
|
+
path_or_frames.to_avi
|
41
|
+
else
|
42
|
+
AviGlitch::Base.new(Pathname(path_or_frames))
|
43
|
+
end
|
40
44
|
end
|
41
45
|
end
|
42
46
|
end
|
data/lib/aviglitch/base.rb
CHANGED
@@ -8,15 +8,13 @@ module AviGlitch
|
|
8
8
|
# To glitch, and save file. The instance returned through AviGlitch#open.
|
9
9
|
#
|
10
10
|
class Base
|
11
|
-
SAFE_FRAMES_COUNT = 150000 # :nodoc:
|
12
|
-
|
13
11
|
# AviGlitch::Frames object generated from the +file+.
|
14
12
|
attr_reader :frames
|
15
13
|
# The input file (copied tempfile).
|
16
14
|
attr_reader :file
|
17
15
|
|
18
16
|
##
|
19
|
-
#
|
17
|
+
# Creates a new instance of AviGlitch::Base, open the file and
|
20
18
|
# make it ready to manipulate.
|
21
19
|
# It requires +path+ as Pathname.
|
22
20
|
def initialize path
|
@@ -32,16 +30,12 @@ module AviGlitch
|
|
32
30
|
unless AviGlitch::Base.surely_formatted? @file
|
33
31
|
raise 'Unsupported file passed.'
|
34
32
|
end
|
35
|
-
unless safe_frames_count? @file
|
36
|
-
close
|
37
|
-
exit
|
38
|
-
end
|
39
33
|
@frames = Frames.new @file
|
40
34
|
# I believe Ruby's GC to close and remove the Tempfile..
|
41
35
|
end
|
42
36
|
|
43
37
|
##
|
44
|
-
#
|
38
|
+
# Outputs the glitched file to +path+, and close the file.
|
45
39
|
def output path
|
46
40
|
FileUtils.cp @file.path, path
|
47
41
|
close
|
@@ -54,7 +48,7 @@ module AviGlitch
|
|
54
48
|
end
|
55
49
|
|
56
50
|
##
|
57
|
-
#
|
51
|
+
# Glitches each frame data.
|
58
52
|
# It is a convent method to iterate each frame.
|
59
53
|
#
|
60
54
|
# The argument +target+ takes symbols listed below:
|
@@ -67,66 +61,53 @@ module AviGlitch
|
|
67
61
|
# It also requires a block. In the block, you take the frame data
|
68
62
|
# as a String parameter.
|
69
63
|
# To modify the data, simply return a modified data.
|
64
|
+
# It returns +self+
|
70
65
|
def glitch target = :all, &block # :yield: data
|
71
|
-
frames.each do |frame|
|
66
|
+
@frames.each do |frame|
|
72
67
|
if valid_target? target, frame
|
73
68
|
frame.data = yield frame.data
|
74
69
|
end
|
75
70
|
end
|
71
|
+
self
|
76
72
|
end
|
77
73
|
|
78
74
|
##
|
79
75
|
# Do glitch with index.
|
80
76
|
def glitch_with_index target = :all, &block # :yield: data, index
|
81
77
|
i = 0
|
82
|
-
frames.each do |frame|
|
78
|
+
@frames.each do |frame|
|
83
79
|
if valid_target? target, frame
|
84
80
|
frame.data = yield(frame.data, i)
|
85
81
|
i += 1
|
86
82
|
end
|
87
83
|
end
|
84
|
+
self
|
88
85
|
end
|
89
86
|
|
90
|
-
|
87
|
+
alias_method :write, :output
|
88
|
+
|
89
|
+
##
|
90
|
+
# Swaps the frames with other Frames data.
|
91
|
+
def frames= other
|
92
|
+
raise TypeError unless other.kind_of?(Frames)
|
93
|
+
@frames.clear
|
94
|
+
@frames.concat other
|
95
|
+
end
|
91
96
|
|
92
97
|
def valid_target? target, frame # :nodoc:
|
93
98
|
return true if target == :all
|
94
99
|
begin
|
95
|
-
frame.send "is_#{target.to_s}?"
|
100
|
+
frame.send "is_#{target.to_s.sub(/frames$/, 'frame')}?"
|
96
101
|
rescue
|
97
102
|
false
|
98
103
|
end
|
99
104
|
end
|
100
105
|
|
101
|
-
|
102
|
-
r = true
|
103
|
-
io.pos = 12
|
104
|
-
while io.read(4) != 'idx1' do
|
105
|
-
s = io.read(4).unpack('V').first
|
106
|
-
io.pos += s
|
107
|
-
end
|
108
|
-
s = io.read(4).unpack('V').first
|
109
|
-
fc = s / 16
|
110
|
-
if fc >= SAFE_FRAMES_COUNT
|
111
|
-
trap(:INT) do
|
112
|
-
close
|
113
|
-
exit
|
114
|
-
end
|
115
|
-
m = ["WARNING: The passed file has too many frames (#{fc}).\n",
|
116
|
-
"It may use a large memory to process. ",
|
117
|
-
"We recommend to chop the movie to smaller chunks before you glitch.\n",
|
118
|
-
"Do you want to continue anyway? [yN] "].join('')
|
119
|
-
a = Readline.readline m
|
120
|
-
r = a == 'y'
|
121
|
-
end
|
122
|
-
r
|
123
|
-
end
|
124
|
-
|
125
|
-
private_instance_methods [:valid_target?, :is_safe_frames_count?]
|
106
|
+
private :valid_target?
|
126
107
|
|
127
108
|
class << self
|
128
109
|
##
|
129
|
-
#
|
110
|
+
# Checks if the +file+ is a correctly formetted AVI file.
|
130
111
|
# +file+ can be String or Pathname or IO.
|
131
112
|
def surely_formatted? file, debug = false
|
132
113
|
answer = true
|
data/lib/aviglitch/frame.rb
CHANGED
@@ -13,7 +13,7 @@ module AviGlitch
|
|
13
13
|
attr_reader :id, :flag
|
14
14
|
|
15
15
|
##
|
16
|
-
#
|
16
|
+
# Creates a new AviGlitch::Frame object.
|
17
17
|
#
|
18
18
|
# The arguments are:
|
19
19
|
# [+data+] just data, without meta-data
|
@@ -35,7 +35,7 @@ module AviGlitch
|
|
35
35
|
|
36
36
|
##
|
37
37
|
# Alias for is_keyframe?
|
38
|
-
|
38
|
+
alias_method :is_iframe?, :is_keyframe?
|
39
39
|
|
40
40
|
##
|
41
41
|
# Returns if it is a video frame and also not a key frame.
|
@@ -45,7 +45,7 @@ module AviGlitch
|
|
45
45
|
|
46
46
|
##
|
47
47
|
# Alias for is_deltaframe?
|
48
|
-
|
48
|
+
alias_method :is_pframe?, :is_deltaframe?
|
49
49
|
|
50
50
|
##
|
51
51
|
# Returns if it is a video frame.
|
data/lib/aviglitch/frames.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
1
3
|
module AviGlitch
|
2
4
|
|
3
5
|
# Frames provides the interface to access each frame
|
@@ -12,12 +14,19 @@ module AviGlitch
|
|
12
14
|
# frame.data = frame.data.gsub(/\d/, '0')
|
13
15
|
# end
|
14
16
|
#
|
15
|
-
# In the block passed into iteration method, the parameter is
|
17
|
+
# In the block passed into iteration method, the parameter is a reference
|
16
18
|
# of AviGlitch::Frame object.
|
17
19
|
#
|
18
20
|
class Frames
|
19
21
|
include Enumerable
|
20
22
|
|
23
|
+
SAFE_FRAMES_COUNT = 150000 # :nodoc:
|
24
|
+
@@warn_if_frames_are_too_large = true # :nodoc:
|
25
|
+
|
26
|
+
attr_reader :meta
|
27
|
+
|
28
|
+
##
|
29
|
+
# Creates a new AviGlitch::Frames object.
|
21
30
|
def initialize io
|
22
31
|
io.rewind
|
23
32
|
io.pos = 12 # /^RIFF[\s\S]{4}AVI $/
|
@@ -38,38 +47,65 @@ module AviGlitch
|
|
38
47
|
:size => io.read(4).unpack('V').first,
|
39
48
|
}
|
40
49
|
end
|
50
|
+
unless safe_frames_count? @meta.size
|
51
|
+
@io.close!
|
52
|
+
exit
|
53
|
+
end
|
41
54
|
io.rewind
|
42
55
|
@io = io
|
43
56
|
end
|
44
57
|
|
58
|
+
##
|
59
|
+
# Enumerates the frames.
|
45
60
|
def each
|
46
61
|
temp = Tempfile.new 'frames'
|
47
|
-
temp.
|
62
|
+
frames_data_as_io(temp, Proc.new)
|
63
|
+
overwrite temp
|
64
|
+
temp.close!
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Returns the number of frames.
|
69
|
+
def size
|
70
|
+
@meta.size
|
71
|
+
end
|
72
|
+
|
73
|
+
def frames_data_as_io(io = nil, block = nil) #:nodoc:
|
74
|
+
io = Tempfile.new('tmep') if io.nil?
|
48
75
|
@meta = @meta.select do |m|
|
49
|
-
@io.pos = @pos_of_movi + m[:offset] + 8
|
76
|
+
@io.pos = @pos_of_movi + m[:offset] + 8 # 8 for id and size
|
50
77
|
frame = Frame.new(@io.read(m[:size]), m[:id], m[:flag])
|
51
|
-
|
52
|
-
|
53
|
-
|
78
|
+
block.call(frame) if block # accept the variable block as Proc
|
79
|
+
yield frame if block_given? # or a given block (or do nothing)
|
80
|
+
unless frame.data.nil?
|
81
|
+
m[:offset] = io.pos + 4 # 4 for 'movi'
|
54
82
|
m[:size] = frame.data.size
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
83
|
+
io.print m[:id]
|
84
|
+
io.print [frame.data.size].pack('V')
|
85
|
+
io.print frame.data
|
86
|
+
io.print "\000" if frame.data.size % 2 == 1
|
59
87
|
true
|
60
88
|
else
|
61
89
|
false
|
62
90
|
end
|
63
91
|
end
|
92
|
+
io
|
93
|
+
end
|
64
94
|
|
95
|
+
def overwrite data #:nodoc:
|
96
|
+
unless safe_frames_count? @meta.size
|
97
|
+
@io.close!
|
98
|
+
exit
|
99
|
+
end
|
65
100
|
# Overwrite the file
|
66
|
-
|
67
|
-
@io.
|
68
|
-
|
69
|
-
|
101
|
+
data.seek 0, IO::SEEK_END
|
102
|
+
@io.pos = @pos_of_movi - 4 # 4 for size
|
103
|
+
@io.print [data.pos + 4].pack('V') # 4 for 'movi'
|
104
|
+
@io.print 'movi'
|
105
|
+
data.rewind
|
106
|
+
while d = data.read(1024) do
|
70
107
|
@io.print d
|
71
108
|
end
|
72
|
-
temp.close true
|
73
109
|
@io.print 'idx1'
|
74
110
|
@io.print [@meta.size * 16].pack('V')
|
75
111
|
@meta.each do |m|
|
@@ -85,13 +121,249 @@ module AviGlitch
|
|
85
121
|
@io.print [eof - 8].pack('V')
|
86
122
|
## frame count
|
87
123
|
@io.pos = 48
|
88
|
-
|
124
|
+
vid_frames = @meta.select do |m|
|
125
|
+
id = m[:id]
|
126
|
+
id[2, 2] == 'db' || id[2, 2] == 'dc'
|
127
|
+
end
|
128
|
+
@io.print [vid_frames.size].pack('V')
|
89
129
|
|
130
|
+
@io.pos
|
90
131
|
end
|
91
132
|
|
92
|
-
|
93
|
-
|
133
|
+
##
|
134
|
+
# Removes all frames and returns self.
|
135
|
+
def clear
|
136
|
+
@meta = []
|
137
|
+
overwrite StringIO.new
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Appends the frames in the other Frames into the tail of self.
|
143
|
+
# It is destructive like Array does.
|
144
|
+
def concat other_frames
|
145
|
+
raise TypeError unless other_frames.kind_of?(Frames)
|
146
|
+
# data
|
147
|
+
this_data = Tempfile.new 'this'
|
148
|
+
self.frames_data_as_io this_data
|
149
|
+
other_data = Tempfile.new 'other'
|
150
|
+
other_frames.frames_data_as_io other_data
|
151
|
+
this_data.seek 0, IO::SEEK_END
|
152
|
+
this_size = this_data.pos
|
153
|
+
other_data.rewind
|
154
|
+
while d = other_data.read(1024) do
|
155
|
+
this_data.print d
|
156
|
+
end
|
157
|
+
other_data.close!
|
158
|
+
# meta
|
159
|
+
other_meta = other_frames.meta.collect do |m|
|
160
|
+
x = m.dup
|
161
|
+
x[:offset] += this_size
|
162
|
+
x
|
163
|
+
end
|
164
|
+
@meta.concat other_meta
|
165
|
+
# close
|
166
|
+
overwrite this_data
|
167
|
+
this_data.close!
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# Returns a concatenation of the two Frames as a new Frames instance.
|
172
|
+
def + other_frames
|
173
|
+
r = self.to_avi
|
174
|
+
r.frames.concat other_frames
|
175
|
+
r.frames
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Returns the new Frames as a +times+ times repeated concatenation
|
180
|
+
# of the original Frames.
|
181
|
+
def * times
|
182
|
+
result = self.slice 0, 0
|
183
|
+
frames = self.slice 0..-1
|
184
|
+
times.times do
|
185
|
+
result.concat frames
|
186
|
+
end
|
187
|
+
result
|
188
|
+
end
|
189
|
+
|
190
|
+
##
|
191
|
+
# Returns the Frame object at the given index or
|
192
|
+
# returns new Frames object that sliced with the given index and length
|
193
|
+
# or with the Range.
|
194
|
+
# Just like Array.
|
195
|
+
def slice *args
|
196
|
+
b, l = get_beginning_and_length *args
|
197
|
+
if l.nil?
|
198
|
+
self.at b
|
199
|
+
else
|
200
|
+
e = b + l - 1
|
201
|
+
r = self.to_avi
|
202
|
+
r.frames.each_with_index do |f, i|
|
203
|
+
unless i >= b && i <= e
|
204
|
+
f.data = nil
|
205
|
+
end
|
206
|
+
end
|
207
|
+
r.frames
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Alias for slice
|
213
|
+
alias_method :[], :slice
|
214
|
+
|
215
|
+
##
|
216
|
+
# Removes frame(s) at the given index or the range (same as slice).
|
217
|
+
# Returns the new Frames contains removed frames.
|
218
|
+
def slice! *args
|
219
|
+
b, l = get_beginning_and_length *args
|
220
|
+
head, sliced, tail = ()
|
221
|
+
sliced = l.nil? ? self.slice(b) : self.slice(b, l)
|
222
|
+
head = self.slice(0, b)
|
223
|
+
l = 1 if l.nil?
|
224
|
+
tail = self.slice((b + l)..-1)
|
225
|
+
self.clear
|
226
|
+
self.concat head + tail
|
227
|
+
sliced
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Removes frame(s) at the given index or the range (same as []).
|
232
|
+
# Inserts the given Frame or Frames's contents into the removed index.
|
233
|
+
def []= *args, value
|
234
|
+
b, l = get_beginning_and_length *args
|
235
|
+
ll = l.nil? ? 1 : l
|
236
|
+
head = self.slice(0, b)
|
237
|
+
rest = self.slice((b + ll)..-1)
|
238
|
+
if l.nil? || value.kind_of?(Frame)
|
239
|
+
head.push value
|
240
|
+
elsif value.kind_of?(Frames)
|
241
|
+
head.concat value
|
242
|
+
else
|
243
|
+
raise TypeError
|
244
|
+
end
|
245
|
+
new_frames = head + rest
|
246
|
+
|
247
|
+
self.clear
|
248
|
+
self.concat new_frames
|
249
|
+
end
|
250
|
+
|
251
|
+
##
|
252
|
+
# Returns one Frame object at the given index.
|
253
|
+
def at n
|
254
|
+
m = @meta[n]
|
255
|
+
return nil if m.nil?
|
256
|
+
@io.pos = @pos_of_movi + m[:offset] + 8
|
257
|
+
frame = Frame.new(@io.read(m[:size]), m[:id], m[:flag])
|
258
|
+
@io.rewind
|
259
|
+
frame
|
260
|
+
end
|
261
|
+
|
262
|
+
##
|
263
|
+
# Returns the first Frame object.
|
264
|
+
def first
|
265
|
+
self.slice(0)
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Returns the last Frame object.
|
270
|
+
def last
|
271
|
+
self.slice(self.size - 1)
|
272
|
+
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# Appends the given Frame into the tail of self.
|
276
|
+
def push frame
|
277
|
+
raise TypeError unless frame.kind_of? Frame
|
278
|
+
# data
|
279
|
+
this_data = Tempfile.new 'this'
|
280
|
+
self.frames_data_as_io this_data
|
281
|
+
this_data.seek 0, IO::SEEK_END
|
282
|
+
this_size = this_data.pos
|
283
|
+
this_data.print frame.id
|
284
|
+
this_data.print [frame.data.size].pack('V')
|
285
|
+
this_data.print frame.data
|
286
|
+
this_data.print "\000" if frame.data.size % 2 == 1
|
287
|
+
# meta
|
288
|
+
@meta << {
|
289
|
+
:id => frame.id,
|
290
|
+
:flag => frame.flag,
|
291
|
+
:offset => this_size + 4, # 4 for 'movi'
|
292
|
+
:size => frame.data.size,
|
293
|
+
}
|
294
|
+
# close
|
295
|
+
overwrite this_data
|
296
|
+
this_data.close!
|
297
|
+
self
|
298
|
+
end
|
299
|
+
|
300
|
+
##
|
301
|
+
# Alias for push
|
302
|
+
alias_method :<<, :push
|
303
|
+
|
304
|
+
##
|
305
|
+
# Insert the given Frame objects into the given index.
|
306
|
+
def insert n, *args
|
307
|
+
new_frames = self.slice(0, n)
|
308
|
+
args.each do |f|
|
309
|
+
new_frames.push f
|
310
|
+
end
|
311
|
+
new_frames.concat self.slice(n..-1)
|
312
|
+
|
313
|
+
self.clear
|
314
|
+
self.concat new_frames
|
315
|
+
self
|
316
|
+
end
|
317
|
+
|
318
|
+
##
|
319
|
+
# Deletes one Frame at the given index.
|
320
|
+
def delete_at n
|
321
|
+
self.slice! n
|
322
|
+
end
|
323
|
+
|
324
|
+
##
|
325
|
+
# Returns true if +other+'s frames are same as self's frames.
|
326
|
+
def == other
|
327
|
+
@meta == other.meta
|
328
|
+
end
|
329
|
+
|
330
|
+
##
|
331
|
+
# Generate new AviGlitch::Base instance using self.
|
332
|
+
def to_avi
|
333
|
+
AviGlitch.open @io.path
|
334
|
+
end
|
335
|
+
|
336
|
+
def get_beginning_and_length *args #:nodoc:
|
337
|
+
b, l = args
|
338
|
+
if args.first.kind_of? Range
|
339
|
+
r = args.first
|
340
|
+
b = r.begin
|
341
|
+
e = r.end >= 0 ? r.end : @meta.size + r.end
|
342
|
+
l = e - b + 1
|
343
|
+
end
|
344
|
+
b = b >= 0 ? b : @meta.size + b
|
345
|
+
[b, l]
|
346
|
+
end
|
347
|
+
|
348
|
+
def safe_frames_count? count # :nodoc:
|
349
|
+
r = true
|
350
|
+
if @@warn_if_frames_are_too_large && count >= SAFE_FRAMES_COUNT
|
351
|
+
trap(:INT) do
|
352
|
+
@io.close!
|
353
|
+
exit
|
354
|
+
end
|
355
|
+
m = ["WARNING: The avi data has too many frames (#{count}).\n",
|
356
|
+
"It may use a large memory to process. ",
|
357
|
+
"We recommend to chop the movie to smaller chunks before you glitch.\n",
|
358
|
+
"Do you want to continue anyway? [yN] "].join('')
|
359
|
+
a = Readline.readline m
|
360
|
+
r = a == 'y'
|
361
|
+
@@warn_if_frames_are_too_large = !r
|
362
|
+
end
|
363
|
+
r
|
94
364
|
end
|
95
365
|
|
366
|
+
protected :frames_data_as_io, :meta
|
367
|
+
private :overwrite, :get_beginning_and_length
|
96
368
|
end
|
97
369
|
end
|
data/spec/aviglitch_spec.rb
CHANGED
@@ -16,25 +16,18 @@ describe AviGlitch do
|
|
16
16
|
FileUtils.rmdir OUTPUT_DIR
|
17
17
|
end
|
18
18
|
|
19
|
-
it 'raise an error against unsupported files' do
|
19
|
+
it 'should raise an error against unsupported files' do
|
20
20
|
lambda {
|
21
21
|
avi = AviGlitch.open __FILE__
|
22
22
|
}.should raise_error
|
23
23
|
end
|
24
24
|
|
25
|
-
it '
|
25
|
+
it 'should return AviGlitch::Base object through the method #open' do
|
26
26
|
avi = AviGlitch.open @in
|
27
27
|
avi.should be_kind_of AviGlitch::Base
|
28
28
|
end
|
29
29
|
|
30
|
-
it '
|
31
|
-
avi = AviGlitch.open @in
|
32
|
-
avi.frames.each do |f|
|
33
|
-
;
|
34
|
-
end
|
35
|
-
avi.output @out
|
36
|
-
FileUtils.cmp(@in, @out).should be true
|
37
|
-
|
30
|
+
it 'should save the same file when nothing is changed' do
|
38
31
|
avi = AviGlitch.open @in
|
39
32
|
avi.glitch do |d|
|
40
33
|
d
|
@@ -43,19 +36,6 @@ describe AviGlitch do
|
|
43
36
|
FileUtils.cmp(@in, @out).should be true
|
44
37
|
end
|
45
38
|
|
46
|
-
it 'can manipulate each frame' do
|
47
|
-
avi = AviGlitch.open @in
|
48
|
-
f = avi.frames
|
49
|
-
f.should be_kind_of Enumerable
|
50
|
-
avi.frames.each do |f|
|
51
|
-
if f.is_keyframe?
|
52
|
-
f.data = f.data.gsub(/\d/, '0')
|
53
|
-
end
|
54
|
-
end
|
55
|
-
avi.output @out
|
56
|
-
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
57
|
-
end
|
58
|
-
|
59
39
|
it 'can glitch each keyframe' do
|
60
40
|
avi = AviGlitch.open @in
|
61
41
|
n = 0
|
@@ -86,28 +66,81 @@ describe AviGlitch do
|
|
86
66
|
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
87
67
|
end
|
88
68
|
|
89
|
-
it '
|
69
|
+
it 'should have some alias methods' do
|
70
|
+
lambda {
|
71
|
+
avi = AviGlitch.open @in
|
72
|
+
avi.write @out
|
73
|
+
}.should_not raise_error
|
74
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'can glitch with :*frames instead of :*frame' do
|
90
78
|
avi = AviGlitch.open @in
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
nil
|
79
|
+
count = 0
|
80
|
+
avi.glitch :keyframes do |kf|
|
81
|
+
count += 1
|
82
|
+
kf
|
96
83
|
end
|
84
|
+
avi.close
|
85
|
+
count.should > 0
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should close file when output' do
|
89
|
+
avi = AviGlitch.open @in
|
97
90
|
avi.output @out
|
98
|
-
|
91
|
+
lambda {
|
92
|
+
avi.glitch do |f|
|
93
|
+
f
|
94
|
+
end
|
95
|
+
}.should raise_error(IOError)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'can explicit close file' do
|
99
|
+
avi = AviGlitch.open @in
|
100
|
+
avi.close
|
101
|
+
lambda {
|
102
|
+
avi.glitch do |f|
|
103
|
+
f
|
104
|
+
end
|
105
|
+
}.should raise_error(IOError)
|
106
|
+
end
|
99
107
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
108
|
+
it 'should offer one liner style coding' do
|
109
|
+
lambda {
|
110
|
+
AviGlitch.open(@in).glitch(:keyframe){|d| '0' * d.size}.output(@out)
|
111
|
+
}.should_not raise_error
|
112
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
104
113
|
end
|
105
114
|
|
106
|
-
it '
|
115
|
+
it 'should not raise error in multiple glitches' do
|
107
116
|
lambda {
|
108
117
|
avi = AviGlitch.open @in
|
109
|
-
avi.
|
118
|
+
avi.glitch(:keyframe) do |d|
|
119
|
+
d.gsub(/\d/, '')
|
120
|
+
end
|
121
|
+
avi.glitch(:keyframe) do |d|
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
avi.glitch(:audioframe) do |d|
|
125
|
+
d * 2
|
126
|
+
end
|
127
|
+
avi.output @out
|
110
128
|
}.should_not raise_error
|
111
129
|
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
112
130
|
end
|
131
|
+
|
132
|
+
it 'can work with another frames instance' do
|
133
|
+
a = AviGlitch.open @in
|
134
|
+
a.glitch :keyframe do |d|
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
a.output(@out.to_s + 'x.avi')
|
138
|
+
b = AviGlitch.open @in
|
139
|
+
c = AviGlitch.open(@out.to_s + 'x.avi')
|
140
|
+
b.frames = c.frames
|
141
|
+
b.output @out
|
142
|
+
|
143
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
144
|
+
end
|
145
|
+
|
113
146
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe AviGlitch, 'datamosh cli' do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
FileUtils.mkdir OUTPUT_DIR unless File.exist? OUTPUT_DIR
|
7
|
+
@in = FILES_DIR + 'sample.avi'
|
8
|
+
@out = OUTPUT_DIR + 'out.avi'
|
9
|
+
datamosh = Pathname.new(
|
10
|
+
File.join(File.dirname(__FILE__), '..', 'bin/datamosh')
|
11
|
+
).realpath
|
12
|
+
@cmd = "ruby %s -o %s " % [datamosh, @out]
|
13
|
+
end
|
14
|
+
|
15
|
+
after :each do
|
16
|
+
FileUtils.rm Dir.glob((OUTPUT_DIR + '*').to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
after :all do
|
20
|
+
FileUtils.rmdir OUTPUT_DIR
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should correctly process files' do
|
24
|
+
system [@cmd, @in].join(' ')
|
25
|
+
o = AviGlitch.open @out
|
26
|
+
o.frames.each_with_index do |f, i|
|
27
|
+
if f.is_keyframe? && i == 0
|
28
|
+
f.data.should_not match /^\000+$/
|
29
|
+
elsif f.is_keyframe?
|
30
|
+
f.data.should match /^\000+$/
|
31
|
+
end
|
32
|
+
end
|
33
|
+
o.close
|
34
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
35
|
+
|
36
|
+
system [@cmd, '-a', @in].join(' ')
|
37
|
+
o = AviGlitch.open @out
|
38
|
+
o.frames.each do |f|
|
39
|
+
if f.is_keyframe?
|
40
|
+
f.data.should match /^\000+$/
|
41
|
+
end
|
42
|
+
end
|
43
|
+
o.close
|
44
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
45
|
+
|
46
|
+
system [@cmd, @in, @in, @in].join(' ')
|
47
|
+
a = AviGlitch.open @in
|
48
|
+
o = AviGlitch.open @out
|
49
|
+
o.frames.size.should == a.frames.size * 3
|
50
|
+
o.frames.each_with_index do |f, i|
|
51
|
+
if f.is_keyframe? && i == 0
|
52
|
+
f.data.should_not match /^\000+$/
|
53
|
+
elsif f.is_keyframe?
|
54
|
+
f.data.should match /^\000+$/
|
55
|
+
end
|
56
|
+
end
|
57
|
+
o.close
|
58
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/spec/frames_spec.rb
ADDED
@@ -0,0 +1,450 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe AviGlitch::Frames do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
AviGlitch::Frames.class_eval do
|
7
|
+
define_method(:get_real_id_with) do |frame|
|
8
|
+
pos = @io.pos
|
9
|
+
@io.pos -= frame.data.size
|
10
|
+
@io.pos -= 8
|
11
|
+
id = @io.read 4
|
12
|
+
@io.pos = pos
|
13
|
+
id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
FileUtils.mkdir OUTPUT_DIR unless File.exist? OUTPUT_DIR
|
18
|
+
@in = FILES_DIR + 'sample.avi'
|
19
|
+
@out = OUTPUT_DIR + 'out.avi'
|
20
|
+
end
|
21
|
+
|
22
|
+
after :each do
|
23
|
+
FileUtils.rm Dir.glob((OUTPUT_DIR + '*').to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
after :all do
|
27
|
+
FileUtils.rmdir OUTPUT_DIR
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should save the same file when nothing is changed' do
|
31
|
+
avi = AviGlitch.open @in
|
32
|
+
avi.frames.each do |f|
|
33
|
+
;
|
34
|
+
end
|
35
|
+
avi.output @out
|
36
|
+
FileUtils.cmp(@in, @out).should be true
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can manipulate each frame' do
|
40
|
+
avi = AviGlitch.open @in
|
41
|
+
f = avi.frames
|
42
|
+
f.should be_kind_of Enumerable
|
43
|
+
avi.frames.each do |f|
|
44
|
+
if f.is_keyframe?
|
45
|
+
f.data = f.data.gsub(/\d/, '0')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
avi.output @out
|
49
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should remove a frame when returning nil' do
|
53
|
+
avi = AviGlitch.open @in
|
54
|
+
in_frame_size = avi.frames.size
|
55
|
+
rem_count = 0
|
56
|
+
avi.glitch :keyframe do |kf|
|
57
|
+
rem_count += 1
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
avi.output @out
|
61
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
62
|
+
|
63
|
+
# frames length in the output file is correct
|
64
|
+
avi = AviGlitch.open @out
|
65
|
+
out_frame_size = avi.frames.size
|
66
|
+
out_frame_size.should == in_frame_size - rem_count
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should read correct positions in #each' do
|
70
|
+
avi = AviGlitch.open @in
|
71
|
+
frames = avi.frames
|
72
|
+
frames.each do |f|
|
73
|
+
real_id = frames.get_real_id_with f
|
74
|
+
real_id.should == f.id
|
75
|
+
end
|
76
|
+
avi.close
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should promise the read frame data is not nil' do
|
80
|
+
avi = AviGlitch.open @in
|
81
|
+
frames = avi.frames
|
82
|
+
frames.each do |f|
|
83
|
+
f.data.should_not == nil
|
84
|
+
end
|
85
|
+
avi.close
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should hide the inner variables' do
|
89
|
+
avi = AviGlitch.open @in
|
90
|
+
frames = avi.frames
|
91
|
+
lambda { frames.meta }.should raise_error(NoMethodError)
|
92
|
+
lambda { frames.io }.should raise_error(NoMethodError)
|
93
|
+
lambda { frames.frames_data_as_io }.should raise_error(NoMethodError)
|
94
|
+
avi.close
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should save video frames count in header' do
|
98
|
+
avi = AviGlitch.open @in
|
99
|
+
c = 0
|
100
|
+
avi.frames.each do |f|
|
101
|
+
c += 1 if f.is_videoframe?
|
102
|
+
end
|
103
|
+
avi.output @out
|
104
|
+
open(@out) do |f|
|
105
|
+
f.pos = 48
|
106
|
+
f.read(4).unpack('V').first.should == c
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should evaluate the equality with owned contents' do
|
111
|
+
a = AviGlitch.open @in
|
112
|
+
b = AviGlitch.open @in
|
113
|
+
a.frames.should == b.frames
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'can generate AviGlitch::Base instance' do
|
117
|
+
a = AviGlitch.open @in
|
118
|
+
b = a.frames.slice(0, 10)
|
119
|
+
c = b.to_avi
|
120
|
+
c.should be_kind_of AviGlitch::Base
|
121
|
+
c.output @out
|
122
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'can concat with other Frames instance with #concat, destructively' do
|
126
|
+
a = AviGlitch.open @in
|
127
|
+
b = AviGlitch.open @in
|
128
|
+
asize = a.frames.size
|
129
|
+
bsize = b.frames.size
|
130
|
+
lambda {
|
131
|
+
a.frames.concat([1,2,3])
|
132
|
+
}.should raise_error(TypeError)
|
133
|
+
a.frames.concat(b.frames)
|
134
|
+
a.frames.size.should == asize + bsize
|
135
|
+
b.frames.size.should == bsize
|
136
|
+
a.output @out
|
137
|
+
b.close
|
138
|
+
|
139
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'can concat with other Frames instance with +' do
|
143
|
+
a = AviGlitch.open @in
|
144
|
+
b = AviGlitch.open @in
|
145
|
+
asize = a.frames.size
|
146
|
+
bsize = b.frames.size
|
147
|
+
c = a.frames + b.frames
|
148
|
+
a.frames.size.should == asize
|
149
|
+
b.frames.size.should == bsize
|
150
|
+
c.should be_kind_of AviGlitch::Frames
|
151
|
+
c.size.should == asize + bsize
|
152
|
+
a.close
|
153
|
+
b.close
|
154
|
+
d = AviGlitch.open c
|
155
|
+
d.output @out
|
156
|
+
|
157
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'can slice frames using start pos and length' do
|
161
|
+
avi = AviGlitch.open @in
|
162
|
+
a = avi.frames
|
163
|
+
asize = a.size
|
164
|
+
c = (a.size / 3).floor
|
165
|
+
b = a.slice(1, c)
|
166
|
+
b.should be_kind_of AviGlitch::Frames
|
167
|
+
b.size.should == c
|
168
|
+
lambda {
|
169
|
+
b.each {|x| x }
|
170
|
+
}.should_not raise_error
|
171
|
+
|
172
|
+
a.size.should == asize # make sure a is not destroyed
|
173
|
+
lambda {
|
174
|
+
a.each {|x| x }
|
175
|
+
}.should_not raise_error
|
176
|
+
|
177
|
+
avi.frames.concat b
|
178
|
+
avi.output @out
|
179
|
+
|
180
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'can slice frames using Range' do
|
184
|
+
avi = AviGlitch.open @in
|
185
|
+
a = avi.frames
|
186
|
+
asize = a.size
|
187
|
+
c = (a.size / 3).floor
|
188
|
+
spos = 3
|
189
|
+
range = spos..(spos + c)
|
190
|
+
b = a.slice(range)
|
191
|
+
b.should be_kind_of AviGlitch::Frames
|
192
|
+
b.size.should == c + 1
|
193
|
+
lambda {
|
194
|
+
b.each {|x| x }
|
195
|
+
}.should_not raise_error
|
196
|
+
|
197
|
+
range = spos..-1
|
198
|
+
d = a.slice(range)
|
199
|
+
d.should be_kind_of AviGlitch::Frames
|
200
|
+
d.size.should == asize - spos
|
201
|
+
lambda {
|
202
|
+
d.each {|x| x }
|
203
|
+
}.should_not raise_error
|
204
|
+
|
205
|
+
x = -5
|
206
|
+
range = spos..x
|
207
|
+
e = a.slice(range)
|
208
|
+
e.should be_kind_of AviGlitch::Frames
|
209
|
+
e.size.should == asize - spos + x + 1
|
210
|
+
lambda {
|
211
|
+
e.each {|x| x }
|
212
|
+
}.should_not raise_error
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'can concat repeatedly the same sliced frames' do
|
217
|
+
a = AviGlitch.open @in
|
218
|
+
b = a.frames.slice(0, 5)
|
219
|
+
c = a.frames.slice(0, 10)
|
220
|
+
10.times do
|
221
|
+
b.concat(c)
|
222
|
+
end
|
223
|
+
b.size.should == 5 + (10 * 10)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'can get one single frame using slice(n)' do
|
227
|
+
a = AviGlitch.open @in
|
228
|
+
pos = 10
|
229
|
+
b = nil
|
230
|
+
a.frames.each_with_index do |f, i|
|
231
|
+
b = f if i == pos
|
232
|
+
end
|
233
|
+
c = a.frames.slice(pos)
|
234
|
+
c.should be_kind_of AviGlitch::Frame
|
235
|
+
c.data.should == b.data
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'can get one single frame using at(n)' do
|
239
|
+
a = AviGlitch.open @in
|
240
|
+
pos = 10
|
241
|
+
b = nil
|
242
|
+
a.frames.each_with_index do |f, i|
|
243
|
+
b = f if i == pos
|
244
|
+
end
|
245
|
+
c = a.frames.at(pos)
|
246
|
+
c.should be_kind_of AviGlitch::Frame
|
247
|
+
c.data.should == b.data
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'can get a first frame ussing first, a last frame using last' do
|
251
|
+
a = AviGlitch.open @in
|
252
|
+
b0 = c0 = nil
|
253
|
+
a.frames.each_with_index do |f, i|
|
254
|
+
b0 = f if i == 0
|
255
|
+
c0 = f if i == a.frames.size - 1
|
256
|
+
end
|
257
|
+
b1 = a.frames.first
|
258
|
+
c1 = a.frames.last
|
259
|
+
|
260
|
+
b1.data.should == b0.data
|
261
|
+
c1.data.should == c0.data
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'can add a frame at last using push' do
|
265
|
+
a = AviGlitch.open @in
|
266
|
+
s = a.frames.size
|
267
|
+
b = a.frames[10]
|
268
|
+
lambda {
|
269
|
+
a.frames.push 100
|
270
|
+
}.should raise_error(TypeError)
|
271
|
+
c = a.frames + a.frames.slice(10, 1)
|
272
|
+
|
273
|
+
x = a.frames.push b
|
274
|
+
a.frames.size.should == s + 1
|
275
|
+
x.should == a.frames
|
276
|
+
a.frames.should == c
|
277
|
+
a.frames.last.data.should == c.last.data
|
278
|
+
x = a.frames.push b
|
279
|
+
a.frames.size.should == s + 2
|
280
|
+
x.should == a.frames
|
281
|
+
|
282
|
+
a.output @out
|
283
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'can add a frame at last using <<' do
|
287
|
+
a = AviGlitch.open @in
|
288
|
+
s = a.frames.size
|
289
|
+
b = a.frames[10]
|
290
|
+
|
291
|
+
x = a.frames << b
|
292
|
+
a.frames.size.should == s + 1
|
293
|
+
x.should == a.frames
|
294
|
+
|
295
|
+
a.output @out
|
296
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'can delete all frames using clear' do
|
300
|
+
a = AviGlitch.open @in
|
301
|
+
a.frames.clear
|
302
|
+
a.frames.size.should == 0
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'can delete one frame using delete_at' do
|
306
|
+
a = AviGlitch.open @in
|
307
|
+
l = a.frames.size
|
308
|
+
b = a.frames[10]
|
309
|
+
c = a.frames[11]
|
310
|
+
x = a.frames.delete_at 10
|
311
|
+
|
312
|
+
x.data.should == b.data
|
313
|
+
a.frames[10].data.should == c.data
|
314
|
+
a.frames.size.should == l - 1
|
315
|
+
|
316
|
+
a.output @out
|
317
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'can insert one frame into other frames using insert' do
|
321
|
+
a = AviGlitch.open @in
|
322
|
+
l = a.frames.size
|
323
|
+
b = a.frames[10]
|
324
|
+
x = a.frames.insert 5, b
|
325
|
+
|
326
|
+
x.should == a.frames
|
327
|
+
a.frames[5].data.should == b.data
|
328
|
+
a.frames[11].data.should == b.data
|
329
|
+
a.frames.size.should == l + 1
|
330
|
+
|
331
|
+
a.output @out
|
332
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'can slice frames destructively using slice!' do
|
336
|
+
a = AviGlitch.open @in
|
337
|
+
l = a.frames.size
|
338
|
+
|
339
|
+
b = a.frames.slice!(10)
|
340
|
+
b.should be_kind_of AviGlitch::Frame
|
341
|
+
a.frames.size.should == l - 1
|
342
|
+
|
343
|
+
c = a.frames.slice!(0, 10)
|
344
|
+
c.should be_kind_of AviGlitch::Frames
|
345
|
+
a.frames.size.should == l - 1 - 10
|
346
|
+
|
347
|
+
d = a.frames.slice!(0..9)
|
348
|
+
d.should be_kind_of AviGlitch::Frames
|
349
|
+
a.frames.size.should == l - 1 - 10 - 10
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'can swap frame(s) using []=' do
|
353
|
+
a = AviGlitch.open @in
|
354
|
+
l = a.frames.size
|
355
|
+
lambda {
|
356
|
+
a.frames[10] = "xxx"
|
357
|
+
}.should raise_error(TypeError)
|
358
|
+
|
359
|
+
b = a.frames[20]
|
360
|
+
a.frames[10] = b
|
361
|
+
a.frames.size.should == l
|
362
|
+
a.frames[10].data.should == b.data
|
363
|
+
|
364
|
+
a.output @out
|
365
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
366
|
+
|
367
|
+
a = AviGlitch.open @in
|
368
|
+
pl = 5
|
369
|
+
pp = 3
|
370
|
+
b = a.frames[20, pl]
|
371
|
+
a.frames[10..(10 + pp)] = b
|
372
|
+
a.frames.size.should == l - pp + pl - 1
|
373
|
+
pp.times do |i|
|
374
|
+
a.frames[10 + i].data.should == b[i].data
|
375
|
+
end
|
376
|
+
|
377
|
+
lambda {
|
378
|
+
a.frames[10] = a.frames.slice(100, 1)
|
379
|
+
}.should raise_error(TypeError)
|
380
|
+
|
381
|
+
a.output @out
|
382
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'can repeat frames using *' do
|
386
|
+
a = AviGlitch.open @in
|
387
|
+
|
388
|
+
r = 20
|
389
|
+
b = a.frames.slice(10, 10)
|
390
|
+
c = b * r
|
391
|
+
c.size.should == 10 * r
|
392
|
+
|
393
|
+
c.to_avi.output @out
|
394
|
+
AviGlitch::Base.surely_formatted?(@out, true).should be true
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should manipulate frames like array does' do
|
398
|
+
avi = AviGlitch.open @in
|
399
|
+
a = avi.frames
|
400
|
+
x = Array.new a.size
|
401
|
+
|
402
|
+
fa = a.slice(0, 100)
|
403
|
+
fx = x.slice(0, 100)
|
404
|
+
fa.size.should == fx.size
|
405
|
+
|
406
|
+
fa = a.slice(100..-1)
|
407
|
+
fx = x.slice(100..-1)
|
408
|
+
fa.size.should == fx.size
|
409
|
+
|
410
|
+
fa = a.slice(100..-10)
|
411
|
+
fx = x.slice(100..-10)
|
412
|
+
fa.size.should == fx.size
|
413
|
+
|
414
|
+
fa = a.slice(-200, 10)
|
415
|
+
fx = x.slice(-200, 10)
|
416
|
+
fa.size.should == fx.size
|
417
|
+
|
418
|
+
a[100] = a.at 200
|
419
|
+
x[100] = x.at 200
|
420
|
+
a.size.should == x.size
|
421
|
+
|
422
|
+
a[100..150] = a.slice(100, 100)
|
423
|
+
x[100..150] = x.slice(100, 100)
|
424
|
+
a.size.should == x.size
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'should have the method alias to slice as []' do
|
428
|
+
a = AviGlitch.open @in
|
429
|
+
|
430
|
+
b = a.frames[10]
|
431
|
+
b.should be_kind_of AviGlitch::Frame
|
432
|
+
|
433
|
+
c = a.frames[0, 10]
|
434
|
+
c.should be_kind_of AviGlitch::Frames
|
435
|
+
c.size.should == 10
|
436
|
+
|
437
|
+
d = a.frames[0..9]
|
438
|
+
d.should be_kind_of AviGlitch::Frames
|
439
|
+
d.size.should == 10
|
440
|
+
end
|
441
|
+
|
442
|
+
it 'should return nil when getting a frame at out-of-range index' do
|
443
|
+
a = AviGlitch.open @in
|
444
|
+
|
445
|
+
x = a.frames.at(a.frames.size + 1)
|
446
|
+
x.should be_nil
|
447
|
+
end
|
448
|
+
|
449
|
+
|
450
|
+
end
|
data/spec/spec.opts
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
-c
|
2
|
+
-fs
|
metadata
CHANGED
@@ -1,12 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aviglitch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
version: 0.0.2
|
4
|
+
version: 0.0.3
|
10
5
|
platform: ruby
|
11
6
|
authors:
|
12
7
|
- ucnv
|
@@ -14,7 +9,7 @@ autorequire:
|
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
11
|
|
17
|
-
date: 2010-
|
12
|
+
date: 2010-07-07 00:00:00 +09:00
|
18
13
|
default_executable: datamosh
|
19
14
|
dependencies: []
|
20
15
|
|
@@ -39,7 +34,9 @@ files:
|
|
39
34
|
- lib/aviglitch/frame.rb
|
40
35
|
- lib/aviglitch/frames.rb
|
41
36
|
- spec/aviglitch_spec.rb
|
37
|
+
- spec/datamosh_spec.rb
|
42
38
|
- spec/files/sample.avi
|
39
|
+
- spec/frames_spec.rb
|
43
40
|
- spec/spec.opts
|
44
41
|
- spec/spec_helper.rb
|
45
42
|
- LICENSE
|
@@ -56,23 +53,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
56
53
|
requirements:
|
57
54
|
- - ">="
|
58
55
|
- !ruby/object:Gem::Version
|
59
|
-
segments:
|
60
|
-
- 0
|
61
56
|
version: "0"
|
57
|
+
version:
|
62
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
59
|
requirements:
|
64
60
|
- - ">="
|
65
61
|
- !ruby/object:Gem::Version
|
66
|
-
segments:
|
67
|
-
- 0
|
68
62
|
version: "0"
|
63
|
+
version:
|
69
64
|
requirements: []
|
70
65
|
|
71
66
|
rubyforge_project:
|
72
|
-
rubygems_version: 1.3.
|
67
|
+
rubygems_version: 1.3.5
|
73
68
|
signing_key:
|
74
69
|
specification_version: 3
|
75
70
|
summary: A Ruby library to destroy your AVI files.
|
76
71
|
test_files:
|
77
72
|
- spec/aviglitch_spec.rb
|
73
|
+
- spec/datamosh_spec.rb
|
74
|
+
- spec/frames_spec.rb
|
78
75
|
- spec/spec_helper.rb
|