diff --git a/filter/vfps.go b/filter/vfps.go new file mode 100644 index 00000000..93b6f543 --- /dev/null +++ b/filter/vfps.go @@ -0,0 +1,67 @@ +/* +DESCRIPTION + A motion filter that has a variable frame rate. When motion is detected, + the filter sends all frames and when it is not, the filter sends frames + at a reduced rate, as set by a parameter. + +AUTHORS + Scott Barnard + +LICENSE + vfps.go is Copyright (C) 2019 the Australian Ocean Lab (AusOcean) + + It is free software: you can redistribute it and/or modify them + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + in gpl.txt. If not, see http://www.gnu.org/licenses. +*/ + +package filter + +import ( + "io" +) + +// VariableFPSFilter is a filter that has a variable frame rate. When motion is +// detected, the filter sends all frames and when it is not, the filter +// sends frames at a reduced framerate. +type VariableFPSFilter struct { + filter Filter + dst io.WriteCloser + frames uint + count uint +} + +// NewVariableFPSFilter returns a pointer to a new VariableFPSFilter struct. +func NewVariableFPSFilter(dst io.WriteCloser, minFPS float64, filter Filter) *VariableFPSFilter { + frames := uint(25 / minFPS) + return &VariableFPSFilter{filter, dst, frames, 0} +} + +// Implements io.Writer. +// Write applies the motion filter to the video stream. Frames are sent +// at a reduced frame rate, except when motion is detected, then all frames +// with motion are sent. +func (v *VariableFPSFilter) Write(f []byte) (int, error) { + v.count = (v.count + 1) % v.frames + + if v.count == 0 { + return v.dst.Write(f) + } + + return v.filter.Write(f) +} + +// Implements io.Closer. +// Close calls the motion filter's Close method. +func (v *VariableFPSFilter) Close() error { + return v.filter.Close() +} diff --git a/revid/config/config.go b/revid/config/config.go index 275abda3..00c4dda0 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -112,6 +112,7 @@ const ( const ( FilterNoOp = iota FilterMOG + FilterVariableFPS ) // Config provides parameters relevant to a revid instance. A new config must diff --git a/revid/revid.go b/revid/revid.go index 6d2832a3..d2558057 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -333,6 +333,8 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. r.filter = filter.NewNoOp(r.encoders) case config.FilterMOG: r.filter = filter.NewMOGFilter(r.encoders, 25, 20, 500, 3, true) + case config.FilterVariableFPS: + r.filter = filter.NewVariableFPSFilter(r.encoders, 1.0, filter.NewMOGFilter(r.encoders, 25, 20, 500, 3, true)) default: panic("Undefined Filter") } @@ -645,7 +647,7 @@ func (r *Revid) Update(vars map[string]string) error { r.cfg.Logger.Log(logger.Warning, pkg+"invalid VerticalFlip param", "value", value) } case "Filter": - m := map[string]int{"NoOp": config.FilterNoOp, "MOG": config.FilterMOG} + m := map[string]int{"NoOp": config.FilterNoOp, "MOG": config.FilterMOG, "VariableFPS": config.FilterVariableFPS} v, ok := m[value] if !ok { r.cfg.Logger.Log(logger.Warning, pkg+"invalid FilterMethod param", "value", value)