109 lines
1.8 KiB
Go
109 lines
1.8 KiB
Go
package libipcamera
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
type Frame struct {
|
|
Data []byte
|
|
Elapsed uint32
|
|
}
|
|
type RTPRelay struct {
|
|
close bool
|
|
listener net.PacketConn
|
|
Context context.Context
|
|
Frames chan Frame
|
|
}
|
|
|
|
var closeFlag bool
|
|
|
|
func CreateRTPRelay(ctx context.Context) *RTPRelay {
|
|
conn, err := net.ListenPacket("udp", ":6669")
|
|
if err != nil {
|
|
log.Printf("ERROR: %s\n", err)
|
|
}
|
|
|
|
closeFlag = false
|
|
relay := &RTPRelay{
|
|
close: false,
|
|
listener: conn,
|
|
Context: ctx,
|
|
Frames: make(chan Frame, 30),
|
|
}
|
|
|
|
go relay.readLoop()
|
|
|
|
return relay
|
|
}
|
|
|
|
func (r *RTPRelay) readLoop() {
|
|
buf := make([]byte, 2048)
|
|
packetReader := bytes.NewReader(buf)
|
|
header := streamHeader{}
|
|
var payload []byte
|
|
|
|
frameBuffer := bytes.Buffer{}
|
|
|
|
var elapsed uint32 // <-- store last timestamp
|
|
|
|
for {
|
|
r.listener.SetReadDeadline(time.Now().Add(10 * time.Second))
|
|
|
|
select {
|
|
case <-r.Context.Done():
|
|
close(r.Frames)
|
|
return
|
|
default:
|
|
}
|
|
|
|
_, _, err := r.listener.ReadFrom(buf)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
packetReader.Reset(buf)
|
|
|
|
binary.Read(packetReader, binary.BigEndian, &header)
|
|
|
|
if header.Magic != 0xBCDE {
|
|
continue
|
|
}
|
|
|
|
if header.Length > 0 {
|
|
payload = make([]byte, header.Length)
|
|
_, err := io.ReadFull(packetReader, payload)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
} else {
|
|
payload = []byte{}
|
|
}
|
|
|
|
switch header.MessageType {
|
|
case 0x0001:
|
|
frameBuffer.Write(payload)
|
|
case 0x0002:
|
|
if len(payload) >= 16 {
|
|
elapsed = binary.LittleEndian.Uint32(payload[12:])
|
|
}
|
|
// Emit a full H264 frame
|
|
if frameBuffer.Len() > 0 {
|
|
cp := append([]byte{}, frameBuffer.Bytes()...)
|
|
r.Frames <- Frame{Data: cp, Elapsed: elapsed}
|
|
frameBuffer.Reset()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *RTPRelay) Stop() {
|
|
closeFlag = true
|
|
r.close = true
|
|
r.listener.Close()
|
|
close(r.Frames)
|
|
}
|