diff --git a/cmd/revid-cli/main.go b/cmd/revid-cli/main.go index bced0a4f..fc4d863f 100644 --- a/cmd/revid-cli/main.go +++ b/cmd/revid-cli/main.go @@ -122,6 +122,7 @@ func handleFlags() config.Config { httpAddressPtr = flag.String("HttpAddress", "", "Destination address of http posts") verticalFlipPtr = flag.Bool("VerticalFlip", false, "Flip video vertically: Yes, No") horizontalFlipPtr = flag.Bool("HorizontalFlip", false, "Flip video horizontally: Yes, No") + loopPtr = flag.Bool("Loop", false, "Loop video if EOF encountered: true, false") bitratePtr = flag.Uint("Bitrate", 0, "Bitrate of recorded video") heightPtr = flag.Uint("Height", 0, "Height in pixels") widthPtr = flag.Uint("Width", 0, "Width in pixels") @@ -179,6 +180,8 @@ func handleFlags() config.Config { } } + cfg.Loop = *loopPtr + switch *inputPtr { case "Raspivid": cfg.Input = config.InputRaspivid diff --git a/revid/config/config.go b/revid/config/config.go index 194faf33..47a8eaf9 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -297,6 +297,9 @@ type Config struct { 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 + + // If true will restart reading of input after an io.EOF. + Loop bool } // TypeData contains information about all of the variables that diff --git a/revid/revid.go b/revid/revid.go index 8b1b42da..9c414480 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -428,13 +428,8 @@ func (r *Revid) Start() error { return err } - err = r.input.Start() - if err != nil { - return fmt.Errorf("could not start input device: %w", err) - } - r.wg.Add(1) - go r.processFrom(r.input, 0) + go r.processFrom(r.input, (1000/25)*time.Millisecond) r.running = true return nil @@ -845,6 +840,11 @@ func (r *Revid) Update(vars map[string]string) error { break } r.cfg.MOGHistory = uint(v) + case "mode": + r.cfg.Loop = false + if value == "Loop" { + r.cfg.Loop = true + } } } r.cfg.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.cfg)) @@ -853,14 +853,35 @@ func (r *Revid) Update(vars map[string]string) error { // processFrom is run as a routine to read from a input data source, lex and // then send individual access units to revid's encoders. -func (r *Revid) processFrom(read io.Reader, delay time.Duration) { - err := r.lexTo(r.filters[0], read, delay) - r.cfg.Logger.Log(logger.Debug, pkg+"finished lexing") +func (r *Revid) processFrom(in device.AVDevice, delay time.Duration) { +restart: + err := in.Start() + if err != nil { + r.err <- fmt.Errorf("could not start input device: %w", err) + r.wg.Done() + return + } + + // Lex data from input device, in, until finished or an error is encountered. + // For a continuous source e.g. a camera or microphone, we should remain + // in this call indefinitely unless in.Stop() is called and an io.EOF is forced. + err = r.lexTo(r.filters[0], in, delay) switch err { - case nil: // Do nothing. - case io.EOF: // TODO: handle this depending on loop mode. + case nil, io.EOF, io.ErrUnexpectedEOF: default: r.err <- err } + + err = in.Stop() + if err != nil { + r.err <- fmt.Errorf("could not stop input source: %w", err) + } + + if r.cfg.Loop { + r.cfg.Logger.Log(logger.Info, pkg+"looping input") + goto restart + } + + r.cfg.Logger.Log(logger.Info, pkg+"finished lexing") r.wg.Done() }