commit baaea663292b3165b7b67c663676c2f8798c7ce5
parent b113263c7e5e7cb104c5fff7a9c61d0c10db31f4
Author: Oliver Lowe <o@olowe.co>
Date: Tue, 28 May 2024 14:30:14 +1000
m3u8: write all tags, attributes of playlist segments
There were still some that we weren't writing out in m3u8 text format.
Diffstat:
2 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/m3u8/m3u8.go b/m3u8/m3u8.go
@@ -3,8 +3,10 @@
package m3u8
import (
+ "encoding/hex"
"fmt"
"strconv"
+ "strings"
"time"
"github.com/untangledco/streaming/scte35"
@@ -12,6 +14,8 @@ import (
const MimeType string = "application/vnd.apple.mpegurl"
+const RFC3339Milli string = "2006-01-02T15:04:05.999Z07:00"
+
type Playlist struct {
Version int
Segments []Segment
@@ -70,6 +74,24 @@ type Key struct {
IV [16]byte
}
+func (k Key) String() string {
+ var attrs []string
+ attrs = append(attrs, fmt.Sprintf("METHOD=%s", k.Method))
+ attrs = append(attrs, fmt.Sprintf("URI=%q", k.URI))
+ attrs = append(attrs, fmt.Sprintf("IV=0x%s", hex.EncodeToString(k.IV[:])))
+ if k.Format != "" {
+ attrs = append(attrs, fmt.Sprintf("KEYFORMAT=%q", k.Format))
+ }
+ if k.FormatVersions != nil {
+ ss := make([]string, len(k.FormatVersions))
+ for i := range k.FormatVersions {
+ ss[i] = strconv.Itoa(int(k.FormatVersions[i]))
+ }
+ attrs = append(attrs, fmt.Sprintf("KEYFORMATVERSIONS=%q", strings.Join(ss, "/")))
+ }
+ return strings.Join(attrs, ",")
+}
+
type EncryptMethod uint8
const (
diff --git a/m3u8/write.go b/m3u8/write.go
@@ -34,6 +34,18 @@ func Encode(w io.Writer, p *Playlist) error {
return fmt.Errorf("write date range: %w", err)
}
}
+ if seg.Range != [2]int{0, 0} {
+ fmt.Fprintf(w, "%s:%s\n", tagByteRange, seg.Range)
+ }
+ if seg.Key != nil {
+ fmt.Fprintf(w, "%s:%s\n", tagKey, seg.Key)
+ }
+ if seg.Map != nil {
+ writeMap(w, *seg.Map)
+ }
+ if !seg.DateTime.IsZero() {
+ fmt.Fprintf(w, "%s:%s\n", tagDateTime, seg.DateTime.Format(RFC3339Milli))
+ }
us := seg.Duration / time.Microsecond
// we do .03f for the same precision as test-streams.mux.dev.
fmt.Fprintf(w, "%s:%.03f\n", tagSegmentDuration, float32(us)/1e6)
@@ -176,3 +188,10 @@ func writeDateRange(w io.Writer, dr *DateRange) error {
}
return nil
}
+
+func writeMap(w io.Writer, m Map) (n int, err error) {
+ if m.ByteRange != [2]int{0, 0} {
+ return fmt.Fprintf(w, "%s:URI=%q,BYTERANGE=%s\n", tagMap, m.URI, m.ByteRange)
+ }
+ return fmt.Fprintf(w, "%s:URI=%q\n", tagMap, m.URI)
+}