hls: send PCR once, at the beginning of every TS segment

This commit is contained in:
aler9 2021-08-14 17:25:40 +02:00
parent 2d71e69e43
commit 93b143395e
2 changed files with 39 additions and 25 deletions

View file

@ -34,7 +34,6 @@ type Muxer struct {
h264SPS []byte h264SPS []byte
h264PPS []byte h264PPS []byte
aacConfig rtpaac.MPEG4AudioConfig aacConfig rtpaac.MPEG4AudioConfig
startPCR time.Time
videoDTSEst *h264.DTSEstimator videoDTSEst *h264.DTSEstimator
audioAUCount int audioAUCount int
tsCurrent *tsFile tsCurrent *tsFile
@ -42,6 +41,7 @@ type Muxer struct {
tsByName map[string]*tsFile tsByName map[string]*tsFile
tsDeleteCount int tsDeleteCount int
mutex sync.RWMutex mutex sync.RWMutex
startPCR time.Time
startPTS time.Duration startPTS time.Duration
} }
@ -82,7 +82,6 @@ func NewMuxer(
h264SPS: h264SPS, h264SPS: h264SPS,
h264PPS: h264PPS, h264PPS: h264PPS,
aacConfig: aacConfig, aacConfig: aacConfig,
startPCR: time.Now(),
videoDTSEst: h264.NewDTSEstimator(), videoDTSEst: h264.NewDTSEstimator(),
tsCurrent: newTSFile(videoTrack, audioTrack), tsCurrent: newTSFile(videoTrack, audioTrack),
tsByName: make(map[string]*tsFile), tsByName: make(map[string]*tsFile),
@ -122,11 +121,10 @@ func (m *Muxer) WriteH264(pts time.Duration, nalus [][]byte) error {
if idrPresent && if idrPresent &&
m.tsCurrent.firstPacketWritten && m.tsCurrent.firstPacketWritten &&
m.tsCurrent.duration() >= m.hlsSegmentDuration { m.tsCurrent.duration() >= m.hlsSegmentDuration {
if m.tsCurrent != nil { m.tsCurrent.close()
m.tsCurrent.close()
}
m.tsCurrent = newTSFile(m.videoTrack, m.audioTrack) m.tsCurrent = newTSFile(m.videoTrack, m.audioTrack)
m.tsCurrent.setStartPCR(m.startPCR)
m.tsByName[m.tsCurrent.name] = m.tsCurrent m.tsByName[m.tsCurrent.name] = m.tsCurrent
m.tsQueue = append(m.tsQueue, 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++ m.tsDeleteCount++
} }
} else if !m.tsCurrent.firstPacketWritten { } else if !m.tsCurrent.firstPacketWritten {
m.startPCR = time.Now()
m.startPTS = pts m.startPTS = pts
m.tsCurrent.setStartPCR(m.startPCR)
} }
pts = pts + ptsOffset - m.startPTS pts = pts + ptsOffset - m.startPTS
m.tsCurrent.setPCR(time.Since(m.startPCR))
err := m.tsCurrent.writeH264( err := m.tsCurrent.writeH264(
m.h264SPS, m.h264SPS,
m.h264PPS, m.h264PPS,
@ -164,13 +163,13 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error {
if m.audioAUCount >= segmentMinAUCount && if m.audioAUCount >= segmentMinAUCount &&
m.tsCurrent.firstPacketWritten && m.tsCurrent.firstPacketWritten &&
m.tsCurrent.duration() >= m.hlsSegmentDuration { m.tsCurrent.duration() >= m.hlsSegmentDuration {
m.tsCurrent.close()
if m.tsCurrent != nil {
m.tsCurrent.close()
}
m.audioAUCount = 0 m.audioAUCount = 0
m.tsCurrent = newTSFile(m.videoTrack, m.audioTrack) m.tsCurrent = newTSFile(m.videoTrack, m.audioTrack)
m.tsCurrent.setStartPCR(m.startPCR)
m.tsByName[m.tsCurrent.name] = m.tsCurrent m.tsByName[m.tsCurrent.name] = m.tsCurrent
m.tsQueue = append(m.tsQueue, m.tsCurrent) m.tsQueue = append(m.tsQueue, m.tsCurrent)
if len(m.tsQueue) > m.hlsSegmentCount { if len(m.tsQueue) > m.hlsSegmentCount {
@ -179,7 +178,9 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error {
m.tsDeleteCount++ m.tsDeleteCount++
} }
} else if !m.tsCurrent.firstPacketWritten { } else if !m.tsCurrent.firstPacketWritten {
m.startPCR = time.Now()
m.startPTS = pts m.startPTS = pts
m.tsCurrent.setStartPCR(m.startPCR)
} }
} else { } else {
if !m.tsCurrent.firstPacketWritten { if !m.tsCurrent.firstPacketWritten {
@ -192,8 +193,6 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error {
for i, au := range aus { for i, au := range aus {
auPTS := pts + time.Duration(i)*1000*time.Second/time.Duration(m.aacConfig.SampleRate) 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( err := m.tsCurrent.writeAAC(
m.aacConfig.SampleRate, m.aacConfig.SampleRate,
m.aacConfig.ChannelCount, m.aacConfig.ChannelCount,
@ -202,6 +201,8 @@ func (m *Muxer) WriteAAC(pts time.Duration, aus [][]byte) error {
if err != nil { if err != nil {
return err return err
} }
m.audioAUCount++
} }
return nil return nil

View file

@ -18,10 +18,10 @@ type tsFile struct {
name string name string
buf *multiAccessBuffer buf *multiAccessBuffer
mux *astits.Muxer mux *astits.Muxer
pcr time.Duration
firstPacketWritten bool firstPacketWritten bool
minPTS time.Duration minPTS time.Duration
maxPTS time.Duration maxPTS time.Duration
startPCR time.Time
} }
func newTSFile(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) *tsFile { func newTSFile(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) *tsFile {
@ -69,8 +69,8 @@ func (t *tsFile) duration() time.Duration {
return t.maxPTS - t.minPTS return t.maxPTS - t.minPTS
} }
func (t *tsFile) setPCR(pcr time.Duration) { func (t *tsFile) setStartPCR(startPCR time.Time) {
t.pcr = pcr t.startPCR = startPCR
} }
func (t *tsFile) newReader() io.Reader { func (t *tsFile) newReader() io.Reader {
@ -81,7 +81,6 @@ func (t *tsFile) writeH264(
h264SPS []byte, h264PPS []byte, h264SPS []byte, h264PPS []byte,
dts time.Duration, pts time.Duration, isIDR bool, nalus [][]byte) error { dts time.Duration, pts time.Duration, isIDR bool, nalus [][]byte) error {
if !t.firstPacketWritten { if !t.firstPacketWritten {
t.firstPacketWritten = true
t.minPTS = pts t.minPTS = pts
t.maxPTS = pts t.maxPTS = pts
} else { } else {
@ -115,17 +114,30 @@ func (t *tsFile) writeH264(
filteredNALUs = append(filteredNALUs, nalu) 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) enc, err := h264.EncodeAnnexB(filteredNALUs)
if err != nil { if err != nil {
return err return err
} }
af := &astits.PacketAdaptationField{
RandomAccessIndicator: isIDR,
HasPCR: true,
PCR: &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)},
}
_, err = t.mux.WriteData(&astits.MuxerData{ _, err = t.mux.WriteData(&astits.MuxerData{
PID: 256, PID: 256,
AdaptationField: af, AdaptationField: af,
@ -148,7 +160,6 @@ func (t *tsFile) writeH264(
func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, au []byte) error { func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, au []byte) error {
if t.videoTrack == nil { if t.videoTrack == nil {
if !t.firstPacketWritten { if !t.firstPacketWritten {
t.firstPacketWritten = true
t.minPTS = pts t.minPTS = pts
t.maxPTS = pts t.maxPTS = pts
} else { } else {
@ -176,9 +187,11 @@ func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, a
RandomAccessIndicator: true, RandomAccessIndicator: true,
} }
if t.videoTrack == nil { if t.videoTrack == nil && !t.firstPacketWritten {
t.firstPacketWritten = true
af.HasPCR = 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{ _, err = t.mux.WriteData(&astits.MuxerData{