commit c0e0995563ad5bbb07ebdf0be7dbd67aed858ee0
parent cfe53d45307ceb8e8d49b2d1a0ed1c6396c20340
Author: Oliver Lowe <o@olowe.co>
Date: Sat, 1 Jun 2024 17:35:57 +1000
m3u8: clearly separate master, media playlists with a separtate source file
I kept getting lost when looking for certain stuff when working on
master playlists versus media playlists. Resolves
https://github.com/untangledco/streaming/issues/17
Diffstat:
| M | m3u8/m3u8.go | | | 142 | +++---------------------------------------------------------------------------- |
| A | m3u8/master.go | | | 138 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 142 insertions(+), 138 deletions(-)
diff --git a/m3u8/m3u8.go b/m3u8/m3u8.go
@@ -17,8 +17,10 @@ const MimeType string = "application/vnd.apple.mpegurl"
const RFC3339Milli string = "2006-01-02T15:04:05.999Z07:00"
type Playlist struct {
- Version int
- Segments []Segment
+ Version int
+ Segments []Segment
+ IndependentSegments bool
+ Start *StartPoint
// Media playlist
// RFC 8216, 4.4.3.1
@@ -34,10 +36,6 @@ type Playlist struct {
Variants []Variant
SessionData []SessionData
SessionKey *Key
-
- // Both Media and Master playlists.
- IndependentSegments bool
- Start *StartPoint
}
type Segment struct {
@@ -171,135 +169,3 @@ type StartPoint struct {
Offset float32
Precise bool
}
-
-// Rendition represents a unique rendition as described by a single
-// EXT-X-MEDIA tag.
-type Rendition struct {
- Type MediaType
- URI string
- Group string
- Language string
- AssocLanguage string
- Name string
- Default bool
- AutoSelect bool
- Forced bool
- InstreamID *CCInfo
- Characteristics []string
- Channels []string
-}
-
-type MediaType uint8
-
-const (
- MediaAudio MediaType = 0 + iota
- MediaVideo
- MediaSubtitles
- MediaClosedCaptions
-)
-
-func (t MediaType) String() string {
- switch t {
- case MediaAudio:
- return "AUDIO"
- case MediaVideo:
- return "VIDEO"
- case MediaSubtitles:
- return "SUBTITLES"
- case MediaClosedCaptions:
- return "CLOSED-CAPTIONS"
- }
- return "invalid"
-}
-
-type CCInfo struct {
- ID int
- Service bool
-}
-
-func (info *CCInfo) String() string {
- if info.Service {
- return fmt.Sprintf("%s%d", "SERVICE", info.ID)
- }
- return fmt.Sprintf("%s%d", "CC", info.ID)
-}
-
-const (
- CharacteristicTranscribesDialog = "public.accessibility.transcribes-spoken-dialog"
- CharacteristicDescribesMusicAndSound = "public.accessibility.transcribes-spoken-dialog"
- ChractersticEasyToRead = "public.easy-to-read"
- CharacteristicDescribesVideo = "public.accessibility.describes-video"
-)
-
-// EXT-X-STREAM-INF 4.3.4.2
-type Variant struct {
- URI string
- Bandwidth int
- AverageBandwidth int
- Codecs []string
- Resolution [2]int
- FrameRate float32
- HDCP HDCPLevel
- Audio string
- Video string
- Subtitles string
- // May be NoClosedCaptions or the empty string to indicate
- // absence of closed captions.
- ClosedCaptions string
-}
-
-// NoClosedCaptions may be the value for Variant.ClosedCaptions to
-// explicitly indicate that no closed captions are available for the
-// Variant.
-const NoClosedCaptions string = "NONE"
-
-type HDCPLevel uint8
-
-const (
- HDCPNone HDCPLevel = 0 + iota
- HDCPType0
- HDCPType1
-)
-
-func (l HDCPLevel) String() string {
- switch l {
- case HDCPNone:
- return "NONE"
- case HDCPType0:
- return "TYPE-0"
- case HDCPType1:
- return "TYPE-1"
- }
- return "unknown"
-}
-
-// IFrameInfo represents the EXT-X-I-FRAME-STREAM-INF tag.
-// It has the same structure as Variant, but the following fields should be unset:
-// - FrameRate
-// - Audio
-// - Subtitles
-// - ClosedCaptions
-type IFrameInfo Variant
-
-// SessionData represents the EXT-X-SESSION-DATA tag.
-type SessionData struct {
- ID string // This attribute is REQUIRED
- Value string // MUST contain either a VALUE or URI attribute, but not both
- URI string
- Language string // This attribute is OPTIONAL.
-}
-
-func (sd SessionData) String() string {
- var attrs []string
- attrs = append(attrs, fmt.Sprintf("DATA-ID=%q", sd.ID))
- if sd.Value != "" {
- attrs = append(attrs, fmt.Sprintf("VALUE=%q", sd.Value))
- }
- if sd.URI != "" {
- attrs = append(attrs, fmt.Sprintf("URI=%q", sd.URI))
- }
- if sd.Language != "" {
- attrs = append(attrs, fmt.Sprintf("LANGUAGE=%q", sd.Language))
- }
- return strings.Join(attrs, ",")
-}
diff --git a/m3u8/master.go b/m3u8/master.go
@@ -0,0 +1,138 @@
+package m3u8
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Rendition represents a unique rendition as described by a single
+// EXT-X-MEDIA tag.
+type Rendition struct {
+ Type MediaType
+ URI string
+ Group string
+ Language string
+ AssocLanguage string
+ Name string
+ Default bool
+ AutoSelect bool
+ Forced bool
+ InstreamID *CCInfo
+ Characteristics []string
+ Channels []string
+}
+
+type MediaType uint8
+
+const (
+ MediaAudio MediaType = 0 + iota
+ MediaVideo
+ MediaSubtitles
+ MediaClosedCaptions
+)
+
+func (t MediaType) String() string {
+ switch t {
+ case MediaAudio:
+ return "AUDIO"
+ case MediaVideo:
+ return "VIDEO"
+ case MediaSubtitles:
+ return "SUBTITLES"
+ case MediaClosedCaptions:
+ return "CLOSED-CAPTIONS"
+ }
+ return "invalid"
+}
+
+type CCInfo struct {
+ ID int
+ Service bool
+}
+
+func (info *CCInfo) String() string {
+ if info.Service {
+ return fmt.Sprintf("%s%d", "SERVICE", info.ID)
+ }
+ return fmt.Sprintf("%s%d", "CC", info.ID)
+}
+
+const (
+ CharacteristicTranscribesDialog = "public.accessibility.transcribes-spoken-dialog"
+ CharacteristicDescribesMusicAndSound = "public.accessibility.transcribes-spoken-dialog"
+ ChractersticEasyToRead = "public.easy-to-read"
+ CharacteristicDescribesVideo = "public.accessibility.describes-video"
+)
+
+// EXT-X-STREAM-INF 4.3.4.2
+type Variant struct {
+ URI string
+ Bandwidth int
+ AverageBandwidth int
+ Codecs []string
+ Resolution [2]int
+ FrameRate float32
+ HDCP HDCPLevel
+ Audio string
+ Video string
+ Subtitles string
+ // May be NoClosedCaptions or the empty string to indicate
+ // absence of closed captions.
+ ClosedCaptions string
+}
+
+// NoClosedCaptions may be the value for Variant.ClosedCaptions to
+// explicitly indicate that no closed captions are available for the
+// Variant.
+const NoClosedCaptions string = "NONE"
+
+type HDCPLevel uint8
+
+const (
+ HDCPNone HDCPLevel = 0 + iota
+ HDCPType0
+ HDCPType1
+)
+
+func (l HDCPLevel) String() string {
+ switch l {
+ case HDCPNone:
+ return "NONE"
+ case HDCPType0:
+ return "TYPE-0"
+ case HDCPType1:
+ return "TYPE-1"
+ }
+ return "unknown"
+}
+
+// IFrameInfo represents the EXT-X-I-FRAME-STREAM-INF tag.
+// It has the same structure as Variant, but the following fields should be unset:
+// - FrameRate
+// - Audio
+// - Subtitles
+// - ClosedCaptions
+type IFrameInfo Variant
+
+// SessionData represents the EXT-X-SESSION-DATA tag.
+type SessionData struct {
+ ID string // This attribute is REQUIRED
+ Value string // MUST contain either a VALUE or URI attribute, but not both
+ URI string
+ Language string // This attribute is OPTIONAL.
+}
+
+func (sd SessionData) String() string {
+ var attrs []string
+ attrs = append(attrs, fmt.Sprintf("DATA-ID=%q", sd.ID))
+ if sd.Value != "" {
+ attrs = append(attrs, fmt.Sprintf("VALUE=%q", sd.Value))
+ }
+ if sd.URI != "" {
+ attrs = append(attrs, fmt.Sprintf("URI=%q", sd.URI))
+ }
+ if sd.Language != "" {
+ attrs = append(attrs, fmt.Sprintf("LANGUAGE=%q", sd.Language))
+ }
+ return strings.Join(attrs, ",")
+}