aviglitch 0.1.3 → 0.2.0

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/lib/aviglitch.rb CHANGED
@@ -1,12 +1,10 @@
1
1
  require 'tempfile'
2
- require 'fileutils'
3
- require 'readline'
4
2
  require 'pathname'
5
3
  require 'stringio'
4
+ require 'aviglitch/avi'
6
5
  require 'aviglitch/base'
7
6
  require 'aviglitch/frame'
8
7
  require 'aviglitch/frames'
9
- require 'aviglitch/tempfile'
10
8
 
11
9
  # AviGlitch provides the ways to glitch AVI formatted video files.
12
10
  #
@@ -15,7 +13,7 @@ require 'aviglitch/tempfile'
15
13
  # You can manipulate each frame, like:
16
14
  #
17
15
  # avi = AviGlitch.open '/path/to/your.avi'
18
- # avi.frames.each |frame|
16
+ # avi.frames.each do |frame|
19
17
  # if frame.is_keyframe?
20
18
  # frame.data = frame.data.gsub(/\d/, '0')
21
19
  # end
@@ -30,18 +28,17 @@ require 'aviglitch/tempfile'
30
28
  # end
31
29
  # avi.output '/path/to/broken.avi'
32
30
  #
33
- #--
34
- # It does not support AVI2, interleave format.
35
- #
36
31
  module AviGlitch
37
32
 
38
- VERSION = '0.1.3'
33
+ VERSION = '0.2.0'
34
+
35
+ BUFFER_SIZE = 2 ** 24
39
36
 
40
37
  class << self
41
38
  ##
42
39
  # Returns AviGlitch::Base instance.
43
40
  # It requires +path_or_frames+ as String or Pathname, or Frames instance.
44
- def AviGlitch.open path_or_frames
41
+ def open path_or_frames
45
42
  if path_or_frames.kind_of?(Frames)
46
43
  path_or_frames.to_avi
47
44
  else
data/spec/avi2_spec.rb ADDED
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe AviGlitch, 'AVI2.0' do
4
+
5
+ it 'should save same file when nothing has changed' do
6
+ avi = AviGlitch.open @in2
7
+ avi.glitch do |d|
8
+ d
9
+ end
10
+ avi.output @out
11
+ FileUtils.cmp(@in2, @out).should be true
12
+ end
13
+
14
+ it 'should be AVI1.0 when its size has reduced less than 1GB' do
15
+ a = AviGlitch.open @in2
16
+ size = 0
17
+ a.glitch do |d|
18
+ size += d.size
19
+ size < 1024 ** 3 ? d : nil
20
+ end
21
+ a.output @out
22
+ b = AviGlitch.open @out
23
+ b.avi.was_avi2?.should be false
24
+ b.close
25
+ end
26
+
27
+ it 'should be AVI2.0 when its size has increased over 1GB' do
28
+ a = AviGlitch.open @in
29
+ n = Math.log(1024.0 ** 3 / a.frames.data_size.to_f, 2).ceil
30
+ f = a.frames[0..-1]
31
+ n.times do
32
+ fx = f[0..-1]
33
+ f.concat fx
34
+ end
35
+ f.to_avi.output @out
36
+ b = AviGlitch.open @out
37
+ b.avi.was_avi2?.should be true
38
+ b.close
39
+ end
40
+ end
@@ -2,24 +2,10 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe AviGlitch do
4
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
- end
10
-
11
- after :each do
12
- FileUtils.rm Dir.glob((OUTPUT_DIR + '*').to_s)
13
- end
14
-
15
- after :all do
16
- FileUtils.rmdir OUTPUT_DIR
17
- end
18
-
19
5
  it 'should raise an error against unsupported files' do
20
6
  lambda {
21
7
  avi = AviGlitch.open __FILE__
22
- }.should raise_error
8
+ }.should raise_error(RuntimeError)
23
9
  end
24
10
 
25
11
  it 'should return AviGlitch::Base object through the method #open' do
@@ -52,13 +38,24 @@ describe AviGlitch do
52
38
 
53
39
  it 'can glitch each keyframe with index' do
54
40
  avi = AviGlitch.open @in
41
+
42
+ a_size = 0
43
+ avi.glitch :keyframe do |f|
44
+ a_size += 1
45
+ f
46
+ end
47
+
48
+ b_size = 0
55
49
  avi.glitch_with_index :keyframe do |kf, idx|
50
+ b_size += 1
56
51
  if idx < 25
57
52
  kf.slice(10..kf.size)
58
53
  else
59
54
  kf
60
55
  end
61
56
  end
57
+ expect(a_size).to be == b_size
58
+
62
59
  avi.output @out
63
60
  i_size = File.stat(@in).size
64
61
  o_size = File.stat(@out).size
@@ -143,9 +140,9 @@ describe AviGlitch do
143
140
  AviGlitch::Base.surely_formatted?(@out, true).should be true
144
141
  end
145
142
 
146
- it 'should clear keyframes with one method' do
143
+ it 'should mutate keyframes into deltaframes' do
147
144
  a = AviGlitch.open @in
148
- a.clear_keyframes!
145
+ a.mutate_keyframes_into_deltaframes!
149
146
  a.output @out
150
147
  a = AviGlitch.open @out
151
148
  a.frames.each do |f|
@@ -153,7 +150,7 @@ describe AviGlitch do
153
150
  end
154
151
 
155
152
  a = AviGlitch.open @in
156
- a.clear_keyframes! 0..50
153
+ a.mutate_keyframes_into_deltaframes! 0..50
157
154
  a.output @out
158
155
  a = AviGlitch.open @out
159
156
  a.frames.each_with_index do |f, i|
@@ -172,4 +169,26 @@ describe AviGlitch do
172
169
  a.has_keyframe?.should be false
173
170
  end
174
171
 
172
+ it 'should #remove_all_keyframes!' do
173
+ a = AviGlitch.open @in
174
+ a.has_keyframe?.should be true
175
+ a.remove_all_keyframes!
176
+ a.has_keyframe?.should be false
177
+ end
178
+
179
+ it 'should count same number of specific frames' do
180
+ a = AviGlitch.open @in
181
+ dc1 = 0
182
+ dc2 = 0
183
+ a.frames.each do |f|
184
+ dc1 += 1 if f.is_deltaframe?
185
+ end
186
+ a.glitch(:deltaframe) do |d|
187
+ dc2 += 1
188
+ d
189
+ end
190
+
191
+ expect(dc1).to eq(dc2)
192
+ end
193
+
175
194
  end
@@ -3,23 +3,12 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
  describe AviGlitch, 'datamosh cli' do
4
4
 
5
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
6
  here = File.dirname(__FILE__)
10
7
  lib = Pathname.new(File.join(here, '..', 'lib')).realpath
11
8
  datamosh = Pathname.new(File.join(here, '..', 'bin/datamosh')).realpath
12
9
  @cmd = "ruby -I%s %s -o %s " % [lib, datamosh, @out]
13
10
  end
14
11
 
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
12
  it 'should correctly process files' do
24
13
  a = AviGlitch.open @in
25
14
  keys = a.frames.inject(0) do |c, f|
@@ -27,12 +16,13 @@ describe AviGlitch, 'datamosh cli' do
27
16
  c
28
17
  end
29
18
  total = a.frames.size
19
+ first_keyframe = a.frames.index(a.frames.first_of(:keyframe))
30
20
  a.close
31
21
 
32
22
  system [@cmd, @in].join(' ')
33
23
  o = AviGlitch.open @out
34
24
  o.frames.size.should == total
35
- o.frames.first.is_keyframe?.should be true
25
+ o.frames[first_keyframe].is_keyframe?.should be true
36
26
  o.has_keyframe?.should be true
37
27
  o.close
38
28
  AviGlitch::Base.surely_formatted?(@out, true).should be true
@@ -40,7 +30,7 @@ describe AviGlitch, 'datamosh cli' do
40
30
  system [@cmd, '-a', @in].join(' ')
41
31
  o = AviGlitch.open @out
42
32
  o.frames.size.should == total
43
- o.frames.first.is_keyframe?.should be false
33
+ o.frames[first_keyframe].is_keyframe?.should be false
44
34
  o.has_keyframe?.should be false
45
35
  o.close
46
36
  AviGlitch::Base.surely_formatted?(@out, true).should be true
@@ -48,7 +38,7 @@ describe AviGlitch, 'datamosh cli' do
48
38
  system [@cmd, @in, @in, @in].join(' ')
49
39
  o = AviGlitch.open @out
50
40
  o.frames.size.should == total * 3
51
- o.frames.first.is_keyframe?.should be true
41
+ o.frames[first_keyframe].is_keyframe?.should be true
52
42
  o.close
53
43
  AviGlitch::Base.surely_formatted?(@out, true).should be true
54
44
 
data/spec/frames_spec.rb CHANGED
@@ -5,26 +5,21 @@ describe AviGlitch::Frames do
5
5
  before :all do
6
6
  AviGlitch::Frames.class_eval do
7
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
8
+ movi = @avi.get_movi
9
+ pos = movi.pos
10
+ movi.pos -= frame.data.size
11
+ movi.pos -= 8
12
+ id = movi.read 4
13
+ movi.pos = pos
13
14
  id
14
15
  end
15
16
  end
16
17
 
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
18
+ AviGlitch::Avi.class_eval do
19
+ define_method(:get_movi) do
20
+ @movi
21
+ end
22
+ end
28
23
  end
29
24
 
30
25
  it 'should save the same file when nothing is changed' do
@@ -85,15 +80,6 @@ describe AviGlitch::Frames do
85
80
  avi.close
86
81
  end
87
82
 
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
83
  it 'should save video frames count in header' do
98
84
  avi = AviGlitch.open @in
99
85
  c = 0
@@ -460,9 +446,9 @@ describe AviGlitch::Frames do
460
446
  end
461
447
  end
462
448
 
463
- it 'should clear keyframes with one method' do
449
+ it 'should mutate keyframes into deltaframe' do
464
450
  a = AviGlitch.open @in
465
- a.frames.clear_keyframes!
451
+ a.frames.mutate_keyframes_into_deltaframes!
466
452
  a.output @out
467
453
  a = AviGlitch.open @out
468
454
  a.frames.each do |f|
@@ -470,7 +456,7 @@ describe AviGlitch::Frames do
470
456
  end
471
457
 
472
458
  a = AviGlitch.open @in
473
- a.frames.clear_keyframes! 0..50
459
+ a.frames.mutate_keyframes_into_deltaframes! 0..50
474
460
  a.output @out
475
461
  a = AviGlitch.open @out
476
462
  a.frames.each_with_index do |f, i|
@@ -480,4 +466,104 @@ describe AviGlitch::Frames do
480
466
  end
481
467
  end
482
468
 
469
+ it 'should return Enumerator with #each' do
470
+ a = AviGlitch.open @in
471
+ enum = a.frames.each
472
+ enum.each do |f, i|
473
+ if f.is_keyframe?
474
+ f.data = f.data.gsub(/\d/, '')
475
+ end
476
+ end
477
+ a.output @out
478
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
479
+ expect(File.size(@out)).to be < File.size(@in)
480
+ end
481
+
482
+ it 'should use Enumerator as an external iterator',
483
+ :skip => Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('1.9.0') || RUBY_PLATFORM == 'java' do
484
+ a = AviGlitch.open @in
485
+ e = a.frames.each
486
+ expect {
487
+ while f = e.next do
488
+ expect(f).to be_a(AviGlitch::Frame)
489
+ if f.is_keyframe?
490
+ f.data = f.data.gsub(/\d/, '')
491
+ end
492
+ end
493
+ }.to raise_error(StopIteration)
494
+ a.output @out
495
+ AviGlitch::Base.surely_formatted?(@out, true).should be true
496
+ expect(File.size(@out)).to be < File.size(@in)
497
+ end
498
+
499
+ it 'should count the size of specific frames' do
500
+ a = AviGlitch.open @in
501
+ f = a.frames
502
+
503
+ kc1 = f.size_of :keyframes
504
+ kc2 = f.size_of :keyframe
505
+ kc3 = f.size_of :iframes
506
+ kc4 = f.size_of :iframe
507
+
508
+ dc1 = f.size_of :deltaframes
509
+ dc2 = f.size_of :deltaframe
510
+ dc3 = f.size_of :pframes
511
+ dc4 = f.size_of :pframe
512
+
513
+ vc1 = f.size_of :videoframes
514
+ vc2 = f.size_of :videoframe
515
+
516
+ ac1 = f.size_of :audioframes
517
+ ac2 = f.size_of :audioframe
518
+
519
+ kc = dc = vc = ac = 0
520
+ a.frames.each do |x|
521
+ vc += x.is_videoframe? ? 1 : 0
522
+ kc += x.is_keyframe? ? 1 : 0
523
+ dc += x.is_deltaframe? ? 1 : 0
524
+ ac += x.is_audioframe? ? 1 : 0
525
+ end
526
+
527
+ a.close
528
+
529
+ expect(kc1).to eq(kc)
530
+ expect(kc2).to eq(kc)
531
+ expect(kc3).to eq(kc)
532
+ expect(kc4).to eq(kc)
533
+
534
+ expect(dc1).to eq(dc)
535
+ expect(dc2).to eq(dc)
536
+ expect(dc3).to eq(dc)
537
+ expect(dc4).to eq(dc)
538
+
539
+ expect(vc1).to eq(vc)
540
+ expect(vc2).to eq(vc)
541
+
542
+ expect(ac1).to eq(ac)
543
+ expect(ac2).to eq(ac)
544
+ end
545
+
546
+ it 'should pick the first / last frame with a method' do
547
+ a = AviGlitch.open @in
548
+ fkidx = -1
549
+ lkidx = -1
550
+ faidx = -1
551
+ laidx = -1
552
+ a.frames.each_with_index do |f, i|
553
+ if f.is_keyframe?
554
+ fkidx = i if fkidx == -1
555
+ lkidx = i
556
+ end
557
+ if f.is_audioframe?
558
+ faidx = i if faidx == -1
559
+ laidx = i
560
+ end
561
+ end
562
+ a.frames.index(a.frames.first_of(:keyframe)).should eq(fkidx)
563
+ a.frames.rindex(a.frames.last_of(:keyframe)).should eq(lkidx)
564
+ a.frames.index(a.frames.first_of(:audioframe)).should eq(faidx)
565
+ a.frames.rindex(a.frames.last_of(:audioframe)).should eq(laidx)
566
+ a.close
567
+ end
568
+
483
569
  end
data/spec/spec_helper.rb CHANGED
@@ -2,10 +2,54 @@ require 'rspec'
2
2
  require 'aviglitch'
3
3
  require 'pathname'
4
4
  require 'fileutils'
5
+ require 'net/http'
5
6
 
6
7
  FILES_DIR = Pathname.new(File.dirname(__FILE__)).realpath + 'files'
7
8
  OUTPUT_DIR = FILES_DIR + 'output'
8
9
 
9
10
  RSpec.configure do |config|
10
-
11
+ config.filter_run_excluding :skip => true
12
+ config.expect_with :rspec do |c|
13
+ c.syntax = [:should, :expect]
14
+ end
15
+
16
+ config.before(:all) do
17
+ FileUtils.mkdir FILES_DIR unless File.exist? FILES_DIR
18
+ FileUtils.mkdir OUTPUT_DIR unless File.exist? OUTPUT_DIR
19
+ @in = FILES_DIR + 'sample1.avi'
20
+ @in2 = FILES_DIR + 'sample2.avi'
21
+ @out = OUTPUT_DIR + 'out.avi'
22
+ [
23
+ [@in2, 'http://a.ucnv.org/sample2.avi'], [@in, 'http://a.ucnv.org/sample1.avi']
24
+ ].each do |file, url|
25
+ unless File.exist? file
26
+ if file == @in2
27
+ puts 'At first test it needs to download a file over 1GB. It will take a while.'
28
+ end
29
+ puts 'Downloading ' + url
30
+ $stdout.sync = true
31
+ u = URI.parse url
32
+ Net::HTTP.start(u.host, u.port) do |http|
33
+ res = http.request_head u.path
34
+ max = res['content-length'].to_i
35
+ len = 0
36
+ bl = 75
37
+ File.open(file, 'w') do |file|
38
+ http.get(u.path) do |chunk|
39
+ file.write chunk
40
+ len += chunk.length
41
+ pct = '%3.1f' % (100.0 * len / max)
42
+ bar = ('#' * (bl * len / max)).ljust(bl)
43
+ print "\r#{bar} #{'%5s' % pct}%" unless ENV['CI']
44
+ end
45
+ end
46
+ end
47
+ puts
48
+ end
49
+ end
50
+ end
51
+
52
+ config.after(:each) do
53
+ FileUtils.rm Dir.glob((OUTPUT_DIR + '*').to_s)
54
+ end
11
55
  end