mediamtx/internal/stream/stream_format.go

82 lines
1.9 KiB
Go

package stream
import (
"sync"
"sync/atomic"
"time"
"github.com/bluenviron/gortsplib/v3/pkg/formats"
"github.com/bluenviron/gortsplib/v3/pkg/media"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/formatprocessor"
"github.com/bluenviron/mediamtx/internal/logger"
)
type streamFormat struct {
source logger.Writer
proc formatprocessor.Processor
mutex sync.RWMutex
nonRTSPReaders map[interface{}]func(formatprocessor.Unit)
}
func newStreamFormat(
udpMaxPayloadSize int,
forma formats.Format,
generateRTPPackets bool,
source logger.Writer,
) (*streamFormat, error) {
proc, err := formatprocessor.New(udpMaxPayloadSize, forma, generateRTPPackets, source)
if err != nil {
return nil, err
}
sf := &streamFormat{
source: source,
proc: proc,
nonRTSPReaders: make(map[interface{}]func(formatprocessor.Unit)),
}
return sf, nil
}
func (sf *streamFormat) addReader(r interface{}, cb func(formatprocessor.Unit)) {
sf.mutex.Lock()
defer sf.mutex.Unlock()
sf.nonRTSPReaders[r] = cb
}
func (sf *streamFormat) removeReader(r interface{}) {
sf.mutex.Lock()
defer sf.mutex.Unlock()
delete(sf.nonRTSPReaders, r)
}
func (sf *streamFormat) writeUnit(s *Stream, medi *media.Media, data formatprocessor.Unit) {
sf.mutex.RLock()
defer sf.mutex.RUnlock()
hasNonRTSPReaders := len(sf.nonRTSPReaders) > 0
err := sf.proc.Process(data, hasNonRTSPReaders)
if err != nil {
sf.source.Log(logger.Warn, err.Error())
return
}
// forward RTP packets to RTSP readers
for _, pkt := range data.GetRTPPackets() {
atomic.AddUint64(s.bytesReceived, uint64(pkt.MarshalSize()))
s.rtspStream.WritePacketRTPWithNTP(medi, pkt, data.GetNTP())
}
// forward decoded frames to non-RTSP readers
for _, cb := range sf.nonRTSPReaders {
cb(data)
}
}
func (sf *streamFormat) writeRTPPacket(s *Stream, medi *media.Media, pkt *rtp.Packet, ntp time.Time) {
sf.writeUnit(s, medi, sf.proc.UnitForRTPPacket(pkt, ntp))
}