edl 0.1.3 → 0.1.4
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.
- 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
|