mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-10-29 10:52:40 +08:00
208 lines
4.0 KiB
Go
208 lines
4.0 KiB
Go
package magic
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"errors"
|
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
|
"github.com/AlexxIT/go2rtc/pkg/h264"
|
|
"github.com/AlexxIT/go2rtc/pkg/h265"
|
|
"github.com/AlexxIT/go2rtc/pkg/mpegts"
|
|
"github.com/pion/rtp"
|
|
"io"
|
|
)
|
|
|
|
// Client - can read unknown bytestream and autodetect format
|
|
type Client struct {
|
|
Desc string
|
|
URL string
|
|
|
|
Handle func() error
|
|
|
|
r io.ReadCloser
|
|
sniff []byte
|
|
|
|
medias []*core.Media
|
|
receiver *core.Receiver
|
|
|
|
recv int
|
|
}
|
|
|
|
func NewClient(r io.ReadCloser) *Client {
|
|
return &Client{r: r}
|
|
}
|
|
|
|
func (c *Client) Probe() (err error) {
|
|
c.sniff = make([]byte, mpegts.PacketSize*3) // MPEG-TS: SDT+PAT+PMT
|
|
c.recv, err = io.ReadFull(c.r, c.sniff)
|
|
if err != nil {
|
|
_ = c.Close()
|
|
return
|
|
}
|
|
|
|
var codec *core.Codec
|
|
|
|
if bytes.HasPrefix(c.sniff, []byte{0, 0, 0, 1}) {
|
|
switch {
|
|
case h264.NALUType(c.sniff) == h264.NALUTypeSPS:
|
|
codec = &core.Codec{
|
|
Name: core.CodecH264,
|
|
ClockRate: 90000,
|
|
PayloadType: core.PayloadTypeRAW,
|
|
}
|
|
c.Handle = c.ReadBitstreams
|
|
|
|
case h265.NALUType(c.sniff) == h265.NALUTypeVPS:
|
|
codec = &core.Codec{
|
|
Name: core.CodecH265,
|
|
ClockRate: 90000,
|
|
PayloadType: core.PayloadTypeRAW,
|
|
}
|
|
c.Handle = c.ReadBitstreams
|
|
}
|
|
|
|
} else if bytes.HasPrefix(c.sniff, []byte{0xFF, 0xD8}) {
|
|
codec = &core.Codec{
|
|
Name: core.CodecJPEG,
|
|
ClockRate: 90000,
|
|
PayloadType: core.PayloadTypeRAW,
|
|
}
|
|
c.Handle = c.ReadMJPEG
|
|
|
|
} else if c.sniff[0] == mpegts.SyncByte {
|
|
ts := mpegts.NewReader()
|
|
ts.AppendBuffer(c.sniff)
|
|
_ = ts.GetPacket()
|
|
for _, streamType := range ts.GetStreamTypes() {
|
|
switch streamType {
|
|
case mpegts.StreamTypeH264:
|
|
codec = &core.Codec{
|
|
Name: core.CodecH264,
|
|
ClockRate: 90000,
|
|
PayloadType: core.PayloadTypeRAW,
|
|
}
|
|
c.Handle = c.ReadMPEGTS
|
|
}
|
|
}
|
|
}
|
|
|
|
if codec == nil {
|
|
_ = c.Close()
|
|
return errors.New("unknown format: " + hex.EncodeToString(c.sniff[:8]))
|
|
}
|
|
|
|
c.medias = append(c.medias, &core.Media{
|
|
Kind: core.KindVideo,
|
|
Direction: core.DirectionRecvonly,
|
|
Codecs: []*core.Codec{codec},
|
|
})
|
|
|
|
return
|
|
}
|
|
|
|
func (c *Client) ReadBitstreams() error {
|
|
buf := c.sniff // total bufer
|
|
b := make([]byte, 1024*1024) // reading buffer
|
|
|
|
var decodeStream func([]byte) ([]byte, int)
|
|
switch c.receiver.Codec.Name {
|
|
case core.CodecH264:
|
|
decodeStream = h264.DecodeStream
|
|
case core.CodecH265:
|
|
decodeStream = h265.DecodeStream
|
|
}
|
|
|
|
for {
|
|
payload, n := decodeStream(buf)
|
|
if payload == nil {
|
|
n, err := c.r.Read(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
buf = append(buf, b[:n]...)
|
|
c.recv += n
|
|
continue
|
|
}
|
|
|
|
buf = buf[n:]
|
|
|
|
//log.Printf("[AVC] %v, len: %d", h264.Types(payload), len(payload))
|
|
|
|
pkt := &rtp.Packet{
|
|
Header: rtp.Header{Timestamp: core.Now90000()},
|
|
Payload: payload,
|
|
}
|
|
c.receiver.WriteRTP(pkt)
|
|
}
|
|
}
|
|
|
|
func (c *Client) ReadMJPEG() error {
|
|
buf := c.sniff // total bufer
|
|
b := make([]byte, 1024*1024) // reading buffer
|
|
|
|
for {
|
|
// one JPEG end and next start
|
|
i := bytes.Index(buf, []byte{0xFF, 0xD9, 0xFF, 0xD8})
|
|
if i < 0 {
|
|
n, err := c.r.Read(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
buf = append(buf, b[:n]...)
|
|
c.recv += n
|
|
|
|
// if we receive frame
|
|
if n >= 2 && b[n-2] == 0xFF && b[n-1] == 0xD9 {
|
|
i = len(buf)
|
|
} else {
|
|
continue
|
|
}
|
|
} else {
|
|
i += 2
|
|
}
|
|
|
|
pkt := &rtp.Packet{
|
|
Header: rtp.Header{Timestamp: core.Now90000()},
|
|
Payload: buf[:i],
|
|
}
|
|
c.receiver.WriteRTP(pkt)
|
|
|
|
buf = buf[i:]
|
|
}
|
|
}
|
|
|
|
func (c *Client) ReadMPEGTS() error {
|
|
b := make([]byte, 1024*1024) // reading buffer
|
|
|
|
ts := mpegts.NewReader()
|
|
ts.AppendBuffer(c.sniff)
|
|
|
|
for {
|
|
packet := ts.GetPacket()
|
|
if packet == nil {
|
|
n, err := c.r.Read(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ts.AppendBuffer(b[:n])
|
|
c.recv += n
|
|
continue
|
|
}
|
|
|
|
//log.Printf("[AVC] %v, len: %d, ts: %10d", h264.Types(packet.Payload), len(packet.Payload), packet.Timestamp)
|
|
|
|
if packet.PayloadType != mpegts.StreamTypeH264 {
|
|
continue
|
|
}
|
|
|
|
c.receiver.WriteRTP(packet)
|
|
}
|
|
}
|
|
|
|
func (c *Client) Close() error {
|
|
return c.r.Close()
|
|
}
|