Files
engine/rtp.go
2021-06-14 22:15:25 +08:00

128 lines
2.8 KiB
Go

package engine
import (
"sort"
"github.com/Monibuca/utils/v3/codec"
"github.com/pion/rtp"
)
type RTPPublisher struct {
rtp.Packet
Push func(payload []byte)
}
type RTPAudio struct {
RTPPublisher
*AudioTrack
}
type RTPVideo struct {
RTPPublisher
*VideoTrack
}
func (s *Stream) NewRTPVideo(codec byte) (r *RTPVideo) {
r = &RTPVideo{
VideoTrack: s.NewVideoTrack(codec),
}
r.Push = r.push
return
}
func (s *Stream) NewRTPAudio(codec byte) (r *RTPAudio) {
r = &RTPAudio{
AudioTrack: s.NewAudioTrack(codec),
}
r.Push = r.push
return
}
func (v *RTPVideo) push(payload []byte) {
vt := v.VideoTrack
if err := v.Unmarshal(payload); err != nil {
return
}
t := v.Timestamp / 90
if t < vt.Buffer.GetLast().Timestamp {
if vt.WaitIDR.Err() == nil {
return
}
//有B帧
var tmpVT VideoTrack
tmpVT.Buffer = NewRing_Video()
tmpVT.revIDR = func() {
tmpVT.IDRIndex = tmpVT.Buffer.Index
}
// tmpVT.pushRTP = func(p rtp.Packet) {
// tmpVT.Push(VideoPack{Timestamp:p.Timestamp/90,Payload:p.Payload})
// }
gopBuffer := tmpVT.Buffer //缓存一个GOP用来计算dts
var gopFirst byte
var tsSlice TSSlice
for i := vt.IDRIndex; vt.Buffer.Index != i; i++ {
t := vt.Buffer.GetAt(i)
c := gopBuffer.Current
c.VideoPack = t.VideoPack.Clone()
tsSlice = append(tsSlice, gopBuffer.Current.Timestamp)
gopBuffer.NextW()
}
v.Push = func(payload []byte) {
if err := v.Unmarshal(payload); err != nil {
return
}
t := v.Timestamp / 90
c := gopBuffer.Current
vp := VideoPack{Timestamp: t, NALUs: [][]byte{v.Payload}}
tmpVT.PushNalu(vp)
if c != gopBuffer.Current {
if c.IDR {
sort.Sort(tsSlice) //排序后相当于DTS列表
var offset uint32
for i := 0; i < len(tsSlice); i++ {
j := gopFirst + byte(i)
f := gopBuffer.GetAt(j)
if f.Timestamp+offset < tsSlice[i] {
offset = tsSlice[i] - f.Timestamp
}
}
for i := 0; i < len(tsSlice); i++ {
f := gopBuffer.GetAt(gopFirst + byte(i))
f.CompositionTime = f.Timestamp + offset - tsSlice[i]
f.Timestamp = tsSlice[i]
vt.PushNalu(f.VideoPack)
}
gopFirst = gopBuffer.Index - 1
tsSlice = nil
}
tsSlice = append(tsSlice, t)
}
}
v.Push(payload)
return
}
vt.PushNalu(VideoPack{Timestamp: t, NALUs: [][]byte{v.Payload}})
}
func (v *RTPAudio) push(payload []byte) {
at := v.AudioTrack
if err := v.Unmarshal(payload); err != nil {
return
}
switch at.CodecID {
case 10:
v.Push = func(payload []byte) {
if err := v.Unmarshal(payload); err != nil {
return
}
for _, payload = range codec.ParseRTPAAC(v.Payload) {
at.PushRaw(AudioPack{Timestamp: v.Timestamp / 90, Raw: payload})
}
}
case 7, 8:
v.Push = func(payload []byte) {
if err := v.Unmarshal(payload); err != nil {
return
}
at.PushRaw(AudioPack{Timestamp: v.Timestamp / 8, Raw: v.Payload})
}
}
}