-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathparse.go
More file actions
82 lines (70 loc) · 2.28 KB
/
parse.go
File metadata and controls
82 lines (70 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package timecode
import (
"errors"
"regexp"
"strconv"
)
// TimecodeRegex is the pattern for a valid SMPTE timecode
var TimecodeRegex = regexp.MustCompile(`^(\d\d)(:|;)(\d\d)(:|;)(\d\d)(:|;)(\d+)$`)
// MustParse parses a timecode from a string, and treats it using the provided frame rate value
func MustParse(timecode string, rate Rate) *Timecode {
tc, err := Parse(timecode, rate)
if err != nil {
panic(err)
}
return tc
}
// Parse parses a timecode from a string, and treats it using the provided frame rate value
func Parse(timecode string, rate Rate) (*Timecode, error) {
// Match it against the regular expression
match := TimecodeRegex.FindStringSubmatch(timecode)
if match == nil {
return nil, errors.New("invalid timecode format")
}
// Get the components
hours, _ := strconv.ParseInt(match[1], 10, 64)
minutes, _ := strconv.ParseInt(match[3], 10, 64)
seconds, _ := strconv.ParseInt(match[5], 10, 64)
frames, _ := strconv.ParseInt(match[7], 10, 64)
// Determine drop frame based on the final separator
dropFrame := match[6] == ";"
// Combine the components
return FromComponents(Components{
hours,
minutes,
seconds,
frames,
}, rate, dropFrame), nil
}
func FromComponents(components Components, rate Rate, dropFrame bool) *Timecode {
// If the rate is drop frame, we need to check that the provided frame
// isn't a dropped frame, which needs to be rounded to the nearest
// valid frame timecode
if dropFrame && (components.Minutes%10 > 0) && (components.Seconds == 0) && (components.Frames < int64(rate.Drop)) {
// Move to the next valid frame in sequence
components.Frames = int64(rate.Drop)
}
// Count the total number of frames in the timecode
totalMinutes := components.Hours*60 + components.Minutes
totalFrames := (totalMinutes*60+components.Seconds)*int64(rate.Nominal) + components.Frames
// If it's drop frame, account for the drop incidents
if dropFrame {
dropFrameIncidents := totalMinutes - totalMinutes/10
if dropFrameIncidents > 0 {
totalFrames -= dropFrameIncidents * int64(rate.Drop)
}
}
// Return the timecode with the total frames
return &Timecode{
frame: totalFrames,
rate: rate,
dropFrame: dropFrame,
}
}
func FromFrame(frame int64, rate Rate, dropFrame bool) *Timecode {
return &Timecode{
frame,
rate,
dropFrame,
}
}