Files
monibuca/plugin/gb28181/pkg/transceiver.go

222 lines
5.4 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"
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被动模式
}
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 *Receiver) ReadRTP(rtp util.Buffer) (err error) {
lastSeq := p.SequenceNumber
if err = p.Unmarshal(rtp); err != nil {
p.Error("unmarshal error", "err", err)
return
}
if lastSeq == 0 || p.SequenceNumber == lastSeq+1 {
if p.Enabled(p, task.TraceLevel) {
p.Trace("rtp", "len", rtp.Len(), "seq", p.SequenceNumber, "payloadType", p.PayloadType, "ssrc", p.SSRC)
}
copyData := make([]byte, len(p.Payload))
copy(copyData, p.Payload)
p.FeedChan <- copyData
return
}
return ErrRTPReceiveLost
}
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
}
// TCP被动模式
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)
return
}
func (p *Receiver) Dispose() {
if p.listener != nil {
p.listener.Close()
}
if p.RTPReader != nil {
p.RTPReader.Close()
}
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)
}
// 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)
}