Performance improvements (avoid allocations for every packet)

This commit is contained in:
Jonas Köritz 2019-09-03 12:40:10 +02:00
parent 3006672e43
commit ce0a817cb9
3 changed files with 65 additions and 14 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*.jpg
*.jpeg
actioncam
*.prof

View file

@ -11,6 +11,8 @@ import (
"net/http"
"os"
"path/filepath"
"runtime"
"runtime/pprof"
"github.com/jonas-koeritz/actioncam/libipcamera"
"github.com/jonas-koeritz/actioncam/rtsp"
@ -30,6 +32,10 @@ func main() {
var password string
var port int16
var verbose bool
var cpuprofile string
var memoryprofile string
var cpuprofileFile *os.File
var camera *libipcamera.Camera
@ -46,18 +52,50 @@ func main() {
bufio.NewReader(os.Stdin).ReadBytes('\n')
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if cpuprofile != "" {
cpuprofileFile, err := os.Create(cpuprofile)
if err != nil {
log.Printf("Could not create CPU profiling file: %s\n", err)
return
}
err = pprof.StartCPUProfile(cpuprofileFile)
if err != nil {
log.Printf("Could not start CPU profiling: %s\n", err)
}
}
},
PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
},
PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect()
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
pprof.StopCPUProfile()
cpuprofileFile.Close()
runtime.GC()
if memoryprofile != "" {
f, err := os.Create(memoryprofile)
if err != nil {
log.Printf("Could not create Memory profiling file: %s\n", err)
return
}
err = pprof.WriteHeapProfile(f)
if err != nil {
log.Printf("Could not start Memory profiling: %s\n", err)
}
}
},
}
rootCmd.PersistentFlags().Int16VarP(&port, "port", "P", 6666, "Specify an alternative camera port to connect to")
rootCmd.PersistentFlags().StringVarP(&username, "username", "u", "admin", "Specify the camera username")
rootCmd.PersistentFlags().StringVarP(&password, "password", "p", "12345", "Specify the camera password")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print verbose output")
rootCmd.PersistentFlags().StringVarP(&cpuprofile, "cpuprofile", "c", "", "Profile CPU usage")
rootCmd.PersistentFlags().StringVarP(&memoryprofile, "memoryprofile", "m", "", "Profile memory usage")
var ls = &cobra.Command{
Use: "ls [Cameras IP Address]",

View file

@ -42,6 +42,8 @@ func CreateRTPRelay(targetAddress net.IP, targetPort int) *RTPRelay {
func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
buffer := make([]byte, 2048)
packetReader := bytes.NewReader(buffer)
header := StreamHeader{}
var payload []byte
@ -58,7 +60,8 @@ func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
var sequenceNumber uint16
var elapsed uint32
frameBuffer := []byte{}
frameBuffer := bytes.Buffer{}
packetBuffer := bytes.Buffer{}
for {
if relay.close {
@ -67,18 +70,20 @@ func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
}
conn.ReadFrom(buffer)
packetReader := bytes.NewReader(buffer)
packetReader.Reset(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)
_, err := io.ReadFull(packetReader, payload)
if err != nil {
log.Printf("Read Error: %s, %d bytes\n", err, bytesRead)
log.Printf("Read Error: %s\n", err)
break
}
} else {
@ -87,19 +92,26 @@ func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
switch header.MessageType {
case 0x0001: // H.264 Data
frameBuffer = append(frameBuffer, payload...)
frameBuffer.Write(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{}
// Append the Framebuffer
packetBuffer.Write(frameBuffer.Bytes())
// Send out the packet
rtpConn.Write(packetBuffer.Bytes())
// Prepare the next packet
packetBuffer.Reset()
packetBuffer.Write([]byte{0x80, 0x63})
binary.Write(&packetBuffer, binary.BigEndian, sequenceNumber+1)
binary.Write(&packetBuffer, binary.BigEndian, (uint32)(elapsed*90))
binary.Write(&packetBuffer, binary.BigEndian, (uint64(0)))
// Reset the Framebuffer
frameBuffer.Reset()
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))