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) }