From 93b143395e15cc8bd418c1166d027ba41986fdc8 Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat, 14 Aug 2021 17:25:40 +0200 Subject: [PATCH] hls: send PCR once, at the beginning of every TS segment --- internal/hls/muxer.go | 25 +++++++++++++------------ internal/hls/tsfile.go | 39 ++++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/internal/hls/muxer.go b/internal/hls/muxer.go index f0c71def428..c4b5c16e97a 100644 --- a/internal/hls/muxer.go +++ b/internal/hls/muxer.go @@ -34,7 +34,6 @@ type Muxer struct { h264SPS []byte h264PPS []byte aacConfig rtpaac.MPEG4AudioConfig - startPCR time.Time videoDTSEst *h264.DTSEstimator audioAUCount int tsCurrent *tsFile @@ -42,6 +41,7 @@ type Muxer struct { tsByName map[string]*tsFile tsDeleteCount int mutex sync.RWMutex + startPCR time.Time startPTS time.Duration } @@ -82,7 +82,6 @@ func NewMuxer( h264SPS: h264SPS, h264PPS: h264PPS, aacConfig: aacConfig, - startPCR: time.Now(), videoDTSEst: h264.NewDTSEstimator(), tsCurrent: newTSFile(videoTrack, audioTrack), tsByName: make(map[string]*tsFile), @@ -122,11 +121,10 @@ func (m *Muxer) WriteH264(pts time.Duration, nalus [][]byte) error { if idrPresent && m.tsCurrent.firstPacketWritten && m.tsCurrent.duration() >= m.hlsSegmentDuration { - if m.tsCurrent != nil { - m.tsCurrent.close() - } + m.tsCurrent.close() m.tsCurrent = newTSFile(m.videoTrack, m.audioTrack) + m.tsCurrent.setStartPCR(m.startPCR) m.tsByName[m.tsCurrent.name] = m.tsCurrent m.tsQueue = append(m.tsQueue, m.tsCurrent) @@ -136,11 +134,12 @@ func (m *Muxer) WriteH264(pts time.Duration, nalus [][]byte) error { m.tsDeleteCount++ } } else if !m.tsCurrent.firstPacketWritten { + m.startPCR = time.Now() m.startPTS = pts + m.tsCurrent.setStartPCR(m.startPCR) } pts = pts + ptsOffset - m.startPTS - m.tsCurrent.setPCR(time.Since(m.startPCR)) err := m.tsCurrent.writeH264( m.h264SPS, m.h264PPS, @@ -164,13 +163,13 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error { if m.audioAUCount >= segmentMinAUCount && m.tsCurrent.firstPacketWritten && m.tsCurrent.duration() >= m.hlsSegmentDuration { - - if m.tsCurrent != nil { - m.tsCurrent.close() - } + m.tsCurrent.close() m.audioAUCount = 0 + m.tsCurrent = newTSFile(m.videoTrack, m.audioTrack) + m.tsCurrent.setStartPCR(m.startPCR) + m.tsByName[m.tsCurrent.name] = m.tsCurrent m.tsQueue = append(m.tsQueue, m.tsCurrent) if len(m.tsQueue) > m.hlsSegmentCount { @@ -179,7 +178,9 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error { m.tsDeleteCount++ } } else if !m.tsCurrent.firstPacketWritten { + m.startPCR = time.Now() m.startPTS = pts + m.tsCurrent.setStartPCR(m.startPCR) } } else { if !m.tsCurrent.firstPacketWritten { @@ -192,8 +193,6 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error { for i, au := range aus { auPTS := pts + time.Duration(i)*1000*time.Second/time.Duration(m.aacConfig.SampleRate) - m.audioAUCount++ - m.tsCurrent.setPCR(time.Since(m.startPCR)) err := m.tsCurrent.writeAAC( m.aacConfig.SampleRate, m.aacConfig.ChannelCount, @@ -202,6 +201,8 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error { if err != nil { return err } + + m.audioAUCount++ } return nil diff --git a/internal/hls/tsfile.go b/internal/hls/tsfile.go index 49649ced0ba..cc897bf0baf 100644 --- a/internal/hls/tsfile.go +++ b/internal/hls/tsfile.go @@ -18,10 +18,10 @@ type tsFile struct { name string buf *multiAccessBuffer mux *astits.Muxer - pcr time.Duration firstPacketWritten bool minPTS time.Duration maxPTS time.Duration + startPCR time.Time } func newTSFile(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) *tsFile { @@ -69,8 +69,8 @@ func (t *tsFile) duration() time.Duration { return t.maxPTS - t.minPTS } -func (t *tsFile) setPCR(pcr time.Duration) { - t.pcr = pcr +func (t *tsFile) setStartPCR(startPCR time.Time) { + t.startPCR = startPCR } func (t *tsFile) newReader() io.Reader { @@ -81,7 +81,6 @@ func (t *tsFile) writeH264( h264SPS []byte, h264PPS []byte, dts time.Duration, pts time.Duration, isIDR bool, nalus [][]byte) error { if !t.firstPacketWritten { - t.firstPacketWritten = true t.minPTS = pts t.maxPTS = pts } else { @@ -115,17 +114,30 @@ func (t *tsFile) writeH264( filteredNALUs = append(filteredNALUs, nalu) } + var af *astits.PacketAdaptationField + + if isIDR { + if af == nil { + af = &astits.PacketAdaptationField{} + } + af.RandomAccessIndicator = true + } + + if !t.firstPacketWritten { + t.firstPacketWritten = true + if af == nil { + af = &astits.PacketAdaptationField{} + } + af.HasPCR = true + pcr := time.Since(t.startPCR) + af.PCR = &astits.ClockReference{Base: int64(pcr.Seconds() * 90000)} + } + enc, err := h264.EncodeAnnexB(filteredNALUs) if err != nil { return err } - af := &astits.PacketAdaptationField{ - RandomAccessIndicator: isIDR, - HasPCR: true, - PCR: &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)}, - } - _, err = t.mux.WriteData(&astits.MuxerData{ PID: 256, AdaptationField: af, @@ -148,7 +160,6 @@ func (t *tsFile) writeH264( func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, au []byte) error { if t.videoTrack == nil { if !t.firstPacketWritten { - t.firstPacketWritten = true t.minPTS = pts t.maxPTS = pts } else { @@ -176,9 +187,11 @@ func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, a RandomAccessIndicator: true, } - if t.videoTrack == nil { + if t.videoTrack == nil && !t.firstPacketWritten { + t.firstPacketWritten = true af.HasPCR = true - af.PCR = &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)} + pcr := time.Since(t.startPCR) + af.PCR = &astits.ClockReference{Base: int64(pcr.Seconds() * 90000)} } _, err = t.mux.WriteData(&astits.MuxerData{