Browse Source

hls: add EXT-X-PROGRAM-DATE-TIME tag

pull/858/head
aler9 4 years ago
parent
commit
2680ffcecb
  1. 12
      internal/hls/muxer_stream_playlist.go
  2. 6
      internal/hls/muxer_test.go
  3. 6
      internal/hls/muxer_ts_segment.go

12
internal/hls/muxer_stream_playlist.go

@ -72,8 +72,8 @@ func (p *muxerStreamPlaylist) reader() io.Reader {
ret := uint(0) ret := uint(0)
// EXTINF, when rounded to the nearest integer, must be <= EXT-X-TARGETDURATION // EXTINF, when rounded to the nearest integer, must be <= EXT-X-TARGETDURATION
for _, f := range p.segments { for _, s := range p.segments {
v2 := uint(math.Round(f.duration().Seconds())) v2 := uint(math.Round(s.duration().Seconds()))
if v2 > ret { if v2 > ret {
ret = v2 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-TARGETDURATION:" + strconv.FormatUint(uint64(targetDuration), 10) + "\n"
cnt += "#EXT-X-MEDIA-SEQUENCE:" + strconv.FormatInt(int64(p.segmentDeleteCount), 10) + "\n" cnt += "#EXT-X-MEDIA-SEQUENCE:" + strconv.FormatInt(int64(p.segmentDeleteCount), 10) + "\n"
cnt += "\n"
for _, f := range p.segments { for _, s := range p.segments {
cnt += "#EXTINF:" + strconv.FormatFloat(f.duration().Seconds(), 'f', -1, 64) + ",\n" cnt += "#EXT-X-PROGRAM-DATE-TIME:" + s.startTime.Format("2006-01-02T15:04:05+07:00") + "\n" +
cnt += f.name + ".ts\n" "#EXTINF:" + strconv.FormatFloat(s.duration().Seconds(), 'f', -1, 64) + ",\n" +
s.name + ".ts\n"
} }
return []byte(cnt) return []byte(cnt)

6
internal/hls/muxer_test.go

@ -80,12 +80,14 @@ func TestMuxerVideoAudio(t *testing.T) {
`#EXT-X-ALLOW-CACHE:NO\n` + `#EXT-X-ALLOW-CACHE:NO\n` +
`#EXT-X-TARGETDURATION:4\n` + `#EXT-X-TARGETDURATION:4\n` +
`#EXT-X-MEDIA-SEQUENCE:0\n` + `#EXT-X-MEDIA-SEQUENCE:0\n` +
`\n` +
`#EXT-X-PROGRAM-DATE-TIME:(.*?)\n` +
`#EXTINF:4,\n` + `#EXTINF:4,\n` +
`([0-9]+\.ts)\n$`) `([0-9]+\.ts)\n$`)
ma := re.FindStringSubmatch(string(byts)) ma := re.FindStringSubmatch(string(byts))
require.NotEqual(t, 0, len(ma)) 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) require.NoError(t, err)
// PMT // PMT
@ -168,6 +170,8 @@ func TestMuxerAudio(t *testing.T) {
`#EXT-X-ALLOW-CACHE:NO\n` + `#EXT-X-ALLOW-CACHE:NO\n` +
`#EXT-X-TARGETDURATION:1\n` + `#EXT-X-TARGETDURATION:1\n` +
`#EXT-X-MEDIA-SEQUENCE:0\n` + `#EXT-X-MEDIA-SEQUENCE:0\n` +
`\n` +
`#EXT-X-PROGRAM-DATE-TIME:(.*?)\n` +
`#EXTINF:1,\n` + `#EXTINF:1,\n` +
`([0-9]+\.ts)\n$`) `([0-9]+\.ts)\n$`)
ma := re.FindStringSubmatch(string(byts)) ma := re.FindStringSubmatch(string(byts))

6
internal/hls/muxer_ts_segment.go

@ -16,6 +16,7 @@ type muxerTSSegment struct {
videoTrack *gortsplib.TrackH264 videoTrack *gortsplib.TrackH264
writer *muxerTSWriter writer *muxerTSWriter
startTime time.Time
name string name string
buf bytes.Buffer buf bytes.Buffer
startPTS *time.Duration startPTS *time.Duration
@ -29,11 +30,14 @@ func newMuxerTSSegment(
videoTrack *gortsplib.TrackH264, videoTrack *gortsplib.TrackH264,
writer *muxerTSWriter, writer *muxerTSWriter,
) *muxerTSSegment { ) *muxerTSSegment {
now := time.Now()
t := &muxerTSSegment{ t := &muxerTSSegment{
hlsSegmentMaxSize: hlsSegmentMaxSize, hlsSegmentMaxSize: hlsSegmentMaxSize,
videoTrack: videoTrack, videoTrack: videoTrack,
writer: writer, 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 // WriteTable() is called automatically when WriteData() is called with

Loading…
Cancel
Save