func (e *Encoder) fixValues() {
	switch {
	case e.config.Height == 0:
		e.config.Height = DefaultFrameHeight
	case e.config.Height > MaximumFrameSize:
		e.config.Height = MaximumFrameSize
	case e.config.Height < MinimumFrameSize:
		e.config.Height = MinimumFrameSize
	}
	switch {
	case e.config.Width == 0:
		e.config.Width = DefaultFrameWidth
	case e.config.Width > MaximumFrameSize:
		e.config.Width = MaximumFrameSize
	case e.config.Width < MinimumFrameSize:
		e.config.Width = MinimumFrameSize
	}
	switch {
	case e.config.CRF == 0:
		e.config.CRF = DefaultEncodeCRF
	case e.config.CRF < MinimumEncodeCRF:
		e.config.CRF = MinimumEncodeCRF
	case e.config.CRF > MaximumEncodeCRF:
		e.config.CRF = MaximumEncodeCRF
	}
	switch {
	case e.config.Rate == 0:
		e.config.Rate = DefaultFrameRate
	case e.config.Rate < MinimumFrameRate:
		e.config.Rate = MinimumFrameRate
	case e.config.Rate > MaximumFrameRate:
		e.config.Rate = MaximumFrameRate
	}
	if e.config.Time == 0 {
		e.config.Time = DefaultCaptureTime
	} else if e.config.Time > MaximumCaptureTime {
		e.config.Time = MaximumCaptureTime
	}
	if e.config.Size == 0 {
		e.config.Size = DefaultCaptureSize
	} else if e.config.Size > MaximumCaptureSize {
		e.config.Size = MaximumCaptureSize
	}
}
fixValues makes sure video request values are sane.
package ffmpeg
import (
	"bytes"
	"fmt"
	"io"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
)
var (
	DefaultFrameRate   = 5
	MinimumFrameRate   = 1
	MaximumFrameRate   = 60
	DefaultFrameHeight = 720
	DefaultFrameWidth  = 1280
	MinimumFrameSize   = 100
	MaximumFrameSize   = 5000
	DefaultEncodeCRF   = 21
	MinimumEncodeCRF   = 16
	MaximumEncodeCRF   = 30
	DefaultCaptureTime = 15
	MaximumCaptureTime = 1200              
	DefaultCaptureSize = int64(2500000)    
	MaximumCaptureSize = int64(104857600)  
	DefaultFFmpegPath  = "/usr/local/bin/ffmpeg"
	DefaultProfile     = "main"
	DefaultLevel       = "3.0"
)
var (
	ErrorInvalidOutput = fmt.Errorf("output path is not valid")
	ErrorInvalidInput  = fmt.Errorf("input path is not valid")
)
type Config struct {
	Copy   bool    
	Audio  bool    
	Width  int     
	Height int     
	CRF    int     
	Time   int     
	Rate   int     
	Size   int64   
	FFMPEG string  
	Level  string  
	Prof   string  
}
type Encoder struct {
	config *Config
}
func Get(config *Config) *Encoder {
	e := &Encoder{config: config}
	if e.config.FFMPEG == "" {
		e.config.FFMPEG = DefaultFFmpegPath
	}
	e.SetLevel(e.config.Level)
	e.SetProfile(e.config.Prof)
	e.fixValues()
	return e
}
func (e *Encoder) Config() Config {
	return *e.config
}
func (e *Encoder) SetAudio(audio string) bool {
	e.config.Audio, _ = strconv.ParseBool(audio)
	return e.config.Audio
}
func (e *Encoder) SetLevel(level string) string {
	if e.config.Level = level; level != "3.0" && level != "3.1" && level != "4.0" && level != "4.1" && level != "4.2" {
		e.config.Level = DefaultLevel
	}
	return e.config.Level
}
func (e *Encoder) SetProfile(profile string) string {
	if e.config.Prof = profile; e.config.Prof != "main" && e.config.Prof != "baseline" && e.config.Prof != "high" {
		e.config.Prof = DefaultProfile
	}
	return e.config.Prof
}
func (e *Encoder) SetWidth(width string) int {
	e.config.Width, _ = strconv.Atoi(width)
	e.fixValues()
	return e.config.Width
}
func (e *Encoder) SetHeight(height string) int {
	e.config.Height, _ = strconv.Atoi(height)
	e.fixValues()
	return e.config.Height
}
func (e *Encoder) SetCRF(crf string) int {
	e.config.CRF, _ = strconv.Atoi(crf)
	e.fixValues()
	return e.config.CRF
}
func (e *Encoder) SetTime(seconds string) int {
	e.config.Time, _ = strconv.Atoi(seconds)
	e.fixValues()
	return e.config.Time
}
func (e *Encoder) SetRate(rate string) int {
	e.config.Rate, _ = strconv.Atoi(rate)
	e.fixValues()
	return e.config.Rate
}
func (e *Encoder) SetSize(size string) int64 {
	e.config.Size, _ = strconv.ParseInt(size, 10, 64)
	e.fixValues()
	return e.config.Size
}
func (e *Encoder) getVideoHandle(input, output, title string) (string, *exec.Cmd) {
	if title == "" {
		title = filepath.Base(output)
	}
	arg := []string{
		e.config.FFMPEG,
		"-v", "16",  
		"-rtsp_transport", "tcp",
		"-i", input,
		"-f", "mov",
		"-metadata", `title="` + title + `"`,
		"-y", "-map", "0",
	}
	if e.config.Size > 0 {
		arg = append(arg, "-fs", strconv.FormatInt(e.config.Size, 10))
	}
	if e.config.Time > 0 {
		arg = append(arg, "-t", strconv.Itoa(e.config.Time))
	}
	if !e.config.Copy {
		arg = append(arg, "-vcodec", "libx264",
			"-profile:v", e.config.Prof,
			"-level", e.config.Level,
			"-pix_fmt", "yuv420p",
			"-movflags", "faststart",
			"-s", strconv.Itoa(e.config.Width)+"x"+strconv.Itoa(e.config.Height),
			"-preset", "superfast",
			"-crf", strconv.Itoa(e.config.CRF),
			"-r", strconv.Itoa(e.config.Rate),
		)
	} else {
		arg = append(arg, "-c", "copy")
	}
	if !e.config.Audio {
		arg = append(arg, "-an")
	} else {
		arg = append(arg, "-c:a", "copy")
	}
	arg = append(arg, output)  
	return strings.Join(arg, " "), exec.Command(arg[0], arg[1:]...)
}
func (e *Encoder) GetVideo(input, title string) (string, io.ReadCloser, error) {
	if input == "" {
		return "", nil, ErrorInvalidInput
	}
	cmdStr, cmd := e.getVideoHandle(input, "-", title)
	stdoutpipe, err := cmd.StdoutPipe()
	if err != nil {
		return cmdStr, nil, fmt.Errorf("subcommand failed: %w", err)
	}
	return cmdStr, stdoutpipe, cmd.Run()
}
func (e *Encoder) SaveVideo(input, output, title string) (string, string, error) {
	if input == "" {
		return "", "", ErrorInvalidInput
	} else if output == "" || output == "-" {
		return "", "", ErrorInvalidOutput
	}
	cmdStr, cmd := e.getVideoHandle(input, output, title)
	var out bytes.Buffer
	cmd.Stderr, cmd.Stdout = &out, &out
	if err := cmd.Start(); err != nil {
		return cmdStr, strings.TrimSpace(out.String()), fmt.Errorf("subcommand failed: %w", err)
	} else if err := cmd.Wait(); err != nil {
		return cmdStr, strings.TrimSpace(out.String()), fmt.Errorf("subcommand failed: %w", err)
	}
	return cmdStr, strings.TrimSpace(out.String()), nil
}