commit - e5a2561859aaf24e6368af6a4e82fc8112bc3d08
commit + 1146e3cfa554e40c95835cd5fd7c65eb7afb40aa
blob - a1b372a4d257e5b477fb38b5925e2734f7f9da01
blob + a71b7f91295d88116f9117e9fd2185a9749e5751
--- m3u8/parse.go
+++ m3u8/parse.go
return p, fmt.Errorf("parse playlist type: %w", err)
}
p.Type = typ
+
case tagTargetDuration:
it = <-lex.items
dur, err := parseTargetDuration(it)
return p, fmt.Errorf("parse target duration: %w", err)
}
p.TargetDuration = dur
- case tagSegmentDuration, tagByteRange:
+
+ case tagSegmentDuration, tagByteRange, tagKey:
segment, err := parseSegment(lex.items, it)
if err != nil {
return p, fmt.Errorf("parse segment: %w", err)
}
p.Segments = append(p.Segments, *segment)
+
case tagEndList:
p.End = true
case tagMediaSequence:
blob - 553b404c29bccc04438c237fefeb17266afe3f02
blob + 22fc0b281c644f6e25183ceb6de969d198189b80
--- m3u8/segment.go
+++ m3u8/segment.go
)
// parseSegment returns the next segment from items and the leading
-// item which indecated the start of a segment.
+// item which indicated the start of a segment.
func parseSegment(items chan item, leading item) (*Segment, error) {
var seg Segment
switch leading.typ {
return nil, fmt.Errorf("parse segment duration: %w", err)
}
seg.Duration = dur
+ default:
+ return nil, fmt.Errorf("parse leading item %s: unsupported", leading)
}
}
+
for it := range items {
- if it.typ == itemError {
- return nil, errors.New(it.val)
- }
switch it.typ {
+ case itemError:
+ return nil, errors.New(it.val)
case itemURL:
seg.URI = it.val
return &seg, nil
- case itemTag:
- switch it.val {
- case tagSegmentDuration:
- it = <-items
- dur, err := parseSegmentDuration(it)
- if err != nil {
- return nil, fmt.Errorf("parse segment duration: %w", err)
- }
- seg.Duration = dur
- case tagByteRange:
- it = <-items
- if it.typ != itemString {
- return nil, fmt.Errorf("parse byte range: got %s, want item type string", it)
- }
- r, err := parseByteRange(it.val)
- if err != nil {
- return nil, fmt.Errorf("parse byte range: %w", err)
- }
- seg.Range = r
- case tagDiscontinuity:
- seg.Discontinuity = true
- case tagKey:
- return nil, fmt.Errorf("parsing %s unsupported", it)
- default:
- return nil, fmt.Errorf("parsing %s unsupported", it)
+ case itemNewline:
+ continue
+ default:
+ if it.typ != itemTag {
+ return nil, fmt.Errorf("unexpected %s", it)
}
}
+
+ switch it.val {
+ case tagSegmentDuration:
+ it = <-items
+ dur, err := parseSegmentDuration(it)
+ if err != nil {
+ return nil, fmt.Errorf("parse segment duration: %w", err)
+ }
+ seg.Duration = dur
+ case tagByteRange:
+ it = <-items
+ r, err := parseByteRange(it.val)
+ if err != nil {
+ return nil, fmt.Errorf("parse byte range: %w", err)
+ }
+ seg.Range = r
+ case tagDiscontinuity:
+ seg.Discontinuity = true
+ default:
+ return nil, fmt.Errorf("parsing %s unsupported", it)
+ }
}
return nil, fmt.Errorf("no url")
}
blob - 061e68b153f2260427194b6e0c257d9d62b39428
blob + 40d13ffe7d9e39b9073e50c523d8d9341d1e6072
--- m3u8/segment_test.go
+++ m3u8/segment_test.go
import (
"encoding/binary"
+ "os"
+ "reflect"
"testing"
"time"
)
t.Log("want:", want)
}
}
+
+func TestParseSegment(t *testing.T) {
+ f, err := os.Open("testdata/discontinuities.m3u8")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+
+ plist, err := Decode(f)
+ if err != nil {
+ t.Fatalf("decode playlist: %v", err)
+ }
+
+ encrypted := Segment{
+ Duration: 10 * time.Second,
+ Key: &Key{
+ Method: EncryptMethodAES128,
+ URI: "key1.json?f=1041&s=0&p=1822767&m=1506045858",
+ IV: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1B, 0xD0, 0x2F},
+ },
+ URI: "1041_6_1822767.ts?m=1506045858",
+ }
+
+ if !reflect.DeepEqual(plist.Segments[0], encrypted) {
+ t.Errorf("decode encrypted segment: got %v, want %v", plist.Segments[0], encrypted)
+ }
+}