mirror of https://bitbucket.org/ausocean/av.git
Merged in multiple-filters (pull request #315)
Multiple filters Approved-by: Saxon Milton <saxon.milton@gmail.com>
This commit is contained in:
commit
ddd7b5750d
|
@ -54,7 +54,7 @@ func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSi
|
||||||
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize))
|
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize))
|
||||||
var windows []*gocv.Window
|
var windows []*gocv.Window
|
||||||
if debug {
|
if debug {
|
||||||
windows = []*gocv.Window{gocv.NewWindow("Debug: Bounding boxes"), gocv.NewWindow("Debug: Motion")}
|
windows = []*gocv.Window{gocv.NewWindow("KNN: Bounding boxes"), gocv.NewWindow("KNN: Motion")}
|
||||||
}
|
}
|
||||||
return &KNNFilter{dst, area, &bs, k, debug, windows}
|
return &KNNFilter{dst, area, &bs, k, debug, windows}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ func NewMOGFilter(dst io.WriteCloser, area, threshold float64, history int, debu
|
||||||
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3))
|
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3))
|
||||||
var windows []*gocv.Window
|
var windows []*gocv.Window
|
||||||
if debug {
|
if debug {
|
||||||
windows = []*gocv.Window{gocv.NewWindow("Debug: Bounding boxes"), gocv.NewWindow("Debug: Motion")}
|
windows = []*gocv.Window{gocv.NewWindow("MOG: Bounding boxes"), gocv.NewWindow("MOG: Motion")}
|
||||||
}
|
}
|
||||||
return &MOGFilter{dst, area, &bs, k, debug, windows}
|
return &MOGFilter{dst, area, &bs, k, debug, windows}
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,10 +263,10 @@ type Config struct {
|
||||||
Width uint // Width defines the input video width Raspivid input.
|
Width uint // Width defines the input video width Raspivid input.
|
||||||
Bitrate uint // Bitrate specifies the bitrate for constant bitrate in kbps.
|
Bitrate uint // Bitrate specifies the bitrate for constant bitrate in kbps.
|
||||||
|
|
||||||
HorizontalFlip bool // HorizontalFlip flips video horizontally for Raspivid input.
|
HorizontalFlip bool // HorizontalFlip flips video horizontally for Raspivid input.
|
||||||
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
||||||
Filter int // Defines the method of filtering to be used in between lexing and encoding.
|
Filters []int // Defines the methods of filtering to be used in between lexing and encoding.
|
||||||
PSITime int // Sets the time between a packet being sent
|
PSITime int // Sets the time between a packet being sent.
|
||||||
|
|
||||||
// RTMP ring buffer parameters.
|
// RTMP ring buffer parameters.
|
||||||
RTMPRBSize int // The number of elements in the RTMP sender ringbuffer.
|
RTMPRBSize int // The number of elements in the RTMP sender ringbuffer.
|
||||||
|
@ -290,6 +290,7 @@ var TypeData = map[string]string{
|
||||||
"CBR": "bool",
|
"CBR": "bool",
|
||||||
"ClipDuration": "uint",
|
"ClipDuration": "uint",
|
||||||
"Exposure": "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks",
|
"Exposure": "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks",
|
||||||
|
"Filters": "enums:NoOp,MOG,VariableFPS,KNN",
|
||||||
"FrameRate": "uint",
|
"FrameRate": "uint",
|
||||||
"Height": "uint",
|
"Height": "uint",
|
||||||
"HorizontalFlip": "bool",
|
"HorizontalFlip": "bool",
|
||||||
|
|
|
@ -129,8 +129,8 @@ type Revid struct {
|
||||||
// lexTo, encoder and packer handle transcoding the input stream.
|
// lexTo, encoder and packer handle transcoding the input stream.
|
||||||
lexTo func(dest io.Writer, src io.Reader, delay time.Duration) error
|
lexTo func(dest io.Writer, src io.Reader, delay time.Duration) error
|
||||||
|
|
||||||
// filter will hold the filter interface that will write to the chosen filter from the lexer.
|
// filters will hold the filter interface that will write to the chosen filter from the lexer.
|
||||||
filter filter.Filter
|
filters []filter.Filter
|
||||||
|
|
||||||
// encoders will hold the multiWriteCloser that writes to encoders from the filter.
|
// encoders will hold the multiWriteCloser that writes to encoders from the filter.
|
||||||
encoders io.WriteCloser
|
encoders io.WriteCloser
|
||||||
|
@ -346,18 +346,28 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
||||||
|
|
||||||
r.encoders = multiWriter(encoders...)
|
r.encoders = multiWriter(encoders...)
|
||||||
|
|
||||||
switch r.cfg.Filter {
|
l := len(r.cfg.Filters)
|
||||||
case config.FilterNoOp:
|
r.filters = []filter.Filter{filter.NewNoOp(r.encoders)}
|
||||||
r.filter = filter.NewNoOp(r.encoders)
|
if l != 0 {
|
||||||
case config.FilterMOG:
|
r.filters = make([]filter.Filter, l)
|
||||||
r.filter = filter.NewMOGFilter(r.encoders, mogMinArea, mogThreshold, mogHistory, r.cfg.ShowWindows)
|
dst := r.encoders
|
||||||
case config.FilterVariableFPS:
|
|
||||||
r.filter = filter.NewVariableFPSFilter(r.encoders, minFPS, filter.NewMOGFilter(r.encoders, mogMinArea, mogThreshold, mogHistory, r.cfg.ShowWindows))
|
for i := l - 1; i >= 0; i-- {
|
||||||
case config.FilterKNN:
|
switch r.cfg.Filters[i] {
|
||||||
r.filter = filter.NewKNNFilter(r.encoders, knnMinArea, knnThreshold, knnHistory, knnKernel, r.cfg.ShowWindows)
|
case config.FilterNoOp:
|
||||||
|
r.filters[i] = filter.NewNoOp(dst)
|
||||||
|
case config.FilterMOG:
|
||||||
|
r.filters[i] = filter.NewMOGFilter(dst, mogMinArea, mogThreshold, mogHistory, r.cfg.ShowWindows)
|
||||||
|
case config.FilterVariableFPS:
|
||||||
|
r.filters[i] = filter.NewVariableFPSFilter(dst, minFPS, filter.NewMOGFilter(dst, mogMinArea, mogThreshold, mogHistory, r.cfg.ShowWindows))
|
||||||
|
case config.FilterKNN:
|
||||||
|
r.filters[i] = filter.NewKNNFilter(dst, knnMinArea, knnThreshold, knnHistory, knnKernel, r.cfg.ShowWindows)
|
||||||
|
default:
|
||||||
|
panic("Undefined Filter")
|
||||||
|
}
|
||||||
|
dst = r.filters[i]
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
panic("Undefined Filter")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch r.cfg.Input {
|
switch r.cfg.Input {
|
||||||
|
@ -474,10 +484,13 @@ func (r *Revid) Stop() {
|
||||||
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.filter.Close()
|
for _, filter := range r.filters {
|
||||||
if err != nil {
|
err = filter.Close()
|
||||||
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
if err != nil {
|
||||||
|
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"closed pipeline")
|
r.cfg.Logger.Log(logger.Info, pkg+"closed pipeline")
|
||||||
|
|
||||||
if r.cmd != nil && r.cmd.Process != nil {
|
if r.cmd != nil && r.cmd.Process != nil {
|
||||||
|
@ -667,13 +680,17 @@ func (r *Revid) Update(vars map[string]string) error {
|
||||||
default:
|
default:
|
||||||
r.cfg.Logger.Log(logger.Warning, pkg+"invalid VerticalFlip param", "value", value)
|
r.cfg.Logger.Log(logger.Warning, pkg+"invalid VerticalFlip param", "value", value)
|
||||||
}
|
}
|
||||||
case "Filter":
|
case "Filters":
|
||||||
|
filters := strings.Split(value, ",")
|
||||||
m := map[string]int{"NoOp": config.FilterNoOp, "MOG": config.FilterMOG, "VariableFPS": config.FilterVariableFPS, "KNN": config.FilterKNN}
|
m := map[string]int{"NoOp": config.FilterNoOp, "MOG": config.FilterMOG, "VariableFPS": config.FilterVariableFPS, "KNN": config.FilterKNN}
|
||||||
v, ok := m[value]
|
r.cfg.Filters = make([]int, len(filters))
|
||||||
if !ok {
|
for i, filter := range filters {
|
||||||
r.cfg.Logger.Log(logger.Warning, pkg+"invalid FilterMethod param", "value", value)
|
v, ok := m[filter]
|
||||||
|
if !ok {
|
||||||
|
r.cfg.Logger.Log(logger.Warning, pkg+"invalid Filters param", "value", value)
|
||||||
|
}
|
||||||
|
r.cfg.Filters[i] = v
|
||||||
}
|
}
|
||||||
r.cfg.Filter = v
|
|
||||||
case "PSITime":
|
case "PSITime":
|
||||||
v, err := strconv.Atoi(value)
|
v, err := strconv.Atoi(value)
|
||||||
if err != nil || v < 0 {
|
if err != nil || v < 0 {
|
||||||
|
@ -792,7 +809,7 @@ func (r *Revid) Update(vars map[string]string) error {
|
||||||
// processFrom is run as a routine to read from a input data source, lex and
|
// processFrom is run as a routine to read from a input data source, lex and
|
||||||
// then send individual access units to revid's encoders.
|
// then send individual access units to revid's encoders.
|
||||||
func (r *Revid) processFrom(read io.Reader, delay time.Duration) {
|
func (r *Revid) processFrom(read io.Reader, delay time.Duration) {
|
||||||
r.err <- r.lexTo(r.filter, read, delay)
|
r.err <- r.lexTo(r.filters[0], read, delay)
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"finished lexing")
|
r.cfg.Logger.Log(logger.Info, pkg+"finished lexing")
|
||||||
r.wg.Done()
|
r.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue