Skip to content
This repository was archived by the owner on Sep 11, 2025. It is now read-only.

Commit cebd585

Browse files
authored
Merge pull request #222 from rbroggi/issue-221
issue-221: test case fails for alternative renditions when #EXT-X-MED…
2 parents ceed8f0 + 4e18189 commit cebd585

3 files changed

Lines changed: 86 additions & 11 deletions

File tree

reader.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ var reKeyValue = regexp.MustCompile(`([a-zA-Z0-9_-]+)=("[^"]+"|[^",]+)`)
2626

2727
// TimeParse allows globally apply and/or override Time Parser function.
2828
// Available variants:
29-
// * FullTimeParse - implements full featured ISO/IEC 8601:2004
30-
// * StrictTimeParse - implements only RFC3339 Nanoseconds format
29+
// - FullTimeParse - implements full featured ISO/IEC 8601:2004
30+
// - StrictTimeParse - implements only RFC3339 Nanoseconds format
3131
var TimeParse func(value string) (time.Time, error) = FullTimeParse
3232

3333
// Decode parses a master playlist passed from the buffer. If `strict`
@@ -78,12 +78,37 @@ func (p *MasterPlaylist) decode(buf *bytes.Buffer, strict bool) error {
7878
return err
7979
}
8080
}
81+
82+
p.attachRenditionsToVariants(state.alternatives)
83+
8184
if strict && !state.m3u {
8285
return errors.New("#EXTM3U absent")
8386
}
8487
return nil
8588
}
8689

90+
func (p *MasterPlaylist) attachRenditionsToVariants(alternatives []*Alternative) {
91+
for _, variant := range p.Variants {
92+
for _, alt := range alternatives {
93+
if alt == nil {
94+
continue
95+
}
96+
if variant.Video != "" && alt.Type == "VIDEO" && variant.Video == alt.GroupId {
97+
variant.Alternatives = append(variant.Alternatives, alt)
98+
}
99+
if variant.Audio != "" && alt.Type == "AUDIO" && variant.Audio == alt.GroupId {
100+
variant.Alternatives = append(variant.Alternatives, alt)
101+
}
102+
if variant.Captions != "" && alt.Type == "CLOSED-CAPTIONS" && variant.Captions == alt.GroupId {
103+
variant.Alternatives = append(variant.Alternatives, alt)
104+
}
105+
if variant.Subtitles != "" && alt.Type == "SUBTITLES" && variant.Subtitles == alt.GroupId {
106+
variant.Alternatives = append(variant.Alternatives, alt)
107+
}
108+
}
109+
}
110+
}
111+
87112
// Decode parses a media playlist passed from the buffer. If `strict`
88113
// parameter is true then return first syntax error.
89114
func (p *MediaPlaylist) Decode(data bytes.Buffer, strict bool) error {
@@ -220,6 +245,7 @@ func decode(buf *bytes.Buffer, strict bool, customDecoders []CustomDecoder) (Pla
220245
}
221246

222247
err = decodeLineOfMasterPlaylist(master, state, line, strict)
248+
master.attachRenditionsToVariants(state.alternatives)
223249
if strict && err != nil {
224250
return master, state.listType, err
225251
}
@@ -336,10 +362,6 @@ func decodeLineOfMasterPlaylist(p *MasterPlaylist, state *decodingState, line st
336362
state.tagStreamInf = true
337363
state.listType = MASTER
338364
state.variant = new(Variant)
339-
if len(state.alternatives) > 0 {
340-
state.variant.Alternatives = state.alternatives
341-
state.alternatives = nil
342-
}
343365
p.Variants = append(p.Variants, state.variant)
344366
for k, v := range decodeParamsLine(line[18:]) {
345367
switch k {

reader_test.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
Playlist parsing tests.
2+
Playlist parsing tests.
33
4-
Copyright 2013-2019 The Project Developers.
5-
See the AUTHORS and LICENSE files at the top-level directory of this distribution
6-
and at https://github.com/grafov/m3u8/
4+
Copyright 2013-2019 The Project Developers.
5+
See the AUTHORS and LICENSE files at the top-level directory of this distribution
6+
and at https://github.com/grafov/m3u8/
77
8-
ॐ तारे तुत्तारे तुरे स्व
8+
ॐ तारे तुत्तारे तुरे स्व
99
*/
1010
package m3u8
1111

@@ -102,6 +102,41 @@ func TestDecodeMasterPlaylistWithAlternatives(t *testing.T) {
102102
// fmt.Println(p.Encode().String())
103103
}
104104

105+
func TestDecodeMasterPlaylistWithAlternativesB(t *testing.T) {
106+
f, err := os.Open("sample-playlists/master-with-alternatives-b.m3u8")
107+
if err != nil {
108+
t.Fatal(err)
109+
}
110+
p := NewMasterPlaylist()
111+
err = p.DecodeFrom(bufio.NewReader(f), false)
112+
if err != nil {
113+
t.Fatal(err)
114+
}
115+
// check parsed values
116+
if p.ver != 3 {
117+
t.Errorf("Version of parsed playlist = %d (must = 3)", p.ver)
118+
}
119+
if len(p.Variants) != 4 {
120+
t.Fatal("not all variants in master playlist parsed")
121+
}
122+
// TODO check other values
123+
for i, v := range p.Variants {
124+
if i == 0 && len(v.Alternatives) != 3 {
125+
t.Fatalf("not all alternatives from #EXT-X-MEDIA parsed (has %d but should be 3", len(v.Alternatives))
126+
}
127+
if i == 1 && len(v.Alternatives) != 3 {
128+
t.Fatalf("not all alternatives from #EXT-X-MEDIA parsed (has %d but should be 3", len(v.Alternatives))
129+
}
130+
if i == 2 && len(v.Alternatives) != 3 {
131+
t.Fatalf("not all alternatives from #EXT-X-MEDIA parsed (has %d but should be 3", len(v.Alternatives))
132+
}
133+
if i == 3 && len(v.Alternatives) > 0 {
134+
t.Fatal("should not be alternatives for this variant")
135+
}
136+
}
137+
// fmt.Println(p.Encode().String())
138+
}
139+
105140
func TestDecodeMasterPlaylistWithClosedCaptionEqNone(t *testing.T) {
106141
f, err := os.Open("sample-playlists/master-with-closed-captions-eq-none.m3u8")
107142
if err != nil {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#EXTM3U
2+
#EXT-X-STREAM-INF:BANDWIDTH=1280000,VIDEO="low"
3+
low/main/audio-video.m3u8
4+
#EXT-X-STREAM-INF:BANDWIDTH=2560000,VIDEO="mid"
5+
mid/main/audio-video.m3u8
6+
#EXT-X-STREAM-INF:BANDWIDTH=7680000,VIDEO="hi"
7+
hi/main/audio-video.m3u8
8+
#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS="mp4a.40.5"
9+
main/audio-only.m3u8
10+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Main",DEFAULT=YES,URI="low/main/audio-video.m3u8"
11+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Centerfield",DEFAULT=NO,URI="low/centerfield/audio-video.m3u8"
12+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Dugout",DEFAULT=NO,URI="low/dugout/audio-video.m3u8"
13+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Main",DEFAULT=YES,URI="mid/main/audio-video.m3u8"
14+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Centerfield",DEFAULT=NO,URI="mid/centerfield/audio-video.m3u8"
15+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Dugout",DEFAULT=NO,URI="mid/dugout/audio-video.m3u8"
16+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Main",DEFAULT=YES,URI="hi/main/audio-video.m3u8"
17+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Centerfield",DEFAULT=NO,URI="hi/centerfield/audio-video.m3u8"
18+
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Dugout",DEFAULT=NO,URI="hi/dugout/audio-video.m3u8"

0 commit comments

Comments
 (0)