install go2rtc on bob
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
package legacy
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/tutk"
|
||||
"github.com/pion/rtp"
|
||||
)
|
||||
|
||||
func Dial(rawURL string) (*Producer, error) {
|
||||
client, err := NewClient(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, _ := url.Parse(rawURL)
|
||||
query := u.Query()
|
||||
|
||||
err = client.StartMedia(query.Get("subtype"), "")
|
||||
if err != nil {
|
||||
_ = client.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
medias, err := probe(client)
|
||||
if err != nil {
|
||||
_ = client.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Producer{
|
||||
Connection: core.Connection{
|
||||
ID: core.NewID(),
|
||||
FormatName: "xiaomi/legacy",
|
||||
Protocol: "tutk+udp",
|
||||
RemoteAddr: client.RemoteAddr().String(),
|
||||
UserAgent: client.Version(),
|
||||
Medias: medias,
|
||||
Transport: client,
|
||||
},
|
||||
client: client,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
type Producer struct {
|
||||
core.Connection
|
||||
client *Client
|
||||
}
|
||||
|
||||
const codecXiaobaiPCMA = 1 // chuangmi.camera.xiaobai
|
||||
|
||||
func probe(client *Client) ([]*core.Media, error) {
|
||||
_ = client.SetDeadline(time.Now().Add(15 * time.Second))
|
||||
|
||||
var vcodec, acodec *core.Codec
|
||||
|
||||
for {
|
||||
// 0 5000 codec
|
||||
// 2 0000 codec params
|
||||
// 4 01 active clients
|
||||
// 5 34 unknown const
|
||||
// 6 0600 unknown seq(s)
|
||||
// 8 80026801 unknown fixed
|
||||
// 12 ed8d5c69 time in sec
|
||||
// 16 4c03 time in 1/1000
|
||||
// 18 0000
|
||||
hdr, payload, err := client.ReadPacket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch codec := hdr[0]; codec {
|
||||
case tutk.CodecH264, tutk.CodecH265:
|
||||
if vcodec == nil {
|
||||
avcc := annexb.EncodeToAVCC(payload)
|
||||
if codec == tutk.CodecH264 {
|
||||
if h264.NALUType(avcc) == h264.NALUTypeSPS {
|
||||
vcodec = h264.AVCCToCodec(avcc)
|
||||
}
|
||||
} else {
|
||||
if h265.NALUType(avcc) == h265.NALUTypeVPS {
|
||||
vcodec = h265.AVCCToCodec(avcc)
|
||||
}
|
||||
}
|
||||
}
|
||||
case tutk.CodecPCMA, codecXiaobaiPCMA:
|
||||
if acodec == nil {
|
||||
acodec = &core.Codec{Name: core.CodecPCMA, ClockRate: 8000}
|
||||
}
|
||||
case tutk.CodecPCML:
|
||||
if acodec == nil {
|
||||
acodec = &core.Codec{Name: core.CodecPCML, ClockRate: 8000}
|
||||
}
|
||||
case tutk.CodecAACLATM:
|
||||
if acodec == nil {
|
||||
acodec = aac.ADTSToCodec(payload)
|
||||
if acodec != nil {
|
||||
acodec.PayloadType = core.PayloadTypeRAW
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if vcodec != nil && acodec != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
medias := []*core.Media{
|
||||
{
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{vcodec},
|
||||
},
|
||||
{
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{acodec},
|
||||
},
|
||||
}
|
||||
return medias, nil
|
||||
}
|
||||
|
||||
func (c *Producer) Protocol() string {
|
||||
return "tutk+udp"
|
||||
}
|
||||
|
||||
func (c *Producer) Start() error {
|
||||
var audioTS uint32
|
||||
var videoSeq, audioSeq uint16
|
||||
|
||||
for {
|
||||
_ = c.client.SetDeadline(time.Now().Add(5 * time.Second))
|
||||
hdr, payload, err := c.client.ReadPacket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := len(payload)
|
||||
c.Recv += n
|
||||
|
||||
// TODO: rewrite this
|
||||
var name string
|
||||
var pkt *core.Packet
|
||||
|
||||
switch codec := hdr[0]; codec {
|
||||
case tutk.CodecH264, tutk.CodecH265:
|
||||
pkt = &core.Packet{
|
||||
Header: rtp.Header{
|
||||
SequenceNumber: videoSeq,
|
||||
Timestamp: core.Now90000(),
|
||||
},
|
||||
Payload: annexb.EncodeToAVCC(payload),
|
||||
}
|
||||
videoSeq++
|
||||
|
||||
if codec == tutk.CodecH264 {
|
||||
name = core.CodecH264
|
||||
} else {
|
||||
name = core.CodecH265
|
||||
}
|
||||
|
||||
case tutk.CodecPCMA, tutk.CodecPCML, codecXiaobaiPCMA:
|
||||
pkt = &core.Packet{
|
||||
Header: rtp.Header{
|
||||
Version: 2,
|
||||
Marker: true,
|
||||
SequenceNumber: audioSeq,
|
||||
Timestamp: audioTS,
|
||||
},
|
||||
Payload: payload,
|
||||
}
|
||||
audioSeq++
|
||||
|
||||
switch codec {
|
||||
case tutk.CodecPCMA, codecXiaobaiPCMA:
|
||||
name = core.CodecPCMA
|
||||
audioTS += uint32(n)
|
||||
case tutk.CodecPCML:
|
||||
name = core.CodecPCML
|
||||
audioTS += uint32(n / 2) // because 16bit
|
||||
}
|
||||
|
||||
case tutk.CodecAACLATM:
|
||||
pkt = &core.Packet{
|
||||
Header: rtp.Header{
|
||||
SequenceNumber: audioSeq,
|
||||
Timestamp: audioTS,
|
||||
},
|
||||
Payload: payload,
|
||||
}
|
||||
audioSeq++
|
||||
|
||||
name = core.CodecAAC
|
||||
audioTS += 1024
|
||||
}
|
||||
|
||||
for _, recv := range c.Receivers {
|
||||
if recv.Codec.Name == name {
|
||||
recv.WriteRTP(pkt)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Producer) Stop() error {
|
||||
_ = c.client.StopMedia()
|
||||
return c.Connection.Stop()
|
||||
}
|
||||
Reference in New Issue
Block a user