115 lines
2.6 KiB
Go
115 lines
2.6 KiB
Go
package libipcamera
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
)
|
|
|
|
// RTPRelay holds information on the relaying stream listener
|
|
type RTPRelay struct {
|
|
close bool
|
|
targetIP net.IP
|
|
targetPort int
|
|
listener net.PacketConn
|
|
}
|
|
|
|
// CreateRTPRelay creates a UDP listener that handles live data
|
|
// from the camera and forwards it as an RTP stream
|
|
func CreateRTPRelay(targetAddress net.IP, targetPort int) *RTPRelay {
|
|
conn, err := net.ListenPacket("udp", ":6669")
|
|
|
|
if err != nil {
|
|
log.Printf("ERROR: %s\n", err)
|
|
}
|
|
|
|
relay := RTPRelay{
|
|
targetIP: targetAddress,
|
|
targetPort: targetPort,
|
|
listener: conn,
|
|
}
|
|
if err != nil {
|
|
log.Printf("ERROR: %s\n", err)
|
|
}
|
|
|
|
go handleCameraStream(relay, conn)
|
|
|
|
return &relay
|
|
}
|
|
|
|
func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
|
|
buffer := make([]byte, 2048)
|
|
header := StreamHeader{}
|
|
var payload []byte
|
|
|
|
rtpTarget := net.UDPAddr{
|
|
IP: relay.targetIP,
|
|
Port: relay.targetPort,
|
|
}
|
|
rtpSource, _ := net.ResolveUDPAddr("udp", "127.0.0.1")
|
|
rtpConn, err := net.DialUDP("udp", rtpSource, &rtpTarget)
|
|
if err != nil {
|
|
log.Printf("ERROR creating RTP sender: %s\n", err)
|
|
}
|
|
|
|
var sequenceNumber uint16
|
|
var elapsed uint32
|
|
|
|
frameBuffer := []byte{}
|
|
|
|
for {
|
|
if relay.close {
|
|
rtpConn.Close()
|
|
break
|
|
}
|
|
|
|
conn.ReadFrom(buffer)
|
|
packetReader := bytes.NewReader(buffer)
|
|
binary.Read(packetReader, binary.BigEndian, &header)
|
|
|
|
if header.Magic != 0xBCDE {
|
|
log.Printf("Received message with invalid magic (%x).", header.Magic)
|
|
break
|
|
}
|
|
if header.Length > 0 {
|
|
payload = make([]byte, header.Length)
|
|
bytesRead, err := io.ReadFull(packetReader, payload)
|
|
if err != nil {
|
|
log.Printf("Read Error: %s, %d bytes\n", err, bytesRead)
|
|
break
|
|
}
|
|
} else {
|
|
payload = []byte{}
|
|
}
|
|
|
|
switch header.MessageType {
|
|
case 0x0001: // H.264 Data
|
|
frameBuffer = append(frameBuffer, payload...)
|
|
case 0x0002: // Time
|
|
packet := bytes.Buffer{}
|
|
packet.Write([]byte{0x80, 0x63})
|
|
binary.Write(&packet, binary.BigEndian, sequenceNumber)
|
|
binary.Write(&packet, binary.BigEndian, (uint32)(elapsed*90))
|
|
binary.Write(&packet, binary.BigEndian, (uint64(0)))
|
|
packet.Write(frameBuffer)
|
|
rtpConn.Write(packet.Bytes())
|
|
frameBuffer = []byte{}
|
|
sequenceNumber++
|
|
elapsed = binary.LittleEndian.Uint32(payload[12:])
|
|
//log.Printf("Elapsed: %d (%x)\n", elapsed, payload[12:])
|
|
default:
|
|
log.Printf("Received Unknown Message: %+v\n", header)
|
|
log.Printf("Payload:\n%s\n", hex.Dump(payload))
|
|
}
|
|
}
|
|
rtpConn.Close()
|
|
}
|
|
|
|
// Stop stops listening for packets
|
|
func (r *RTPRelay) Stop() {
|
|
r.listener.Close()
|
|
r.close = true
|
|
}
|