Files
monibuca/plugin/gb28181/pkg/transceiver.go
yangjinxing123 db265e0ef0 feat:support receive stream via UDP (#317)
Co-authored-by: yjx <yjx>
2025-08-25 15:59:26 +08:00

342 lines
8.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package gb28181
import (
"errors"
"fmt"
"net"
"os"
"strings"
"github.com/pion/rtp"
"m7s.live/v5"
"m7s.live/v5/pkg"
"m7s.live/v5/pkg/task"
"m7s.live/v5/pkg/util"
"m7s.live/v5/plugin/gb28181/udputils"
rtp2 "m7s.live/v5/plugin/rtp/pkg"
)
const (
StartCodePS = 0x000001ba
StartCodeSYS = 0x000001bb
StartCodeMAP = 0x000001bc
StartCodeVideo = 0x000001e0
StartCodeAudio = 0x000001c0
PrivateStreamCode = 0x000001bd
MEPGProgramEndCode = 0x000001b9
)
type PSPublisher struct {
*m7s.Publisher
*util.BufReader
Receiver Receiver
}
var ErrRTPReceiveLost = errors.New("rtp receive lost")
type Receiver struct {
task.Task
rtp.Packet
FeedChan chan []byte
psm util.Memory
dump *os.File
dumpLen []byte
psVideo PSVideo
psAudio PSAudio
RTPReader *rtp2.TCP
ListenAddr string
Listener net.Listener
StreamMode string // 数据流传输模式UDP:udp传输/TCP-ACTIVEtcp主动模式/TCP-PASSIVEtcp被动模式
SSRC uint32 // RTP SSRC
ListenerUdp *net.UDPConn
RTPReaderUdp *rtp2.UDP
IsSinglePort bool
SingleStop chan struct{}
udpCache *udputils.PriorityQueueRtp
UdpCacheSize int
lastSeq uint16
}
func NewPSPublisher(puber *m7s.Publisher) *PSPublisher {
ret := &PSPublisher{
Publisher: puber,
}
ret.Receiver.FeedChan = make(chan []byte, 10)
ret.BufReader = util.NewBufReaderChan(ret.Receiver.FeedChan)
ret.Receiver.psVideo.SetAllocator(ret.Allocator)
ret.Receiver.psAudio.SetAllocator(ret.Allocator)
return ret
}
func (p *PSPublisher) ReadPayload() (payload util.Memory, err error) {
payloadlen, err := p.ReadBE(2)
if err != nil {
return
}
return p.ReadBytes(payloadlen)
}
func (p *PSPublisher) Demux() {
var payload util.Memory
defer p.Info("demux exit")
for {
code, err := p.ReadBE32(4)
if err != nil {
return
}
p.Trace("demux", "code", code)
switch code {
case StartCodePS:
var psl byte
if err = p.Skip(9); err != nil {
return
}
psl, err = p.ReadByte()
if err != nil {
return
}
psl &= 0x07
if err = p.Skip(int(psl)); err != nil {
return
}
case StartCodeVideo:
payload, err = p.ReadPayload()
var annexB *pkg.AnnexB
annexB, err = p.Receiver.psVideo.parsePESPacket(payload)
if annexB != nil {
err = p.WriteVideo(annexB)
}
case StartCodeAudio:
payload, err = p.ReadPayload()
var audioFrame pkg.IAVFrame
audioFrame, err = p.Receiver.psAudio.parsePESPacket(payload)
if audioFrame != nil {
err = p.WriteAudio(audioFrame)
}
case StartCodeMAP:
p.decProgramStreamMap()
case StartCodeSYS, PrivateStreamCode:
p.ReadPayload()
default:
p.ReadPayload()
}
}
}
func (dec *PSPublisher) decProgramStreamMap() (err error) {
dec.Receiver.psm, err = dec.ReadPayload()
if err != nil {
return err
}
var programStreamInfoLen, programStreamMapLen, elementaryStreamInfoLength uint32
var streamType, elementaryStreamID byte
reader := dec.Receiver.psm.NewReader()
reader.Skip(2)
programStreamInfoLen, err = reader.ReadBE(2)
reader.Skip(int(programStreamInfoLen))
programStreamMapLen, err = reader.ReadBE(2)
for programStreamMapLen > 0 {
streamType, err = reader.ReadByte()
elementaryStreamID, err = reader.ReadByte()
if elementaryStreamID >= 0xe0 && elementaryStreamID <= 0xef {
dec.Receiver.psVideo.streamType = streamType
} else if elementaryStreamID >= 0xc0 && elementaryStreamID <= 0xdf {
dec.Receiver.psAudio.streamType = streamType
}
elementaryStreamInfoLength, err = reader.ReadBE(2)
reader.Skip(int(elementaryStreamInfoLength))
programStreamMapLen -= 4 + elementaryStreamInfoLength
}
return nil
}
func (p *PSPublisher) GetKey() uint32 {
return p.Receiver.SSRC
}
func (p *Receiver) ReadRTP(rtp util.Buffer) (err error) {
lastSeq := p.SequenceNumber
if err = p.Unmarshal(rtp); err != nil {
p.Error("unmarshal error", "err", err)
return
}
// 如果设置了SSRC过滤只处理匹配的SSRC
if p.SSRC != 0 && p.SSRC != p.Packet.SSRC {
p.Info("into single port mode, ssrc mismatch", "expected", p.SSRC, "actual", p.Packet.SSRC)
if p.TraceEnabled() {
p.Trace("rtp ssrc mismatch, skip", "expected", p.SSRC, "actual", p.Packet.SSRC)
}
return nil
}
if lastSeq == 0 || p.SequenceNumber == lastSeq+1 {
if p.TraceEnabled() {
p.Trace("rtp", "len", rtp.Len(), "seq", p.SequenceNumber, "payloadType", p.PayloadType, "ssrc", p.Packet.SSRC)
}
copyData := make([]byte, len(p.Payload))
copy(copyData, p.Payload)
select {
case p.FeedChan <- copyData:
// 成功发送数据
case <-p.Done():
// 任务已停止,返回错误
return task.ErrTaskComplete
}
return
} else {
p.Error("rtp seq mismatch,", "lastSeq", lastSeq, "seq", p.SequenceNumber)
return ErrRTPReceiveLost
}
}
func (p *Receiver) ReadUdpRTP(rtp util.Buffer) (err error) {
//解析rtp
if err = p.Unmarshal(rtp); err != nil {
p.Error("unmarshal error", "err", err)
return nil
}
//判断ssrc
if p.SSRC != 0 && p.SSRC != p.Packet.SSRC {
p.Info("ReadUdpRTP, ssrc mismatch", "expected", p.SSRC, "actual", p.Packet.SSRC)
if p.TraceEnabled() {
p.Trace("rtp ssrc mismatch, skip", "expected", p.SSRC, "actual", p.Packet.SSRC)
}
return nil
}
if p.UdpCacheSize > 0 && p.udpCache == nil {
p.udpCache = udputils.NewPqRtp()
}
//p.Info("ReadUdpRTP, seq", "rtpSeq", p.SequenceNumber)
//加入缓存,自动排序
rtpTmpCache := p.Packet
rtpTmpCache.Payload = make([]byte, len(p.Payload))
copy(rtpTmpCache.Payload, p.Payload)
p.udpCache.Push(rtpTmpCache)
rtpTmp := p.Packet
if p.udpCache.Len() < p.UdpCacheSize-1 {
return nil
} else {
rtpTmp, _ = p.udpCache.Pop()
}
//p.Info("ReadUdpRTP, seq", "rtpTmpSeq", rtpTmp.SequenceNumber)
p.lastSeq = rtpTmp.SequenceNumber
if p.TraceEnabled() {
p.Trace("rtp", "len", rtp.Len(), "seq", p.SequenceNumber, "payloadType", p.PayloadType, "ssrc", p.Packet.SSRC)
}
copyData := make([]byte, len(rtpTmp.Payload))
copy(copyData, rtpTmp.Payload)
select {
case p.FeedChan <- copyData:
// 成功发送数据
case <-p.Done():
// 任务已停止,返回错误
return task.ErrTaskComplete
}
return nil
}
func (p *Receiver) Start() (err error) {
if strings.ToUpper(p.StreamMode) == "TCP-ACTIVE" {
// TCP主动模式不需要监听直接返回
p.Info("TCP-ACTIVE mode, no need to listen")
return nil
} else if strings.ToUpper(p.StreamMode) == "TCP-PASSIVE" {
// TCP被动模式
if p.Listener == nil {
p.Info("start new listener", "addr", p.ListenAddr)
p.Listener, err = net.Listen("tcp4", p.ListenAddr)
if err != nil {
p.Error("start listen", "err", err)
return errors.New("start listen,err" + err.Error())
}
}
p.Info("start listen", "addr", p.ListenAddr)
} else {
if p.ListenerUdp == nil {
p.Info("start new listener", "addr", p.ListenAddr)
p.ListenerUdp, err = util.ListenUDP(p.ListenAddr, 1024*1024*10)
if err != nil {
p.Error("start listen", "err", err)
return errors.New("start listen,err" + err.Error())
}
}
}
return
}
func (p *Receiver) Dispose() {
if p.SSRC == 0 {
p.Info("into multiport mode ,close listener ", p.SSRC)
if p.Listener != nil {
p.Listener.Close()
}
}
if p.RTPReader != nil {
p.RTPReader.Close()
}
if p.ListenerUdp != nil && !p.IsSinglePort {
p.ListenerUdp.Close()
}
if p.IsSinglePort {
close(p.SingleStop)
}
if p.FeedChan != nil {
close(p.FeedChan)
}
}
func (p *Receiver) Go() error {
if strings.ToUpper(p.StreamMode) == "TCP-ACTIVE" {
// TCP主动模式主动连接设备
addr := p.ListenAddr
if !strings.Contains(addr, ":") {
addr = ":" + addr
}
if strings.HasPrefix(addr, ":") {
p.Error("invalid address, missing IP", "addr", addr)
return fmt.Errorf("invalid address %s, missing IP", addr)
}
p.Info("TCP-ACTIVE mode, connecting to device", "addr", addr)
conn, err := net.Dial("tcp", addr)
if err != nil {
p.Error("connect to device failed", "err", err)
return err
}
p.RTPReader = (*rtp2.TCP)(conn.(*net.TCPConn))
p.Info("connected to device", "addr", conn.RemoteAddr())
return p.RTPReader.Read(p.ReadRTP)
} else if strings.ToUpper(p.StreamMode) == "TCP-PASSIVE" { // TCP被动模式
p.Info("start accept")
conn, err := p.Listener.Accept()
if err != nil {
p.Error("accept", "err", err)
return err
}
p.RTPReader = (*rtp2.TCP)(conn.(*net.TCPConn))
p.Info("accept", "addr", conn.RemoteAddr())
return p.RTPReader.Read(p.ReadRTP)
} else { //UDP模式
if p.IsSinglePort {
p.SingleStop = make(chan struct{})
<-p.SingleStop
p.Info("stop udp accept", "ssrc", p.SSRC)
return nil
} else {
p.Info("start udp accept")
p.RTPReaderUdp = (*rtp2.UDP)(p.ListenerUdp)
return p.RTPReaderUdp.Read(p.ReadUdpRTP)
}
}
}