edl 0.1.5 → 0.1.6
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 +4 -4
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +3 -10
- data/Rakefile +10 -22
- data/edl.gemspec +32 -67
- data/lib/edl.rb +115 -116
- data/lib/edl/cutter.rb +15 -12
- data/lib/edl/event.rb +42 -32
- data/lib/edl/grabber.rb +10 -8
- data/lib/edl/linebreak_magician.rb +3 -1
- data/lib/edl/parser.rb +24 -19
- data/lib/edl/timewarp.rb +10 -9
- data/lib/edl/transition.rb +5 -5
- data/lib/edl/version.rb +5 -0
- metadata +20 -71
- data/test/samples/45S_SAMPLE.EDL +0 -48
- data/test/samples/FCP_REVERSE.EDL +0 -9
- data/test/samples/KEY_TRANSITION.EDL +0 -9
- data/test/samples/PLATES.EDL +0 -1
- data/test/samples/REEL_IS_CLIP.txt +0 -8
- data/test/samples/REVERSE.EDL +0 -3
- data/test/samples/SIMPLE_DISSOLVE.EDL +0 -9
- data/test/samples/SPEEDUP_AND_FADEOUT.EDL +0 -11
- data/test/samples/SPEEDUP_REVERSE_AND_FADEOUT.EDL +0 -11
- data/test/samples/SPLICEME.EDL +0 -5
- data/test/samples/TIMEWARP.EDL +0 -5
- data/test/samples/TIMEWARP_HALF.EDL +0 -5
- data/test/samples/TRAILER_EDL.edl +0 -0
- data/test/samples/edl_mixed_line_endings.edl +0 -12
- data/test/test_edl.rb +0 -721
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92c9e98e3aae5318b201b581548227410c0add31
|
4
|
+
data.tar.gz: 775136de2ed133788783aabb995674b68bf610bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64487e6d8b2558e74ae04781a347c2ed91d1c5ad362b764b0af479628077fd70ea831e1df7d1403afabcf794aa10deb1087fa484d7e46f23e70e555b07802ba7
|
7
|
+
data.tar.gz: 6eb2449c27c2188dcfe11df99b4a987d78436f938fdf7795bc996e7c22dc1d7c3f6b9c42a815f07b79238ae626e8e7b9a3d77576b393c8ed17bdc7151b4835c7
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
edl
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,13 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# -*- ruby -*-
|
2
4
|
source 'https://rubygems.org'
|
3
5
|
|
4
|
-
|
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
|
6
|
+
gemspec
|
data/Rakefile
CHANGED
@@ -1,27 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
|
-
require '
|
3
|
-
require '
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
require 'rake/testtask'
|
4
6
|
|
5
|
-
|
6
|
-
|
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"]
|
12
|
-
|
13
|
-
# Do not package invisibles
|
14
|
-
gem.files.exclude ".*"
|
15
|
-
end
|
7
|
+
begin
|
8
|
+
require 'rspec/core/rake_task'
|
16
9
|
|
17
|
-
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
18
11
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
t.libs << "test"
|
23
|
-
t.pattern = 'test/**/test_*.rb'
|
24
|
-
t.verbose = true
|
12
|
+
task default: :spec
|
13
|
+
rescue LoadError
|
14
|
+
# no rspec available
|
25
15
|
end
|
26
|
-
|
27
|
-
task :default => [ :test ]
|
data/edl.gemspec
CHANGED
@@ -1,80 +1,45 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
4
|
+
|
5
|
+
# Maintain your gem's version:
|
6
|
+
require 'edl/version'
|
5
7
|
|
6
8
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version =
|
9
|
+
s.name = 'edl'
|
10
|
+
s.version = EDL::VERSION
|
9
11
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(
|
11
|
-
s.authors = [
|
12
|
-
s.date =
|
13
|
-
s.email =
|
12
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
13
|
+
s.authors = ['Julik Tarkhanov']
|
14
|
+
s.date = '2014-03-24'
|
15
|
+
s.email = 'me@julik.nl'
|
14
16
|
s.extra_rdoc_files = [
|
15
|
-
|
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/samples/edl_mixed_line_endings.edl",
|
46
|
-
"test/test_edl.rb"
|
17
|
+
'README.rdoc'
|
47
18
|
]
|
48
|
-
s.homepage = "http://guerilla-di.org/edl"
|
49
|
-
s.require_paths = ["lib"]
|
50
|
-
s.rubygems_version = "2.0.3"
|
51
|
-
s.summary = "Parser for EDL (Edit Decision List) files"
|
52
19
|
|
53
|
-
|
20
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
s.bindir = 'exe'
|
22
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
s.require_paths = ['lib']
|
24
|
+
|
25
|
+
s.homepage = 'http://guerilla-di.org/edl'
|
26
|
+
s.require_paths = ['lib']
|
27
|
+
s.rubygems_version = '2.0.3'
|
28
|
+
s.summary = 'Parser for EDL (Edit Decision List) files'
|
29
|
+
|
30
|
+
if s.respond_to? :specification_version
|
54
31
|
s.specification_version = 4
|
55
32
|
|
56
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0')
|
57
|
-
s.add_runtime_dependency
|
58
|
-
s.add_development_dependency
|
59
|
-
s.add_development_dependency
|
60
|
-
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
61
|
-
s.add_development_dependency(%q<rake>, [">= 0"])
|
62
|
-
s.add_development_dependency(%q<flexmock>, ["~> 1.3.2"])
|
33
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0')
|
34
|
+
s.add_runtime_dependency 'timecode', '>= 0'
|
35
|
+
s.add_development_dependency 'rake', '>= 0'
|
36
|
+
s.add_development_dependency 'rspec', '~> 3.5'
|
63
37
|
else
|
64
|
-
s.add_dependency
|
65
|
-
s.add_dependency
|
66
|
-
s.add_dependency(%q<test-unit>, [">= 0"])
|
67
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
68
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
69
|
-
s.add_dependency(%q<flexmock>, ["~> 1.3.2"])
|
38
|
+
s.add_dependency 'timecode', '>= 0'
|
39
|
+
s.add_dependency 'rake', '>= 0'
|
70
40
|
end
|
71
41
|
else
|
72
|
-
s.add_dependency
|
73
|
-
s.add_dependency
|
74
|
-
s.add_dependency(%q<test-unit>, [">= 0"])
|
75
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
76
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
77
|
-
s.add_dependency(%q<flexmock>, ["~> 1.3.2"])
|
42
|
+
s.add_dependency 'timecode', '>= 0'
|
43
|
+
s.add_dependency 'rake', '>= 0'
|
78
44
|
end
|
79
45
|
end
|
80
|
-
|
data/lib/edl.rb
CHANGED
@@ -1,48 +1,50 @@
|
|
1
|
-
|
2
|
-
require "timecode"
|
3
|
-
require "stringio"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
3
|
+
require 'timecode'
|
4
|
+
require 'pp'
|
5
|
+
require 'stringio'
|
6
|
+
require 'edl/cutter'
|
7
|
+
require 'edl/event'
|
8
|
+
require 'edl/grabber'
|
9
|
+
require 'edl/linebreak_magician'
|
10
|
+
require 'edl/parser'
|
11
|
+
require 'edl/timewarp'
|
12
|
+
require 'edl/transition'
|
13
|
+
require 'edl/version'
|
10
14
|
|
11
15
|
# A simplistic EDL parser
|
12
16
|
module EDL
|
13
|
-
VERSION = "0.1.5"
|
14
17
|
DEFAULT_FPS = 25.0
|
15
|
-
|
18
|
+
|
16
19
|
# Represents an EDL, is returned from the parser. Traditional operation is functional style, i.e.
|
17
20
|
# edl.renumbered.without_transitions.without_generators
|
18
21
|
class List < Array
|
19
|
-
|
20
22
|
def events #:nodoc:
|
21
|
-
STDERR.puts
|
23
|
+
STDERR.puts 'EDL::List#events is deprecated and will be removed, use EDL::List as an array instead'
|
22
24
|
self
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
# Return the same EDL with all dissolves stripped and replaced by the clips underneath
|
26
28
|
def without_transitions
|
27
29
|
# Find dissolves
|
28
30
|
cpy = []
|
29
|
-
each_with_index do |
|
31
|
+
each_with_index do |e, i|
|
30
32
|
# A dissolve always FOLLOWS the incoming clip
|
31
33
|
if e.ends_with_transition?
|
32
|
-
dissolve = self[i+1]
|
34
|
+
dissolve = self[i + 1]
|
33
35
|
len = dissolve.transition.duration.to_i
|
34
|
-
|
36
|
+
|
35
37
|
# The dissolve contains the OUTGOING clip, we are the INCOMING. Extend the
|
36
38
|
# incoming clip by the length of the dissolve, that's the whole mission actually
|
37
39
|
incoming = e.copy_properties_to(e.class.new)
|
38
40
|
incoming.src_end_tc += len
|
39
41
|
incoming.rec_end_tc += len
|
40
|
-
|
42
|
+
|
41
43
|
outgoing = dissolve.copy_properties_to(Event.new)
|
42
|
-
|
44
|
+
|
43
45
|
# Add the A suffix to the ex-dissolve
|
44
46
|
outgoing.num += 'A'
|
45
|
-
|
47
|
+
|
46
48
|
# Take care to join the two if they overlap - TODO
|
47
49
|
cpy << incoming
|
48
50
|
cpy << outgoing
|
@@ -56,27 +58,30 @@ module EDL
|
|
56
58
|
# (0...cpy.length).map{|e| cpy[e].num = "%03d" % e }
|
57
59
|
self.class.new(cpy)
|
58
60
|
end
|
59
|
-
|
61
|
+
|
60
62
|
# Return the same EDL, with events renumbered starting from 001
|
61
63
|
def renumbered
|
62
|
-
renumed =
|
64
|
+
renumed = dup
|
63
65
|
pad = renumed.length.to_s.length
|
64
66
|
pad = 3 if pad < 3
|
65
|
-
|
66
|
-
(0...renumed.length).map{|e| renumed[e].num = "%0#{pad}d" % (e+1) }
|
67
|
+
|
68
|
+
(0...renumed.length).map { |e| renumed[e].num = "%0#{pad}d" % (e + 1) }
|
67
69
|
self.class.new(renumed)
|
68
70
|
end
|
69
|
-
|
71
|
+
|
70
72
|
# Return the same EDL with all timewarps expanded to native length. Clip length
|
71
73
|
# changes have rippling effect on footage that comes after the timewarped clip
|
72
74
|
# (so this is best used in concert with the original EDL where record TC is pristine)
|
73
75
|
def without_timewarps
|
74
76
|
self.class.new(
|
75
|
-
map do |
|
77
|
+
map do |e|
|
76
78
|
if e.has_timewarp?
|
77
79
|
repl = e.copy_properties_to(e.class.new)
|
78
|
-
from
|
79
|
-
|
80
|
+
from = e.timewarp.actual_src_start_tc
|
81
|
+
to = e.timewarp.actual_src_end_tc
|
82
|
+
repl.src_start_tc = from
|
83
|
+
repl.src_end_tc = to
|
84
|
+
repl.timewarp = nil
|
80
85
|
repl
|
81
86
|
else
|
82
87
|
e
|
@@ -84,36 +89,36 @@ module EDL
|
|
84
89
|
end
|
85
90
|
)
|
86
91
|
end
|
87
|
-
|
92
|
+
|
88
93
|
# Return the same EDL without AX, BL and other GEN events (like slug, text and solids).
|
89
94
|
# Usually used in concert with "without_transitions"
|
90
95
|
def without_generators
|
91
|
-
self.class.new(
|
96
|
+
self.class.new(reject(&:generator?))
|
92
97
|
end
|
93
|
-
|
98
|
+
|
94
99
|
# Return the list of clips used by this EDL at full capture length
|
95
100
|
def capture_list
|
96
101
|
without_generators.without_timewarps.spliced.from_zero
|
97
102
|
end
|
98
|
-
|
103
|
+
|
99
104
|
# Return the same EDL with the first event starting at 00:00:00:00 and all subsequent events
|
100
105
|
# shifted accordingly
|
101
106
|
def from_zero
|
102
107
|
shift_by = self[0].rec_start_tc
|
103
108
|
self.class.new(
|
104
|
-
map do |
|
109
|
+
map do |original|
|
105
110
|
e = original.dup
|
106
|
-
e.rec_start_tc =
|
107
|
-
e.rec_end_tc =
|
111
|
+
e.rec_start_tc = (e.rec_start_tc - shift_by)
|
112
|
+
e.rec_end_tc = (e.rec_end_tc - shift_by)
|
108
113
|
e
|
109
114
|
end
|
110
115
|
)
|
111
116
|
end
|
112
|
-
|
117
|
+
|
113
118
|
# Return the same EDL with neighbouring clips joined at cuts where applicable (if a clip
|
114
119
|
# is divided in two pieces it will be spliced). Most useful in combination with without_timewarps
|
115
120
|
def spliced
|
116
|
-
spliced_edl =
|
121
|
+
spliced_edl = each_with_object([]) do |cur, spliced|
|
117
122
|
latest = spliced[-1]
|
118
123
|
# Append to latest if splicable
|
119
124
|
if latest && (latest.reel == cur.reel) && (cur.src_start_tc == (latest.src_end_tc + 1))
|
@@ -122,140 +127,135 @@ module EDL
|
|
122
127
|
else
|
123
128
|
spliced << cur.dup
|
124
129
|
end
|
125
|
-
spliced
|
126
130
|
end
|
127
131
|
self.class.new(spliced_edl)
|
128
132
|
end
|
129
133
|
end
|
130
|
-
|
134
|
+
|
131
135
|
#:stopdoc:
|
132
|
-
|
136
|
+
|
133
137
|
# A generic matcher
|
134
138
|
class Matcher
|
135
139
|
class ApplyError < RuntimeError
|
136
140
|
def initialize(msg, line)
|
137
|
-
super(
|
141
|
+
super('%s - offending line was %s' % [msg, line.inspect])
|
138
142
|
end
|
139
143
|
end
|
140
|
-
|
144
|
+
|
141
145
|
def initialize(with_regexp)
|
142
146
|
@regexp = with_regexp
|
143
147
|
end
|
144
|
-
|
148
|
+
|
145
149
|
def matches?(line)
|
146
|
-
|
150
|
+
line =~ @regexp
|
147
151
|
end
|
148
|
-
|
149
|
-
def apply(
|
152
|
+
|
153
|
+
def apply(_stack, line)
|
150
154
|
STDERR.puts "Skipping #{line}"
|
151
155
|
end
|
152
156
|
end
|
153
|
-
|
157
|
+
|
154
158
|
# EDL clip comment matcher, a generic one
|
155
159
|
class CommentMatcher < Matcher
|
156
160
|
def initialize
|
157
|
-
super(
|
161
|
+
super(/^\*(.+)/)
|
158
162
|
end
|
159
|
-
|
163
|
+
|
160
164
|
def apply(stack, line)
|
161
|
-
raise ApplyError.new(
|
165
|
+
raise ApplyError.new('No event to attach a comment to', line) if stack.empty?
|
162
166
|
# TODO: we should really remove "* " prefixes from comments
|
163
|
-
stack[-1].comments.push(
|
167
|
+
stack[-1].comments.push('* %s' % line.scan(@regexp).flatten.pop.strip)
|
164
168
|
end
|
165
169
|
end
|
166
|
-
|
170
|
+
|
167
171
|
# Fallback matcher for things like FINAL CUT PRO REEL
|
168
172
|
class FallbackMatcher < Matcher
|
169
173
|
def initialize
|
170
174
|
super(/^(\w)(.+)/)
|
171
175
|
end
|
172
|
-
|
176
|
+
|
173
177
|
def apply(stack, line)
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
raise ApplyError.new("Line can only be a comment but no event was on the stack", line)
|
178
|
-
end
|
178
|
+
stack[-1].comments << line.scan(@regexp).flatten.join.strip
|
179
|
+
rescue NoMethodError
|
180
|
+
raise ApplyError.new('Line can only be a comment but no event was on the stack', line)
|
179
181
|
end
|
180
182
|
end
|
181
183
|
|
182
184
|
# Clip name matcher
|
183
185
|
class NameMatcher < Matcher
|
184
186
|
def initialize
|
185
|
-
super(
|
187
|
+
super(/^\*\s*FROM CLIP NAME:(\s+)(.+)/)
|
186
188
|
end
|
187
|
-
|
189
|
+
|
188
190
|
def apply(stack, line)
|
189
191
|
stack[-1].clip_name = line.scan(@regexp).flatten.pop.strip
|
190
192
|
CommentMatcher.new.apply(stack, line)
|
191
193
|
end
|
192
194
|
end
|
193
|
-
|
195
|
+
|
194
196
|
class EffectMatcher < Matcher
|
195
197
|
def initialize
|
196
|
-
super(
|
198
|
+
super(/^\*\s*EFFECT NAME:(\s+)(.+)/)
|
197
199
|
end
|
198
|
-
|
200
|
+
|
199
201
|
def apply(stack, line)
|
200
202
|
stack[-1].transition.effect = line.scan(@regexp).flatten.pop.strip
|
201
203
|
CommentMatcher.new.apply(stack, line)
|
202
204
|
end
|
203
205
|
end
|
204
|
-
|
206
|
+
|
205
207
|
class TimewarpMatcher < Matcher
|
206
|
-
|
207
208
|
attr_reader :fps
|
208
|
-
|
209
|
+
|
209
210
|
def initialize(fps)
|
210
211
|
@fps = fps
|
211
212
|
@regexp = /M2(\s+)(\w+)(\s+)(\-?\d+\.\d+)(\s+)(\d{1,2}):(\d{1,2}):(\d{1,2}):(\d{1,2})/
|
212
213
|
end
|
213
|
-
|
214
|
+
|
214
215
|
def apply(stack, line)
|
215
|
-
matches = line.scan(@regexp).flatten.map
|
216
|
-
|
216
|
+
matches = line.scan(@regexp).flatten.map(&:strip).reject { |e| e.nil? || e.empty? }
|
217
|
+
|
217
218
|
from_reel = matches.shift
|
218
219
|
fps = matches.shift
|
219
|
-
|
220
|
+
|
220
221
|
begin
|
221
222
|
# FIXME
|
222
223
|
tw_start_source_tc = Parser.timecode_from_line_elements(matches, @fps)
|
223
224
|
rescue Timecode::Error => e
|
224
|
-
raise ApplyError
|
225
|
+
raise ApplyError.new("Invalid TC in timewarp (#{e})", line)
|
225
226
|
end
|
226
|
-
|
227
|
-
evt_with_tw = stack.reverse.find{|e| e.src_start_tc == tw_start_source_tc && e.reel == from_reel }
|
228
|
-
|
229
|
-
|
230
|
-
raise ApplyError, "Cannot find event marked by timewarp", line
|
231
|
-
else
|
227
|
+
|
228
|
+
evt_with_tw = stack.reverse.find { |e| e.src_start_tc == tw_start_source_tc && e.reel == from_reel }
|
229
|
+
|
230
|
+
if evt_with_tw
|
232
231
|
tw = Timewarp.new
|
233
|
-
tw.actual_framerate
|
232
|
+
tw.actual_framerate = fps.to_f
|
233
|
+
tw.clip = evt_with_tw
|
234
234
|
evt_with_tw.timewarp = tw
|
235
|
+
else
|
236
|
+
raise ApplyError.new('Cannot find event marked by timewarp', line)
|
235
237
|
end
|
236
238
|
end
|
237
239
|
end
|
238
|
-
|
240
|
+
|
239
241
|
# Drop frame goodbye
|
240
242
|
TC = /(\d{1,2}):(\d{1,2}):(\d{1,2}):(\d{1,2})/
|
241
|
-
|
242
|
-
class EventMatcher < Matcher
|
243
243
|
|
244
|
+
class EventMatcher < Matcher
|
244
245
|
# 021 009 V C 00:39:04:21 00:39:05:09 01:00:26:17 01:00:27:05
|
245
|
-
EVENT_PAT = /(\d+)(\s+)(
|
246
|
-
|
246
|
+
EVENT_PAT = /(\d+)(\s+)([^\s]+)(\s+)(\w+)(\s+)(\w+)(\s+)((\w+\s+)?)#{TC} #{TC} #{TC} #{TC}/
|
247
|
+
|
247
248
|
attr_reader :fps
|
248
|
-
|
249
|
+
|
249
250
|
def initialize(some_fps)
|
250
251
|
super(EVENT_PAT)
|
251
252
|
@fps = some_fps
|
252
253
|
end
|
253
|
-
|
254
|
+
|
254
255
|
def apply(stack, line)
|
255
|
-
|
256
256
|
matches = line.scan(@regexp).shift
|
257
257
|
props = {}
|
258
|
-
|
258
|
+
|
259
259
|
# FIrst one is the event number
|
260
260
|
props[:num] = matches.shift
|
261
261
|
matches.shift
|
@@ -271,7 +271,7 @@ module EDL
|
|
271
271
|
# Then the type
|
272
272
|
props[:transition] = matches.shift
|
273
273
|
matches.shift
|
274
|
-
|
274
|
+
|
275
275
|
# Then the optional generator group - skip for now
|
276
276
|
if props[:transition] != 'C'
|
277
277
|
props[:duration] = matches.shift.strip
|
@@ -279,50 +279,49 @@ module EDL
|
|
279
279
|
matches.shift
|
280
280
|
end
|
281
281
|
matches.shift
|
282
|
-
|
282
|
+
|
283
283
|
# Then the timecodes
|
284
|
-
[:src_start_tc, :src_end_tc, :rec_start_tc, :rec_end_tc].each do |
|
284
|
+
[:src_start_tc, :src_end_tc, :rec_start_tc, :rec_end_tc].each do |k|
|
285
285
|
begin
|
286
286
|
props[k] = EDL::Parser.timecode_from_line_elements(matches, @fps)
|
287
|
-
rescue Timecode::Error => e
|
288
|
-
raise ApplyError
|
287
|
+
rescue Timecode::Error => e
|
288
|
+
raise ApplyError.new("Cannot parse timecode - #{e}", line)
|
289
289
|
end
|
290
290
|
end
|
291
|
-
|
291
|
+
|
292
292
|
evt = Event.new
|
293
293
|
transition_idx = props.delete(:transition)
|
294
294
|
evt.transition = case transition_idx
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
295
|
+
when 'C'
|
296
|
+
nil
|
297
|
+
when 'D'
|
298
|
+
d = Dissolve.new
|
299
|
+
d.duration = props.delete(:duration).to_i
|
300
|
+
d
|
301
|
+
when /W(\d+)/
|
302
|
+
w = Wipe.new
|
303
|
+
w.duration = props.delete(:duration).to_i
|
304
|
+
w.smpte_wipe_index = transition_idx.delete('W')
|
305
|
+
w
|
306
|
+
when 'K'
|
307
|
+
k = Key.new
|
308
|
+
k.duration = props.delete(:duration).to_i
|
309
|
+
k
|
310
|
+
else
|
311
|
+
raise "Unknown transition type #{transition_idx}"
|
312
312
|
end
|
313
|
-
|
313
|
+
|
314
314
|
# Give a hint on the incoming clip as well
|
315
315
|
if evt.transition && stack[-1]
|
316
316
|
stack[-1].outgoing_transition_duration = evt.transition.duration
|
317
317
|
end
|
318
|
-
|
319
|
-
props.each_pair { |
|
320
|
-
|
318
|
+
|
319
|
+
props.each_pair { |k, v| evt.send("#{k}=", v) }
|
320
|
+
|
321
321
|
stack << evt
|
322
|
-
evt # FIXME - we dont need to return this is only used by tests
|
322
|
+
evt # FIXME: - we dont need to return this is only used by tests
|
323
323
|
end
|
324
324
|
end
|
325
|
-
|
326
|
-
#:startdoc:
|
327
325
|
|
326
|
+
#:startdoc:
|
328
327
|
end
|