mediamtx/internal/hls/muxer_ts_segment.go

186 lines
3.8 KiB
Go
Raw Normal View History

package hls
2021-04-11 17:05:08 +00:00
import (
"bytes"
"fmt"
"io"
2021-04-11 17:05:08 +00:00
"strconv"
"time"
"github.com/aler9/gortsplib"
2021-04-11 17:05:08 +00:00
"github.com/asticode/go-astits"
)
2022-03-20 17:20:32 +00:00
const (
// an offset between PCR and PTS/DTS is needed to avoid PCR > PTS
pcrOffset = 500 * time.Millisecond
)
type muxerTSSegment struct {
hlsSegmentMaxSize uint64
videoTrack *gortsplib.TrackH264
2022-03-20 16:58:39 +00:00
writeData func(*astits.MuxerData) (int, error)
2022-02-21 16:13:09 +00:00
startTime time.Time
name string
buf bytes.Buffer
startPTS *time.Duration
endPTS time.Duration
pcrSendCounter int
audioAUCount int
2021-04-11 17:05:08 +00:00
}
func newMuxerTSSegment(
2022-03-20 17:07:51 +00:00
now time.Time,
hlsSegmentMaxSize uint64,
videoTrack *gortsplib.TrackH264,
2022-03-20 16:58:39 +00:00
writeData func(*astits.MuxerData) (int, error),
) *muxerTSSegment {
t := &muxerTSSegment{
hlsSegmentMaxSize: hlsSegmentMaxSize,
videoTrack: videoTrack,
2022-03-20 16:58:39 +00:00
writeData: writeData,
2022-02-21 16:13:09 +00:00
startTime: now,
name: strconv.FormatInt(now.Unix(), 10),
2021-04-11 17:05:08 +00:00
}
// WriteTable() is called automatically when WriteData() is called with
// - PID == PCRPID
// - AdaptationField != nil
// - RandomAccessIndicator = true
2021-04-11 17:05:08 +00:00
return t
}
func (t *muxerTSSegment) duration() time.Duration {
return t.endPTS - *t.startPTS
2021-04-11 17:05:08 +00:00
}
func (t *muxerTSSegment) write(p []byte) (int, error) {
if uint64(len(p)+t.buf.Len()) > t.hlsSegmentMaxSize {
return 0, fmt.Errorf("reached maximum segment size")
}
return t.buf.Write(p)
2021-04-11 17:05:08 +00:00
}
func (t *muxerTSSegment) reader() io.Reader {
return bytes.NewReader(t.buf.Bytes())
}
func (t *muxerTSSegment) writeH264(
2022-03-20 17:07:51 +00:00
pcr time.Duration,
2021-08-15 07:06:55 +00:00
dts time.Duration,
pts time.Duration,
idrPresent bool,
enc []byte) error {
var af *astits.PacketAdaptationField
if idrPresent {
2022-03-13 13:49:50 +00:00
af = &astits.PacketAdaptationField{}
af.RandomAccessIndicator = true
}
// send PCR once in a while
if t.pcrSendCounter == 0 {
if af == nil {
af = &astits.PacketAdaptationField{}
}
af.HasPCR = true
2022-03-20 17:07:51 +00:00
af.PCR = &astits.ClockReference{Base: int64(pcr.Seconds() * 90000)}
t.pcrSendCounter = 3
}
t.pcrSendCounter--
2021-08-20 11:07:35 +00:00
oh := &astits.PESOptionalHeader{
MarkerBits: 2,
}
if dts == pts {
oh.PTSDTSIndicator = astits.PTSDTSIndicatorOnlyPTS
2022-03-20 17:20:32 +00:00
oh.PTS = &astits.ClockReference{Base: int64((pts + pcrOffset).Seconds() * 90000)}
2021-08-20 11:07:35 +00:00
} else {
oh.PTSDTSIndicator = astits.PTSDTSIndicatorBothPresent
2022-03-20 17:20:32 +00:00
oh.DTS = &astits.ClockReference{Base: int64((dts + pcrOffset).Seconds() * 90000)}
oh.PTS = &astits.ClockReference{Base: int64((pts + pcrOffset).Seconds() * 90000)}
2021-04-11 17:05:08 +00:00
}
2022-03-20 16:58:39 +00:00
_, err := t.writeData(&astits.MuxerData{
2021-04-11 17:05:08 +00:00
PID: 256,
AdaptationField: af,
PES: &astits.PESData{
Header: &astits.PESHeader{
2021-08-20 11:07:35 +00:00
OptionalHeader: oh,
2021-09-23 18:14:20 +00:00
StreamID: 224, // video
2021-04-11 17:05:08 +00:00
},
Data: enc,
},
})
if err != nil {
return err
}
2021-04-11 17:05:08 +00:00
if t.startPTS == nil {
t.startPTS = &pts
2021-04-11 17:05:08 +00:00
}
2022-02-21 15:56:07 +00:00
if pts > t.endPTS {
t.endPTS = pts
}
return nil
}
2021-04-11 17:05:08 +00:00
func (t *muxerTSSegment) writeAAC(
2022-03-20 17:07:51 +00:00
pcr time.Duration,
pts time.Duration,
enc []byte,
ausLen int) error {
2021-04-11 17:05:08 +00:00
af := &astits.PacketAdaptationField{
RandomAccessIndicator: true,
}
2021-08-15 07:06:55 +00:00
if t.videoTrack == nil {
// send PCR once in a while
if t.pcrSendCounter == 0 {
af.HasPCR = true
2022-03-20 17:07:51 +00:00
af.PCR = &astits.ClockReference{Base: int64(pcr.Seconds() * 90000)}
t.pcrSendCounter = 3
}
2021-04-11 17:05:08 +00:00
}
2022-03-20 16:58:39 +00:00
_, err := t.writeData(&astits.MuxerData{
2021-04-11 17:05:08 +00:00
PID: 257,
AdaptationField: af,
PES: &astits.PESData{
Header: &astits.PESHeader{
OptionalHeader: &astits.PESOptionalHeader{
MarkerBits: 2,
PTSDTSIndicator: astits.PTSDTSIndicatorOnlyPTS,
2022-03-20 17:20:32 +00:00
PTS: &astits.ClockReference{Base: int64((pts + pcrOffset).Seconds() * 90000)},
2021-04-11 17:05:08 +00:00
},
PacketLength: uint16(len(enc) + 8),
2021-09-23 18:14:20 +00:00
StreamID: 192, // audio
2021-04-11 17:05:08 +00:00
},
Data: enc,
2021-04-11 17:05:08 +00:00
},
})
if err != nil {
return err
}
if t.videoTrack == nil {
t.audioAUCount += ausLen
}
if t.startPTS == nil {
t.startPTS = &pts
}
2022-02-21 15:56:07 +00:00
if pts > t.endPTS {
t.endPTS = pts
}
return nil
2021-04-11 17:05:08 +00:00
}