Compare commits

...

6 Commits

Author SHA1 Message Date
Cedric Verstraeten
4cc8135e1a move StoreSnapshot to separate method 2023-02-17 20:03:15 +01:00
Cedric Verstraeten
3cb38099ea add process memory + boot time 2023-02-15 13:01:16 +01:00
Cedric Verstraeten
deb0308dc4 rename attributes 2023-02-15 07:02:16 +01:00
Cedric Verstraeten
24c729eea3 Update Cloud.go 2023-02-14 23:11:55 +01:00
Cedric Verstraeten
c59d511ea3 fix for macs and ips 2023-02-14 22:55:18 +01:00
Cedric Verstraeten
6f8745dc3a alignment of motion recordings, make sure there is no overlap between two sibling recordings 2023-02-14 16:59:00 +01:00
5 changed files with 91 additions and 153 deletions

View File

@@ -272,6 +272,9 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
var file *os.File
var err error
var lastDuration time.Duration
var lastRecordingTime int64
for motion := range communication.HandleMotion {
timestamp = time.Now().Unix()
@@ -281,7 +284,16 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
// If we have prerecording we will substract the number of seconds.
// Taking into account FPS = GOP size (Keyfram interval)
if config.Capture.PreRecording > 0 {
startRecording = startRecording - int64(config.Capture.PreRecording) + 1
// Might be that recordings are coming short after each other.
// Therefore we do some math with the current time and the last recording time.
timeBetweenNowAndLastRecording := startRecording - lastRecordingTime
if timeBetweenNowAndLastRecording > int64(config.Capture.PreRecording) {
startRecording = startRecording - int64(config.Capture.PreRecording) + 1
} else {
startRecording = startRecording - timeBetweenNowAndLastRecording
}
}
// timestamp_microseconds_instanceName_regionCoordinates_numberOfChanges_token
@@ -351,7 +363,7 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
log.Log.Info("HandleRecordStream: closing recording (timestamp: " + strconv.FormatInt(timestamp, 10) + ", recordingPeriod: " + strconv.FormatInt(recordingPeriod, 10) + ", now: " + strconv.FormatInt(now, 10) + ", startRecording: " + strconv.FormatInt(startRecording, 10) + ", maxRecordingPeriod: " + strconv.FormatInt(maxRecordingPeriod, 10))
break
}
if pkt.IsKeyFrame && !start {
if pkt.IsKeyFrame && !start && pkt.Time >= lastDuration {
log.Log.Info("HandleRecordStream: write frames")
start = true
}
@@ -378,6 +390,9 @@ func HandleRecordStream(queue *pubsub.Queue, configuration *models.Configuration
myMuxer.WriteTrailerWithPacket(nextPkt)
log.Log.Info("HandleRecordStream: file save: " + name)
lastDuration = pkt.Time
lastRecordingTime = time.Now().Unix()
// Cleanup muxer
myMuxer.Close()
myMuxer = nil

View File

@@ -95,6 +95,9 @@ func GetSystemInfo() (models.System, error) {
var usedMem uint64 = 0
var totalMem uint64 = 0
var freeMem uint64 = 0
var processUsedMem uint64 = 0
architecture := ""
cpuId := ""
KernelVersion := ""
@@ -133,18 +136,27 @@ func GetSystemInfo() (models.System, error) {
}
}
process, err := sysinfo.Self()
if err == nil {
memInfo, err := process.Memory()
if err == nil {
processUsedMem = memInfo.Resident
}
}
system := models.System{
Hostname: hostname,
CPUId: cpuId,
KernelVersion: KernelVersion,
Version: agentVersion,
MACs: MACs,
IPs: IPs,
BootTime: uint64(bootTime.Unix()),
Architecture: architecture,
UsedMemory: usedMem,
TotalMemory: totalMem,
FreeMemory: freeMem,
Hostname: hostname,
CPUId: cpuId,
KernelVersion: KernelVersion,
Version: agentVersion,
MACs: MACs,
IPs: IPs,
BootTime: uint64(bootTime.Unix()),
Architecture: architecture,
UsedMemory: usedMem,
TotalMemory: totalMem,
FreeMemory: freeMem,
ProcessUsedMemory: processUsedMem,
}
return system, nil
@@ -200,6 +212,11 @@ func HandleHeartBeat(configuration *models.Configuration, communication *models.
uptimeString := carbon.Parse(uptimeFormatted).DiffForHumans()
uptimeString = strings.ReplaceAll(uptimeString, "ago", "")
// Do the same for boottime
bootTimeFormatted := time.Unix(int64(system.BootTime), 0).Format("2006-01-02 15:04:05")
boottimeString := carbon.Parse(bootTimeFormatted).DiffForHumans()
boottimeString = strings.ReplaceAll(boottimeString, "ago", "")
// We'll check which mode is enabled for the camera.
onvifEnabled := "false"
if config.Capture.IPCamera.ONVIFXAddr != "" {
@@ -221,6 +238,10 @@ func HandleHeartBeat(configuration *models.Configuration, communication *models.
isEnterprise = true
}
// Congert to string
macs, _ := json.Marshal(system.MACs)
ips, _ := json.Marshal(system.IPs)
var object = fmt.Sprintf(`{
"key" : "%s",
"version" : "3.0.0",
@@ -235,13 +256,15 @@ func HandleHeartBeat(configuration *models.Configuration, communication *models.
"totalMemory" : "%d",
"usedMemory" : "%d",
"freeMemory" : "%d",
"macs" : "%v",
"ips" : "%v",
"processMemory" : "%d",
"mac_list" : %s,
"ip_list" : %s,
"board" : "",
"disk1size" : "%s",
"disk3size" : "%s",
"diskvdasize" : "%s",
"uptime" : "%s",
"boot_time" : "%s",
"siteID" : "%s",
"onvif" : "%s",
"numberoffiles" : "33",
@@ -250,7 +273,7 @@ func HandleHeartBeat(configuration *models.Configuration, communication *models.
"docker" : true,
"kios" : false,
"raspberrypi" : false
}`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.MACs, system.IPs, "0", "0", "0", uptimeString, config.HubSite, onvifEnabled)
}`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled)
var jsonStr = []byte(object)
buffy := bytes.NewBuffer(jsonStr)

View File

@@ -130,26 +130,7 @@ func ProcessMotion(motionCursor *pubsub.QueueCursor, configuration *models.Confi
// Store snapshots (jpg) for hull.
if config.Capture.Snapshots != "false" {
files, err := ioutil.ReadDir("./data/snapshots")
if err == nil {
rgbImage, err := GetRawImage(frame, pkt, decoder, decoderMutex)
if err == nil {
sort.Slice(files, func(i, j int) bool {
return files[i].ModTime().Before(files[j].ModTime())
})
if len(files) > 3 {
os.Remove("./data/snapshots/" + files[0].Name())
}
// Save image
t := strconv.FormatInt(time.Now().Unix(), 10)
f, err := os.Create("./data/snapshots/" + t + ".jpg")
if err == nil {
jpeg.Encode(f, &rgbImage.Image, &jpeg.Options{Quality: 15})
f.Close()
}
}
}
StoreSnapshot(frame, pkt, decoder, decoderMutex)
}
// Check if within time interval
@@ -255,3 +236,26 @@ func AbsDiffBitwiseAndThreshold(img1 *image.Gray, img2 *image.Gray, img3 *image.
}
return changes
}
func StoreSnapshot(frame *ffmpeg.VideoFrame, pkt av.Packet, decoder *ffmpeg.VideoDecoder, decoderMutex *sync.Mutex) {
files, err := ioutil.ReadDir("./data/snapshots")
if err == nil {
rgbImage, err := GetRawImage(frame, pkt, decoder, decoderMutex)
if err == nil {
sort.Slice(files, func(i, j int) bool {
return files[i].ModTime().Before(files[j].ModTime())
})
if len(files) > 3 {
os.Remove("./data/snapshots/" + files[0].Name())
}
// Save image
t := strconv.FormatInt(time.Now().Unix(), 10)
f, err := os.Create("./data/snapshots/" + t + ".jpg")
if err == nil {
jpeg.Encode(f, &rgbImage.Image, &jpeg.Options{Quality: 15})
f.Close()
}
}
}
}

View File

@@ -1,16 +1,17 @@
package models
type System struct {
CPUId string `json:"cpu_idle" bson:"cpu_idle"`
Hostname string `json:"hostname" bson:"hostname"`
Version string `json:"version" bson:"version"`
Release string `json:"release" bson:"release"`
BootTime uint64 `json:"boot_time" bson:"boot_time"`
KernelVersion string `json:"kernel_version" bson:"kernel_version"`
MACs []string `json:"macs" bson:"macs"`
IPs []string `json:"ips" bson:"ips"`
Architecture string `json:"architecture" bson:"architecture"`
UsedMemory uint64 `json:"used_memory" bson:"used_memory"`
TotalMemory uint64 `json:"total_memory" bson:"total_memory"`
FreeMemory uint64 `json:"free_memory" bson:"free_memory"`
CPUId string `json:"cpu_idle" bson:"cpu_idle"`
Hostname string `json:"hostname" bson:"hostname"`
Version string `json:"version" bson:"version"`
Release string `json:"release" bson:"release"`
BootTime uint64 `json:"boot_time" bson:"boot_time"`
KernelVersion string `json:"kernel_version" bson:"kernel_version"`
MACs []string `json:"macs" bson:"macs"`
IPs []string `json:"ips" bson:"ips"`
Architecture string `json:"architecture" bson:"architecture"`
UsedMemory uint64 `json:"used_memory" bson:"used_memory"`
TotalMemory uint64 `json:"total_memory" bson:"total_memory"`
FreeMemory uint64 `json:"free_memory" bson:"free_memory"`
ProcessUsedMemory uint64 `json:"process_used_memory" bson:"process_used_memory"`
}

View File

@@ -271,108 +271,3 @@ func CreateFragmentedMP4(fullName string, fragmentedDuration int64) {
os.Remove(fullName)
os.Rename(fullName+"f.mp4", fullName)
}
/*func FloatToString(input_num float64) string {
// to convert a float number to a string
return strconv.FormatFloat(input_num, 'f', 6, 64)
}
func ParseFMP4(file *bytes.Reader) (error, uint64, uint64, []*mp4.MediaSegment, uint64) {
var ftypSize, moovSize uint64
var segments []*mp4.MediaSegment
var duration uint64
parsedMp4, err := mp4.DecodeFile(file, mp4.WithDecodeMode(mp4.DecModeLazyMdat))
if parsedMp4 != nil && parsedMp4.Init != nil && err == nil {
ftypSize = parsedMp4.Init.Ftyp.Size()
moovSize = parsedMp4.Init.Moov.Size()
duration = parsedMp4.Moov.Trak.Tkhd.Duration
segments = parsedMp4.Segments
}
return err, ftypSize, moovSize, segments, duration
}
func ParseFMP4Detail(fullName string) {
// open fullName
file, err := os.Open(fullName)
if err != nil {
log.Log.Error("Error opening file: " + err.Error())
}
defer file.Close()
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
log.Log.Error("Error reading file: " + err.Error())
}
fileReader := bytes.NewReader(fileBytes)
err, ftypSize, moovSize, segments, dur := ParseFMP4(fileReader)
fmt.Println("========== Fragmented details =================")
fmt.Println(dur)
fmt.Println(ftypSize)
fmt.Println(moovSize)
fmt.Println(len(segments))
// Calculate duration of segments
var totalDuration uint64
for _, segment := range segments {
fragments := segment.Fragments
for _, fragment := range fragments {
var sampleDuration uint32
samples := fragment.Moof.Traf.Trun.Samples
for _, sample := range samples {
sampleDuration += sample.Dur
}
fmt.Println(sampleDuration)
totalDuration += uint64(sampleDuration)
}
}
misingDuration := dur - totalDuration/100
fmt.Println(misingDuration)
fmt.Println(totalDuration/100 + misingDuration)
}
func CreateFragmentByteRanges(log log.Logging, fileName string, ftypSize uint64, moovSize uint64, segments []*mp4.MediaSegment) (string, []models.BytesRangeOnTime) {
size := strconv.FormatInt(int64(ftypSize+moovSize), 10)
var fileFragments strings.Builder
fileFragments.WriteString("#EXT-X-MAP:URI=\"" + fileName + "\",BYTERANGE=\"" + size + "@0\"\n")
var bytesRangeOnTime []models.BytesRangeOnTime
var currentTime uint32
for _, segment := range segments {
fragments := segment.Fragments
for _, fragment := range fragments {
var sampleDuration uint32
samples := fragment.Moof.Traf.Trun.Samples
for _, sample := range samples {
sampleDuration += sample.Dur
}
currentTime = currentTime + sampleDuration
duration := FloatToString(float64(sampleDuration / 100000))
startPos := fragment.Moof.StartPos
start := strconv.FormatInt(int64(startPos), 10)
totalSize := fragment.Mdat.Size() + fragment.Moof.Size()
size := strconv.FormatInt(int64(totalSize), 10)
fileFragments.WriteString("#EXTINF:" + duration + ",\n") // @TODO calculate the duration
fileFragments.WriteString("#EXT-X-BYTERANGE:" + size + "@" + start + "\n")
fileFragments.WriteString(fileName + "\n")
byteRange := models.BytesRangeOnTime{
Duration: duration,
Time: FloatToString(float64(currentTime) / 100000),
Range: size + "@" + start,
}
bytesRangeOnTime = append(bytesRangeOnTime, byteRange)
}
}
bytesRanges := fileFragments.String()
log.Info("Fragments calculate from " + fileName + ": " + bytesRanges)
return bytesRanges, bytesRangeOnTime
}*/