edl 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,34 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EDL
2
4
  # Can chop an offline edit into events according to the EDL
3
5
  class Cutter #:nodoc:
4
6
  def initialize(source_path)
5
7
  @source_path = source_path
6
8
  end
7
-
9
+
8
10
  def cut(edl)
9
- source_for_cutting = edl.from_zero #.without_transitions.without_generators
11
+ source_for_cutting = edl.from_zero # .without_transitions.without_generators
10
12
  # We need to use the original length in record
11
- source_for_cutting.events.each do | evt |
13
+ source_for_cutting.events.each do |evt|
12
14
  cut_segment(evt, evt.rec_start_tc, evt.rec_start_tc + evt.length)
13
15
  end
14
16
  end
15
-
17
+
16
18
  def cut_segment(evt, start_at, end_at)
17
19
  STDERR.puts "Cutting #{@source_path} from #{start_at} to #{end_at} - #{evt.num}"
18
20
  end
19
21
  end
20
-
22
+
21
23
  class FFMpegCutter < Cutter #:nodoc:
22
24
  def cut_segment(evt, start_at, end_at)
23
- source_dir, source_file = File.dirname(@source_path), File.basename(@source_path)
25
+ source_dir = File.dirname(@source_path)
26
+ source_file = File.basename(@source_path)
24
27
  dest_segment = File.join(source_dir, ('%s_%s' % [evt.num, source_file]))
25
- # dest_segment.gsub!(/\.mov$/i, '.mp4')
26
-
28
+ # dest_segment.gsub!(/\.mov$/i, '.mp4')
29
+
27
30
  offset = end_at - start_at
28
-
31
+
29
32
  cmd = "/opt/local/bin/ffmpeg -i #{@source_path} -ss #{start_at} -vframes #{offset.total} -vcodec photojpeg -acodec copy #{dest_segment}"
30
- #puts cmd
31
- `#{cmd}`
33
+ # puts cmd
34
+ `#{cmd}`
32
35
  end
33
36
  end
34
- end
37
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EDL
2
4
  # Represents an edit event (or, more specifically, an EDL line denoting a clip being part of an EDL event)
3
5
  class Event
@@ -6,7 +8,7 @@ module EDL
6
8
 
7
9
  # Reel name as in the EDL
8
10
  attr_accessor :reel
9
-
11
+
10
12
  # Event tracks as in the EDL
11
13
  attr_accessor :track
12
14
 
@@ -19,7 +21,7 @@ module EDL
19
21
  attr_accessor :src_end_tc
20
22
 
21
23
  # Record start timecode of the event in the master as in the EDL
22
- attr_accessor :rec_start_tc
24
+ attr_accessor :rec_start_tc
23
25
 
24
26
  # Record end timecode of the event in the master as in the EDL,
25
27
  # outgoing transition is not included
@@ -36,76 +38,76 @@ module EDL
36
38
 
37
39
  # Incoming transition metadata (EDL::Transition), or nil if no transition is used
38
40
  attr_accessor :transition
39
-
41
+
40
42
  # How long is the incoming transition on the next event
41
43
  attr_accessor :outgoing_transition_duration
42
-
44
+
43
45
  # Where is this event located in the original file
44
46
  attr_accessor :line_number
45
-
47
+
46
48
  def initialize(opts = {})
47
- opts.each_pair{|k,v| send("#{k}=", v) }
49
+ opts.each_pair { |k, v| send("#{k}=", v) }
48
50
  yield(self) if block_given?
49
51
  end
50
-
52
+
51
53
  # Output a textual description (will not work as an EDL line!)
52
54
  def to_s
53
- %w( num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc).map{|a| self.send(a).to_s}.join(" ")
55
+ %w[num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc].map { |a| send(a).to_s }.join(' ')
54
56
  end
55
-
57
+
56
58
  def inspect
57
59
  to_s
58
60
  end
59
-
61
+
60
62
  def comments #:nodoc:
61
63
  @comments ||= []
62
64
  @comments
63
65
  end
64
-
66
+
65
67
  def outgoing_transition_duration #:nodoc:
66
68
  @outgoing_transition_duration ||= 0
67
69
  end
68
-
70
+
69
71
  # Is the clip reversed in the edit?
70
72
  def reverse?
71
73
  (timewarp && timewarp.reverse?)
72
74
  end
73
- alias_method :reversed?, :reverse?
74
-
75
+ alias reversed? reverse?
76
+
75
77
  def copy_properties_to(evt)
76
- %w( num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc).each do | k |
78
+ %w[num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc].each do |k|
77
79
  evt.send("#{k}=", send(k)) if evt.respond_to?(k)
78
80
  end
79
81
  evt
80
82
  end
81
-
83
+
82
84
  # Returns true if the clip starts with a transiton (not a jump cut)
83
85
  def has_transition?
84
86
  !!@transition
85
87
  end
86
- alias_method :starts_with_transition?, :has_transition?
87
-
88
+ alias starts_with_transition? has_transition?
89
+
88
90
  # The duration of the incoming transition, or 0 if no transition is used
89
91
  def incoming_transition_duration
90
92
  @transition ? @transition.duration : 0
91
93
  end
92
-
94
+
93
95
  # Returns true if the clip ends with a transition (if the next clip starts with a transition)
94
96
  def ends_with_transition?
95
97
  outgoing_transition_duration > 0
96
98
  end
97
-
99
+
98
100
  # Returns true if the clip has a timewarp (speed ramp, motion memory, you name it)
99
101
  def has_timewarp?
100
102
  !timewarp.nil?
101
103
  end
102
-
104
+
103
105
  # Is this a black slug?
104
106
  def black?
105
107
  reel == 'BL'
106
108
  end
107
- alias_method :slug?, :black?
108
-
109
+ alias slug? black?
110
+
109
111
  # Get the record length of the event (how long it occupies in the EDL without an eventual outgoing transition)
110
112
  def rec_length
111
113
  (rec_end_tc.to_i - rec_start_tc.to_i).to_i
@@ -115,37 +117,45 @@ module EDL
115
117
  def rec_length_with_transition
116
118
  rec_length + outgoing_transition_duration.to_i
117
119
  end
118
-
120
+
119
121
  # How long does the capture need to be to complete this event including timewarps and transitions
120
122
  def src_length
121
123
  @timewarp ? @timewarp.actual_length_of_source : rec_length_with_transition
122
124
  end
123
-
124
- alias_method :capture_length, :src_length
125
+
126
+ alias capture_length src_length
125
127
 
126
128
  # Capture from (and including!) this timecode to complete this event including timewarps and transitions
127
129
  def capture_from_tc
128
130
  @timewarp ? @timewarp.source_used_from : src_start_tc
129
131
  end
130
-
132
+
131
133
  # Capture up to AND INCLUDING this timecode to complete this event including timewarps and transitions
132
134
  def capture_to_and_including_tc
133
135
  capture_to_tc - 1
134
136
  end
135
-
137
+
136
138
  # Capture up to BUT NOT INCLUDING this timecode to complete this event including timewarps and transitions
137
139
  def capture_to_tc
138
140
  @timewarp ? @timewarp.source_used_upto : (src_end_tc + outgoing_transition_duration)
139
141
  end
140
-
142
+
141
143
  # Speed of this clip in percent relative to the source speed. 100 for non-timewarped events
142
144
  def speed
143
145
  @timewarp ? @timewarp.speed : 100.0
144
146
  end
145
-
147
+
148
+ # Sets the reel name and outputs a warning if it contains dots or spaces
149
+ def reel=(new_reel_name)
150
+ if new_reel_name =~ /[\s\.]/
151
+ $stderr.puts "Reel name #{new_reel_name.inspect} contains dots or spaces, beware."
152
+ end
153
+ @reel = new_reel_name
154
+ end
155
+
146
156
  # Returns true if this event is a generator
147
157
  def generator?
148
- black? || (%(AX GEN).include?(reel))
158
+ black? || %(AX GEN).include?(reel)
149
159
  end
150
160
  end
151
- end
161
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EDL
2
4
  # When initialized with a file and passed an EDL, will generate thumbnail images
3
5
  # of the first frame of every event. It is assumed that the movie file starts at the same
@@ -7,23 +9,23 @@ module EDL
7
9
  def initialize(with_file)
8
10
  @source_path = with_file
9
11
  end
10
-
12
+
11
13
  def ffmpeg_bin
12
14
  @ffmpeg_bin || 'ffmpeg'
13
15
  end
14
-
16
+
15
17
  def grab(edl)
16
- edl.from_zero.events.each do | evt |
17
- grab_frame_tc = evt.rec_start_tc + (offset || 0 )
18
-
18
+ edl.from_zero.events.each do |evt|
19
+ grab_frame_tc = evt.rec_start_tc + (offset || 0)
20
+
19
21
  to_file = File.dirname(@source_path) + '/' + evt.num + '_' + File.basename(@source_path).gsub(/\.(\w+)$/, '')
20
22
  generate_grab(evt.num, grab_frame_tc, to_file)
21
23
  end
22
24
  end
23
-
24
- def generate_grab(evt, at, to_file)
25
+
26
+ def generate_grab(_evt, at, to_file)
25
27
  cmd = "#{ffmpeg_bin} -i #{@source_path} -an -ss #{at.with_frames_as_fraction} -vframes 1 -y #{to_file}%d.jpg"
26
28
  `#{cmd}`
27
29
  end
28
30
  end
29
- end
31
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # EDLs sometimes come with \r line breaks, and this is something that fails
2
4
  # with Ruby standard line separator detection. We need something to help us
3
5
  # with that. In this case we can just do a bulk replace because EDLs will be relatively
@@ -8,4 +10,4 @@ class EDL::LinebreakMagician < StringIO
8
10
  blob = with_io.read
9
11
  super(blob.gsub(LOOSE_CR, "\n"))
10
12
  end
11
- end
13
+ end
@@ -1,48 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EDL
2
-
3
4
  # Is used to parse an EDL
5
+ # Parsing errors are collected in +errors+
4
6
  class Parser
5
-
6
7
  attr_reader :fps
7
-
8
- # Initialize an EDL parser. Pass the FPS to it, as the usual EDL does not contain any kind of reference
8
+ attr_accessor :errors
9
+
10
+ # Initialize an EDL parser. Pass the FPS to it, as the usual EDL does not contain any kind of reference
9
11
  # to it's framerate
10
12
  def initialize(with_fps = DEFAULT_FPS)
11
13
  @fps = with_fps
12
14
  end
13
-
15
+
14
16
  def get_matchers #:nodoc:
15
- [ EventMatcher.new(@fps), EffectMatcher.new, NameMatcher.new, TimewarpMatcher.new(@fps), CommentMatcher.new ]
17
+ [EventMatcher.new(@fps), EffectMatcher.new, NameMatcher.new, TimewarpMatcher.new(@fps), CommentMatcher.new]
16
18
  end
17
-
19
+
18
20
  # Parse a passed File or IO object line by line, or the whole string
19
21
  def parse(input_string_or_io)
20
22
  return parse(StringIO.new(input_string_or_io)) unless input_string_or_io.respond_to?(:read)
21
-
22
- magic = ::EDL::LinebreakMagician.new(input_string_or_io)
23
-
23
+ self.errors = []
24
+
25
+ magic = EDL::LinebreakMagician.new(input_string_or_io)
26
+
24
27
  # Normalize line breaks
25
- stack, matchers = List.new, get_matchers
26
-
28
+ stack = List.new
29
+ matchers = get_matchers
30
+
27
31
  while current_line = magic.gets
28
-
29
- m = matchers.find{|m| m.matches?(current_line) }
30
-
32
+ m = matchers.find { |m| m.matches?(current_line) }
33
+
31
34
  next unless m
32
35
  begin
33
36
  m.apply(stack, current_line)
34
37
  stack[-1].line_number = magic.lineno if m.is_a?(EventMatcher)
35
38
  rescue Matcher::ApplyError => e
36
- STDERR.puts "Cannot parse #{current_line} - #{e}"
39
+ error = "Cannot parse #{current_line} - #{e}"
40
+ errors << error
41
+ STDERR.puts error
37
42
  end
38
43
  end
39
44
  stack
40
45
  end
41
-
46
+
42
47
  # Init a Timecode object from the passed elements with the passed framerate
43
48
  def self.timecode_from_line_elements(elements, fps) #:nodoc:
44
- args = (0..3).map{|_| elements.shift.to_i} + [fps.to_f]
49
+ args = (0..3).map { |_| elements.shift.to_i } + [fps.to_f]
45
50
  Timecode.at(*args)
46
51
  end
47
52
  end
48
- end
53
+ end
@@ -1,24 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EDL
2
4
  # Represents a timewarp. Will be placed in EDL::Event#timewarp
3
5
  # For a reversed clip, the source start we get from the EDL in the src start
4
- # is the LAST used frame. For a pos rate clip, the source start is the bona fide source start. Nice eh?
6
+ # is the LAST used frame. For a pos rate clip, the source start is the bona fide source start. Nice eh?
5
7
  class Timewarp
6
-
7
8
  # What is the actual framerate of the clip (float)
8
9
  attr_accessor :actual_framerate
9
10
  attr_accessor :clip #:nodoc:
10
-
11
+
11
12
  # Does this timewarp reverse the clip?
12
13
  def reverse?
13
14
  @actual_framerate < 0
14
15
  end
15
-
16
+
16
17
  # Get the speed in percent
17
18
  def speed_in_percent
18
19
  (@actual_framerate / @clip.rec_start_tc.fps) * 100
19
20
  end
20
- alias_method :speed, :speed_in_percent
21
-
21
+ alias speed speed_in_percent
22
+
22
23
  # Compute the length of the clip we need to capture. The length is computed in frames and
23
24
  # is always rounded up (better one frame more than one frame less!)
24
25
  def actual_length_of_source
@@ -28,7 +29,7 @@ module EDL
28
29
  factor = @actual_framerate / @clip.rec_start_tc.fps
29
30
  (target_len * factor).ceil.abs
30
31
  end
31
-
32
+
32
33
  # What is the starting frame for the captured clip? If we are a reverse, then the src start of the
33
34
  # clip is our LAST frame, otherwise it's the first
34
35
  def source_used_from
@@ -36,10 +37,10 @@ module EDL
36
37
  compensation = 2
37
38
  reverse? ? (@clip.src_start_tc - actual_length_of_source + compensation) : @clip.src_start_tc
38
39
  end
39
-
40
+
40
41
  # Where to end the capture? This is also dependent on whether we are a reverse or not
41
42
  def source_used_upto
42
43
  source_used_from + actual_length_of_source
43
44
  end
44
45
  end
45
- end
46
+ end
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EDL
2
4
  # Represents a transition. We currently only support dissolves and SMPTE wipes
3
5
  # Will be avilable as EDL::Clip#transition
4
6
  class Transition
5
-
6
7
  # Length of the transition in frames
7
8
  attr_accessor :duration
8
-
9
+
9
10
  # Which effect is used (like CROSS DISSOLVE)
10
11
  attr_accessor :effect
11
12
  end
@@ -16,11 +17,10 @@ module EDL
16
17
 
17
18
  # Represents an SMPTE wipe
18
19
  class Wipe < Transition
19
-
20
20
  # Which SMPTE wipe is needed
21
21
  attr_accessor :smpte_wipe_index
22
22
  end
23
-
23
+
24
24
  class Key < Transition
25
25
  end
26
- end
26
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EDL
4
+ VERSION = '0.1.6'
5
+ end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: edl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2014-03-24 00:00:00.000000000 Z
12
12
  dependencies:
@@ -14,86 +14,44 @@ dependencies:
14
14
  name: timecode
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: shoulda-context
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: test-unit
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '>='
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: jeweler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - '>='
24
+ - - ">="
67
25
  - !ruby/object:Gem::Version
68
26
  version: '0'
69
27
  - !ruby/object:Gem::Dependency
70
28
  name: rake
71
29
  requirement: !ruby/object:Gem::Requirement
72
30
  requirements:
73
- - - '>='
31
+ - - ">="
74
32
  - !ruby/object:Gem::Version
75
33
  version: '0'
76
34
  type: :development
77
35
  prerelease: false
78
36
  version_requirements: !ruby/object:Gem::Requirement
79
37
  requirements:
80
- - - '>='
38
+ - - ">="
81
39
  - !ruby/object:Gem::Version
82
40
  version: '0'
83
41
  - !ruby/object:Gem::Dependency
84
- name: flexmock
42
+ name: rspec
85
43
  requirement: !ruby/object:Gem::Requirement
86
44
  requirements:
87
- - - ~>
45
+ - - "~>"
88
46
  - !ruby/object:Gem::Version
89
- version: 1.3.2
47
+ version: '3.5'
90
48
  type: :development
91
49
  prerelease: false
92
50
  version_requirements: !ruby/object:Gem::Requirement
93
51
  requirements:
94
- - - ~>
52
+ - - "~>"
95
53
  - !ruby/object:Gem::Version
96
- version: 1.3.2
54
+ version: '3.5'
97
55
  description:
98
56
  email: me@julik.nl
99
57
  executables: []
@@ -101,6 +59,11 @@ extensions: []
101
59
  extra_rdoc_files:
102
60
  - README.rdoc
103
61
  files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".ruby-gemset"
65
+ - ".ruby-version"
66
+ - ".travis.yml"
104
67
  - Gemfile
105
68
  - History.txt
106
69
  - README.rdoc
@@ -115,21 +78,7 @@ files:
115
78
  - lib/edl/parser.rb
116
79
  - lib/edl/timewarp.rb
117
80
  - lib/edl/transition.rb
118
- - test/samples/45S_SAMPLE.EDL
119
- - test/samples/FCP_REVERSE.EDL
120
- - test/samples/KEY_TRANSITION.EDL
121
- - test/samples/PLATES.EDL
122
- - test/samples/REEL_IS_CLIP.txt
123
- - test/samples/REVERSE.EDL
124
- - test/samples/SIMPLE_DISSOLVE.EDL
125
- - test/samples/SPEEDUP_AND_FADEOUT.EDL
126
- - test/samples/SPEEDUP_REVERSE_AND_FADEOUT.EDL
127
- - test/samples/SPLICEME.EDL
128
- - test/samples/TIMEWARP.EDL
129
- - test/samples/TIMEWARP_HALF.EDL
130
- - test/samples/TRAILER_EDL.edl
131
- - test/samples/edl_mixed_line_endings.edl
132
- - test/test_edl.rb
81
+ - lib/edl/version.rb
133
82
  homepage: http://guerilla-di.org/edl
134
83
  licenses: []
135
84
  metadata: {}
@@ -139,17 +88,17 @@ require_paths:
139
88
  - lib
140
89
  required_ruby_version: !ruby/object:Gem::Requirement
141
90
  requirements:
142
- - - '>='
91
+ - - ">="
143
92
  - !ruby/object:Gem::Version
144
93
  version: '0'
145
94
  required_rubygems_version: !ruby/object:Gem::Requirement
146
95
  requirements:
147
- - - '>='
96
+ - - ">="
148
97
  - !ruby/object:Gem::Version
149
98
  version: '0'
150
99
  requirements: []
151
100
  rubyforge_project:
152
- rubygems_version: 2.0.3
101
+ rubygems_version: 2.6.11
153
102
  signing_key:
154
103
  specification_version: 4
155
104
  summary: Parser for EDL (Edit Decision List) files