Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

140 lines
3.0 KiB

// Package stream contains the Stream object.
package stream
import (
"sync"
"time"
"github.com/bluenviron/gortsplib/v4"
"github.com/bluenviron/gortsplib/v4/pkg/description"
"github.com/bluenviron/gortsplib/v4/pkg/format"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
)
// Stream is a media stream.
// It stores tracks, readers and allow to write data to readers.
type Stream struct {
desc *description.Session
bytesReceived *uint64
smedias map[*description.Media]*streamMedia
mutex sync.RWMutex
rtspStream *gortsplib.ServerStream
rtspsStream *gortsplib.ServerStream
}
// New allocates a Stream.
func New(
udpMaxPayloadSize int,
desc *description.Session,
generateRTPPackets bool,
bytesReceived *uint64,
source logger.Writer,
) (*Stream, error) {
s := &Stream{
bytesReceived: bytesReceived,
desc: desc,
}
s.smedias = make(map[*description.Media]*streamMedia)
for _, media := range desc.Medias {
var err error
s.smedias[media], err = newStreamMedia(udpMaxPayloadSize, media, generateRTPPackets, source)
if err != nil {
return nil, err
}
}
return s, nil
}
// Close closes all resources of the stream.
func (s *Stream) Close() {
if s.rtspStream != nil {
s.rtspStream.Close()
}
if s.rtspsStream != nil {
s.rtspsStream.Close()
}
}
// Desc returns description of the stream.
func (s *Stream) Desc() *description.Session {
return s.desc
}
// RTSPStream returns the RTSP stream.
func (s *Stream) RTSPStream(server *gortsplib.Server) *gortsplib.ServerStream {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.rtspStream == nil {
s.rtspStream = gortsplib.NewServerStream(server, s.desc)
}
return s.rtspStream
}
// RTSPSStream returns the RTSPS stream.
func (s *Stream) RTSPSStream(server *gortsplib.Server) *gortsplib.ServerStream {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.rtspsStream == nil {
s.rtspsStream = gortsplib.NewServerStream(server, s.desc)
}
return s.rtspsStream
}
// AddReader adds a reader.
func (s *Stream) AddReader(r interface{}, medi *description.Media, forma format.Format, cb func(unit.Unit)) {
s.mutex.Lock()
defer s.mutex.Unlock()
sm := s.smedias[medi]
sf := sm.formats[forma]
sf.addReader(r, cb)
}
// RemoveReader removes a reader.
func (s *Stream) RemoveReader(r interface{}) {
s.mutex.Lock()
defer s.mutex.Unlock()
for _, sm := range s.smedias {
for _, sf := range sm.formats {
sf.removeReader(r)
}
}
}
// WriteUnit writes a Unit.
func (s *Stream) WriteUnit(medi *description.Media, forma format.Format, data unit.Unit) {
sm := s.smedias[medi]
sf := sm.formats[forma]
s.mutex.RLock()
defer s.mutex.RUnlock()
sf.writeUnit(s, medi, data)
}
// WriteRTPPacket writes a RTP packet.
func (s *Stream) WriteRTPPacket(
medi *description.Media,
forma format.Format,
pkt *rtp.Packet,
ntp time.Time,
pts time.Duration,
) {
sm := s.smedias[medi]
sf := sm.formats[forma]
s.mutex.RLock()
defer s.mutex.RUnlock()
sf.writeRTPPacket(s, medi, pkt, ntp, pts)
}