Files
mediamtx/internal/stream/sub_stream_format.go
T

190 lines
4.6 KiB
Go

package stream
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
)
type subStreamFormat struct {
curFormat format.Format
streamFormat *streamFormat
useRTPPackets bool
rtpDecoder rtpDecoder
tempRTPEncoder rtpEncoder
tempRTPTimeOffset uint32
}
func (ssf *subStreamFormat) initialize() error {
if ssf.useRTPPackets {
var err error
ssf.rtpDecoder, err = newRTPDecoder(ssf.curFormat)
if err != nil {
return err
}
}
if ssf.streamFormat.rtpEncoder == nil && (!ssf.useRTPPackets || ssf.streamFormat.alwaysAvailable) {
var err error
ssf.tempRTPEncoder, err = newRTPEncoder(ssf.curFormat, ssf.streamFormat.rtpMaxPayloadSize, nil, nil)
if err != nil {
return err
}
ssf.tempRTPTimeOffset, err = randUint32()
if err != nil {
return err
}
}
return nil
}
func (ssf *subStreamFormat) initialize2(firstTimeReceived bool, lastPTS time.Duration, lastSystemTime time.Time) {
if ssf.tempRTPEncoder != nil {
if ssf.streamFormat.rtpEncoder == nil {
ssf.streamFormat.rtpEncoder = ssf.tempRTPEncoder
ssf.streamFormat.rtpTimeOffset = ssf.tempRTPTimeOffset
}
ssf.tempRTPEncoder = nil
ssf.tempRTPTimeOffset = 0
}
if ssf.streamFormat.alwaysAvailable {
if firstTimeReceived {
ptsOffsetGo := lastPTS + time.Since(lastSystemTime)
ssf.streamFormat.ptsOffset = multiplyAndDivide(int64(ptsOffsetGo),
int64(ssf.streamFormat.format.ClockRate()), int64(time.Second))
}
switch curFormat := ssf.curFormat.(type) {
case *format.H265:
vps, sps, pps := curFormat.SafeParams()
if vps != nil && sps != nil && pps != nil {
ssf.writeUnit(&unit.Unit{
PTS: 0,
NTP: time.Time{},
RTPPackets: nil,
Payload: unit.PayloadH265([][]byte{vps, sps, pps}),
})
}
case *format.H264:
sps, pps := curFormat.SafeParams()
if sps != nil && pps != nil {
ssf.writeUnit(&unit.Unit{
PTS: 0,
NTP: time.Time{},
RTPPackets: nil,
Payload: unit.PayloadH264([][]byte{sps, pps}),
})
}
}
}
}
func (ssf *subStreamFormat) writeUnit(u *unit.Unit) {
err := ssf.writeUnitInner(u)
if err != nil {
ssf.streamFormat.inboundFramesInError.Add(err)
return
}
}
func (ssf *subStreamFormat) writeUnitInner(u *unit.Unit) error {
if ssf.streamFormat.alwaysAvailable {
u.PTS += ssf.streamFormat.ptsOffset
ssf.streamFormat.updateLastTime(
multiplyAndDivide2(time.Duration(u.PTS),
time.Second, time.Duration(ssf.streamFormat.format.ClockRate())))
}
if ssf.streamFormat.replaceNTP {
u.NTP = ssf.streamFormat.ntpEstimator.Estimate(u.PTS)
}
if len(u.RTPPackets) != 0 {
if ssf.rtpDecoder != nil {
var err error
u.Payload, err = ssf.rtpDecoder.decode(u.RTPPackets[0])
if err != nil {
return err
}
}
if ssf.streamFormat.rtpEncoder == nil {
for _, pkt := range u.RTPPackets {
if len(pkt.Payload) > ssf.streamFormat.rtpMaxPayloadSize {
var err error
ssf.streamFormat.rtpEncoder, err = newRTPEncoder(ssf.streamFormat.format, ssf.streamFormat.rtpMaxPayloadSize,
ptrOf(pkt.SSRC), ptrOf(pkt.SequenceNumber))
if err != nil {
var err2 rtpEncoderNotAvailableError
if errors.As(err, &err2) {
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), ssf.streamFormat.rtpMaxPayloadSize)
}
return err
}
ssf.streamFormat.rtpTimeOffset = pkt.Timestamp - uint32(u.PTS)
ssf.streamFormat.parent.Log(logger.Info,
"RTP packets are too big (%d > %d), remuxing them into smaller ones",
len(pkt.Payload), ssf.streamFormat.rtpMaxPayloadSize)
break
}
}
}
if ssf.streamFormat.rtpEncoder != nil {
u.RTPPackets = nil
}
}
if !u.NilPayload() {
ssf.streamFormat.formatUpdater(ssf.streamFormat.format, u.Payload)
u.Payload = ssf.streamFormat.unitRemuxer(ssf.streamFormat.format, u.Payload)
if ssf.streamFormat.rtpEncoder != nil && !u.NilPayload() {
var err error
u.RTPPackets, err = ssf.streamFormat.rtpEncoder.encode(u.Payload)
if err != nil {
return err
}
for _, pkt := range u.RTPPackets {
pkt.Timestamp += ssf.streamFormat.rtpTimeOffset + uint32(u.PTS)
}
}
}
size := unitSize(u)
ssf.streamFormat.addInboundBytes(size)
ssf.streamFormat.writeRTSP(ssf.streamFormat.media, u.RTPPackets, u.NTP)
for sr, onData := range ssf.streamFormat.onDatas {
csr := sr
cOnData := onData
sr.push(func() error {
if !csr.SkipBytesSent {
ssf.streamFormat.addOutboundBytes(size)
}
return cOnData(u)
})
}
return nil
}