mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Add DASH streams for VP9 transcoding (#3275)
This commit is contained in:
206
vendor/github.com/zencoder/go-dash/v3/mpd/duration.go
generated
vendored
Normal file
206
vendor/github.com/zencoder/go-dash/v3/mpd/duration.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// based on code from golang src/time/time.go
|
||||
|
||||
package mpd
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Duration time.Duration
|
||||
|
||||
var (
|
||||
rStart = "^P" // Must start with a 'P'
|
||||
rDays = "(\\d+D)?" // We only allow Days for durations, not Months or Years
|
||||
rTime = "(?:T" // If there's any 'time' units then they must be preceded by a 'T'
|
||||
rHours = "(\\d+H)?" // Hours
|
||||
rMinutes = "(\\d+M)?" // Minutes
|
||||
rSeconds = "([\\d.]+S)?" // Seconds (Potentially decimal)
|
||||
rEnd = ")?$" // end of regex must close "T" capture group
|
||||
)
|
||||
|
||||
var xmlDurationRegex = regexp.MustCompile(rStart + rDays + rTime + rHours + rMinutes + rSeconds + rEnd)
|
||||
|
||||
func (d Duration) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
|
||||
return xml.Attr{Name: name, Value: d.String()}, nil
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalXMLAttr(attr xml.Attr) error {
|
||||
dur, err := ParseDuration(attr.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = Duration(dur)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String renders a Duration in XML Duration Data Type format
|
||||
func (d *Duration) String() string {
|
||||
// Largest time is 2540400h10m10.000000000s
|
||||
var buf [32]byte
|
||||
w := len(buf)
|
||||
|
||||
u := uint64(*d)
|
||||
neg := *d < 0
|
||||
if neg {
|
||||
u = -u
|
||||
}
|
||||
|
||||
if u < uint64(time.Second) {
|
||||
// Special case: if duration is smaller than a second,
|
||||
// use smaller units, like 1.2ms
|
||||
var prec int
|
||||
w--
|
||||
buf[w] = 'S'
|
||||
w--
|
||||
if u == 0 {
|
||||
return "PT0S"
|
||||
}
|
||||
/*
|
||||
switch {
|
||||
case u < uint64(Millisecond):
|
||||
// print microseconds
|
||||
prec = 3
|
||||
// U+00B5 'µ' micro sign == 0xC2 0xB5
|
||||
w-- // Need room for two bytes.
|
||||
copy(buf[w:], "µ")
|
||||
default:
|
||||
// print milliseconds
|
||||
prec = 6
|
||||
buf[w] = 'm'
|
||||
}
|
||||
*/
|
||||
w, u = fmtFrac(buf[:w], u, prec)
|
||||
w = fmtInt(buf[:w], u)
|
||||
} else {
|
||||
w--
|
||||
buf[w] = 'S'
|
||||
|
||||
w, u = fmtFrac(buf[:w], u, 9)
|
||||
|
||||
// u is now integer seconds
|
||||
w = fmtInt(buf[:w], u%60)
|
||||
u /= 60
|
||||
|
||||
// u is now integer minutes
|
||||
if u > 0 {
|
||||
w--
|
||||
buf[w] = 'M'
|
||||
w = fmtInt(buf[:w], u%60)
|
||||
u /= 60
|
||||
|
||||
// u is now integer hours
|
||||
// Stop at hours because days can be different lengths.
|
||||
if u > 0 {
|
||||
w--
|
||||
buf[w] = 'H'
|
||||
w = fmtInt(buf[:w], u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
w--
|
||||
buf[w] = '-'
|
||||
}
|
||||
|
||||
return "PT" + string(buf[w:])
|
||||
}
|
||||
|
||||
// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the
|
||||
// tail of buf, omitting trailing zeros. it omits the decimal
|
||||
// point too when the fraction is 0. It returns the index where the
|
||||
// output bytes begin and the value v/10**prec.
|
||||
func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) {
|
||||
// Omit trailing zeros up to and including decimal point.
|
||||
w := len(buf)
|
||||
print := false
|
||||
for i := 0; i < prec; i++ {
|
||||
digit := v % 10
|
||||
print = print || digit != 0
|
||||
if print {
|
||||
w--
|
||||
buf[w] = byte(digit) + '0'
|
||||
}
|
||||
v /= 10
|
||||
}
|
||||
if print {
|
||||
w--
|
||||
buf[w] = '.'
|
||||
}
|
||||
return w, v
|
||||
}
|
||||
|
||||
// fmtInt formats v into the tail of buf.
|
||||
// It returns the index where the output begins.
|
||||
func fmtInt(buf []byte, v uint64) int {
|
||||
w := len(buf)
|
||||
if v == 0 {
|
||||
w--
|
||||
buf[w] = '0'
|
||||
} else {
|
||||
for v > 0 {
|
||||
w--
|
||||
buf[w] = byte(v%10) + '0'
|
||||
v /= 10
|
||||
}
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func ParseDuration(str string) (time.Duration, error) {
|
||||
if len(str) < 3 {
|
||||
return 0, errors.New("At least one number and designator are required")
|
||||
}
|
||||
|
||||
if strings.Contains(str, "-") {
|
||||
return 0, errors.New("Duration cannot be negative")
|
||||
}
|
||||
|
||||
// Check that only the parts we expect exist and that everything's in the correct order
|
||||
if !xmlDurationRegex.Match([]byte(str)) {
|
||||
return 0, errors.New("Duration must be in the format: P[nD][T[nH][nM][nS]]")
|
||||
}
|
||||
|
||||
var parts = xmlDurationRegex.FindStringSubmatch(str)
|
||||
var total time.Duration
|
||||
|
||||
if parts[1] != "" {
|
||||
days, err := strconv.Atoi(strings.TrimRight(parts[1], "D"))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Error parsing Days: %s", err)
|
||||
}
|
||||
total += time.Duration(days) * time.Hour * 24
|
||||
}
|
||||
|
||||
if parts[2] != "" {
|
||||
hours, err := strconv.Atoi(strings.TrimRight(parts[2], "H"))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Error parsing Hours: %s", err)
|
||||
}
|
||||
total += time.Duration(hours) * time.Hour
|
||||
}
|
||||
|
||||
if parts[3] != "" {
|
||||
mins, err := strconv.Atoi(strings.TrimRight(parts[3], "M"))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Error parsing Minutes: %s", err)
|
||||
}
|
||||
total += time.Duration(mins) * time.Minute
|
||||
}
|
||||
|
||||
if parts[4] != "" {
|
||||
secs, err := strconv.ParseFloat(strings.TrimRight(parts[4], "S"), 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Error parsing Seconds: %s", err)
|
||||
}
|
||||
total += time.Duration(secs * float64(time.Second))
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
Reference in New Issue
Block a user