streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

commit 14875bf92d627b37f9d33e762f897f9f611d34ec
parent 65ddb6704d4b8a8a8c1dc40ff84556f3c56d1dd9
Author: Oliver Lowe <o@olowe.co>
Date:   Wed,  5 Jun 2024 14:51:01 +1000

m3u8: more validation when writing DateRange tags

In particular: we always need to write ID and Start attributes, and
here are some special rules when EndOnNext is set. This serves as prep for work on

References: https://github.com/untangledco/streaming/issues/19

Diffstat:
Mm3u8/m3u8.go | 1+
Mm3u8/write.go | 32+++++++++++++++++++-------------
2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/m3u8/m3u8.go b/m3u8/m3u8.go @@ -57,6 +57,7 @@ type Segment struct { DateRange *DateRange } +// Key represents the EXT-X-KEY tag specified in RFC 8216 seciton 4.3.2.3. // A Key specifies how to decrypt encrypted playlist segments. type Key struct { Method EncryptMethod diff --git a/m3u8/write.go b/m3u8/write.go @@ -79,20 +79,20 @@ func writeVariant(w io.Writer, v *Variant) (n int, err error) { } func writeDateRange(w io.Writer, dr *DateRange) error { - fmt.Fprint(w, tagDateRange+":") + if dr.ID == "" { + return fmt.Errorf("empty ID") + } else if dr.Start.IsZero() { + return fmt.Errorf("zero start time") + } var attrs []string - if dr.ID != "" { - attrs = append(attrs, fmt.Sprintf("ID=%q", dr.ID)) + attrs = append(attrs, fmt.Sprintf("ID=%q", dr.ID)) + attrs = append(attrs, fmt.Sprintf("START-DATE=%q", dr.Start.Format(time.RFC3339))) + if !dr.End.IsZero() { + attrs = append(attrs, fmt.Sprintf("END-DATE=%q", dr.End.Format(time.RFC3339))) } if dr.Class != "" { attrs = append(attrs, fmt.Sprintf("CLASS=%q", dr.Class)) } - if !dr.Start.IsZero() { - attrs = append(attrs, fmt.Sprintf("START-DATE=%q", dr.Start.Format(time.RFC3339))) - } - if !dr.End.IsZero() { - attrs = append(attrs, fmt.Sprintf("END-DATE=%q", dr.End.Format(time.RFC3339))) - } // TODO(otl): dr.Duration, dr.Planned. Differentiate zero value and user-set zero. // TODO(otl): dr.Custom. // TODO(otl): dr.CueCommand, when to write this versuse cuein, cueout. @@ -111,12 +111,18 @@ func writeDateRange(w io.Writer, dr *DateRange) error { attrs = append(attrs, fmt.Sprintf("SCTE35-OUT=0x%s", hex.EncodeToString(b))) } if dr.EndOnNext { + if dr.Class == "" { + return fmt.Errorf("empty class with end-on-next set") + } else if !dr.End.IsZero() { + return fmt.Errorf("non-zero end time with end-on-next set") + } else if dr.Duration > 0 { + return fmt.Errorf("non-zero duration %s with end-on-next set", dr.Duration) + } attrs = append(attrs, "END-ON-NEXT:YES") } - if _, err := fmt.Fprintln(w, strings.Join(attrs, ",")); err != nil { - return err - } - return nil + tag := tagDateRange + ":" + strings.Join(attrs, ",") + _, err := fmt.Fprintln(w, tag) + return err } func writeMap(w io.Writer, m Map) (n int, err error) {