diff --git a/internal/hls/muxer_stream_playlist.go b/internal/hls/muxer_stream_playlist.go index 17b2cce4..7985ed84 100644 --- a/internal/hls/muxer_stream_playlist.go +++ b/internal/hls/muxer_stream_playlist.go @@ -72,8 +72,8 @@ func (p *muxerStreamPlaylist) reader() io.Reader { ret := uint(0) // EXTINF, when rounded to the nearest integer, must be <= EXT-X-TARGETDURATION - for _, f := range p.segments { - v2 := uint(math.Round(f.duration().Seconds())) + for _, s := range p.segments { + v2 := uint(math.Round(s.duration().Seconds())) if v2 > ret { ret = v2 } @@ -84,10 +84,12 @@ func (p *muxerStreamPlaylist) reader() io.Reader { cnt += "#EXT-X-TARGETDURATION:" + strconv.FormatUint(uint64(targetDuration), 10) + "\n" cnt += "#EXT-X-MEDIA-SEQUENCE:" + strconv.FormatInt(int64(p.segmentDeleteCount), 10) + "\n" + cnt += "\n" - for _, f := range p.segments { - cnt += "#EXTINF:" + strconv.FormatFloat(f.duration().Seconds(), 'f', -1, 64) + ",\n" - cnt += f.name + ".ts\n" + for _, s := range p.segments { + cnt += "#EXT-X-PROGRAM-DATE-TIME:" + s.startTime.Format("2006-01-02T15:04:05+07:00") + "\n" + + "#EXTINF:" + strconv.FormatFloat(s.duration().Seconds(), 'f', -1, 64) + ",\n" + + s.name + ".ts\n" } return []byte(cnt) diff --git a/internal/hls/muxer_test.go b/internal/hls/muxer_test.go index 212a438b..dacf5aae 100644 --- a/internal/hls/muxer_test.go +++ b/internal/hls/muxer_test.go @@ -80,12 +80,14 @@ func TestMuxerVideoAudio(t *testing.T) { `#EXT-X-ALLOW-CACHE:NO\n` + `#EXT-X-TARGETDURATION:4\n` + `#EXT-X-MEDIA-SEQUENCE:0\n` + + `\n` + + `#EXT-X-PROGRAM-DATE-TIME:(.*?)\n` + `#EXTINF:4,\n` + `([0-9]+\.ts)\n$`) ma := re.FindStringSubmatch(string(byts)) require.NotEqual(t, 0, len(ma)) - byts, err = ioutil.ReadAll(m.Segment(ma[1])) + byts, err = ioutil.ReadAll(m.Segment(ma[2])) require.NoError(t, err) // PMT @@ -168,6 +170,8 @@ func TestMuxerAudio(t *testing.T) { `#EXT-X-ALLOW-CACHE:NO\n` + `#EXT-X-TARGETDURATION:1\n` + `#EXT-X-MEDIA-SEQUENCE:0\n` + + `\n` + + `#EXT-X-PROGRAM-DATE-TIME:(.*?)\n` + `#EXTINF:1,\n` + `([0-9]+\.ts)\n$`) ma := re.FindStringSubmatch(string(byts)) diff --git a/internal/hls/muxer_ts_segment.go b/internal/hls/muxer_ts_segment.go index 19dbebd9..9983ffc0 100644 --- a/internal/hls/muxer_ts_segment.go +++ b/internal/hls/muxer_ts_segment.go @@ -16,6 +16,7 @@ type muxerTSSegment struct { videoTrack *gortsplib.TrackH264 writer *muxerTSWriter + startTime time.Time name string buf bytes.Buffer startPTS *time.Duration @@ -29,11 +30,14 @@ func newMuxerTSSegment( videoTrack *gortsplib.TrackH264, writer *muxerTSWriter, ) *muxerTSSegment { + now := time.Now() + t := &muxerTSSegment{ hlsSegmentMaxSize: hlsSegmentMaxSize, videoTrack: videoTrack, writer: writer, - name: strconv.FormatInt(time.Now().Unix(), 10), + startTime: now, + name: strconv.FormatInt(now.Unix(), 10), } // WriteTable() is called automatically when WriteData() is called with