Skip to content

Commit f45fef2

Browse files
committed
Add support eseecloud source #1690
1 parent 699a995 commit f45fef2

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed

internal/eseecloud/eseecloud.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package eseecloud
2+
3+
import (
4+
"github.com/AlexxIT/go2rtc/internal/streams"
5+
"github.com/AlexxIT/go2rtc/pkg/eseecloud"
6+
)
7+
8+
func Init() {
9+
streams.HandleFunc("eseecloud", eseecloud.Dial)
10+
}

main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/AlexxIT/go2rtc/internal/doorbird"
1010
"github.com/AlexxIT/go2rtc/internal/dvrip"
1111
"github.com/AlexxIT/go2rtc/internal/echo"
12+
"github.com/AlexxIT/go2rtc/internal/eseecloud"
1213
"github.com/AlexxIT/go2rtc/internal/exec"
1314
"github.com/AlexxIT/go2rtc/internal/expr"
1415
"github.com/AlexxIT/go2rtc/internal/ffmpeg"
@@ -90,6 +91,7 @@ func main() {
9091
doorbird.Init() // doorbird source
9192
v4l2.Init() // v4l2 source
9293
flussonic.Init()
94+
eseecloud.Init()
9395

9496
// 6. Helper modules
9597

pkg/eseecloud/eseecloud.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package eseecloud
2+
3+
import (
4+
"bytes"
5+
"encoding/binary"
6+
"errors"
7+
"io"
8+
"net/http"
9+
"regexp"
10+
"strings"
11+
12+
"github.com/AlexxIT/go2rtc/pkg/core"
13+
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
14+
"github.com/pion/rtp"
15+
)
16+
17+
type Producer struct {
18+
core.Connection
19+
rd *core.ReadBuffer
20+
21+
videoPT, audioPT uint8
22+
}
23+
24+
func Dial(rawURL string) (core.Producer, error) {
25+
rawURL, _ = strings.CutPrefix(rawURL, "eseecloud")
26+
res, err := http.Get("http" + rawURL)
27+
if err != nil {
28+
return nil, err
29+
}
30+
31+
prod, err := Open(res.Body)
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
if info, ok := prod.(core.Info); ok {
37+
info.SetProtocol("http")
38+
info.SetURL(rawURL)
39+
}
40+
41+
return prod, nil
42+
}
43+
44+
func Open(r io.Reader) (core.Producer, error) {
45+
prod := &Producer{
46+
Connection: core.Connection{
47+
ID: core.NewID(),
48+
FormatName: "eseecloud",
49+
Transport: r,
50+
},
51+
rd: core.NewReadBuffer(r),
52+
}
53+
54+
if err := prod.probe(); err != nil {
55+
return nil, err
56+
}
57+
58+
return prod, nil
59+
}
60+
61+
func (p *Producer) probe() error {
62+
b, err := p.rd.Peek(1024)
63+
if err != nil {
64+
return err
65+
}
66+
67+
i := bytes.Index(b, []byte("\r\n\r\n"))
68+
if i == -1 {
69+
return io.EOF
70+
}
71+
72+
b = make([]byte, i+4)
73+
_, _ = p.rd.Read(b)
74+
75+
re := regexp.MustCompile(`m=(video|audio) (\d+) (\w+)/(\d+)\S*`)
76+
for _, item := range re.FindAllStringSubmatch(string(b), 2) {
77+
p.SDP += item[0] + "\n"
78+
79+
switch item[3] {
80+
case "H264", "H265":
81+
p.Medias = append(p.Medias, &core.Media{
82+
Kind: core.KindVideo,
83+
Direction: core.DirectionRecvonly,
84+
Codecs: []*core.Codec{
85+
{
86+
Name: item[3],
87+
ClockRate: 90000,
88+
PayloadType: core.PayloadTypeRAW,
89+
},
90+
},
91+
})
92+
p.videoPT = byte(core.Atoi(item[2]))
93+
94+
case "G711":
95+
p.Medias = append(p.Medias, &core.Media{
96+
Kind: core.KindAudio,
97+
Direction: core.DirectionRecvonly,
98+
Codecs: []*core.Codec{
99+
{
100+
Name: core.CodecPCMA,
101+
ClockRate: 8000,
102+
},
103+
},
104+
})
105+
p.audioPT = byte(core.Atoi(item[2]))
106+
}
107+
}
108+
109+
return nil
110+
}
111+
112+
func (p *Producer) Start() error {
113+
receivers := make(map[uint8]*core.Receiver)
114+
115+
for _, receiver := range p.Receivers {
116+
switch receiver.Codec.Kind() {
117+
case core.KindVideo:
118+
receivers[p.videoPT] = receiver
119+
case core.KindAudio:
120+
receivers[p.audioPT] = receiver
121+
}
122+
}
123+
124+
for {
125+
pkt, err := p.readPacket()
126+
if err != nil {
127+
return err
128+
}
129+
130+
if recv := receivers[pkt.PayloadType]; recv != nil {
131+
switch recv.Codec.Name {
132+
case core.CodecH264, core.CodecH265:
133+
// timestamp = seconds x 1000000
134+
pkt = &rtp.Packet{
135+
Header: rtp.Header{
136+
Timestamp: uint32(uint64(pkt.Timestamp) * 90000 / 1000000),
137+
},
138+
Payload: annexb.EncodeToAVCC(pkt.Payload),
139+
}
140+
case core.CodecPCMA:
141+
pkt = &rtp.Packet{
142+
Header: rtp.Header{
143+
Version: 2,
144+
SequenceNumber: pkt.SequenceNumber,
145+
Timestamp: uint32(uint64(pkt.Timestamp) * 8000 / 1000000),
146+
},
147+
Payload: pkt.Payload,
148+
}
149+
}
150+
recv.WriteRTP(pkt)
151+
}
152+
}
153+
}
154+
155+
func (p *Producer) readPacket() (*core.Packet, error) {
156+
b := make([]byte, 8)
157+
158+
if _, err := io.ReadFull(p.rd, b); err != nil {
159+
return nil, err
160+
}
161+
162+
if b[0] != '$' {
163+
return nil, errors.New("eseecloud: wrong start byte")
164+
}
165+
166+
size := binary.BigEndian.Uint32(b[4:])
167+
b = make([]byte, size)
168+
if _, err := io.ReadFull(p.rd, b); err != nil {
169+
return nil, err
170+
}
171+
172+
pkt := &core.Packet{}
173+
if err := pkt.Unmarshal(b); err != nil {
174+
return nil, err
175+
}
176+
177+
p.Recv += int(size)
178+
179+
return pkt, nil
180+
}

0 commit comments

Comments
 (0)