diff --git a/revid/revid.go b/revid/revid.go index 7932ff49..29ac89f7 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -36,7 +36,6 @@ import ( "io" "os" "os/exec" - "path/filepath" "strconv" "time" @@ -88,7 +87,6 @@ type Revid struct { ringBuffer *ring.Buffer config Config isRunning bool - inputFile *os.File generator generator.Generator parser parser.Parser cmd *exec.Cmd @@ -172,7 +170,7 @@ func (r *Revid) reset(config Config) error { switch r.config.Input { case Raspivid: - r.setupInput = r.setupInputForRaspivid + r.setupInput = r.startRaspivid case File: r.setupInput = r.setupInputForFile } @@ -432,13 +430,14 @@ func (r *Revid) outputClips() { } } -// setupInputForRaspivid sets up things for input from raspivid i.e. starts +// startRaspivid sets up things for input from raspivid i.e. starts // a raspivid process and pipes it's data output. -func (r *Revid) setupInputForRaspivid() error { +func (r *Revid) startRaspivid() error { r.Log(Info, "Starting raspivid!") switch r.config.InputCodec { case H264: - arguments := []string{"-cd", "H264", + args := []string{ + "-cd", "H264", "-o", "-", "-n", "-t", r.config.Timeout, @@ -449,33 +448,18 @@ func (r *Revid) setupInputForRaspivid() error { "-ih", "-g", r.config.IntraRefreshPeriod, } - if r.config.QuantizationMode == QuantizationOn { - arguments = append(arguments, "-qp") - arguments = append(arguments, r.config.Quantization) + args = append(args, "-qp", r.config.Quantization) } - if r.config.HorizontalFlip == Yes { - arguments = append(arguments, "-hf") + args = append(args, "-hf") + } + if r.config.VerticalFlip == Yes { + args = append(args, "-vf") } - if r.config.VerticalFlip == Yes { - arguments = append(arguments, "-vf") - } - name := "raspivid" - r.cmd = &exec.Cmd{ - Path: name, - Args: append([]string{name}, arguments...), - } - r.Log(Info, fmt.Sprintf("Startin raspivid with args: %v", r.cmd.Args)) - if filepath.Base(name) == name { - if lp, err := exec.LookPath(name); err != nil { - r.Log(Error, err.Error()) - return err - } else { - r.cmd.Path = lp - } - } + r.Log(Info, fmt.Sprintf("Starting raspivid with args: %v", args)) + r.cmd = exec.Command("raspivid", args...) case Mjpeg: r.cmd = exec.Command("raspivid", @@ -486,31 +470,29 @@ func (r *Revid) setupInputForRaspivid() error { "-fps", r.config.FrameRate, ) } - stdout, _ := r.cmd.StdoutPipe() - go r.cmd.Run() + stdout, err := r.cmd.StdoutPipe() + if err != nil { + return err + } + err = r.cmd.Start() + if err != nil { + return err + } r.inputReader = bufio.NewReader(stdout) go r.readCamera() return nil } -// setupInputForFile sets things up for getting input from a file -func (r *Revid) setupInputForFile() error { - fps, _ := strconv.Atoi(r.config.FrameRate) - r.parser.SetDelay(uint(float64(1000) / float64(fps))) - r.readFile() - return nil -} - // readCamera reads data from the defined camera while the Revid is running. // TODO: use ringbuffer here instead of allocating mem every time! func (r *Revid) readCamera() { r.Log(Info, "Reading camera data!") for r.isRunning { - data := make([]byte, 1) - _, err := io.ReadFull(r.inputReader, data) + var data [1]byte + _, err := io.ReadFull(r.inputReader, data[:]) switch { // We know this means we're getting nothing from the cam - case (err != nil && err.Error() == "EOF" && r.isRunning) || (err != nil && r.isRunning): + case err != nil && r.isRunning: r.Log(Error, "No data from camera!") time.Sleep(cameraRetryPeriod) default: @@ -520,31 +502,39 @@ func (r *Revid) readCamera() { r.Log(Info, "Not trying to read from camera anymore!") } +// setupInputForFile sets things up for getting input from a file +func (r *Revid) setupInputForFile() error { + fps, err := strconv.Atoi(r.config.FrameRate) + if err != nil { + return err + } + r.parser.SetDelay(uint(float64(1000) / float64(fps))) + return r.readFile() +} + // readFile reads data from the defined file while the Revid is running. func (r *Revid) readFile() error { - var err error - r.inputFile, err = os.Open(r.config.InputFileName) + f, err := os.Open(r.config.InputFileName) if err != nil { r.Log(Error, err.Error()) r.Stop() return err } - stats, err := r.inputFile.Stat() - if err != nil { - r.Log(Error, "Could not get input file stats!") - r.Stop() - return err + defer f.Close() + var buf [1 << 12]byte + for { + n, err := f.Read(buf[:]) + for _, b := range buf[:n] { + r.parser.InputChan() <- b + } + if err != nil { + if err == io.EOF { + break + } + r.Log(Error, err.Error()) + r.Stop() + return err + } } - data := make([]byte, stats.Size()) - _, err = r.inputFile.Read(data) - if err != nil { - r.Log(Error, err.Error()) - r.Stop() - return err - } - for i := range data { - r.parser.InputChan() <- data[i] - } - r.inputFile.Close() return nil }