Files
go2rtc/pkg/mjpeg/client.go
2023-03-19 17:17:05 +03:00

132 lines
2.2 KiB
Go

package mjpeg
import (
"bufio"
"errors"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/tcp"
"github.com/pion/rtp"
"io"
"net/http"
"net/textproto"
"strconv"
"strings"
"time"
)
type Client struct {
core.Listener
UserAgent string
RemoteAddr string
closed bool
res *http.Response
medias []*core.Media
receiver *core.Receiver
recv int
}
func NewClient(res *http.Response) *Client {
return &Client{res: res}
}
func (c *Client) startJPEG() error {
buf, err := io.ReadAll(c.res.Body)
if err != nil {
return err
}
packet := &rtp.Packet{Header: rtp.Header{Timestamp: now()}, Payload: buf}
c.receiver.WriteRTP(packet)
c.recv += len(buf)
req := c.res.Request
for !c.closed {
res, err := tcp.Do(req)
if err != nil {
return err
}
if res.StatusCode != http.StatusOK {
return errors.New("wrong status: " + res.Status)
}
buf, err = io.ReadAll(res.Body)
if err != nil {
return err
}
if c.receiver != nil {
packet = &rtp.Packet{Header: rtp.Header{Timestamp: now()}, Payload: buf}
c.receiver.WriteRTP(packet)
}
c.recv += len(buf)
}
return nil
}
func (c *Client) startMJPEG(boundary string) error {
// some cameras add prefix to boundary header:
// https://github.com/TheTimeWalker/wallpanel-android
if !strings.HasPrefix(boundary, "--") {
boundary = "--" + boundary
}
r := bufio.NewReader(c.res.Body)
tp := textproto.NewReader(r)
for !c.closed {
s, err := tp.ReadLine()
if err != nil {
return err
}
if !strings.HasPrefix(s, boundary) {
return errors.New("wrong boundary: " + s)
}
header, err := tp.ReadMIMEHeader()
if err != nil {
return err
}
s = header.Get("Content-Length")
if s == "" {
return errors.New("no content length")
}
size, err := strconv.Atoi(s)
if err != nil {
return err
}
buf := make([]byte, size)
if _, err = io.ReadFull(r, buf); err != nil {
return err
}
if c.receiver != nil {
packet := &rtp.Packet{Header: rtp.Header{Timestamp: now()}, Payload: buf}
c.receiver.WriteRTP(packet)
}
c.recv += len(buf)
if _, err = r.Discard(2); err != nil {
return err
}
}
return nil
}
func now() uint32 {
return uint32(time.Now().UnixMilli() * 90)
}