Commit Diff


commit - e5a2561859aaf24e6368af6a4e82fc8112bc3d08
commit + 1146e3cfa554e40c95835cd5fd7c65eb7afb40aa
blob - a1b372a4d257e5b477fb38b5925e2734f7f9da01
blob + a71b7f91295d88116f9117e9fd2185a9749e5751
--- m3u8/parse.go
+++ m3u8/parse.go
@@ -70,6 +70,7 @@ func Decode(rd io.Reader) (*Playlist, error) {
 					return p, fmt.Errorf("parse playlist type: %w", err)
 				}
 				p.Type = typ
+
 			case tagTargetDuration:
 				it = <-lex.items
 				dur, err := parseTargetDuration(it)
@@ -77,12 +78,14 @@ func Decode(rd io.Reader) (*Playlist, error) {
 					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
@@ -25,7 +25,7 @@ const (
 )
 
 // 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 {
@@ -38,43 +38,46 @@ func parseSegment(items chan item, leading item) (*Seg
 				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
@@ -2,6 +2,8 @@ package m3u8
 
 import (
 	"encoding/binary"
+	"os"
+	"reflect"
 	"testing"
 	"time"
 )
@@ -93,3 +95,30 @@ func TestWriteKey(t *testing.T) {
 		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)
+	}
+}