timecode 0.2.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.DS_Store +0 -0
- data/.gemtest +0 -0
- data/History.txt +12 -0
- data/Manifest.txt +4 -3
- data/{README.txt → README.rdoc} +0 -0
- data/Rakefile +5 -3
- data/{SPECS.txt → SPECS.rdoc} +5 -1
- data/lib/timecode.rb +39 -5
- data/test/test_timecode.rb +34 -1
- metadata +42 -28
data/.DS_Store
ADDED
Binary file
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
=== 1.1.0 / 2011-02-16
|
2
|
+
|
3
|
+
* Added timecode with ticks support, used by CineCanvas (wolfgangw)
|
4
|
+
|
5
|
+
=== 1.0.0 / 2011-02-16
|
6
|
+
|
7
|
+
* After all these years we consider Timecode stable
|
8
|
+
|
9
|
+
=== 0.3.0 / 2010-10-25
|
10
|
+
|
11
|
+
* Let Timecode.parse and Timecode#to_s handle 24fps timecode with a plus sign (00:00:00+10)
|
12
|
+
|
1
13
|
=== 0.2.1 / 2010-05-11
|
2
14
|
|
3
15
|
* Add Timecode#coerce and Timecode#adjacent_to?
|
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
File without changes
|
data/Rakefile
CHANGED
@@ -4,13 +4,15 @@ require './lib/timecode.rb'
|
|
4
4
|
|
5
5
|
Hoe.spec('timecode') do |p|
|
6
6
|
p.version = Timecode::VERSION
|
7
|
+
p.readme_file = 'README.rdoc'
|
8
|
+
p.extra_rdoc_files = FileList['*.rdoc']
|
9
|
+
|
7
10
|
p.developer('Julik', 'me@julik.nl')
|
8
|
-
p.
|
9
|
-
p.extra_deps << ['test-spec', '>=0']
|
11
|
+
p.extra_dev_deps = {"test-spec" => ">=0"}
|
10
12
|
p.rubyforge_name = 'guerilla-di'
|
11
13
|
p.remote_rdoc_dir = 'timecode'
|
12
14
|
end
|
13
15
|
|
14
16
|
task "specs" do
|
15
|
-
`specrb test/* --rdox > SPECS.
|
17
|
+
`specrb test/* --rdox > SPECS.rdoc`
|
16
18
|
end
|
data/{SPECS.txt → SPECS.rdoc}
RENAMED
@@ -85,7 +85,11 @@
|
|
85
85
|
|
86
86
|
== Timecode.parse should
|
87
87
|
* handle complete SMPTE timecode
|
88
|
+
* handle complete SMPTE timecode with plus for 24 frames per second
|
88
89
|
* handle timecode with fractional seconds
|
90
|
+
* handle timecode with ticks
|
91
|
+
* raise when there are more than 249 ticks
|
92
|
+
* handle timecode with fractional seconds with spaces at start and end
|
89
93
|
* parse a row of numbers as parts of a timecode starting from the right
|
90
94
|
* parse a number with f suffix as frames
|
91
95
|
* parse a number with s suffix as seconds
|
@@ -109,4 +113,4 @@
|
|
109
113
|
* parse from a 4x4bits packed 32bit unsigned int
|
110
114
|
* properly convert itself back to 4x4 bits 32bit unsigned int
|
111
115
|
|
112
|
-
|
116
|
+
78 specifications (124 requirements), 0 failures
|
data/lib/timecode.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
# :mapping => [%w(source_tc_frames total), %w(tape_fps fps)]
|
13
13
|
|
14
14
|
class Timecode
|
15
|
-
VERSION = '
|
15
|
+
VERSION = '1.1.0'
|
16
16
|
|
17
17
|
include Comparable
|
18
18
|
|
@@ -20,14 +20,19 @@ class Timecode
|
|
20
20
|
|
21
21
|
#:stopdoc:
|
22
22
|
NTSC_FPS = (30.0 * 1000 / 1001).freeze
|
23
|
+
FILMSYNC_FPS = (24.0 * 1000 / 1001).freeze
|
23
24
|
ALLOWED_FPS_DELTA = (0.001).freeze
|
24
25
|
|
25
26
|
COMPLETE_TC_RE = /^(\d{2}):(\d{2}):(\d{2}):(\d{2})$/
|
27
|
+
COMPLETE_TC_RE_24 = /^(\d{2}):(\d{2}):(\d{2})\+(\d{2})$/
|
26
28
|
DF_TC_RE = /^(\d{1,2}):(\d{1,2}):(\d{1,2});(\d{2})$/
|
27
|
-
FRACTIONAL_TC_RE = /^(\d{2}):(\d{2}):(\d{2})
|
29
|
+
FRACTIONAL_TC_RE = /^(\d{2}):(\d{2}):(\d{2})\.(\d{1,8})$/
|
30
|
+
TICKS_TC_RE = /^(\d{2}):(\d{2}):(\d{2}):(\d{3})$/
|
28
31
|
|
29
32
|
WITH_FRACTIONS_OF_SECOND = "%02d:%02d:%02d.%02d"
|
30
33
|
WITH_FRAMES = "%02d:%02d:%02d:%02d"
|
34
|
+
WITH_FRAMES_24 = "%02d:%02d:%02d+%02d"
|
35
|
+
|
31
36
|
#:startdoc:
|
32
37
|
|
33
38
|
# All Timecode lib errors inherit from this
|
@@ -76,7 +81,9 @@ class Timecode
|
|
76
81
|
# * 10h 20m 10s 1f (or any combination thereof) - will be disassembled to hours, frames, seconds and so on automatically
|
77
82
|
# * 123 - will be parsed as 00:00:01:23
|
78
83
|
# * 00:00:00:00 - will be parsed as zero TC
|
79
|
-
def parse(
|
84
|
+
def parse(spaced_input, with_fps = DEFAULT_FPS)
|
85
|
+
input = spaced_input.strip
|
86
|
+
|
80
87
|
# Drop frame goodbye
|
81
88
|
if (input =~ DF_TC_RE)
|
82
89
|
raise Error, "We do not support drop-frame TC"
|
@@ -84,9 +91,16 @@ class Timecode
|
|
84
91
|
elsif (input =~ COMPLETE_TC_RE)
|
85
92
|
atoms_and_fps = input.scan(COMPLETE_TC_RE).to_a.flatten.map{|e| e.to_i} + [with_fps]
|
86
93
|
return at(*atoms_and_fps)
|
94
|
+
# 00:00:00+00
|
95
|
+
elsif (input =~ COMPLETE_TC_RE_24)
|
96
|
+
atoms_and_fps = input.scan(COMPLETE_TC_RE_24).to_a.flatten.map{|e| e.to_i} + [24]
|
97
|
+
return at(*atoms_and_fps)
|
87
98
|
# 00:00:00.0
|
88
99
|
elsif input =~ FRACTIONAL_TC_RE
|
89
100
|
parse_with_fractional_seconds(input, with_fps)
|
101
|
+
# 00:00:00:000
|
102
|
+
elsif input =~ TICKS_TC_RE
|
103
|
+
parse_with_ticks(input, with_fps)
|
90
104
|
# 10h 20m 10s 1f 00:00:00:01 - space separated is a sum of parts
|
91
105
|
elsif input =~ /\s/
|
92
106
|
parts = input.gsub(/\s/, ' ').split.reject{|e| e.strip.empty? }
|
@@ -150,6 +164,22 @@ class Timecode
|
|
150
164
|
|
151
165
|
parse(tc_with_frameno, fps)
|
152
166
|
end
|
167
|
+
|
168
|
+
# Parse a timecode with ticks of a second instead of frames. A 'tick' is defined as
|
169
|
+
# 4 msec and has a range of 0 to 249. This format can show up in subtitle files for digital cinema
|
170
|
+
# used by CineCanvas systems
|
171
|
+
def parse_with_ticks(tc_with_ticks, fps = DEFAULT_FPS)
|
172
|
+
ticks_expr = /(\d{3})$/
|
173
|
+
num_ticks = tc_with_ticks.scan(ticks_expr).to_s.to_i
|
174
|
+
|
175
|
+
raise RangeError, "Invalid tick count #{num_ticks}" if num_ticks > 249
|
176
|
+
|
177
|
+
seconds_per_frame = 1.0 / fps
|
178
|
+
frame_idx = ( (num_ticks * 0.004) / seconds_per_frame ).floor
|
179
|
+
tc_with_frameno = tc_with_ticks.gsub(ticks_expr, "%02d" % frame_idx)
|
180
|
+
|
181
|
+
parse(tc_with_frameno, fps)
|
182
|
+
end
|
153
183
|
|
154
184
|
# create a timecode from the number of seconds. This is how current time is supplied by
|
155
185
|
# QuickTime and other systems which have non-frame-based timescales
|
@@ -248,7 +278,11 @@ class Timecode
|
|
248
278
|
|
249
279
|
# get formatted SMPTE timecode
|
250
280
|
def to_s
|
251
|
-
|
281
|
+
if (framerate_in_delta(fps, 24))
|
282
|
+
WITH_FRAMES_24 % value_parts
|
283
|
+
else
|
284
|
+
WITH_FRAMES % value_parts
|
285
|
+
end
|
252
286
|
end
|
253
287
|
|
254
288
|
# get total frames as float
|
@@ -352,4 +386,4 @@ class Timecode
|
|
352
386
|
@value ||= validate!
|
353
387
|
end
|
354
388
|
|
355
|
-
end
|
389
|
+
end
|
data/test/test_timecode.rb
CHANGED
@@ -297,7 +297,7 @@ context "A Timecode used with fractional number of seconds" do
|
|
297
297
|
tc.with_frames_as_fraction.should.equal "00:00:03.96"
|
298
298
|
tc.with_fractional_seconds.should.equal "00:00:03.96"
|
299
299
|
end
|
300
|
-
|
300
|
+
|
301
301
|
specify "properly translate to frames when instantiated from fractional seconds" do
|
302
302
|
fraction = 7.1
|
303
303
|
tc = Timecode.from_seconds(fraction, 10)
|
@@ -348,11 +348,44 @@ context "Timecode.parse should" do
|
|
348
348
|
Timecode.parse(simple_tc).to_s.should.equal(simple_tc)
|
349
349
|
end
|
350
350
|
|
351
|
+
specify "handle complete SMPTE timecode with plus for 24 frames per second" do
|
352
|
+
simple_tc = "00:10:34+10"
|
353
|
+
p = Timecode.parse(simple_tc)
|
354
|
+
p.to_s.should.equal(simple_tc)
|
355
|
+
p.fps.should.equal 24
|
356
|
+
end
|
357
|
+
|
351
358
|
specify "handle timecode with fractional seconds" do
|
352
359
|
tc = Timecode.parse("10:10:10.2", 25)
|
353
360
|
tc.to_s.should.equal "10:10:10:05"
|
354
361
|
end
|
355
362
|
|
363
|
+
specify "handle timecode with ticks" do
|
364
|
+
tc = Timecode.parse("10:10:10:103", 25)
|
365
|
+
tc.to_s.should.equal "10:10:10:10"
|
366
|
+
|
367
|
+
tc = Timecode.parse("10:10:10:249", 25)
|
368
|
+
tc.to_s.should.equal "10:10:10:24"
|
369
|
+
end
|
370
|
+
|
371
|
+
specify "raise when there are more than 249 ticks" do
|
372
|
+
lambda {
|
373
|
+
tc = Timecode.parse("10:10:10:250", 25)
|
374
|
+
}.should.raise(Timecode::RangeError)
|
375
|
+
end
|
376
|
+
|
377
|
+
specify "handle timecode with fractional seconds with spaces at start and end" do
|
378
|
+
tc = Timecode.parse(" 00:00:01.040 ")
|
379
|
+
tc.to_s.should.equal "00:00:01:01"
|
380
|
+
end
|
381
|
+
|
382
|
+
# I am commenting this one out for now, these were present in some odd subtitle file.
|
383
|
+
# What we probably need is a way for Timecode to "extract" timecodes from a chunk of text.
|
384
|
+
# specify "handle timecode with fractional seconds with weirdo UTF spaces at start and end" do
|
385
|
+
# tc = Timecode.parse("00:00:01.040")
|
386
|
+
# tc.to_s.should.equal "00:00:01:01"
|
387
|
+
# end
|
388
|
+
|
356
389
|
specify "parse a row of numbers as parts of a timecode starting from the right" do
|
357
390
|
Timecode.parse("10").should.equal Timecode.new(10)
|
358
391
|
Timecode.parse("210").should.equal Timecode.new(60)
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timecode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 1.1.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Julik
|
@@ -9,39 +15,39 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2011-05-15 00:00:00 +02:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: test-spec
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
23
32
|
version: "0"
|
24
|
-
version:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: rubyforge
|
27
33
|
type: :development
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 2.0.4
|
34
|
-
version:
|
34
|
+
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: hoe
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
|
43
|
+
hash: 41
|
44
|
+
segments:
|
45
|
+
- 2
|
46
|
+
- 9
|
47
|
+
- 1
|
48
|
+
version: 2.9.1
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
45
51
|
description: Value class for SMPTE timecode information
|
46
52
|
email:
|
47
53
|
- me@julik.nl
|
@@ -52,16 +58,18 @@ extensions: []
|
|
52
58
|
extra_rdoc_files:
|
53
59
|
- History.txt
|
54
60
|
- Manifest.txt
|
55
|
-
- README.
|
56
|
-
- SPECS.
|
61
|
+
- README.rdoc
|
62
|
+
- SPECS.rdoc
|
57
63
|
files:
|
64
|
+
- .DS_Store
|
58
65
|
- History.txt
|
59
66
|
- Manifest.txt
|
60
|
-
- README.
|
61
|
-
- SPECS.txt
|
67
|
+
- README.rdoc
|
62
68
|
- Rakefile
|
69
|
+
- SPECS.rdoc
|
63
70
|
- lib/timecode.rb
|
64
71
|
- test/test_timecode.rb
|
72
|
+
- .gemtest
|
65
73
|
has_rdoc: true
|
66
74
|
homepage: http://guerilla-di.org/timecode
|
67
75
|
licenses: []
|
@@ -69,25 +77,31 @@ licenses: []
|
|
69
77
|
post_install_message:
|
70
78
|
rdoc_options:
|
71
79
|
- --main
|
72
|
-
- README.
|
80
|
+
- README.rdoc
|
73
81
|
require_paths:
|
74
82
|
- lib
|
75
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
76
85
|
requirements:
|
77
86
|
- - ">="
|
78
87
|
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
79
91
|
version: "0"
|
80
|
-
version:
|
81
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
82
94
|
requirements:
|
83
95
|
- - ">="
|
84
96
|
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
85
100
|
version: "0"
|
86
|
-
version:
|
87
101
|
requirements: []
|
88
102
|
|
89
103
|
rubyforge_project: guerilla-di
|
90
|
-
rubygems_version: 1.
|
104
|
+
rubygems_version: 1.4.1
|
91
105
|
signing_key:
|
92
106
|
specification_version: 3
|
93
107
|
summary: Value class for SMPTE timecode information
|