diff --git a/reader.go b/reader.go index b19324eb..caf021bc 100644 --- a/reader.go +++ b/reader.go @@ -708,6 +708,15 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l state.scte.Elapsed, _ = strconv.ParseFloat(value, 64) } } + case !state.tagSCTE35 && strings.HasPrefix(line, "#EXT-X-CUE-OUT"): + state.tagSCTE35 = true + state.scte = new(SCTE) + state.scte.Syntax = SCTE35_OATCLS + state.scte.CueType = SCTE35Cue_Start + lenLine := len(line) + if lenLine > 14 { + state.scte.Time, _ = strconv.ParseFloat(line[15:], 64) + } case !state.tagSCTE35 && line == "#EXT-X-CUE-IN": state.tagSCTE35 = true state.scte = new(SCTE) diff --git a/reader_test.go b/reader_test.go index 8d60b16c..ead4e55c 100644 --- a/reader_test.go +++ b/reader_test.go @@ -972,6 +972,41 @@ func TestDecodeMediaPlaylistStartTime(t *testing.T) { } } +func TestDecodeMediaPlaylistWithCueOutCueIn(t *testing.T) { + f, err := os.Open("sample-playlists/media-playlist-with-cue-out-in-without-oatcls.m3u8") + if err != nil { + t.Fatal(err) + } + p, listType, err := DecodeFrom(bufio.NewReader(f), true) + if err != nil { + t.Fatal(err) + } + pp := p.(*MediaPlaylist) + CheckType(t, pp) + if listType != MEDIA { + t.Error("Sample not recognized as media playlist.") + } + + if pp.Segments[5].SCTE.CueType != SCTE35Cue_Start { + t.Errorf("EXT-CUE-OUT must result in SCTE35Cue_Start") + } + if pp.Segments[5].SCTE.Time != 0 { + t.Errorf("EXT-CUE-OUT without duration must not have Time set") + } + if pp.Segments[9].SCTE.CueType != SCTE35Cue_End { + t.Errorf("EXT-CUE-IN must result in SCTE35Cue_End") + } + if pp.Segments[30].SCTE.CueType != SCTE35Cue_Start { + t.Errorf("EXT-CUE-OUT must result in SCTE35Cue_Start") + } + if pp.Segments[30].SCTE.Time != 180 { + t.Errorf("EXT-CUE-OUT:180.0 must have time set to 180") + } + if pp.Segments[60].SCTE.CueType != SCTE35Cue_End { + t.Errorf("EXT-CUE-IN must result in SCTE35Cue_End") + } +} + /**************** * Benchmarks * ****************/ diff --git a/sample-playlists/media-playlist-with-cue-out-in-without-oatcls.m3u8 b/sample-playlists/media-playlist-with-cue-out-in-without-oatcls.m3u8 new file mode 100644 index 00000000..569072ef --- /dev/null +++ b/sample-playlists/media-playlist-with-cue-out-in-without-oatcls.m3u8 @@ -0,0 +1,136 @@ +#EXTM3U +#EXT-X-VERSION:4 +#EXT-X-MEDIA-SEQUENCE:275163116 +#EXT-X-INDEPENDENT-SEGMENTS +#EXT-X-TARGETDURATION:9 +#USP-X-TIMESTAMP-MAP:MPEGTS=7984482175,LOCAL=2022-04-26T13:11:31.333300Z +#EXTINF:6, no desc +364992-275163141.ts +#EXTINF:5.1666, no desc +364992-275163142.ts +#EXT-X-CUE-IN +#EXTINF:6.8333, no desc +364992-275163143.ts +#EXTINF:6, no desc +364992-275163144.ts +#EXTINF:6, no desc +364992-275163150.ts +#EXT-X-CUE-OUT +#EXTINF:6, no desc +364992-275163151.ts +#EXTINF:6, no desc +364992-275163152.ts +#EXTINF:6, no desc +364992-275163153.ts +#EXTINF:6, no desc +364992-275163154.ts +#EXT-X-CUE-IN +#EXTINF:6, no desc +364992-275163155.ts +#EXTINF:6, no desc +364992-275163156.ts +#EXTINF:6, no desc +364992-275163157.ts +#EXTINF:6, no desc +364992-275163158.ts +#EXTINF:6, no desc +364992-275163159.ts +#EXTINF:6, no desc +364992-275163160.ts +#EXTINF:6, no desc +364992-275163161.ts +#EXTINF:6, no desc +364992-275163162.ts +#EXTINF:6, no desc +364992-275163163.ts +#EXTINF:6, no desc +364992-275163164.ts +#EXTINF:6, no desc +364992-275163165.ts +#EXTINF:6, no desc +364992-275163166.ts +#EXTINF:6, no desc +364992-275163167.ts +#EXTINF:6, no desc +364992-275163168.ts +#EXTINF:6, no desc +364992-275163169.ts +#EXTINF:6, no desc +364992-275163170.ts +#EXTINF:6, no desc +364992-275163171.ts +#EXTINF:6, no desc +364992-275163172.ts +#EXTINF:6, no desc +364992-275163173.ts +#EXTINF:6, no desc +364992-275163174.ts +#EXTINF:5.2, no desc +364992-275163175.ts +#EXT-X-CUE-OUT:180 +#EXTINF:6.8, no desc +364992-275163176.ts +#EXTINF:6, no desc +364992-275163177.ts +#EXTINF:6, no desc +364992-275163178.ts +#EXTINF:6, no desc +364992-275163179.ts +#EXTINF:6, no desc +364992-275163180.ts +#EXTINF:6, no desc +364992-275163181.ts +#EXTINF:6, no desc +364992-275163182.ts +#EXTINF:6, no desc +364992-275163183.ts +#EXTINF:6, no desc +364992-275163184.ts +#EXTINF:6, no desc +364992-275163185.ts +#EXTINF:6, no desc +364992-275163186.ts +#EXTINF:6, no desc +364992-275163187.ts +#EXTINF:6, no desc +364992-275163188.ts +#EXTINF:6, no desc +364992-275163189.ts +#EXTINF:5.2, no desc +364992-275163190.ts +#EXTINF:6.8, no desc +364992-275163191.ts +#EXTINF:6, no desc +364992-275163192.ts +#EXTINF:6, no desc +364992-275163193.ts +#EXTINF:6, no desc +364992-275163194.ts +#EXTINF:6, no desc +364992-275163195.ts +#EXTINF:6, no desc +364992-275163196.ts +#EXTINF:6, no desc +364992-275163197.ts +#EXTINF:6, no desc +364992-275163198.ts +#EXTINF:6, no desc +364992-275163199.ts +#EXTINF:5.2, no desc +364992-275163200.ts +#EXTINF:6.8, no desc +364992-275163201.ts +#EXTINF:6, no desc +364992-275163202.ts +#EXTINF:6, no desc +364992-275163203.ts +#EXTINF:6, no desc +364992-275163204.ts +#EXTINF:5.2333, no desc +364992-275163205.ts +#EXT-X-CUE-IN +#EXTINF:6.7666, no desc +364992-275163206.ts +#EXTINF:6, no desc +364992-275163207.ts +#EXTINF:6, no desc diff --git a/writer.go b/writer.go index 8024ffc1..0e32ea3a 100644 --- a/writer.go +++ b/writer.go @@ -593,9 +593,11 @@ func (p *MediaPlaylist) Encode() *bytes.Buffer { case SCTE35_OATCLS: switch seg.SCTE.CueType { case SCTE35Cue_Start: - p.buf.WriteString("#EXT-OATCLS-SCTE35:") - p.buf.WriteString(seg.SCTE.Cue) - p.buf.WriteRune('\n') + if seg.SCTE.Cue != "" { + p.buf.WriteString("#EXT-OATCLS-SCTE35:") + p.buf.WriteString(seg.SCTE.Cue) + p.buf.WriteRune('\n') + } p.buf.WriteString("#EXT-X-CUE-OUT:") p.buf.WriteString(strconv.FormatFloat(seg.SCTE.Time, 'f', -1, 64)) p.buf.WriteRune('\n')