diff --git a/filter/basic.go b/filter/basic.go index 2bc0b6fb..1b439d2a 100644 --- a/filter/basic.go +++ b/filter/basic.go @@ -34,6 +34,13 @@ import ( "image/jpeg" "io" "sync" + + "bitbucket.org/ausocean/av/revid/config" +) + +const ( + defaultBasicThreshold = 45000 + defaultBasicPixels = 1000 ) type pixel struct{ r, g, b uint32 } @@ -54,11 +61,22 @@ type Basic struct { } // NewBasic returns a pointer to a new Basic filter struct. -func NewBasic(dst io.WriteCloser, t, p int) *Basic { +func NewBasic(dst io.WriteCloser, c config.Config) *Basic { + // Validate parameters. + if c.MotionThreshold <= 0 { + c.LogInvalidField("MotionThreshold", defaultBasicThreshold) + c.MotionThreshold = defaultBasicThreshold + } + + if c.MotionPixels <= 0 { + c.LogInvalidField("MotionPixels", defaultBasicPixels) + c.MotionPixels = defaultBasicPixels + } + return &Basic{ dst: dst, - thresh: t, - pix: p, + thresh: int(c.MotionThreshold), + pix: c.MotionPixels, debugging: newWindows("BASIC"), } } diff --git a/filter/difference.go b/filter/difference.go index 2593407f..7d36d5c2 100644 --- a/filter/difference.go +++ b/filter/difference.go @@ -33,9 +33,12 @@ import ( "fmt" "io" + "bitbucket.org/ausocean/av/revid/config" "gocv.io/x/gocv" ) +const defaultDiffThreshold = 3 + // Difference is a filter that provides basic motion detection. Difference calculates // the absolute difference for each pixel between two frames, then finds the mean. If // the mean is above a given threshold, then it is considered motion. @@ -47,10 +50,16 @@ type Difference struct { } // NewDifference returns a pointer to a new Difference struct. -func NewDifference(dst io.WriteCloser, threshold float64) *Difference { +func NewDifference(dst io.WriteCloser, c config.Config) *Difference { + // Validate parameters. + if c.MotionThreshold <= 0 { + c.LogInvalidField("MotionThreshold", defaultDiffThreshold) + c.MotionThreshold = defaultDiffThreshold + } + return &Difference{ dst: dst, - thresh: threshold, + thresh: c.MotionThreshold, prev: gocv.NewMat(), debugging: newWindows("DIFF"), } diff --git a/filter/filters_circleci.go b/filter/filters_circleci.go index ab9a9620..127e3dda 100644 --- a/filter/filters_circleci.go +++ b/filter/filters_circleci.go @@ -30,20 +30,22 @@ package filter import ( "image" "io" + + "bitbucket.org/ausocean/av/revid/config" ) // NewMOG returns a pointer to a new NoOp struct for testing purposes only. -func NewMOG(dst io.WriteCloser, area, threshold float64, history int, hf int, scaleFactor int) *NoOp { +func NewMOG(dst io.WriteCloser, c config.Config) *NoOp { return &NoOp{dst: dst} } // NewKNN returns a pointer to a new NoOp struct for testing purposes only. -func NewKNN(dst io.WriteCloser, area, threshold float64, history, kernelSize int, hf int, scaleFactor int) *NoOp { +func NewKNN(dst io.WriteCloser, c config.Config) *NoOp { return &NoOp{dst: dst} } // NewDiffference returns a pointer to a new NoOp struct for testing purposes only. -func NewDifference(dst io.WriteCloser, threshold float64) *NoOp { +func NewDifference(dst io.WriteCloser, c config.Config) *NoOp { return &NoOp{dst: dst} } diff --git a/filter/knn.go b/filter/knn.go index 72873b4a..31c97c27 100644 --- a/filter/knn.go +++ b/filter/knn.go @@ -33,9 +33,19 @@ import ( "image" "io" + "bitbucket.org/ausocean/av/revid/config" "gocv.io/x/gocv" ) +const ( + defaultKNNMinArea = 25.0 + defaultKNNThreshold = 300 + defaultKNNHistory = 300 + defaultKNNKernel = 4 + defaultKNNDownscaling = 2 + defaultKNNInterval = 1 +) + // KNN is a filter that provides basic motion detection. KNN is short for // K-Nearest Neighbours method. type KNN struct { @@ -51,17 +61,44 @@ type KNN struct { } // NewKNN returns a pointer to a new KNN filter struct. -func NewKNN(dst io.WriteCloser, area, threshold float64, history, kernelSize int, hf int, scaleFactor int) *KNN { - bs := gocv.NewBackgroundSubtractorKNNWithParams(history, threshold, false) - k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize)) +func NewKNN(dst io.WriteCloser, c config.Config) *KNN { + // Validate parameters. + if c.MotionMinArea <= 0 { + c.LogInvalidField("MotionMinArea", defaultKNNMinArea) + c.MotionMinArea = defaultKNNMinArea + } + if c.MotionThreshold <= 0 { + c.LogInvalidField("MotionThreshold", defaultKNNThreshold) + c.MotionThreshold = defaultKNNThreshold + } + if c.MotionHistory == 0 { + c.LogInvalidField("MotionHistory", defaultKNNHistory) + c.MotionHistory = defaultKNNHistory + } + if c.MotionDownscaling <= 0 { + c.LogInvalidField("MotionDownscaling", defaultKNNDownscaling) + c.MotionDownscaling = defaultKNNDownscaling + } + if c.MotionInterval <= 0 { + c.LogInvalidField("MotionInterval", defaultKNNInterval) + c.MotionInterval = defaultKNNInterval + } + if c.MotionKernel <= 0 { + c.LogInvalidField("MotionKernel", defaultKNNKernel) + c.MotionKernel = defaultKNNKernel + } + + bs := gocv.NewBackgroundSubtractorKNNWithParams(int(c.MotionHistory), c.MotionThreshold, false) + k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(int(c.MotionKernel), int(c.MotionKernel))) + return &KNN{ dst: dst, - area: area, + area: c.MotionMinArea, bs: &bs, knl: k, - hold: make([][]byte, hf-1), - hf: hf, - scale: 1 / float64(scaleFactor), + hold: make([][]byte, c.MotionInterval-1), + hf: c.MotionInterval, + scale: 1 / float64(c.MotionDownscaling), debugging: newWindows("KNN"), } } diff --git a/filter/mog.go b/filter/mog.go index 701cf0ff..93bd4f92 100644 --- a/filter/mog.go +++ b/filter/mog.go @@ -33,9 +33,19 @@ import ( "image" "io" + "bitbucket.org/ausocean/av/revid/config" "gocv.io/x/gocv" ) +const ( + defaultMOGMinArea = 25.0 + defaultMOGThreshold = 20.0 + defaultMOGHistory = 500 + defaultMOGKernel = 3 + defaultMOGDownscaling = 2 + defaultMOGInterval = 1 +) + // MOG is a filter that provides basic motion detection. MoG is short for // Mixture of Gaussians method. type MOG struct { @@ -51,17 +61,43 @@ type MOG struct { } // NewMOG returns a pointer to a new MOG filter struct. -func NewMOG(dst io.WriteCloser, area, threshold float64, history int, hf int, scaleFactor int) *MOG { - bs := gocv.NewBackgroundSubtractorMOG2WithParams(history, threshold, false) +func NewMOG(dst io.WriteCloser, c config.Config) *MOG { + // Validate parameters. + if c.MotionMinArea <= 0 { + c.LogInvalidField("MotionMinArea", defaultMOGMinArea) + c.MotionMinArea = defaultMOGMinArea + } + if c.MotionThreshold <= 0 { + c.LogInvalidField("MotionThreshold", defaultMOGThreshold) + c.MotionThreshold = defaultMOGThreshold + } + if c.MotionHistory == 0 { + c.LogInvalidField("MotionHistory", defaultMOGHistory) + c.MotionHistory = defaultMOGHistory + } + if c.MotionDownscaling <= 0 { + c.LogInvalidField("MotionDownscaling", defaultMOGDownscaling) + c.MotionDownscaling = defaultMOGDownscaling + } + if c.MotionInterval <= 0 { + c.LogInvalidField("MotionInterval", defaultMOGInterval) + c.MotionInterval = defaultMOGInterval + } + if c.MotionKernel <= 0 { + c.LogInvalidField("MotionKernel", defaultMOGKernel) + c.MotionKernel = defaultMOGKernel + } + + bs := gocv.NewBackgroundSubtractorMOG2WithParams(int(c.MotionHistory), c.MotionThreshold, false) k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3)) return &MOG{ dst: dst, - area: area, + area: c.MotionMinArea, bs: &bs, knl: k, - hold: make([][]byte, hf-1), - hf: hf, - scale: 1 / float64(scaleFactor), + hold: make([][]byte, c.MotionInterval-1), + hf: c.MotionInterval, + scale: 1 / float64(c.MotionDownscaling), debugging: newWindows("MOG"), } } diff --git a/revid/config/config.go b/revid/config/config.go index 04dc88ba..cb483526 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -91,24 +91,7 @@ const ( defaultRBWriteTimeout = 5 // Motion filter parameter defaults. - defaultMinFPS = 1.0 - defaultMotionDownscaling = 1 - defaultMotionInterval = 1 - - // KNN filter parameter defaults. - defaultKNNMinArea = 25.0 - defaultKNNThreshold = 300 - defaultKNNHistory = 300 - defaultKNNKernel = 9 - - // MOG filter parameter defaults. - defaultMOGMinArea = 25.0 - defaultMOGThreshold = 20.0 - defaultMOGHistory = 500 - - // Basic filter parameter defaults - defaultBasicThreshold = 45000 - defaultBasicPixels = 1000 + defaultMinFPS = 1.0 ) // Quality represents video quality. @@ -283,27 +266,16 @@ type Config struct { RBWriteTimeout int // The ringbuffer write timeout in seconds. // Motion filter parameters. + // Some parameters can be used with any filter, while others can only be used by a few. MinFPS float64 // The reduced framerate of the video when there is no motion. - MotionInterval int // Sets the number of frames that are held before the filter is used (on the nth frame) + MotionInterval int // Sets the number of frames that are held before the filter is used (on the nth frame). MotionDownscaling int // Downscaling factor of frames used for motion detection. - // KNN filter parameters. - KNNMinArea float64 // Used to ignore small areas of motion detection. - KNNThreshold float64 // Intensity value from the KNN motion detection algorithm that is considered motion. - KNNHistory uint // Length of KNN filter's history - KNNKernel uint // Size of kernel used for filling holes and removing noise. - - // MOG filter parameters. - MOGMinArea float64 // Used to ignore small areas of motion detection. - MOGThreshold float64 // Intensity value from the KNN motion detection algorithm that is considered motion. - MOGHistory uint // Length of MOG filter's history. - - // Difference filter parameters. - DiffThreshold float64 // Intensity value from the Difference motion detection algorithm that is considered motion. - - // Basic filter parameters. - BasicThreshold int - BasicPixels int + MotionMinArea float64 // Used to ignore small areas of motion detection (KNN & MOG only). + MotionThreshold float64 // Intensity value that is considered motion. + MotionHistory uint // Length of filter's history (KNN & MOG only). + MotionKernel uint // Size of kernel used for filling holes and removing noise (KNN only). + MotionPixels int // Number of pixels with motion that is needed for a whole frame to be considered as moving (Basic only). // If true will restart reading of input after an io.EOF. Loop bool @@ -316,8 +288,6 @@ type Config struct { // can be set over the web. It is a psuedo const. var TypeData = map[string]string{ "AutoWhiteBalance": "enum:off,auto,sun,cloud,shade,tungsten,fluorescent,incandescent,flash,horizon", - "BasicPixels": "int", - "BasicThreshold": "int", "BitDepth": "int", "Brightness": "uint", "BurstPeriod": "uint", @@ -325,7 +295,6 @@ var TypeData = map[string]string{ "CameraIP": "string", "CBR": "bool", "ClipDuration": "uint", - "DiffThreshold": "float", "Exposure": "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks", "FileFPS": "int", "Filters": "enums:NoOp,MOG,VariableFPS,KNN,Difference,Basic", @@ -336,20 +305,18 @@ var TypeData = map[string]string{ "Input": "enum:raspivid,rtsp,v4l,file", "InputCodec": "enum:H264,MJPEG", "InputPath": "string", - "KNNHistory": "uint", - "KNNKernel": "float", - "KNNMinArea": "float", - "KNNThreshold": "float", "logging": "enum:Debug,Info,Warning,Error,Fatal", "Loop": "bool", "MinFPS": "float", "MinFrames": "uint", "mode": "enum:Normal,Paused,Burst,Loop", - "MOGHistory": "uint", - "MOGMinArea": "float", - "MOGThreshold": "float", "MotionDownscaling": "uint", + "MotionHistory": "uint", "MotionInterval": "int", + "MotionKernel": "uint", + "MotionMinArea": "float", + "MotionPixels": "int", + "MotionThreshold": "float", "Output": "enum:File,Http,Rtmp,Rtp", "OutputPath": "string", "Outputs": "enums:File,Http,Rtmp,Rtp", @@ -378,19 +345,19 @@ func (c *Config) Validate() error { switch c.LogLevel { case logger.Debug, logger.Info, logger.Warning, logger.Error, logger.Fatal: default: - c.logInvalidField("LogLevel", defaultVerbosity) + c.LogInvalidField("LogLevel", defaultVerbosity) c.LogLevel = defaultVerbosity } if c.CameraIP == "" { - c.logInvalidField("CameraIP", defaultCameraIP) + c.LogInvalidField("CameraIP", defaultCameraIP) c.CameraIP = defaultCameraIP } switch c.Input { case InputRaspivid, InputV4L, InputFile, InputAudio, InputRTSP: case NothingDefined: - c.logInvalidField("Input", defaultInput) + c.LogInvalidField("Input", defaultInput) c.Input = defaultInput default: return errors.New("bad input type defined in config") @@ -401,16 +368,16 @@ func (c *Config) Validate() error { default: switch c.Input { case OutputAudio: - c.logInvalidField("InputCodec", defaultAudioInputCodec) + c.LogInvalidField("InputCodec", defaultAudioInputCodec) c.InputCodec = defaultAudioInputCodec default: - c.logInvalidField("InputCodec", defaultInputCodec) + c.LogInvalidField("InputCodec", defaultInputCodec) c.InputCodec = defaultInputCodec } } if c.Outputs == nil { - c.logInvalidField("Outputs", defaultOutput) + c.LogInvalidField("Outputs", defaultOutput) c.Outputs = append(c.Outputs, defaultOutput) } @@ -428,14 +395,14 @@ func (c *Config) Validate() error { } if c.BurstPeriod == 0 { - c.logInvalidField("BurstPeriod", defaultBurstPeriod) + c.LogInvalidField("BurstPeriod", defaultBurstPeriod) c.BurstPeriod = defaultBurstPeriod } const maxMinFrames = 1000 switch { case c.MinFrames == 0: - c.logInvalidField("MinFrames", defaultMinFrames) + c.LogInvalidField("MinFrames", defaultMinFrames) c.MinFrames = defaultMinFrames case c.MinFrames < 0: return errors.New("refresh period is less than 0") @@ -444,115 +411,60 @@ func (c *Config) Validate() error { } if c.FrameRate <= 0 { - c.logInvalidField("FrameRate", defaultFrameRate) + c.LogInvalidField("FrameRate", defaultFrameRate) c.FrameRate = defaultFrameRate } if c.WriteRate <= 0 { - c.logInvalidField("writeRate", defaultWriteRate) + c.LogInvalidField("writeRate", defaultWriteRate) c.WriteRate = defaultWriteRate } if c.ClipDuration == 0 { - c.logInvalidField("ClipDuration", defaultClipDuration) + c.LogInvalidField("ClipDuration", defaultClipDuration) c.ClipDuration = defaultClipDuration } else if c.ClipDuration < 0 { return errors.New("clip duration is less than 0") } if c.RTPAddress == "" { - c.logInvalidField("RTPAddress", defaultRtpAddr) + c.LogInvalidField("RTPAddress", defaultRtpAddr) c.RTPAddress = defaultRtpAddr } if c.RBMaxElements <= 0 { - c.logInvalidField("RBMaxElements", defaultRBMaxElements) + c.LogInvalidField("RBMaxElements", defaultRBMaxElements) c.RBMaxElements = defaultRBMaxElements } if c.RBCapacity <= 0 { - c.logInvalidField("RBCapacity", defaultRBCapacity) + c.LogInvalidField("RBCapacity", defaultRBCapacity) c.RBCapacity = defaultRBCapacity } if c.RBWriteTimeout <= 0 { - c.logInvalidField("RBWriteTimeout", defaultRBWriteTimeout) + c.LogInvalidField("RBWriteTimeout", defaultRBWriteTimeout) c.RBWriteTimeout = defaultRBWriteTimeout } if c.PSITime <= 0 { - c.logInvalidField("PSITime", defaultPSITime) + c.LogInvalidField("PSITime", defaultPSITime) c.PSITime = defaultPSITime } - if c.MotionInterval <= 0 { - c.logInvalidField("MotionInterval", defaultMotionInterval) - c.MotionInterval = defaultMotionInterval - } - if c.MinFPS <= 0 { - c.logInvalidField("MinFPS", defaultMinFPS) + c.LogInvalidField("MinFPS", defaultMinFPS) c.MinFPS = defaultMinFPS } - if c.KNNMinArea <= 0 { - c.logInvalidField("KNNMinArea", defaultKNNMinArea) - c.KNNMinArea = defaultKNNMinArea - } - - if c.KNNThreshold <= 0 { - c.logInvalidField("KNNThreshold", defaultKNNThreshold) - c.KNNThreshold = defaultKNNThreshold - } - - if c.KNNHistory == 0 { - c.logInvalidField("KNNHistory", defaultKNNHistory) - c.KNNHistory = defaultKNNHistory - } - - if c.KNNKernel <= 0 { - c.logInvalidField("KNNKernel", defaultKNNKernel) - c.KNNKernel = defaultKNNKernel - } - - if c.MOGMinArea <= 0 { - c.logInvalidField("MOGMinArea", defaultMOGMinArea) - c.MOGMinArea = defaultMOGMinArea - } - - if c.MOGThreshold <= 0 { - c.logInvalidField("MOGThreshold", defaultMOGThreshold) - c.MOGThreshold = defaultMOGThreshold - } - - if c.MOGHistory == 0 { - c.logInvalidField("MOGHistory", defaultMOGHistory) - c.MOGHistory = defaultMOGHistory - } - - if c.BasicThreshold <= 0 { - c.logInvalidField("BasicThreshold", defaultBasicThreshold) - c.BasicThreshold = defaultBasicThreshold - } - - if c.BasicPixels <= 0 { - c.logInvalidField("BasicPixels", defaultBasicPixels) - c.BasicPixels = defaultBasicPixels - } - - if c.MotionDownscaling <= 0 { - c.logInvalidField("MotionDownscaling", defaultMotionDownscaling) - c.MotionDownscaling = defaultMotionDownscaling - } - if c.FileFPS <= 0 || (c.FileFPS > 0 && c.Input != InputFile) { - c.logInvalidField("FileFPS", defaultFileFPS) + c.LogInvalidField("FileFPS", defaultFileFPS) c.FileFPS = defaultFileFPS } return nil } -func (c *Config) logInvalidField(name string, def interface{}) { +func (c *Config) LogInvalidField(name string, def interface{}) { c.Logger.Log(logger.Info, pkg+name+" bad or unset, defaulting", name, def) } diff --git a/revid/revid.go b/revid/revid.go index 5dd37678..fae9b1ea 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -334,15 +334,15 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. case config.FilterNoOp: r.filters[i] = filter.NewNoOp(dst) case config.FilterMOG: - r.filters[i] = filter.NewMOG(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.MotionInterval, r.cfg.MotionDownscaling) + r.filters[i] = filter.NewMOG(dst, r.cfg) case config.FilterVariableFPS: - r.filters[i] = filter.NewVariableFPS(dst, r.cfg.MinFPS, filter.NewMOG(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.MotionInterval, r.cfg.MotionDownscaling)) + r.filters[i] = filter.NewVariableFPS(dst, r.cfg.MinFPS, filter.NewMOG(dst, r.cfg)) case config.FilterKNN: - r.filters[i] = filter.NewKNN(dst, r.cfg.KNNMinArea, r.cfg.KNNThreshold, int(r.cfg.KNNHistory), int(r.cfg.KNNKernel), r.cfg.MotionInterval, r.cfg.MotionDownscaling) + r.filters[i] = filter.NewKNN(dst, r.cfg) case config.FilterDifference: - r.filters[i] = filter.NewDifference(dst, r.cfg.DiffThreshold) + r.filters[i] = filter.NewDifference(dst, r.cfg) case config.FilterBasic: - r.filters[i] = filter.NewBasic(dst, r.cfg.BasicThreshold, r.cfg.BasicPixels) + r.filters[i] = filter.NewBasic(dst, r.cfg) default: panic("Undefined Filter") } @@ -685,13 +685,6 @@ func (r *Revid) Update(vars map[string]string) error { } r.cfg.Filters[i] = v } - case "MotionInterval": - v, err := strconv.Atoi(value) - if err != nil || v < 0 { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionInterval var", "value", value) - break - } - r.cfg.MotionInterval = v case "PSITime": v, err := strconv.Atoi(value) if err != nil || v < 0 { @@ -800,77 +793,55 @@ func (r *Revid) Update(vars map[string]string) error { break } r.cfg.MinFPS = v - case "KNNMinArea": + case "MotionMinArea": v, err := strconv.ParseFloat(value, 64) if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid KNNMinArea var", "value", value) + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionMinArea var", "value", value) break } - r.cfg.KNNMinArea = v - case "KNNThreshold": + r.cfg.MotionMinArea = v + case "MotionThreshold": v, err := strconv.ParseFloat(value, 64) if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid KNNThreshold var", "value", value) + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionThreshold var", "value", value) break } - r.cfg.KNNThreshold = v - case "DiffThreshold": - v, err := strconv.ParseFloat(value, 64) - if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid DiffThreshold var", "value", value) - break - } - r.cfg.DiffThreshold = v - case "KNNKernel": + r.cfg.MotionThreshold = v + case "MotionKernel": v, err := strconv.Atoi(value) if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid KNNKernel var", "value", value) + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionKernel var", "value", value) break } - r.cfg.KNNKernel = uint(v) - case "MOGMinArea": - v, err := strconv.ParseFloat(value, 64) - if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid MOGMinArea var", "value", value) - break - } - r.cfg.MOGMinArea = v - case "MOGThreshold": - v, err := strconv.ParseFloat(value, 64) - if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid MOGThreshold var", "value", value) - break - } - r.cfg.MOGThreshold = v - case "KNNHistory": + r.cfg.MotionKernel = uint(v) + case "MotionHistory": v, err := strconv.Atoi(value) if err != nil || v <= 0 { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid KNNHistory var", "value", value) + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionHistory var", "value", value) break } - r.cfg.KNNHistory = uint(v) - case "MOGHistory": - v, err := strconv.Atoi(value) - if err != nil || v <= 0 { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid MOGHistory var", "value", value) - break - } - r.cfg.MOGHistory = uint(v) - - case "BasicThreshold": + r.cfg.MotionHistory = uint(v) + case "MotionPixels": v, err := strconv.Atoi(value) if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid BasicThreshold var", "value", value) + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionPixels var", "value", value) break } - r.cfg.BasicThreshold = v - case "BasicPixels": + r.cfg.MotionPixels = v + case "MotionDownscaling": v, err := strconv.Atoi(value) if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid BasicPixels var", "value", value) + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionDownscaling var", "value", value) break } - r.cfg.BasicPixels = v + r.cfg.MotionDownscaling = v + case "MotionInterval": + v, err := strconv.Atoi(value) + if err != nil || v < 0 { + r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionInterval var", "value", value) + break + } + r.cfg.MotionInterval = v case "FileFPS": v, err := strconv.Atoi(value) if err != nil { @@ -883,13 +854,6 @@ func (r *Revid) Update(vars map[string]string) error { if value == "Loop" { r.cfg.Loop = true } - case "MotionDownscaling": - v, err := strconv.Atoi(value) - if err != nil { - r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionDownscaling var", "value", value) - break - } - r.cfg.MotionDownscaling = v } } r.cfg.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.cfg))