|
|
|
@ -2,7 +2,6 @@ package streamproc |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"encoding/binary" |
|
|
|
"encoding/binary" |
|
|
|
"sync" |
|
|
|
|
|
|
|
"sync/atomic" |
|
|
|
"sync/atomic" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
@ -16,68 +15,63 @@ type Path interface { |
|
|
|
|
|
|
|
|
|
|
|
// TrackInfo contains infos about a track.
|
|
|
|
// TrackInfo contains infos about a track.
|
|
|
|
type TrackInfo struct { |
|
|
|
type TrackInfo struct { |
|
|
|
Initialized bool |
|
|
|
|
|
|
|
LastSequenceNumber uint16 |
|
|
|
LastSequenceNumber uint16 |
|
|
|
RTPTime uint32 |
|
|
|
LastTimeRTP uint32 |
|
|
|
NTPTime time.Time |
|
|
|
LastTimeNTP int64 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type trackInfo struct { |
|
|
|
type track struct { |
|
|
|
initialized bool |
|
|
|
|
|
|
|
lastSequenceNumber uint32 |
|
|
|
lastSequenceNumber uint32 |
|
|
|
timeMutex sync.Mutex |
|
|
|
lastTimeRTP uint32 |
|
|
|
rtpTime uint32 |
|
|
|
lastTimeNTP int64 |
|
|
|
ntpTime time.Time |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// StreamProc is a stream processor, an intermediate layer between a source and a path.
|
|
|
|
// StreamProc is a stream processor, an intermediate layer between a source and a path.
|
|
|
|
type StreamProc struct { |
|
|
|
type StreamProc struct { |
|
|
|
path Path |
|
|
|
path Path |
|
|
|
trackInfos []trackInfo |
|
|
|
tracks []*track |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// New allocates a StreamProc.
|
|
|
|
// New allocates a StreamProc.
|
|
|
|
func New(path Path, tracksLen int) *StreamProc { |
|
|
|
func New(path Path, tracksLen int) *StreamProc { |
|
|
|
return &StreamProc{ |
|
|
|
sp := &StreamProc{ |
|
|
|
path: path, |
|
|
|
path: path, |
|
|
|
trackInfos: make([]trackInfo, tracksLen), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sp.tracks = make([]*track, tracksLen) |
|
|
|
|
|
|
|
for i := range sp.tracks { |
|
|
|
|
|
|
|
sp.tracks[i] = &track{} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sp |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TrackInfos returns infos about the tracks of the stream.
|
|
|
|
// TrackInfos returns infos about the tracks of the stream.
|
|
|
|
func (sp *StreamProc) TrackInfos() []TrackInfo { |
|
|
|
func (sp *StreamProc) TrackInfos() []TrackInfo { |
|
|
|
ret := make([]TrackInfo, len(sp.trackInfos)) |
|
|
|
ret := make([]TrackInfo, len(sp.tracks)) |
|
|
|
|
|
|
|
for trackID, track := range sp.tracks { |
|
|
|
for trackID := range sp.trackInfos { |
|
|
|
|
|
|
|
sp.trackInfos[trackID].timeMutex.Lock() |
|
|
|
|
|
|
|
ret[trackID] = TrackInfo{ |
|
|
|
ret[trackID] = TrackInfo{ |
|
|
|
Initialized: sp.trackInfos[trackID].initialized, |
|
|
|
LastSequenceNumber: uint16(atomic.LoadUint32(&track.lastSequenceNumber)), |
|
|
|
LastSequenceNumber: uint16(atomic.LoadUint32(&sp.trackInfos[trackID].lastSequenceNumber)), |
|
|
|
LastTimeRTP: atomic.LoadUint32(&track.lastTimeRTP), |
|
|
|
RTPTime: sp.trackInfos[trackID].rtpTime, |
|
|
|
LastTimeNTP: atomic.LoadInt64(&track.lastTimeNTP), |
|
|
|
NTPTime: sp.trackInfos[trackID].ntpTime, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
sp.trackInfos[trackID].timeMutex.Unlock() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ret |
|
|
|
return ret |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// OnFrame processes a frame.
|
|
|
|
// OnFrame processes a frame.
|
|
|
|
func (sp *StreamProc) OnFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { |
|
|
|
func (sp *StreamProc) OnFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { |
|
|
|
if streamType == gortsplib.StreamTypeRTP && len(payload) >= 8 { |
|
|
|
if streamType == gortsplib.StreamTypeRTP && len(payload) >= 8 { |
|
|
|
|
|
|
|
track := sp.tracks[trackID] |
|
|
|
|
|
|
|
|
|
|
|
// store last sequence number
|
|
|
|
// store last sequence number
|
|
|
|
sequenceNumber := binary.BigEndian.Uint16(payload[2 : 2+2]) |
|
|
|
sequenceNumber := binary.BigEndian.Uint16(payload[2 : 2+2]) |
|
|
|
atomic.StoreUint32(&sp.trackInfos[trackID].lastSequenceNumber, uint32(sequenceNumber)) |
|
|
|
atomic.StoreUint32(&track.lastSequenceNumber, uint32(sequenceNumber)) |
|
|
|
|
|
|
|
|
|
|
|
// store time mapping
|
|
|
|
// store last RTP time and correspondent NTP time
|
|
|
|
if !sp.trackInfos[trackID].initialized { |
|
|
|
timestamp := binary.BigEndian.Uint32(payload[4 : 4+4]) |
|
|
|
timestamp := binary.BigEndian.Uint32(payload[4 : 4+4]) |
|
|
|
atomic.StoreUint32(&track.lastTimeRTP, timestamp) |
|
|
|
sp.trackInfos[trackID].timeMutex.Lock() |
|
|
|
atomic.StoreInt64(&track.lastTimeNTP, time.Now().Unix()) |
|
|
|
sp.trackInfos[trackID].initialized = true |
|
|
|
|
|
|
|
sp.trackInfos[trackID].rtpTime = timestamp |
|
|
|
|
|
|
|
sp.trackInfos[trackID].ntpTime = time.Now() |
|
|
|
|
|
|
|
sp.trackInfos[trackID].timeMutex.Unlock() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sp.path.OnSPFrame(trackID, streamType, payload) |
|
|
|
sp.path.OnSPFrame(trackID, streamType, payload) |
|
|
|
|