82 lines
1.9 KiB
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))
|
|
}
|