aviglitch 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,11 @@
1
+ == 0.0.2 / 2010-05-17
2
+
3
+ * Removed AviGlitch#new. Use AviGlitch#open instead of #new.
4
+ * Added warning for a large file.
5
+ * Changed datamosh command interface.
6
+ * Changed the library file layout.
7
+ * And tiny internal changes.
8
+
1
9
  == 0.0.1 / 2009-08-01
2
10
 
3
11
  * initial release
@@ -8,7 +8,7 @@ AviGlitch destroys your AVI files.
8
8
 
9
9
  I can't explain why they're going to destroy their own data.
10
10
 
11
- See followig urls for details;
11
+ See following urls for details;
12
12
  * vimeo http://www.vimeo.com/groups/artifacts
13
13
  * wikipedia http://en.wikipedia.org/wiki/Compression_artifact
14
14
 
@@ -22,22 +22,21 @@ See followig urls for details;
22
22
 
23
23
  require 'aviglitch'
24
24
 
25
- avi = AviGlitch.new('/path/to/your.avi')
25
+ avi = AviGlitch.open('/path/to/your.avi')
26
26
  avi.glitch(:keyframe) do |data|
27
27
  data.gsub(/\d/, '0')
28
28
  end
29
- avi.write('/path/to/broken.avi')
29
+ avi.output('/path/to/broken.avi')
30
30
 
31
- This library also includes a command tool named +datamosh+.
31
+ This library also includes a command line tool named +datamosh+.
32
32
  It creates the keyframes removed video.
33
33
 
34
- $ datamosh /path/to/your.avi /path/to/broken.avi
34
+ $ datamosh /path/to/your.avi -o /path/to/broken.avi
35
35
 
36
36
  == Installation
37
37
 
38
- gem sources -a http://gems.github.com
39
- sudo gem install ucnv-aviglitch
38
+ gem install aviglitch
40
39
 
41
40
  == Copyright
42
41
 
43
- Copyright (c) 2009 ucnv. See LICENSE for details.
42
+ Copyright (c) 2009 - 2010 ucnv. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -1,25 +1,51 @@
1
1
  #!/usr/bin/env ruby
2
2
  # Generate datamoshing
3
3
 
4
+ require 'optparse'
4
5
  require 'rubygems'
5
6
  require 'aviglitch'
6
7
 
7
- if ARGV.size < 1 || ARGV.first == '--help'
8
- puts <<-BANNER.gsub(/^\s+/, '')
9
- Usage: #{File.basename $0} INPUT [OUTPUT]
10
- Generate a datamoshing video from INPUT to OUTPUT (./out.avi by default).
11
- BANNER
12
- exit 0
13
- end
8
+ output = './out.avi'
9
+ all = false
10
+ force = false
14
11
 
15
- input, output = ARGV
12
+ opts = OptionParser.new do |opts|
13
+ opts.banner = "datamosh - AviGlitch's datamoshing video generator."
14
+ opts.define_head "Usage: #{File.basename($0)} <input> [options]"
15
+ opts.separator "Options:"
16
+ opts.on("-o", "--output [OUTPUT]",
17
+ "Output the video to OUTPUT (./out.avi by default)") do |f|
18
+ output = f
19
+ end
20
+ opts.on("-f", "--force", "Overwrite an existing output file") do
21
+ force = true
22
+ end
23
+ opts.on("-a", "--all",
24
+ "Remove all keyframes (It remains a first keyframe by default)") do
25
+ all = true
26
+ end
27
+ opts.on_tail("-h", "--help", "Show this message") do
28
+ puts opts
29
+ exit
30
+ end
31
+ end
32
+ input = opts.parse!
33
+ if input.empty?
34
+ puts opts
35
+ exit 1
36
+ end
37
+ if !force && File.exists?(output)
38
+ puts "!!! `#{output}' already exists. Use -f option to overwrite."
39
+ exit 1
40
+ end
16
41
 
17
- a = AviGlitch.new input
42
+ a = AviGlitch.open input.first
18
43
  a.glitch_with_index :keyframe do |frame, i|
19
- if i == 0 # keep the first frame
44
+ if !all && i == 0 # keep the first frame
20
45
  frame
21
46
  else
22
47
  "\000" * frame.size
23
48
  end
24
49
  end
25
- a.write(output || 'out.avi')
50
+ a.output(output)
51
+
@@ -1,5 +1,4 @@
1
- require 'tempfile'
2
- require 'fileutils'
1
+ require 'aviglitch/base'
3
2
  require 'aviglitch/frame'
4
3
  require 'aviglitch/frames'
5
4
 
@@ -9,162 +8,35 @@ require 'aviglitch/frames'
9
8
  #
10
9
  # You can manipulate each frame, like:
11
10
  #
12
- # avi = Aviglitch.new '/path/to/your.avi'
11
+ # avi = AviGlitch.open '/path/to/your.avi'
13
12
  # avi.frames.each |frame|
14
13
  # if frame.is_keyframe?
15
14
  # frame.data = frame.data.gsub(/\d/, '0')
16
15
  # end
17
16
  # end
18
- # avi.write '/path/to/broken.avi'
17
+ # avi.output '/path/to/broken.avi'
19
18
  #
20
19
  # Using the method glitch, it can be written like:
21
20
  #
22
- # avi = AviGlitch.new '/path/to/your.avi'
21
+ # avi = AviGlitch.open '/path/to/your.avi'
23
22
  # avi.glitch(:keyframe) do |data|
24
23
  # data.gsub(/\d/, '0')
25
24
  # end
26
- # avi.write '/path/to/broken.avi'
25
+ # avi.output '/path/to/broken.avi'
27
26
  #
28
27
  #--
29
28
  # It does not support AVI2, interleave format.
30
29
  #
31
- class AviGlitch
30
+ module AviGlitch
32
31
 
33
- VERSION = '0.0.1'
32
+ VERSION = '0.0.2'
34
33
 
35
- # AviGlitch::Frames object generated from the +file+.
36
- attr_reader :frames
37
- # The input file (copied tempfile).
38
- attr_reader :file
39
-
40
- ##
41
- # Create a new instance of AviGlitch, open the file and
42
- # make it ready to manipulate.
43
- # It requires +path+ as String or Pathname.
44
- def initialize path
45
- File.open(path) do |f|
46
- # copy as tempfile
47
- @file = Tempfile.open 'aviglitch'
48
- f.rewind
49
- while d = f.read(1024) do
50
- @file.print d
51
- end
52
- end
53
-
54
- unless AviGlitch.surely_formatted? @file
55
- raise 'Unsupported file passed.'
56
- end
57
- @frames = Frames.new @file
58
- # I believe Ruby's GC to close and remove the Tempfile..
59
- end
60
-
61
- ##
62
- # Output the glitched file to +path+, and close the file.
63
- def write path
64
- FileUtils.cp @file.path, path
65
- close
66
- end
67
-
68
- ##
69
- # An explicit file close.
70
- def close
71
- @file.close!
72
- end
73
-
74
- ##
75
- # Glitch each frame data.
76
- # It is a convent method to iterate each frame.
77
- #
78
- # The argument +target+ takes symbols listed below:
79
- # [<tt>:keyframe</tt> or <tt>:iframe</tt>] select video key frames (aka I-frame)
80
- # [<tt>:deltaframe</tt> or <tt>:pframe</tt>] select video delta frames (difference frames)
81
- # [<tt>:videoframe</tt>] select both of keyframe and deltaframe
82
- # [<tt>:audioframe</tt>] select audio frames
83
- # [<tt>:all</tt>] select all frames
84
- #
85
- # It also requires a block. In the block, you take the frame data
86
- # as a String parameter.
87
- # To modify the data, simply return a modified data.
88
- def glitch target = :all, &block # :yield: data
89
- frames.each do |frame|
90
- if valid_target? target, frame
91
- frame.data = yield frame.data
92
- end
93
- end
94
- end
95
-
96
- ##
97
- # Do glitch with index.
98
- def glitch_with_index target = :all, &block # :yield: data, index
99
- i = 0
100
- frames.each do |frame|
101
- if valid_target? target, frame
102
- frame.data = yield(frame.data, i)
103
- i += 1
104
- end
105
- end
106
- end
107
-
108
- alias :output :write
109
-
110
- def valid_target? target, frame # :nodoc:
111
- return true if target == :all
112
- begin
113
- frame.send "is_#{target.to_s}?"
114
- rescue
115
- false
116
- end
117
- end
118
-
119
- private_instance_methods :valid_target?
120
34
  class << self
121
-
122
35
  ##
123
- # Check if the +file+ is a correctly formetted AVI file.
124
- # +file+ can be String or Pathname or IO.
125
- def surely_formatted? file, debug = false
126
- answer = true
127
- is_io = file.respond_to?(:seek) # Probably IO.
128
- file = File.open(file) unless is_io
129
- begin
130
- file.seek 0, IO::SEEK_END
131
- eof = file.pos
132
- file.rewind
133
- unless file.read(4) == 'RIFF'
134
- answer = false
135
- warn 'RIFF sign is not found' if debug
136
- end
137
- len = file.read(4).unpack('V').first
138
- unless len + 8 == eof
139
- answer = false
140
- warn 'Length info is invalid' if debug
141
- end
142
- unless file.read(4) == 'AVI '
143
- answer = false
144
- warn 'AVI sign is not found' if debug
145
- end
146
- while file.read(4) =~ /^(?:LIST|JUNK)$/ do
147
- s = file.read(4).unpack('V').first
148
- file.pos += s
149
- end
150
- file.pos -= 4
151
- # we require idx1
152
- unless file.read(4) == 'idx1'
153
- answer = false
154
- warn 'idx1 is not found' if debug
155
- end
156
- s = file.read(4).unpack('V').first
157
- file.pos += s
158
- rescue => err
159
- warn err.message if debug
160
- answer = false
161
- ensure
162
- file.close unless is_io
163
- end
164
- answer
36
+ # Returns AviGlitch::Base instance.
37
+ # It requires +path+ as String or Pathname.
38
+ def AviGlitch.open path
39
+ AviGlitch::Base.new(Pathname(path))
165
40
  end
166
-
167
- alias :open :new
168
-
169
41
  end
170
42
  end
@@ -0,0 +1,170 @@
1
+ require 'tempfile'
2
+ require 'fileutils'
3
+ require 'readline'
4
+ require 'pathname'
5
+
6
+ module AviGlitch
7
+ # Base is the object that provides interfaces mainly used.
8
+ # To glitch, and save file. The instance returned through AviGlitch#open.
9
+ #
10
+ class Base
11
+ SAFE_FRAMES_COUNT = 150000 # :nodoc:
12
+
13
+ # AviGlitch::Frames object generated from the +file+.
14
+ attr_reader :frames
15
+ # The input file (copied tempfile).
16
+ attr_reader :file
17
+
18
+ ##
19
+ # Create a new instance of AviGlitch::Base, open the file and
20
+ # make it ready to manipulate.
21
+ # It requires +path+ as Pathname.
22
+ def initialize path
23
+ File.open(path) do |f|
24
+ # copy as tempfile
25
+ @file = Tempfile.open 'aviglitch'
26
+ f.rewind
27
+ while d = f.read(1024) do
28
+ @file.print d
29
+ end
30
+ end
31
+
32
+ unless AviGlitch::Base.surely_formatted? @file
33
+ raise 'Unsupported file passed.'
34
+ end
35
+ unless safe_frames_count? @file
36
+ close
37
+ exit
38
+ end
39
+ @frames = Frames.new @file
40
+ # I believe Ruby's GC to close and remove the Tempfile..
41
+ end
42
+
43
+ ##
44
+ # Output the glitched file to +path+, and close the file.
45
+ def output path
46
+ FileUtils.cp @file.path, path
47
+ close
48
+ end
49
+
50
+ ##
51
+ # An explicit file close.
52
+ def close
53
+ @file.close!
54
+ end
55
+
56
+ ##
57
+ # Glitch each frame data.
58
+ # It is a convent method to iterate each frame.
59
+ #
60
+ # The argument +target+ takes symbols listed below:
61
+ # [<tt>:keyframe</tt> or <tt>:iframe</tt>] select video key frames (aka I-frame)
62
+ # [<tt>:deltaframe</tt> or <tt>:pframe</tt>] select video delta frames (difference frames)
63
+ # [<tt>:videoframe</tt>] select both of keyframe and deltaframe
64
+ # [<tt>:audioframe</tt>] select audio frames
65
+ # [<tt>:all</tt>] select all frames
66
+ #
67
+ # It also requires a block. In the block, you take the frame data
68
+ # as a String parameter.
69
+ # To modify the data, simply return a modified data.
70
+ def glitch target = :all, &block # :yield: data
71
+ frames.each do |frame|
72
+ if valid_target? target, frame
73
+ frame.data = yield frame.data
74
+ end
75
+ end
76
+ end
77
+
78
+ ##
79
+ # Do glitch with index.
80
+ def glitch_with_index target = :all, &block # :yield: data, index
81
+ i = 0
82
+ frames.each do |frame|
83
+ if valid_target? target, frame
84
+ frame.data = yield(frame.data, i)
85
+ i += 1
86
+ end
87
+ end
88
+ end
89
+
90
+ alias :write :output
91
+
92
+ def valid_target? target, frame # :nodoc:
93
+ return true if target == :all
94
+ begin
95
+ frame.send "is_#{target.to_s}?"
96
+ rescue
97
+ false
98
+ end
99
+ end
100
+
101
+ def safe_frames_count? io # :nodoc:
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?]
126
+
127
+ class << self
128
+ ##
129
+ # Check if the +file+ is a correctly formetted AVI file.
130
+ # +file+ can be String or Pathname or IO.
131
+ def surely_formatted? file, debug = false
132
+ answer = true
133
+ is_io = file.respond_to?(:seek) # Probably IO.
134
+ file = File.open(file) unless is_io
135
+ begin
136
+ file.seek 0, IO::SEEK_END
137
+ eof = file.pos
138
+ file.rewind
139
+ unless file.read(4) == 'RIFF'
140
+ answer = false
141
+ warn 'RIFF sign is not found' if debug
142
+ end
143
+ len = file.read(4).unpack('V').first
144
+ unless file.read(4) == 'AVI '
145
+ answer = false
146
+ warn 'AVI sign is not found' if debug
147
+ end
148
+ while file.read(4) =~ /^(?:LIST|JUNK)$/ do
149
+ s = file.read(4).unpack('V').first
150
+ file.pos += s
151
+ end
152
+ file.pos -= 4
153
+ # we require idx1
154
+ unless file.read(4) == 'idx1'
155
+ answer = false
156
+ warn 'idx1 is not found' if debug
157
+ end
158
+ s = file.read(4).unpack('V').first
159
+ file.pos += s
160
+ rescue => err
161
+ warn err.message if debug
162
+ answer = false
163
+ ensure
164
+ file.close unless is_io
165
+ end
166
+ answer
167
+ end
168
+ end
169
+ end
170
+ end
@@ -1,4 +1,4 @@
1
- class AviGlitch
1
+ module AviGlitch
2
2
 
3
3
  # Frame is the struct of the frame data and meta-data.
4
4
  # You can access this class through AviGlitch::Frames.
@@ -1,4 +1,4 @@
1
- class AviGlitch
1
+ module AviGlitch
2
2
 
3
3
  # Frames provides the interface to access each frame
4
4
  # in the AVI file.
@@ -18,28 +18,33 @@ describe AviGlitch do
18
18
 
19
19
  it 'raise an error against unsupported files' do
20
20
  lambda {
21
- avi = AviGlitch.new __FILE__
21
+ avi = AviGlitch.open __FILE__
22
22
  }.should raise_error
23
23
  end
24
24
 
25
+ it 'returns AviGlitch::Base object through the method #open' do
26
+ avi = AviGlitch.open @in
27
+ avi.should be_kind_of AviGlitch::Base
28
+ end
29
+
25
30
  it 'saves the same file when nothing is changed' do
26
- avi = AviGlitch.new @in
31
+ avi = AviGlitch.open @in
27
32
  avi.frames.each do |f|
28
33
  ;
29
34
  end
30
- avi.write @out
35
+ avi.output @out
31
36
  FileUtils.cmp(@in, @out).should be true
32
37
 
33
- avi = AviGlitch.new @in
38
+ avi = AviGlitch.open @in
34
39
  avi.glitch do |d|
35
40
  d
36
41
  end
37
- avi.write @out
42
+ avi.output @out
38
43
  FileUtils.cmp(@in, @out).should be true
39
44
  end
40
45
 
41
46
  it 'can manipulate each frame' do
42
- avi = AviGlitch.new @in
47
+ avi = AviGlitch.open @in
43
48
  f = avi.frames
44
49
  f.should be_kind_of Enumerable
45
50
  avi.frames.each do |f|
@@ -47,26 +52,26 @@ describe AviGlitch do
47
52
  f.data = f.data.gsub(/\d/, '0')
48
53
  end
49
54
  end
50
- avi.write @out
51
- AviGlitch.surely_formatted?(@out, true).should be true
55
+ avi.output @out
56
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
52
57
  end
53
58
 
54
59
  it 'can glitch each keyframe' do
55
- avi = AviGlitch.new @in
60
+ avi = AviGlitch.open @in
56
61
  n = 0
57
62
  avi.glitch :keyframe do |kf|
58
63
  n += 1
59
64
  kf.slice(10..kf.size)
60
65
  end
61
- avi.write @out
66
+ avi.output @out
62
67
  i_size = File.stat(@in).size
63
68
  o_size = File.stat(@out).size
64
69
  o_size.should == i_size - (10 * n)
65
- AviGlitch.surely_formatted?(@out, true).should be true
70
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
66
71
  end
67
72
 
68
73
  it 'can glitch each keyframe with index' do
69
- avi = AviGlitch.new @in
74
+ avi = AviGlitch.open @in
70
75
  avi.glitch_with_index :keyframe do |kf, idx|
71
76
  if idx < 25
72
77
  kf.slice(10..kf.size)
@@ -74,26 +79,26 @@ describe AviGlitch do
74
79
  kf
75
80
  end
76
81
  end
77
- avi.write @out
82
+ avi.output @out
78
83
  i_size = File.stat(@in).size
79
84
  o_size = File.stat(@out).size
80
85
  o_size.should == i_size - (10 * 25)
81
- AviGlitch.surely_formatted?(@out, true).should be true
86
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
82
87
  end
83
88
 
84
89
  it 'can remove a frame with returning nil' do
85
- avi = AviGlitch.new @in
90
+ avi = AviGlitch.open @in
86
91
  in_frame_size = avi.frames.size
87
92
  rem_count = 0
88
93
  avi.glitch :keyframe do |kf|
89
94
  rem_count += 1
90
95
  nil
91
96
  end
92
- avi.write @out
93
- AviGlitch.surely_formatted?(@out, true).should be true
97
+ avi.output @out
98
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
94
99
 
95
100
  # frames length in the output file is correct
96
- avi = AviGlitch.new @out
101
+ avi = AviGlitch.open @out
97
102
  out_frame_size = avi.frames.size
98
103
  out_frame_size.should == in_frame_size - rem_count
99
104
  end
@@ -101,9 +106,8 @@ describe AviGlitch do
101
106
  it 'has some alias methods' do
102
107
  lambda {
103
108
  avi = AviGlitch.open @in
104
- avi.output @out
109
+ avi.write @out
105
110
  }.should_not raise_error
106
- AviGlitch.surely_formatted?(@out, true).should be true
111
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
107
112
  end
108
-
109
113
  end
@@ -0,0 +1 @@
1
+ --color
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - ucnv
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2009-08-02 00:00:00 +09:00
17
+ date: 2010-05-17 00:00:00 +09:00
18
18
  default_executable: datamosh
19
19
  dependencies: []
20
20
 
@@ -35,10 +35,12 @@ files:
35
35
  - VERSION
36
36
  - bin/datamosh
37
37
  - lib/aviglitch.rb
38
+ - lib/aviglitch/base.rb
38
39
  - lib/aviglitch/frame.rb
39
40
  - lib/aviglitch/frames.rb
40
41
  - spec/aviglitch_spec.rb
41
42
  - spec/files/sample.avi
43
+ - spec/spec.opts
42
44
  - spec/spec_helper.rb
43
45
  - LICENSE
44
46
  has_rdoc: true