Performance improvements (avoid allocations for every packet)
This commit is contained in:
parent
3006672e43
commit
ce0a817cb9
3 changed files with 65 additions and 14 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@
|
||||||
*.jpg
|
*.jpg
|
||||||
*.jpeg
|
*.jpeg
|
||||||
actioncam
|
actioncam
|
||||||
|
*.prof
|
||||||
|
|
|
||||||
38
actioncam.go
38
actioncam.go
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
|
|
||||||
"github.com/jonas-koeritz/actioncam/libipcamera"
|
"github.com/jonas-koeritz/actioncam/libipcamera"
|
||||||
"github.com/jonas-koeritz/actioncam/rtsp"
|
"github.com/jonas-koeritz/actioncam/rtsp"
|
||||||
|
|
@ -30,6 +32,10 @@ func main() {
|
||||||
var password string
|
var password string
|
||||||
var port int16
|
var port int16
|
||||||
var verbose bool
|
var verbose bool
|
||||||
|
var cpuprofile string
|
||||||
|
var memoryprofile string
|
||||||
|
|
||||||
|
var cpuprofileFile *os.File
|
||||||
|
|
||||||
var camera *libipcamera.Camera
|
var camera *libipcamera.Camera
|
||||||
|
|
||||||
|
|
@ -46,18 +52,50 @@ func main() {
|
||||||
|
|
||||||
bufio.NewReader(os.Stdin).ReadBytes('\n')
|
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) {
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
|
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
|
||||||
},
|
},
|
||||||
PostRun: func(cmd *cobra.Command, args []string) {
|
PostRun: func(cmd *cobra.Command, args []string) {
|
||||||
camera.Disconnect()
|
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().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(&username, "username", "u", "admin", "Specify the camera username")
|
||||||
rootCmd.PersistentFlags().StringVarP(&password, "password", "p", "12345", "Specify the camera password")
|
rootCmd.PersistentFlags().StringVarP(&password, "password", "p", "12345", "Specify the camera password")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print verbose output")
|
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{
|
var ls = &cobra.Command{
|
||||||
Use: "ls [Cameras IP Address]",
|
Use: "ls [Cameras IP Address]",
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ func CreateRTPRelay(targetAddress net.IP, targetPort int) *RTPRelay {
|
||||||
|
|
||||||
func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
|
func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
|
||||||
buffer := make([]byte, 2048)
|
buffer := make([]byte, 2048)
|
||||||
|
packetReader := bytes.NewReader(buffer)
|
||||||
|
|
||||||
header := StreamHeader{}
|
header := StreamHeader{}
|
||||||
var payload []byte
|
var payload []byte
|
||||||
|
|
||||||
|
|
@ -58,7 +60,8 @@ func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
|
||||||
var sequenceNumber uint16
|
var sequenceNumber uint16
|
||||||
var elapsed uint32
|
var elapsed uint32
|
||||||
|
|
||||||
frameBuffer := []byte{}
|
frameBuffer := bytes.Buffer{}
|
||||||
|
packetBuffer := bytes.Buffer{}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if relay.close {
|
if relay.close {
|
||||||
|
|
@ -67,18 +70,20 @@ func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.ReadFrom(buffer)
|
conn.ReadFrom(buffer)
|
||||||
packetReader := bytes.NewReader(buffer)
|
packetReader.Reset(buffer)
|
||||||
|
|
||||||
binary.Read(packetReader, binary.BigEndian, &header)
|
binary.Read(packetReader, binary.BigEndian, &header)
|
||||||
|
|
||||||
if header.Magic != 0xBCDE {
|
if header.Magic != 0xBCDE {
|
||||||
log.Printf("Received message with invalid magic (%x).", header.Magic)
|
log.Printf("Received message with invalid magic (%x).", header.Magic)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if header.Length > 0 {
|
if header.Length > 0 {
|
||||||
payload = make([]byte, header.Length)
|
payload = make([]byte, header.Length)
|
||||||
bytesRead, err := io.ReadFull(packetReader, payload)
|
_, err := io.ReadFull(packetReader, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Read Error: %s, %d bytes\n", err, bytesRead)
|
log.Printf("Read Error: %s\n", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -87,19 +92,26 @@ func handleCameraStream(relay RTPRelay, conn net.PacketConn) {
|
||||||
|
|
||||||
switch header.MessageType {
|
switch header.MessageType {
|
||||||
case 0x0001: // H.264 Data
|
case 0x0001: // H.264 Data
|
||||||
frameBuffer = append(frameBuffer, payload...)
|
frameBuffer.Write(payload)
|
||||||
case 0x0002: // Time
|
case 0x0002: // Time
|
||||||
packet := bytes.Buffer{}
|
// Append the Framebuffer
|
||||||
packet.Write([]byte{0x80, 0x63})
|
packetBuffer.Write(frameBuffer.Bytes())
|
||||||
binary.Write(&packet, binary.BigEndian, sequenceNumber)
|
|
||||||
binary.Write(&packet, binary.BigEndian, (uint32)(elapsed*90))
|
// Send out the packet
|
||||||
binary.Write(&packet, binary.BigEndian, (uint64(0)))
|
rtpConn.Write(packetBuffer.Bytes())
|
||||||
packet.Write(frameBuffer)
|
|
||||||
rtpConn.Write(packet.Bytes())
|
// Prepare the next packet
|
||||||
frameBuffer = []byte{}
|
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++
|
sequenceNumber++
|
||||||
|
|
||||||
elapsed = binary.LittleEndian.Uint32(payload[12:])
|
elapsed = binary.LittleEndian.Uint32(payload[12:])
|
||||||
//log.Printf("Elapsed: %d (%x)\n", elapsed, payload[12:])
|
|
||||||
default:
|
default:
|
||||||
log.Printf("Received Unknown Message: %+v\n", header)
|
log.Printf("Received Unknown Message: %+v\n", header)
|
||||||
log.Printf("Payload:\n%s\n", hex.Dump(payload))
|
log.Printf("Payload:\n%s\n", hex.Dump(payload))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue