Add DASH streams for VP9 transcoding (#3275)

This commit is contained in:
DingDongSoLong4
2023-03-07 03:57:27 +02:00
committed by GitHub
parent 71e1451c94
commit 2d4384169a
21 changed files with 2118 additions and 34 deletions

206
vendor/github.com/zencoder/go-dash/v3/mpd/duration.go generated vendored Normal file
View 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
}

18
vendor/github.com/zencoder/go-dash/v3/mpd/events.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
package mpd
import "encoding/xml"
type EventStream struct {
XMLName xml.Name `xml:"EventStream"`
SchemeIDURI *string `xml:"schemeIdUri,attr"`
Value *string `xml:"value,attr,omitempty"`
Timescale *uint `xml:"timescale,attr"`
Events []Event `xml:"Event,omitempty"`
}
type Event struct {
XMLName xml.Name `xml:"Event"`
ID *string `xml:"id,attr,omitempty"`
PresentationTime *uint64 `xml:"presentationTime,attr,omitempty"`
Duration *uint64 `xml:"duration,attr,omitempty"`
}

1168
vendor/github.com/zencoder/go-dash/v3/mpd/mpd.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

57
vendor/github.com/zencoder/go-dash/v3/mpd/mpd_attr.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package mpd
type AttrMPD interface {
GetStrptr() *string
}
type attrAvailabilityStartTime struct {
strptr *string
}
func (attr *attrAvailabilityStartTime) GetStrptr() *string {
return attr.strptr
}
// AttrAvailabilityStartTime returns AttrMPD object for NewMPD
func AttrAvailabilityStartTime(value string) AttrMPD {
return &attrAvailabilityStartTime{strptr: &value}
}
type attrMinimumUpdatePeriod struct {
strptr *string
}
func (attr *attrMinimumUpdatePeriod) GetStrptr() *string {
return attr.strptr
}
// AttrMinimumUpdatePeriod returns AttrMPD object for NewMPD
func AttrMinimumUpdatePeriod(value string) AttrMPD {
return &attrMinimumUpdatePeriod{strptr: &value}
}
type attrMediaPresentationDuration struct {
strptr *string
}
func (attr *attrMediaPresentationDuration) GetStrptr() *string {
return attr.strptr
}
// AttrMediaPresentationDuration returns AttrMPD object for NewMPD
func AttrMediaPresentationDuration(value string) AttrMPD {
return &attrMediaPresentationDuration{strptr: &value}
}
type attrPublishTime struct {
strptr *string
}
func (attr *attrPublishTime) GetStrptr() *string {
return attr.strptr
}
// AttrPublishTime returns AttrMPD object for NewMPD
func AttrPublishTime(value string) AttrMPD {
return &attrPublishTime{strptr: &value}
}

View File

@@ -0,0 +1,87 @@
package mpd
import (
"bufio"
"bytes"
"encoding/xml"
"io"
"os"
)
// Reads an MPD XML file from disk into a MPD object.
// path - File path to an MPD on disk
func ReadFromFile(path string) (*MPD, error) {
f, err := os.OpenFile(path, os.O_RDONLY, 0666)
if err != nil {
return nil, err
}
defer f.Close()
return Read(f)
}
// Reads a string into a MPD object.
// xmlStr - MPD manifest data as a string.
func ReadFromString(xmlStr string) (*MPD, error) {
b := bytes.NewBufferString(xmlStr)
return Read(b)
}
// Reads from an io.Reader interface into an MPD object.
// r - Must implement the io.Reader interface.
func Read(r io.Reader) (*MPD, error) {
var mpd MPD
d := xml.NewDecoder(r)
err := d.Decode(&mpd)
if err != nil {
return nil, err
}
return &mpd, nil
}
// Writes an MPD object to a file on disk.
// path - Output path to write the manifest to.
func (m *MPD) WriteToFile(path string) error {
// Open the file to write the XML to
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
if err = m.Write(f); err != nil {
return err
}
if err = f.Sync(); err != nil {
return err
}
return err
}
// Writes an MPD object to a string.
func (m *MPD) WriteToString() (string, error) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
err := m.Write(w)
if err != nil {
return "", err
}
err = w.Flush()
if err != nil {
return "", err
}
return b.String(), err
}
// Writes an MPD object to an io.Writer interface
// w - Must implement the io.Writer interface.
func (m *MPD) Write(w io.Writer) error {
b, err := xml.MarshalIndent(m, "", " ")
if err != nil {
return err
}
_, _ = w.Write([]byte(xml.Header))
_, _ = w.Write(b)
_, _ = w.Write([]byte("\n"))
return nil
}

41
vendor/github.com/zencoder/go-dash/v3/mpd/pssh.go generated vendored Normal file
View File

@@ -0,0 +1,41 @@
package mpd
import (
"bytes"
"encoding/binary"
"fmt"
)
func MakePSSHBox(systemID, payload []byte) ([]byte, error) {
if len(systemID) != 16 {
return nil, fmt.Errorf("SystemID must be 16 bytes, was: %d", len(systemID))
}
psshBuf := &bytes.Buffer{}
size := uint32(12 + 16 + 4 + len(payload)) // 3 uint32s, systemID, "pssh" string and payload
if err := binary.Write(psshBuf, binary.BigEndian, size); err != nil {
return nil, err
}
if err := binary.Write(psshBuf, binary.BigEndian, []byte("pssh")); err != nil {
return nil, err
}
if err := binary.Write(psshBuf, binary.BigEndian, uint32(0)); err != nil {
return nil, err
}
if _, err := psshBuf.Write(systemID); err != nil {
return nil, err
}
if err := binary.Write(psshBuf, binary.BigEndian, uint32(len(payload))); err != nil {
return nil, err
}
if _, err := psshBuf.Write(payload); err != nil {
return nil, err
}
return psshBuf.Bytes(), nil
}

47
vendor/github.com/zencoder/go-dash/v3/mpd/segment.go generated vendored Normal file
View File

@@ -0,0 +1,47 @@
package mpd
type SegmentBase struct {
Initialization *URL `xml:"Initialization,omitempty"`
RepresentationIndex *URL `xml:"RepresentationIndex,omitempty"`
Timescale *uint32 `xml:"timescale,attr,omitempty"`
PresentationTimeOffset *uint64 `xml:"presentationTimeOffset,attr,omitempty"`
IndexRange *string `xml:"indexRange,attr,omitempty"`
IndexRangeExact *bool `xml:"indexRangeExact,attr,omitempty"`
AvailabilityTimeOffset *float32 `xml:"availabilityTimeOffset,attr,omitempty"`
AvailabilityTimeComplete *bool `xml:"availabilityTimeComplete,attr,omitempty"`
}
type MultipleSegmentBase struct {
SegmentBase
SegmentTimeline *SegmentTimeline `xml:"SegmentTimeline,omitempty"`
BitstreamSwitching *URL `xml:"BitstreamSwitching,omitempty"`
Duration *uint32 `xml:"duration,attr,omitempty"`
StartNumber *uint32 `xml:"startNumber,attr,omitempty"`
}
type SegmentList struct {
MultipleSegmentBase
SegmentURLs []*SegmentURL `xml:"SegmentURL,omitempty"`
}
type SegmentURL struct {
Media *string `xml:"media,attr,omitempty"`
MediaRange *string `xml:"mediaRange,attr,omitempty"`
Index *string `xml:"index,attr,omitempty"`
IndexRange *string `xml:"indexRange,attr,omitempty"`
}
type SegmentTimeline struct {
Segments []*SegmentTimelineSegment `xml:"S,omitempty"`
}
type SegmentTimelineSegment struct {
StartTime *uint64 `xml:"t,attr,omitempty"`
Duration uint64 `xml:"d,attr"`
RepeatCount *int `xml:"r,attr,omitempty"`
}
type URL struct {
SourceURL *string `xml:"sourceURL,attr,omitempty"`
Range *string `xml:"range,attr,omitempty"`
}

View File

@@ -0,0 +1,9 @@
package mpd
// Validate checks for incomplete MPD object
func (m *MPD) Validate() error {
if m.Profiles == nil {
return ErrNoDASHProfileSet
}
return nil
}