edl 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +13 -0
- data/{README.txt → README.rdoc} +14 -8
- data/Rakefile +21 -12
- data/edl.gemspec +64 -28
- data/lib/edl.rb +15 -7
- data/lib/edl/transition.rb +3 -0
- data/test/samples/KEY_TRANSITION.EDL +9 -0
- data/test/samples/REEL_IS_CLIP.txt +8 -0
- data/test/test_edl.rb +321 -291
- metadata +113 -135
- data/.DS_Store +0 -0
- data/Manifest.txt +0 -29
- data/SPECS.txt +0 -96
- data/test/.DS_Store +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dde5075293fc802bba0d09eb6dc71071b912ce22
|
4
|
+
data.tar.gz: a6af8337266f89253d64909d16fc354ee5a0a522
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: eef75cec8b6edb8c4abef6a672ffcb5158537e33afe64d529de88765dc263644755485797a8a52abb3df258644300a437919059bd2d4b4f44499c1b026ad6cf0
|
7
|
+
data.tar.gz: 75afefe92e6aed8ad08a5dc5a86617c272fbdf41997aa7c06c8f15af0b1e97cd2882a24cdba34911aee3bf6356f15aeba8dbd9813d762c68e2857c8842d07347
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
source 'https://rubygems.org'
|
3
|
+
|
4
|
+
gem "timecode"
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'shoulda-context'
|
8
|
+
gem "test-unit", :require => "test/unit"
|
9
|
+
gem "jeweler"
|
10
|
+
gem "rake"
|
11
|
+
flexmock_ver = (RUBY_VERSION > "1.8") ? "~> 1.3.2" : "~> 0.8"
|
12
|
+
gem "flexmock", flexmock_ver, :require => %w( flexmock flexmock/test_unit )
|
13
|
+
end
|
data/{README.txt → README.rdoc}
RENAMED
@@ -1,16 +1,22 @@
|
|
1
|
-
= EDL
|
2
|
-
|
3
|
-
== DESCRIPTION:
|
4
|
-
|
5
1
|
Work with EDL files from Ruby
|
6
2
|
http://en.wikipedia.org/wiki/Edit_decision_list
|
7
3
|
|
4
|
+
The library assists in parsing [EDL files](http://en.wikipedia.org/wiki/Edit_decision_list) in CMX 3600 format.
|
5
|
+
You can use it to generate capture lists, inspect needed video segments for the assembled program
|
6
|
+
and display edit timelines. Together with the depix you could write your own "blind"
|
7
|
+
conform utility in about 10 minutes, no joke.
|
8
|
+
|
8
9
|
== SYNOPSIS:
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
require 'rubygems'
|
12
|
+
require 'edl'
|
13
|
+
|
14
|
+
list = EDL::Parser.new(fps=25).parse(File.open('OFFLINE.EDL'))
|
15
|
+
list.events.each do | evt |
|
16
|
+
evt.clip_name #=> Boat_Trip_Take1
|
17
|
+
evt.capture_from_tc #=> 01:20:22:10
|
18
|
+
evt.capture_to_tc #=> 01:20:26:15, accounts for outgoing transition AND M2 timewarps
|
19
|
+
end
|
14
20
|
|
15
21
|
== REQUIREMENTS:
|
16
22
|
|
data/Rakefile
CHANGED
@@ -1,18 +1,27 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'hoe'
|
3
2
|
require './lib/edl.rb'
|
3
|
+
require 'jeweler'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
gem.version = EDL::VERSION
|
7
|
+
gem.name = "edl"
|
8
|
+
gem.summary = "Parser for EDL (Edit Decision List) files"
|
9
|
+
gem.email = "me@julik.nl"
|
10
|
+
gem.homepage = "http://guerilla-di.org/edl"
|
11
|
+
gem.authors = ["Julik Tarkhanov"]
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
p.extra_deps = {"flexmock" => ">=0", "timecode" => ">=0.1.9", "test-spec" => ">=0"}
|
12
|
-
p.rubyforge_name = 'guerilla-di'
|
13
|
-
p.developer('Julik Tarkhanov', 'me@julik.nl')
|
13
|
+
# Do not package invisibles
|
14
|
+
gem.files.exclude ".*"
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
Jeweler::RubygemsDotOrgTasks.new
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
desc "Run all tests"
|
21
|
+
Rake::TestTask.new("test") do |t|
|
22
|
+
t.libs << "test"
|
23
|
+
t.pattern = 'test/**/test_*.rb'
|
24
|
+
t.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
task :default => [ :test ]
|
data/edl.gemspec
CHANGED
@@ -1,43 +1,79 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
|
-
s.name =
|
5
|
-
s.version = "0.
|
7
|
+
s.name = "edl"
|
8
|
+
s.version = "0.1.4"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Julik Tarkhanov"]
|
9
|
-
s.date =
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
|
13
|
-
|
14
|
-
s.
|
15
|
-
|
12
|
+
s.date = "2014-02-18"
|
13
|
+
s.email = "me@julik.nl"
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"README.rdoc"
|
16
|
+
]
|
17
|
+
s.files = [
|
18
|
+
"Gemfile",
|
19
|
+
"History.txt",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"edl.gemspec",
|
23
|
+
"illustr/edl-explain.ai",
|
24
|
+
"lib/edl.rb",
|
25
|
+
"lib/edl/cutter.rb",
|
26
|
+
"lib/edl/event.rb",
|
27
|
+
"lib/edl/grabber.rb",
|
28
|
+
"lib/edl/linebreak_magician.rb",
|
29
|
+
"lib/edl/parser.rb",
|
30
|
+
"lib/edl/timewarp.rb",
|
31
|
+
"lib/edl/transition.rb",
|
32
|
+
"test/samples/45S_SAMPLE.EDL",
|
33
|
+
"test/samples/FCP_REVERSE.EDL",
|
34
|
+
"test/samples/KEY_TRANSITION.EDL",
|
35
|
+
"test/samples/PLATES.EDL",
|
36
|
+
"test/samples/REEL_IS_CLIP.txt",
|
37
|
+
"test/samples/REVERSE.EDL",
|
38
|
+
"test/samples/SIMPLE_DISSOLVE.EDL",
|
39
|
+
"test/samples/SPEEDUP_AND_FADEOUT.EDL",
|
40
|
+
"test/samples/SPEEDUP_REVERSE_AND_FADEOUT.EDL",
|
41
|
+
"test/samples/SPLICEME.EDL",
|
42
|
+
"test/samples/TIMEWARP.EDL",
|
43
|
+
"test/samples/TIMEWARP_HALF.EDL",
|
44
|
+
"test/samples/TRAILER_EDL.edl",
|
45
|
+
"test/test_edl.rb"
|
46
|
+
]
|
47
|
+
s.homepage = "http://guerilla-di.org/edl"
|
16
48
|
s.require_paths = ["lib"]
|
17
|
-
s.
|
18
|
-
s.
|
19
|
-
s.summary = %q{Work with EDL files from Ruby http://en.wikipedia.org/wiki/Edit_decision_list}
|
20
|
-
s.test_files = ["test/test_edl.rb"]
|
49
|
+
s.rubygems_version = "2.0.3"
|
50
|
+
s.summary = "Parser for EDL (Edit Decision List) files"
|
21
51
|
|
22
52
|
if s.respond_to? :specification_version then
|
23
|
-
|
24
|
-
s.specification_version = 2
|
53
|
+
s.specification_version = 4
|
25
54
|
|
26
|
-
if Gem::Version.new(Gem::
|
27
|
-
s.add_runtime_dependency(%q<
|
28
|
-
s.
|
29
|
-
s.
|
30
|
-
s.add_development_dependency(%q<
|
55
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
56
|
+
s.add_runtime_dependency(%q<timecode>, [">= 0"])
|
57
|
+
s.add_development_dependency(%q<shoulda-context>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<test-unit>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<flexmock>, ["~> 1.3.2"])
|
31
62
|
else
|
32
|
-
s.add_dependency(%q<
|
33
|
-
s.add_dependency(%q<
|
34
|
-
s.add_dependency(%q<
|
35
|
-
s.add_dependency(%q<
|
63
|
+
s.add_dependency(%q<timecode>, [">= 0"])
|
64
|
+
s.add_dependency(%q<shoulda-context>, [">= 0"])
|
65
|
+
s.add_dependency(%q<test-unit>, [">= 0"])
|
66
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
67
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
68
|
+
s.add_dependency(%q<flexmock>, ["~> 1.3.2"])
|
36
69
|
end
|
37
70
|
else
|
38
|
-
s.add_dependency(%q<
|
39
|
-
s.add_dependency(%q<
|
40
|
-
s.add_dependency(%q<
|
41
|
-
s.add_dependency(%q<
|
71
|
+
s.add_dependency(%q<timecode>, [">= 0"])
|
72
|
+
s.add_dependency(%q<shoulda-context>, [">= 0"])
|
73
|
+
s.add_dependency(%q<test-unit>, [">= 0"])
|
74
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
75
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
76
|
+
s.add_dependency(%q<flexmock>, ["~> 1.3.2"])
|
42
77
|
end
|
43
78
|
end
|
79
|
+
|
data/lib/edl.rb
CHANGED
@@ -10,7 +10,7 @@ require File.dirname(__FILE__) + '/edl/linebreak_magician'
|
|
10
10
|
|
11
11
|
# A simplistic EDL parser
|
12
12
|
module EDL
|
13
|
-
VERSION = "0.1.
|
13
|
+
VERSION = "0.1.4"
|
14
14
|
DEFAULT_FPS = 25.0
|
15
15
|
|
16
16
|
# Represents an EDL, is returned from the parser. Traditional operation is functional style, i.e.
|
@@ -134,7 +134,7 @@ module EDL
|
|
134
134
|
class Matcher
|
135
135
|
class ApplyError < RuntimeError
|
136
136
|
def initialize(msg, line)
|
137
|
-
super("%s - offending line was
|
137
|
+
super("%s - offending line was %s" % [msg, line.inspect])
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
@@ -154,10 +154,12 @@ module EDL
|
|
154
154
|
# EDL clip comment matcher, a generic one
|
155
155
|
class CommentMatcher < Matcher
|
156
156
|
def initialize
|
157
|
-
super(/\*
|
157
|
+
super(/\*(.+)/)
|
158
158
|
end
|
159
159
|
|
160
160
|
def apply(stack, line)
|
161
|
+
raise ApplyError.new("No event to attach a comment to", line) if stack.empty?
|
162
|
+
# TODO: we should really remove "* " prefixes from comments
|
161
163
|
stack[-1].comments.push("* %s" % line.scan(@regexp).flatten.pop.strip)
|
162
164
|
end
|
163
165
|
end
|
@@ -180,7 +182,7 @@ module EDL
|
|
180
182
|
# Clip name matcher
|
181
183
|
class NameMatcher < Matcher
|
182
184
|
def initialize
|
183
|
-
super(
|
185
|
+
super(/\*\s*FROM CLIP NAME:(\s+)(.+)/)
|
184
186
|
end
|
185
187
|
|
186
188
|
def apply(stack, line)
|
@@ -191,7 +193,7 @@ module EDL
|
|
191
193
|
|
192
194
|
class EffectMatcher < Matcher
|
193
195
|
def initialize
|
194
|
-
super(
|
196
|
+
super(/\*\s*EFFECT NAME:(\s+)(.+)/)
|
195
197
|
end
|
196
198
|
|
197
199
|
def apply(stack, line)
|
@@ -290,6 +292,8 @@ module EDL
|
|
290
292
|
evt = Event.new
|
291
293
|
transition_idx = props.delete(:transition)
|
292
294
|
evt.transition = case transition_idx
|
295
|
+
when 'C'
|
296
|
+
nil
|
293
297
|
when 'D'
|
294
298
|
d = Dissolve.new
|
295
299
|
d.duration = props.delete(:duration).to_i
|
@@ -299,8 +303,12 @@ module EDL
|
|
299
303
|
w.duration = props.delete(:duration).to_i
|
300
304
|
w.smpte_wipe_index = transition_idx.gsub(/W/, '')
|
301
305
|
w
|
306
|
+
when 'K'
|
307
|
+
k = Key.new
|
308
|
+
k.duration = props.delete(:duration).to_i
|
309
|
+
k
|
302
310
|
else
|
303
|
-
|
311
|
+
raise "Unknown transition type #{transition_idx}"
|
304
312
|
end
|
305
313
|
|
306
314
|
# Give a hint on the incoming clip as well
|
@@ -317,4 +325,4 @@ module EDL
|
|
317
325
|
|
318
326
|
#:startdoc:
|
319
327
|
|
320
|
-
end
|
328
|
+
end
|
data/lib/edl/transition.rb
CHANGED
@@ -0,0 +1,9 @@
|
|
1
|
+
TITLE: FOR_TEST
|
2
|
+
FCM: DROP FRAME
|
3
|
+
|
4
|
+
002 AX V K B 00:01:06:06 00:01:08:03 01:00:04:10 01:00:06:07
|
5
|
+
002 AX V K 000 00:00:03:08 00:00:03:08 01:00:04:10 01:00:04:10
|
6
|
+
* FROM CLIP NAME: foobarz_0118_023-APPLE PRORES WITH ALPHA.MOV
|
7
|
+
* COMMENT:
|
8
|
+
* KEY CLIP NAME: foobarz_0118_026-APPLE PRORES WITH ALPHA.MOV
|
9
|
+
* CLIP FILTER: COLOR CORRECTOR 3-WAY
|
@@ -0,0 +1,8 @@
|
|
1
|
+
0001 KASS1 A1234V C 00:00:00:00 00:00:12:24 10:00:00:00 10:00:12:24
|
2
|
+
* REEL RC100009 IS CLIP 28661.mov
|
3
|
+
0002 KASS1 A1234V C 00:00:00:00 00:00:13:03 10:00:12:24 10:00:26:02
|
4
|
+
* REEL RC100003 IS CLIP 28655.mov
|
5
|
+
0003 KASS1 A1234V C 00:00:00:00 00:00:15:06 10:00:26:02 10:00:41:08
|
6
|
+
* REEL RC100005 IS CLIP 28657.mov
|
7
|
+
0004 KASS1 A1234V C 00:00:00:00 00:00:16:06 10:00:41:08 10:00:57:14
|
8
|
+
* REEL RC100010 IS CLIP 28662.mov
|
data/test/test_edl.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
Bundler.require(:default, :development)
|
4
|
+
require 'flexmock/test_unit'
|
5
|
+
|
6
|
+
|
1
7
|
require File.dirname(__FILE__) + '/../lib/edl'
|
2
8
|
require File.dirname(__FILE__) + '/../lib/edl/cutter'
|
3
9
|
require File.dirname(__FILE__) + '/../lib/edl/grabber'
|
4
10
|
|
5
|
-
require 'rubygems'
|
6
|
-
require 'test/unit'
|
7
|
-
require 'test/spec'
|
8
|
-
require 'flexmock'
|
9
|
-
require 'flexmock/test_unit'
|
10
|
-
|
11
11
|
TRAILER_EDL = File.dirname(__FILE__) + '/samples/TRAILER_EDL.edl'
|
12
12
|
SIMPLE_DISSOLVE = File.dirname(__FILE__) + '/samples/SIMPLE_DISSOLVE.EDL'
|
13
13
|
SPLICEME = File.dirname(__FILE__) + '/samples/SPLICEME.EDL'
|
@@ -19,6 +19,8 @@ SPEEDUP_AND_FADEOUT = File.dirname(__FILE__) + '/samples/SPEEDUP_AND_FAD
|
|
19
19
|
SPEEDUP_REVERSE_AND_FADEOUT = File.dirname(__FILE__) + '/samples/SPEEDUP_REVERSE_AND_FADEOUT.EDL'
|
20
20
|
FCP_REVERSE = File.dirname(__FILE__) + '/samples/FCP_REVERSE.EDL'
|
21
21
|
PLATES = File.dirname(__FILE__) + '/samples/PLATES.EDL'
|
22
|
+
KEY = File.dirname(__FILE__) + '/samples/KEY_TRANSITION.EDL'
|
23
|
+
CLIP_NAMES = File.dirname(__FILE__) + '/samples/REEL_IS_CLIP.txt'
|
22
24
|
|
23
25
|
class String
|
24
26
|
def tc(fps = Timecode::DEFAULT_FPS)
|
@@ -26,254 +28,246 @@ class String
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
evt.should.respond_to em
|
34
|
-
end
|
31
|
+
class EDLTest < Test::Unit::TestCase
|
32
|
+
|
33
|
+
def assert_zero(v, message = "Should be zero")
|
34
|
+
assert v.zero?, message
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
context "An Event" do
|
38
|
+
should "support hash initialization" do
|
38
39
|
evt = EDL::Event.new(:src_start_tc => "01:00:00:00".tc)
|
39
|
-
|
40
|
+
assert_equal "01:00:00:00".tc, evt.src_start_tc
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
+
should "support block initialization" do
|
43
44
|
evt = EDL::Event.new do | e |
|
44
45
|
e.src_start_tc = "01:00:00:04".tc
|
45
46
|
end
|
46
|
-
|
47
|
+
assert_equal "01:00:00:04".tc, evt.src_start_tc
|
47
48
|
end
|
48
49
|
|
49
|
-
|
50
|
+
should "respond to ends_with_transition? with false if outgoing_transition_duration is zero" do
|
50
51
|
evt = EDL::Event.new
|
51
52
|
evt.outgoing_transition_duration = 0
|
52
|
-
evt.ends_with_transition
|
53
|
+
assert !evt.ends_with_transition?
|
53
54
|
end
|
54
|
-
|
55
|
-
|
55
|
+
|
56
|
+
should "respond to ends_with_transition? with true if outgoing_transition_duration set above zero" do
|
56
57
|
evt = EDL::Event.new
|
57
58
|
evt.outgoing_transition_duration = 24
|
58
|
-
evt.ends_with_transition
|
59
|
+
assert evt.ends_with_transition?
|
59
60
|
end
|
60
|
-
|
61
|
-
|
61
|
+
|
62
|
+
should "respond to has_timewarp? with false if no timewarp assigned" do
|
62
63
|
evt = EDL::Event.new(:timewarp => nil)
|
63
|
-
evt.has_timewarp
|
64
|
+
assert !evt.has_timewarp?
|
64
65
|
end
|
65
66
|
|
66
|
-
|
67
|
+
should "respond to has_timewarp? with true if a timewarp is assigned" do
|
67
68
|
evt = EDL::Event.new(:timewarp => true)
|
68
|
-
evt.has_timewarp
|
69
|
+
assert evt.has_timewarp?
|
69
70
|
end
|
70
|
-
|
71
|
-
|
71
|
+
|
72
|
+
should "report rec_length as a difference of record timecodes" do
|
72
73
|
evt = EDL::Event.new(:rec_start_tc => "1h".tc, :rec_end_tc => "1h 10s 2f".tc )
|
73
|
-
|
74
|
+
assert_equal "10s 2f".tc.to_i, evt.rec_length
|
74
75
|
end
|
75
76
|
|
76
|
-
|
77
|
+
should "report rec_length_with_transition as a difference of record timecodes if no transition set" do
|
77
78
|
evt = EDL::Event.new(:rec_start_tc => "1h".tc, :rec_end_tc => "1h 10s 2f".tc, :outgoing_transition_duration => 0)
|
78
|
-
|
79
|
+
assert_equal "10s 2f".tc.to_i, evt.rec_length_with_transition
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
+
should "add transition length to rec_length_with_transition if a transition is set" do
|
82
83
|
evt = EDL::Event.new(:rec_start_tc => "1h".tc, :rec_end_tc => "1h 10s 2f".tc, :outgoing_transition_duration => 10)
|
83
|
-
|
84
|
+
assert_equal "10s 2f".tc.to_i + 10, evt.rec_length_with_transition
|
84
85
|
end
|
85
86
|
|
86
|
-
|
87
|
-
EDL::Event.new.comments
|
87
|
+
should "return a default array for comments" do
|
88
|
+
assert_kind_of Enumerable, EDL::Event.new.comments
|
88
89
|
end
|
89
90
|
|
90
|
-
|
91
|
-
EDL::Event.new(:transition => nil).has_transition
|
91
|
+
should "respond false to has_transition? if incoming transition is set" do
|
92
|
+
assert !EDL::Event.new(:transition => nil).has_transition?
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
-
EDL::Event.new(:transition => true).has_transition
|
95
|
+
should "respond true to has_transition? if incoming transition is set" do
|
96
|
+
assert EDL::Event.new(:transition => true).has_transition?
|
96
97
|
end
|
97
|
-
|
98
|
-
|
99
|
-
EDL::Event.new(:reel => "BL").
|
100
|
-
EDL::Event.new(:reel => "001").
|
98
|
+
|
99
|
+
should "respond true to black? if reel is BL" do
|
100
|
+
assert EDL::Event.new(:reel => "BL").black?
|
101
|
+
assert !EDL::Event.new(:reel => "001").black?
|
101
102
|
end
|
102
103
|
|
103
|
-
|
104
|
-
EDL::Event.new(:reel => "BL").
|
105
|
-
EDL::Event.new(:reel => "AX").
|
106
|
-
EDL::Event.new(:reel => "001").
|
104
|
+
should "respond true to generator? if reel is BL or AX" do
|
105
|
+
assert EDL::Event.new(:reel => "BL").generator?
|
106
|
+
assert EDL::Event.new(:reel => "AX").generator?
|
107
|
+
assert !EDL::Event.new(:reel => "001").generator?
|
107
108
|
end
|
108
|
-
|
109
|
-
|
109
|
+
|
110
|
+
should "report src_length as rec_length_with_transition" do
|
110
111
|
e = EDL::Event.new(:rec_start_tc => "2h".tc, :rec_end_tc => "2h 2s".tc)
|
111
|
-
|
112
|
+
assert_equal "2s".tc.to_i, e.src_length
|
112
113
|
end
|
113
|
-
|
114
|
-
|
115
|
-
EDL::Event.new.line_number
|
116
|
-
EDL::Event.new(:line_number => 3).line_number
|
114
|
+
|
115
|
+
should "support line_number" do
|
116
|
+
assert_nil EDL::Event.new.line_number
|
117
|
+
assert_equal 3, EDL::Event.new(:line_number => 3).line_number
|
117
118
|
end
|
118
|
-
|
119
|
-
|
119
|
+
|
120
|
+
should "support capture_length as an alias to src_length" do
|
120
121
|
tw = flexmock
|
121
122
|
tw.should_receive(:actual_length_of_source).and_return(:something)
|
122
123
|
e = EDL::Event.new(:timewarp => tw)
|
123
|
-
e.
|
124
|
+
assert_equal e.capture_length, e.src_length
|
124
125
|
end
|
125
|
-
|
126
|
-
|
126
|
+
|
127
|
+
should "delegate src_length to the timewarp if it is there" do
|
127
128
|
tw = flexmock
|
128
129
|
tw.should_receive(:actual_length_of_source).and_return(:something).once
|
129
130
|
e = EDL::Event.new(:timewarp => tw)
|
130
|
-
e.src_length
|
131
|
+
assert_equal :something, e.src_length
|
131
132
|
end
|
132
|
-
|
133
|
-
|
133
|
+
|
134
|
+
should "report reverse? and reversed? based on the timewarp" do
|
134
135
|
e = EDL::Event.new(:timewarp => nil)
|
135
|
-
e.
|
136
|
-
e.
|
136
|
+
assert !e.reverse?
|
137
|
+
assert !e.reversed?
|
137
138
|
|
138
139
|
tw = flexmock
|
139
140
|
tw.should_receive(:reverse?).and_return(true)
|
140
141
|
|
141
142
|
e = EDL::Event.new(:timewarp => tw)
|
142
|
-
e.
|
143
|
-
e.
|
143
|
+
assert e.reverse?
|
144
|
+
assert e.reversed?
|
144
145
|
end
|
145
|
-
|
146
|
-
|
146
|
+
|
147
|
+
should "report speed as 100 percent without a timewarp" do
|
147
148
|
e = EDL::Event.new
|
148
|
-
e.speed
|
149
|
-
e.speed.should.equal 100.0
|
149
|
+
assert_equal 100.0, e.speed
|
150
150
|
end
|
151
151
|
|
152
|
-
|
152
|
+
should "consult the timewarp for speed" do
|
153
153
|
tw = flexmock
|
154
154
|
tw.should_receive(:speed).and_return(:something)
|
155
155
|
|
156
156
|
e = EDL::Event.new(:timewarp => tw)
|
157
|
-
e.speed
|
157
|
+
assert_equal :something, e.speed
|
158
158
|
end
|
159
159
|
|
160
|
-
|
161
|
-
|
162
|
-
e.should.respond_to :starts_with_transition?
|
163
|
-
e.should.not.be.starts_with_transition
|
160
|
+
should "report false for starts_with_transition? if transision is nil" do
|
161
|
+
assert !EDL::Event.new.starts_with_transition?
|
164
162
|
end
|
165
163
|
|
166
|
-
|
167
|
-
|
168
|
-
e.should.respond_to :incoming_transition_duration
|
169
|
-
e.incoming_transition_duration.should.zero
|
164
|
+
should "report zero for incoming_transition_duration if transision is nil" do
|
165
|
+
assert_zero EDL::Event.new.incoming_transition_duration
|
170
166
|
end
|
171
167
|
|
172
|
-
|
168
|
+
should "report true for starts_with_transition? if transision is not nil" do
|
173
169
|
e = EDL::Event.new :transition => true
|
174
|
-
e.
|
175
|
-
e.should.starts_with_transition
|
170
|
+
assert e.starts_with_transition?
|
176
171
|
end
|
177
172
|
|
178
|
-
|
173
|
+
should "consult the transition for incoming_transition_duration if it's present" do
|
179
174
|
tr = flexmock
|
180
175
|
tr.should_receive(:duration).and_return(:something)
|
181
|
-
|
176
|
+
|
182
177
|
e = EDL::Event.new(:transition => tr)
|
183
|
-
e.
|
184
|
-
e.incoming_transition_duration.should.equal :something
|
178
|
+
assert_equal :something, e.incoming_transition_duration
|
185
179
|
end
|
186
|
-
|
187
|
-
|
180
|
+
|
181
|
+
should "report capture_from_tc as the source start without a timewarp" do
|
188
182
|
e = EDL::Event.new(:src_start_tc => "1h".tc)
|
189
|
-
|
183
|
+
assert_equal "1h".tc, e.capture_from_tc
|
190
184
|
end
|
191
|
-
|
192
|
-
|
185
|
+
|
186
|
+
should "consult the timewarp for capture_from_tc if a timewarp is there" do
|
193
187
|
tw = flexmock
|
194
188
|
tw.should_receive(:source_used_from).and_return(:something)
|
195
|
-
|
189
|
+
|
196
190
|
e = EDL::Event.new(:timewarp => tw)
|
197
|
-
e.capture_from_tc
|
191
|
+
assert_equal :something, e.capture_from_tc
|
198
192
|
end
|
199
193
|
|
200
|
-
|
194
|
+
should "report capture_to_tc as record length plus transition when no timewarp present" do
|
201
195
|
e = EDL::Event.new(:src_end_tc => "1h 10s".tc, :outgoing_transition_duration => 2 )
|
202
|
-
|
196
|
+
assert_equal "1h 10s 2f".tc, e.capture_to_tc
|
203
197
|
end
|
204
198
|
|
205
|
-
|
199
|
+
should "report capture_to_and_including_tc as record length plus transition when no timewarp present" do
|
206
200
|
e = EDL::Event.new(:src_end_tc => "1h 10s".tc, :outgoing_transition_duration => 2 )
|
207
|
-
|
201
|
+
assert_equal "1h 10s 1f".tc, e.capture_to_and_including_tc
|
208
202
|
end
|
209
203
|
|
210
|
-
|
204
|
+
should "consult the timewarp for capture_to_tc if timewarp is present" do
|
211
205
|
tw = flexmock
|
212
206
|
tw.should_receive(:source_used_upto).and_return(:something)
|
213
207
|
|
214
208
|
e = EDL::Event.new(:timewarp => tw)
|
215
|
-
e.capture_to_tc
|
209
|
+
assert_equal :something, e.capture_to_tc
|
216
210
|
end
|
217
|
-
|
218
|
-
|
219
211
|
end
|
220
212
|
|
221
|
-
context "A Parser
|
222
|
-
|
223
|
-
specify "store the passed framerate" do
|
213
|
+
context "A Parser" do
|
214
|
+
should "store the passed framerate" do
|
224
215
|
p = EDL::Parser.new(45)
|
225
|
-
p.
|
226
|
-
p.fps.should.equal 45
|
216
|
+
assert_equal 45, p.fps
|
227
217
|
end
|
228
218
|
|
229
|
-
|
219
|
+
should "return matchers tuned with the passed framerate" do
|
230
220
|
p = EDL::Parser.new(30)
|
231
221
|
matchers = p.get_matchers
|
232
222
|
event_matcher = matchers.find{|e| e.is_a?(EDL::EventMatcher) }
|
233
|
-
event_matcher.fps
|
223
|
+
assert_equal 30, event_matcher.fps
|
234
224
|
end
|
235
225
|
|
236
|
-
|
226
|
+
should "create a Timecode from stringified elements" do
|
237
227
|
elems = ["08", "04", "24", "24"]
|
238
|
-
|
228
|
+
assert_nothing_raised do
|
229
|
+
@tc = EDL::Parser.timecode_from_line_elements(elems, 30)
|
230
|
+
end
|
239
231
|
|
240
|
-
@tc
|
241
|
-
|
232
|
+
assert_kind_of Timecode, @tc
|
233
|
+
assert_equal "08:04:24:24".tc(30), @tc
|
242
234
|
|
243
|
-
elems.length
|
235
|
+
assert_zero elems.length
|
244
236
|
end
|
245
237
|
|
246
|
-
|
238
|
+
should "parse from a String" do
|
247
239
|
p = EDL::Parser.new
|
248
|
-
|
240
|
+
assert_nothing_raised do
|
241
|
+
@edl = p.parse File.read(SIMPLE_DISSOLVE)
|
242
|
+
end
|
249
243
|
|
250
|
-
|
251
|
-
@edl.length
|
244
|
+
assert_kind_of EDL::List, @edl
|
245
|
+
assert_equal 2, @edl.length
|
252
246
|
end
|
253
247
|
|
254
|
-
|
248
|
+
should "parse from a File/IOish" do
|
255
249
|
p = EDL::Parser.new
|
256
|
-
|
250
|
+
assert_nothing_raised do
|
251
|
+
@edl = p.parse File.open(SIMPLE_DISSOLVE)
|
252
|
+
end
|
257
253
|
|
258
|
-
|
259
|
-
@edl.length
|
254
|
+
assert_kind_of EDL::List, @edl
|
255
|
+
assert_equal 2, @edl.length
|
260
256
|
end
|
261
257
|
|
262
|
-
|
258
|
+
should "properly parse a dissolve" do
|
263
259
|
# TODO: reformulate
|
264
260
|
p = EDL::Parser.new
|
265
|
-
|
266
|
-
|
267
|
-
@edl.should.be.kind_of EDL::List
|
268
|
-
@edl.length.should.equal 2
|
261
|
+
@edl = p.parse File.open(SIMPLE_DISSOLVE)
|
269
262
|
|
270
263
|
first, second = @edl
|
271
|
-
first.should.be.kind_of EDL::Event
|
272
|
-
second.should.be.kind_of EDL::Event
|
273
264
|
|
274
|
-
|
275
|
-
|
276
|
-
|
265
|
+
assert_kind_of EDL::Event, first
|
266
|
+
assert_kind_of EDL::Event, second
|
267
|
+
|
268
|
+
assert second.has_transition?
|
269
|
+
assert first.ends_with_transition?
|
270
|
+
assert !second.ends_with_transition?
|
277
271
|
|
278
272
|
no_trans = @edl.without_transitions
|
279
273
|
|
@@ -287,15 +281,17 @@ context "A Parser should" do
|
|
287
281
|
"The outgoing clip should have been left in place"
|
288
282
|
end
|
289
283
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
@spliced.length
|
294
|
-
@spliced[0]
|
295
|
-
|
284
|
+
should "return a spliced EDL if the sources allow" do
|
285
|
+
@spliced = EDL::Parser.new.parse(File.open(SPLICEME)).spliced
|
286
|
+
|
287
|
+
assert_equal 1, @spliced.length
|
288
|
+
evt = @spliced[0]
|
289
|
+
|
290
|
+
assert_equal '06:42:50:18'.tc, evt.src_start_tc
|
291
|
+
assert_equal '06:42:52:16'.tc, evt.src_end_tc
|
296
292
|
end
|
297
293
|
|
298
|
-
|
294
|
+
should "not apply any Matchers if a match is found" do
|
299
295
|
p = EDL::Parser.new
|
300
296
|
m1 = flexmock
|
301
297
|
m1.should_receive(:matches?).with("plop").once.and_return(true)
|
@@ -303,106 +299,116 @@ context "A Parser should" do
|
|
303
299
|
|
304
300
|
flexmock(p).should_receive(:get_matchers).once.and_return([m1, m1])
|
305
301
|
result = p.parse("plop")
|
306
|
-
result.
|
302
|
+
assert result.empty?
|
307
303
|
end
|
308
304
|
|
309
|
-
|
305
|
+
should "register line numbers of the detected events" do
|
310
306
|
p = EDL::Parser.new
|
311
307
|
events = p.parse(File.open(SPLICEME))
|
312
308
|
|
313
|
-
events[0].line_number
|
314
|
-
events[
|
315
|
-
|
316
|
-
events[1].line_number.should.not.be.nil
|
317
|
-
events[1].line_number.should.equal 5
|
309
|
+
assert_equal 4, events[0].line_number
|
310
|
+
assert_equal 5, events[1].line_number
|
318
311
|
end
|
319
312
|
end
|
320
313
|
|
321
|
-
context "A TimewarpMatcher
|
314
|
+
context "A TimewarpMatcher" do
|
322
315
|
|
323
|
-
|
316
|
+
should "not create any extra events when used within a Parser" do
|
324
317
|
@edl = EDL::Parser.new.parse(File.open(SIMPLE_TIMEWARP))
|
325
|
-
@edl.length
|
318
|
+
assert_equal 1, @edl.length
|
326
319
|
end
|
327
320
|
|
328
|
-
|
321
|
+
should "properly describe a speedup" do
|
329
322
|
clip = EDL::Parser.new.parse(File.open(SIMPLE_TIMEWARP)).pop
|
330
323
|
|
331
324
|
tw = clip.timewarp
|
332
325
|
|
333
|
-
|
334
|
-
tw.source_used_upto
|
326
|
+
assert_kind_of EDL::Timewarp, tw
|
327
|
+
assert_operator tw.source_used_upto, :>, clip.src_end_tc
|
335
328
|
|
336
|
-
|
337
|
-
clip.timewarp.actual_length_of_source
|
338
|
-
|
339
|
-
tw.reverse?.should.be false
|
329
|
+
assert_equal clip.src_start_tc, tw.source_used_from
|
330
|
+
assert_equal 124, clip.timewarp.actual_length_of_source
|
331
|
+
assert !tw.reverse?
|
340
332
|
end
|
341
333
|
|
342
|
-
|
334
|
+
should "properly describe a slomo" do
|
343
335
|
clip = EDL::Parser.new.parse(File.open(SLOMO_TIMEWARP)).pop
|
344
336
|
|
345
|
-
clip.rec_length
|
346
|
-
clip.src_length
|
337
|
+
assert_equal 10, clip.rec_length
|
338
|
+
assert_equal 5, clip.src_length
|
347
339
|
|
348
340
|
tw = clip.timewarp
|
349
|
-
|
341
|
+
|
342
|
+
assert_operator tw.source_used_upto, :<, clip.src_end_tc
|
350
343
|
|
351
|
-
tw.source_used_upto
|
352
|
-
tw.source_used_upto.should.equal "03:03:19:24".tc
|
353
|
-
tw.speed_in_percent.to_i.should.equal 50
|
354
|
-
tw.actual_length_of_source.should.equal 5
|
344
|
+
assert_equal "03:03:19:24".tc, tw.source_used_upto
|
355
345
|
|
356
|
-
tw.
|
346
|
+
assert_equal 50, tw.speed_in_percent.to_i
|
347
|
+
assert_equal 5, tw.actual_length_of_source
|
348
|
+
assert !tw.reverse?
|
357
349
|
end
|
358
350
|
|
359
351
|
end
|
360
352
|
|
361
|
-
context "A reverse timewarp EDL coming from Avid
|
353
|
+
context "A reverse timewarp EDL coming from Avid" do
|
362
354
|
|
363
|
-
|
355
|
+
should "be parsed properly" do
|
364
356
|
|
365
357
|
clip = EDL::Parser.new.parse(File.open(AVID_REVERSE)).pop
|
366
358
|
|
367
|
-
clip.rec_length
|
359
|
+
assert_equal 52, clip.rec_length
|
368
360
|
|
369
361
|
tw = clip.timewarp
|
370
|
-
tw.actual_framerate.to_i.should.equal -25
|
371
362
|
|
372
|
-
tw.
|
373
|
-
|
374
|
-
tw.actual_length_of_source
|
363
|
+
assert_equal -25, tw.actual_framerate.to_i
|
364
|
+
assert tw.reverse?
|
365
|
+
assert_equal 52, tw.actual_length_of_source
|
375
366
|
|
376
367
|
assert_equal 52, clip.src_length, "The src length should be computed the same as its just a reverse"
|
377
368
|
assert_equal -100.0, clip.timewarp.speed
|
378
369
|
end
|
379
370
|
end
|
380
371
|
|
381
|
-
context "
|
372
|
+
context "EDL with clip reels in comments" do
|
373
|
+
should "parse clip names into the reel field" do
|
374
|
+
clips = EDL::Parser.new.parse(File.open(CLIP_NAMES))
|
375
|
+
# flunk "This still has to be finalized"
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
context "A Final Cut Pro originating reverse" do
|
382
380
|
|
383
|
-
|
381
|
+
should "be interpreted properly" do
|
384
382
|
e = EDL::Parser.new.parse(File.open(FCP_REVERSE)).pop
|
385
383
|
|
386
|
-
e.rec_length
|
387
|
-
e.src_length
|
384
|
+
assert_equal 1000, e.rec_length
|
385
|
+
assert_equal 1000, e.src_length
|
388
386
|
|
389
|
-
|
390
|
-
|
387
|
+
assert_equal "1h".tc, e.rec_start_tc
|
388
|
+
assert_equal "1h 40s".tc, e.rec_end_tc
|
391
389
|
|
392
|
-
e.
|
393
|
-
e.timewarp
|
390
|
+
assert e.reverse?
|
391
|
+
assert_not_nil e.timewarp
|
394
392
|
|
395
393
|
tw = e.timewarp
|
396
394
|
|
397
|
-
|
398
|
-
e.speed.
|
395
|
+
assert_equal -100, tw.speed
|
396
|
+
assert_equal e.speed, tw.speed
|
399
397
|
|
400
|
-
|
401
|
-
|
398
|
+
assert_equal "1h".tc, tw.source_used_from
|
399
|
+
assert_equal "1h 40s".tc, tw.source_used_upto
|
402
400
|
end
|
403
401
|
end
|
404
402
|
|
405
|
-
context "
|
403
|
+
# context "An edit with keyer transition" do
|
404
|
+
# should "parse correctly" do
|
405
|
+
# events = EDL::Parser.new.parse(File.open(KEY))
|
406
|
+
# assert_equal 2, events.length
|
407
|
+
# flunk "Key transition processing is not reliable yet - no reference"
|
408
|
+
# end
|
409
|
+
# end
|
410
|
+
|
411
|
+
context "EventMatcher" do
|
406
412
|
|
407
413
|
EVT_PATTERNS = [
|
408
414
|
'020 008C V C 08:04:24:24 08:04:25:19 01:00:25:22 01:00:26:17',
|
@@ -413,61 +419,71 @@ context "EventMatcher should" do
|
|
413
419
|
'025 BL V C 00:00:00:00 00:00:00:00 01:00:29:19 01:00:29:19',
|
414
420
|
'025 GEN V D 025 00:00:55:10 00:00:58:11 01:00:29:19 01:00:32:20',
|
415
421
|
'002 REDACTED V C 03:09:00:13 03:09:55:19 01:00:43:12 01:01:38:18',
|
422
|
+
# '0004 KASS1 A1234V C 00:00:00:00 00:00:16:06 10:00:41:08 10:00:57:14'
|
416
423
|
]
|
417
|
-
|
418
|
-
|
424
|
+
|
425
|
+
# should 'handle the event with multiple audio tracks' do
|
426
|
+
# m = EDL::EventMatcher.new(25)
|
427
|
+
#
|
428
|
+
# clip = m.apply([],
|
429
|
+
# '0004 KASS1 A1234V C 00:00:00:00 00:00:16:06 10:00:41:08 10:00:57:14'
|
430
|
+
# )
|
431
|
+
# assert_kind_of EDL::Event, clip
|
432
|
+
# assert_equal "A1234", clip.track
|
433
|
+
# end
|
434
|
+
|
435
|
+
should "produce an Event" do
|
419
436
|
m = EDL::EventMatcher.new(25)
|
420
437
|
|
421
438
|
clip = m.apply([],
|
422
439
|
'020 008C V C 08:04:24:24 08:04:25:19 01:00:25:22 01:00:26:17'
|
423
440
|
)
|
424
441
|
|
425
|
-
|
426
|
-
|
427
|
-
clip.num.should.equal "020"
|
428
|
-
clip.reel.should.equal "008C"
|
429
|
-
clip.track.should.equal "V"
|
442
|
+
assert_kind_of EDL::Event, clip
|
430
443
|
|
431
|
-
clip.
|
444
|
+
assert_equal "020", clip.num
|
445
|
+
assert_equal "008C", clip.reel
|
446
|
+
assert_equal "V", clip.track
|
432
447
|
|
433
|
-
|
434
|
-
clip.rec_start_tc.should.equal '01:00:25:22'.tc
|
435
|
-
clip.rec_end_tc.should.equal '01:00:26:17'.tc
|
448
|
+
assert_equal '08:04:24:24'.tc, clip.src_start_tc
|
436
449
|
|
437
|
-
clip.
|
438
|
-
clip.
|
439
|
-
clip.
|
450
|
+
assert_equal '08:04:25:19'.tc, clip.src_end_tc
|
451
|
+
assert_equal '01:00:25:22'.tc, clip.rec_start_tc
|
452
|
+
assert_equal '01:00:26:17'.tc, clip.rec_end_tc
|
440
453
|
|
454
|
+
assert_nil clip.transition
|
455
|
+
assert_nil clip.timewarp
|
456
|
+
assert_zero clip.outgoing_transition_duration
|
441
457
|
end
|
442
458
|
|
443
|
-
|
459
|
+
should "produce an Event with dissolve" do
|
444
460
|
m = EDL::EventMatcher.new(25)
|
445
461
|
|
446
462
|
dissolve = m.apply([],
|
447
463
|
'025 GEN V D 025 00:00:55:10 00:00:58:11 01:00:29:19 01:00:32:20'
|
448
464
|
)
|
449
|
-
|
450
|
-
|
451
|
-
dissolve.num.should.equal "025"
|
452
|
-
dissolve.reel.should.equal "GEN"
|
453
|
-
dissolve.track.should.equal "V"
|
465
|
+
assert_kind_of EDL::Event, dissolve
|
454
466
|
|
455
|
-
dissolve.
|
467
|
+
assert_equal "025", dissolve.num
|
468
|
+
assert_equal 'GEN', dissolve.reel
|
469
|
+
assert_equal 'V', dissolve.track
|
470
|
+
assert dissolve.has_transition?
|
456
471
|
|
457
472
|
tr = dissolve.transition
|
458
473
|
|
459
|
-
|
460
|
-
tr.duration
|
474
|
+
assert_kind_of EDL::Dissolve, tr
|
475
|
+
assert_equal 25, tr.duration
|
461
476
|
end
|
462
477
|
|
463
|
-
|
478
|
+
should "produce a vanilla Event with proper source length" do
|
479
|
+
# This one has EXACTLY 4 frames of source
|
464
480
|
m = EDL::EventMatcher.new(25)
|
465
481
|
clip = m.apply([], '001 GEN V C 00:01:00:00 00:01:00:04 01:00:00:00 01:00:00:04')
|
466
|
-
|
467
|
-
clip.src_length
|
482
|
+
assert_kind_of EDL::Event, clip
|
483
|
+
assert_equal 4, clip.src_length
|
468
484
|
end
|
469
485
|
|
470
|
-
|
486
|
+
should "set flag on the previous event in the stack when a dissolve is encountered" do
|
471
487
|
m = EDL::EventMatcher.new(25)
|
472
488
|
previous_evt = flexmock
|
473
489
|
previous_evt.should_receive(:outgoing_transition_duration=).with(25).once
|
@@ -477,44 +493,44 @@ context "EventMatcher should" do
|
|
477
493
|
)
|
478
494
|
end
|
479
495
|
|
480
|
-
|
496
|
+
should "generate a Wipe" do
|
481
497
|
m = EDL::EventMatcher.new(25)
|
482
498
|
wipe = m.apply([],
|
483
499
|
'025 GEN V W001 025 00:00:55:10 00:00:58:11 01:00:29:19 01:00:32:20'
|
484
500
|
)
|
485
501
|
|
486
502
|
tr = wipe.transition
|
487
|
-
|
488
|
-
tr.duration
|
489
|
-
|
503
|
+
assert_kind_of EDL::Wipe, tr
|
504
|
+
assert_equal 25, tr.duration
|
505
|
+
assert_equal '001', tr.smpte_wipe_index
|
490
506
|
end
|
491
507
|
|
492
|
-
|
493
|
-
|
494
|
-
assert EDL::EventMatcher.new(25).matches?(pat)
|
508
|
+
EVT_PATTERNS.each do | pat |
|
509
|
+
should "match #{pat.inspect}" do
|
510
|
+
assert EDL::EventMatcher.new(25).matches?(pat)
|
495
511
|
end
|
496
512
|
end
|
497
513
|
|
498
|
-
|
514
|
+
should "pass the framerate that it received upon instantiation to the Timecodes being created" do
|
499
515
|
|
500
516
|
m = EDL::EventMatcher.new(30)
|
501
517
|
clip = m.apply([],
|
502
518
|
'020 008C V C 08:04:24:24 08:04:25:19 01:00:25:22 01:00:26:17'
|
503
519
|
)
|
504
|
-
clip.rec_start_tc.fps
|
505
|
-
clip.rec_end_tc.fps
|
506
|
-
clip.src_start_tc.fps
|
507
|
-
clip.src_end_tc.fps
|
520
|
+
assert_equal 30, clip.rec_start_tc.fps
|
521
|
+
assert_equal 30, clip.rec_end_tc.fps
|
522
|
+
assert_equal 30, clip.src_start_tc.fps
|
523
|
+
assert_equal 30, clip.src_end_tc.fps
|
508
524
|
end
|
509
525
|
end
|
510
526
|
|
511
|
-
context "CommentMatcher
|
512
|
-
|
527
|
+
context "CommentMatcher" do
|
528
|
+
should "match a comment" do
|
513
529
|
line = "* COMMENT: PURE BULLSHIT"
|
514
530
|
assert EDL::CommentMatcher.new.matches?(line)
|
515
531
|
end
|
516
532
|
|
517
|
-
|
533
|
+
should "apply the comment to the last clip on the stack" do
|
518
534
|
line = "* COMMENT: PURE BULLSHIT"
|
519
535
|
|
520
536
|
comments = []
|
@@ -523,54 +539,61 @@ context "CommentMatcher should" do
|
|
523
539
|
2.times { mok_evt.should_receive(:comments).and_return(comments) }
|
524
540
|
2.times { EDL::CommentMatcher.new.apply([mok_evt], line) }
|
525
541
|
|
526
|
-
|
542
|
+
assert_equal ["* COMMENT: PURE BULLSHIT", "* COMMENT: PURE BULLSHIT"], mok_evt.comments
|
527
543
|
end
|
528
544
|
end
|
529
545
|
|
530
|
-
context "FallbackMatcher
|
531
|
-
|
546
|
+
context "FallbackMatcher" do
|
547
|
+
should "match anything" do
|
532
548
|
line = "SOME"
|
533
|
-
EDL::FallbackMatcher.new.matches?(line)
|
534
|
-
|
549
|
+
assert EDL::FallbackMatcher.new.matches?(line)
|
550
|
+
|
535
551
|
line = "OR ANOTHER "
|
536
|
-
EDL::FallbackMatcher.new.matches?(line)
|
552
|
+
assert EDL::FallbackMatcher.new.matches?(line)
|
537
553
|
end
|
538
554
|
|
539
|
-
|
555
|
+
should "not match whitespace" do
|
540
556
|
line = "\s\s\s\r\n\r"
|
541
|
-
EDL::FallbackMatcher.new.matches?(line)
|
557
|
+
assert !EDL::FallbackMatcher.new.matches?(line)
|
542
558
|
end
|
543
559
|
|
544
|
-
|
560
|
+
should "append the matched content to comments" do
|
545
561
|
e = flexmock
|
546
562
|
cmts = []
|
547
563
|
e.should_receive(:comments).and_return(cmts)
|
548
564
|
|
549
565
|
EDL::FallbackMatcher.new.apply([e], "FOOBAR")
|
550
|
-
|
566
|
+
assert_equal ["FOOBAR"], cmts
|
551
567
|
|
552
568
|
EDL::FallbackMatcher.new.apply([e], "FINAL CUT PRO REEL: 006-I REPLACED BY: 006I")
|
553
|
-
|
569
|
+
assert_equal ["FOOBAR", "FINAL CUT PRO REEL: 006-I REPLACED BY: 006I"], cmts
|
554
570
|
end
|
555
571
|
|
556
|
-
|
557
|
-
|
572
|
+
should "raise an ApplyError if no clip is on the stack" do
|
573
|
+
assert_raise(EDL::Matcher::ApplyError) do
|
574
|
+
EDL::FallbackMatcher.new.apply([], "FINAL CUT PRO REEL: 006-I REPLACED BY: 006I")
|
575
|
+
end
|
558
576
|
end
|
559
577
|
|
560
578
|
end
|
561
579
|
|
562
|
-
context "ClipNameMatcher
|
563
|
-
|
580
|
+
context "ClipNameMatcher" do
|
581
|
+
should "match a clip name" do
|
564
582
|
line = "* FROM CLIP NAME: TAPE_6-10.MOV"
|
565
|
-
EDL::NameMatcher.new.matches?(line)
|
583
|
+
assert EDL::NameMatcher.new.matches?(line)
|
566
584
|
end
|
567
585
|
|
568
|
-
|
586
|
+
should "match a clip name without space after star" do
|
587
|
+
line = "*FROM CLIP NAME: TAPE_6-10.MOV"
|
588
|
+
assert EDL::NameMatcher.new.matches?(line)
|
589
|
+
end
|
590
|
+
|
591
|
+
should "not match a simple comment" do
|
569
592
|
line = "* CRAP"
|
570
|
-
EDL::NameMatcher.new.matches?(line)
|
593
|
+
assert !EDL::NameMatcher.new.matches?(line)
|
571
594
|
end
|
572
595
|
|
573
|
-
|
596
|
+
should "apply the name to the last event on the stack" do
|
574
597
|
line = "* FROM CLIP NAME: TAPE_6-10.MOV"
|
575
598
|
|
576
599
|
mok_evt = flexmock
|
@@ -579,23 +602,28 @@ context "ClipNameMatcher should" do
|
|
579
602
|
mok_evt.should_receive(:comments).and_return(comments).once
|
580
603
|
|
581
604
|
EDL::NameMatcher.new.apply([mok_evt], line)
|
582
|
-
|
605
|
+
assert_equal ["* FROM CLIP NAME: TAPE_6-10.MOV"], comments
|
583
606
|
end
|
584
607
|
|
585
608
|
end
|
586
609
|
|
587
|
-
context "EffectMatcher
|
588
|
-
|
610
|
+
context "EffectMatcher" do
|
611
|
+
should "not match a simple comment" do
|
589
612
|
line = "* STUFF"
|
590
|
-
EDL::EffectMatcher.new.matches?(line)
|
613
|
+
assert !EDL::EffectMatcher.new.matches?(line)
|
591
614
|
end
|
592
615
|
|
593
|
-
|
616
|
+
should "match a dissolve name" do
|
594
617
|
line = "* EFFECT NAME: CROSS DISSOLVE"
|
595
|
-
EDL::EffectMatcher.new.matches?(line)
|
618
|
+
assert EDL::EffectMatcher.new.matches?(line)
|
596
619
|
end
|
597
620
|
|
598
|
-
|
621
|
+
should "match a dissolve name without space after the asterisk" do
|
622
|
+
line = "*EFFECT NAME: CROSS DISSOLVE"
|
623
|
+
assert EDL::EffectMatcher.new.matches?(line)
|
624
|
+
end
|
625
|
+
|
626
|
+
should "apply the effect name to the transition of the last event on the stack" do
|
599
627
|
line = "* EFFECT NAME: CROSS DISSOLVE"
|
600
628
|
mok_evt, mok_transition = flexmock, flexmock
|
601
629
|
cmt = []
|
@@ -607,77 +635,79 @@ context "EffectMatcher should" do
|
|
607
635
|
|
608
636
|
EDL::EffectMatcher.new.apply([mok_evt], line)
|
609
637
|
|
610
|
-
|
638
|
+
assert_equal ["* EFFECT NAME: CROSS DISSOLVE"], cmt
|
611
639
|
end
|
612
640
|
|
613
641
|
end
|
614
642
|
|
615
|
-
context "A complex EDL passed via Parser
|
616
|
-
|
643
|
+
context "A complex EDL passed via Parser" do
|
644
|
+
should "parse without errors" do
|
617
645
|
assert_nothing_raised { EDL::Parser.new.parse(File.open(FORTY_FIVER)) }
|
618
646
|
end
|
619
|
-
|
620
|
-
|
647
|
+
|
648
|
+
should "parse the EDL with \\r line breaks properly" do
|
621
649
|
evts = EDL::Parser.new.parse(File.read(PLATES))
|
622
650
|
assert_equal 3, evts.length
|
623
651
|
end
|
624
|
-
|
652
|
+
|
625
653
|
# TODO: this does not belong here
|
626
|
-
|
654
|
+
should "be properly rewritten from zero" do
|
627
655
|
complex = EDL::Parser.new.parse(File.open(FORTY_FIVER))
|
628
656
|
from_zero = complex.from_zero
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
from_zero[
|
634
|
-
from_zero[-1].rec_end_tc.should.equal '00:00:42:16'.tc
|
657
|
+
|
658
|
+
assert_equal complex.length, from_zero.length, "Should have the same number of events"
|
659
|
+
|
660
|
+
assert_zero from_zero[0].rec_start_tc
|
661
|
+
assert_equal '00:00:42:16'.tc, from_zero[-1].rec_end_tc
|
635
662
|
end
|
636
663
|
end
|
637
664
|
|
638
|
-
context "A FinalCutPro speedup with fade at the end
|
639
|
-
|
665
|
+
context "A FinalCutPro speedup with fade at the end" do
|
666
|
+
should "be parsed cleanly" do
|
640
667
|
list = EDL::Parser.new.parse(File.open(SPEEDUP_AND_FADEOUT))
|
641
|
-
|
642
|
-
list.length
|
668
|
+
|
669
|
+
assert_equal 2, list.length
|
643
670
|
|
644
671
|
first_evt = list[0]
|
645
|
-
|
672
|
+
|
646
673
|
tw = first_evt.timewarp
|
647
|
-
|
648
|
-
|
649
|
-
first_evt.rec_length
|
650
|
-
first_evt.rec_length_with_transition
|
674
|
+
assert_kind_of EDL::Timewarp, tw
|
675
|
+
|
676
|
+
assert_equal 689, first_evt.rec_length
|
677
|
+
assert_equal 714, first_evt.rec_length_with_transition
|
651
678
|
|
652
|
-
tw.actual_length_of_source
|
653
|
-
tw.speed
|
679
|
+
assert_equal 1000, tw.actual_length_of_source
|
680
|
+
assert_equal 140, tw.speed
|
654
681
|
|
655
682
|
assert_equal 1000, first_evt.src_length
|
656
|
-
|
683
|
+
|
657
684
|
assert_equal "01:00:00:00", first_evt.capture_from_tc.to_s
|
658
685
|
assert_equal "01:00:40:00", first_evt.capture_to_tc.to_s
|
659
686
|
end
|
660
687
|
end
|
661
|
-
|
662
|
-
context "In the trailer EDL the event 4
|
663
|
-
|
688
|
+
|
689
|
+
context "In the trailer EDL the event 4" do
|
690
|
+
should "not have too many comments" do
|
664
691
|
evts = EDL::Parser.new.parse(File.open(TRAILER_EDL))
|
665
692
|
evt = evts[6]
|
666
|
-
evt.comments.length
|
693
|
+
assert_equal 5, evt.comments.length
|
667
694
|
end
|
668
695
|
end
|
669
696
|
|
670
|
-
context "A FinalCutPro speedup and reverse with fade at the end
|
671
|
-
|
697
|
+
context "A FinalCutPro speedup and reverse with fade at the end" do
|
698
|
+
should "parse cleanly" do
|
672
699
|
first_evt = EDL::Parser.new.parse(File.open(SPEEDUP_REVERSE_AND_FADEOUT)).shift
|
700
|
+
|
701
|
+
assert first_evt.reverse?
|
673
702
|
|
674
|
-
first_evt.
|
675
|
-
|
676
|
-
first_evt.rec_length.should.equal 689
|
677
|
-
first_evt.rec_length_with_transition.should.equal 714
|
703
|
+
assert_equal 689, first_evt.rec_length
|
704
|
+
assert_equal 714, first_evt.rec_length_with_transition
|
678
705
|
|
679
706
|
tw = first_evt.timewarp
|
680
|
-
|
681
|
-
|
707
|
+
|
708
|
+
assert_equal "1h 1f".tc, tw.source_used_from
|
709
|
+
assert_equal "1h 40s".tc, tw.source_used_upto
|
682
710
|
end
|
683
|
-
end
|
711
|
+
end
|
712
|
+
|
713
|
+
end
|