From 81aa35b586120aafac7c2f2e70ee81736fed0252 Mon Sep 17 00:00:00 2001 From: Saxon Milton Date: Wed, 12 Feb 2020 00:27:08 +0000 Subject: [PATCH] Merged in parameter-implementations (pull request #376) revid/config/parameter: wrote code for the generation of Parameter interface implementations and commit resulting code Using a template, code has been created to generate repetitive implementations of an interface name Parameter. The code iterates through a list of params and creates implementations for each one. Approved-by: Scott Barnard --- revid/config/parameter/generate_parameters.go | 303 ++++++ revid/config/parameter/parameters.go | 903 ++++++++++++++++++ 2 files changed, 1206 insertions(+) create mode 100644 revid/config/parameter/generate_parameters.go create mode 100644 revid/config/parameter/parameters.go diff --git a/revid/config/parameter/generate_parameters.go b/revid/config/parameter/generate_parameters.go new file mode 100644 index 00000000..aeeb2131 --- /dev/null +++ b/revid/config/parameter/generate_parameters.go @@ -0,0 +1,303 @@ +// +build ignore + +/* +DESCRIPTION + generate_parameters.go uses a template to generate implementations for the + Parameter interface. + +LICENSE + Copyright (C) 2020 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 + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. +*/ + +package main + +import ( + "bytes" + "fmt" + "go/format" + "math" + "os" + "strings" + "text/template" +) + +// Filename to house Parameter interface implementations. +const fileName = "parameters.go" + +// Param holds characteristics for describing Parameter interface implementations. +type Param struct { + // N is the name of the struct implementing the Parameter interface. + N string + + // R is the name of the receiver for the Type and Set methods. This is set to + // the lowercase of the first letter of the Parameter implementation name, N. + R string + + // BT is the base type of a Parameter implementation. For example, for a + // Parameter implementation named Bitrate, i.e. type Bitrate uint, the base + // type is uint. + BT string + + // E are the enums of a type i.e. if there is a list of identifiers we wish + // to recocgnise, they are specified here. For example, a Parameter implementation + // named Output may take on a value of HTTP, RTMP, RTP or File, so E is set to + // []string{"HTTP","RTMP","RTP","File"} and a const list of type Output will be + // generated as a result: + // const ( + // OutputHTTP Output = iota + // OutputRTMP + // OutputRTP + // OutputFile + // ) + E []string + + // M, if defined, indicates a "multiple option type", which is to mean a slice + // of another type that is defined. For example, if the base type, BT, is set + // to a slice of a type "[]Output" (where Output is also defined in the params + // list), then M would be set to "Output". The E field must be manually set to + // be consistent with the Enums defined for the Output type. + M string + + // If we wish an int, uint, or float64 value to be constrained to a particular + // range then Min and Max are both set to indicate the inclusive Min and Max + // possible values for a type. This will result in the generation of a range + // check in the implementation's Set method. + Min, Max int +} + +// NB: Alphabetical order. +var params = []Param{ + {N: "AutoWhiteBalance", BT: "uint8", E: []string{"Off", "Auto", "Sun", "Cloud", "Shade", "Tungsten", "Fluorescent", "Incandescent", "Flash", "Horizon"}}, + {N: "BitDepth", BT: "uint"}, // TODO(Trek): bounds. + {N: "Bitrate", BT: "uint", Min: 1000, Max: 10000000}, + {N: "Brightness", BT: "uint", Min: 0, Max: 100}, + {N: "BurstPeriod", BT: "time.Duration"}, + {N: "CBR", BT: "bool"}, + {N: "CameraChan", BT: "uint8", E: []string{"Channel1", "Channel2"}}, + {N: "CameraIP", BT: "string"}, + {N: "Channels", BT: "uint"}, // TODO(Trek): bounds. + {N: "ClipDuration", BT: "time.Duration"}, + {N: "Codec", BT: "uint8", E: []string{"H264", "H265", "MJPEG", "PCM", "ADPCM"}}, + {N: "Exposure", BT: "uint8", E: []string{"Auto", "Night", "NightPreview", "BackLight", "SpotLight", "Sports", "Snow", "Beach", "VeryLong", "FixedFPS", "AntiShake", "Fireworks"}}, + {N: "FileFPS", BT: "uint", Min: 1, Max: 30}, + {N: "Filter", BT: "uint8", E: []string{"NoOp", "MOG", "VariableFPS", "KNN", "Difference", "Basic"}}, + {N: "FrameRate", BT: "uint", Min: 1, Max: 30}, + {N: "HTTPAddress", BT: "string"}, + {N: "Height", BT: "uint", Min: 360, Max: 1080}, + {N: "HorizontalFlip", BT: "bool"}, + {N: "Input", BT: "uint8", E: []string{"File", "Raspivid", "Webcam", "RTSP"}}, + {N: "InputPath", BT: "string"}, + {N: "Level", BT: "uint8", E: []string{"Debug", "Info", "Warning", "Error", "Fatal"}}, + {N: "MinFPS", BT: "uint", Min: 1, Max: 30}, + {N: "MinFrames", BT: "uint", Min: 0, Max: 1000}, + {N: "Mode", BT: "uint8", E: []string{"Normal", "Paused", "Burst", "Loop"}}, + {N: "MotionDownscaling", BT: "uint"}, // TODO(Scott): define bounds. + {N: "MotionHistory", BT: "uint"}, // TODO(Scott/Ella): define bounds. + {N: "MotionInterval", BT: "uint", Min: 0, Max: 30}, + {N: "MotionKernel", BT: "uint"}, // TODO(Scott/Ella): define bounds. + {N: "MotionMinArea", BT: "float64"}, // TODO(Scott/Ella): define bounds. + {N: "MotionPixels", BT: "uint"}, // TODO(Scott/Ella): define bounds. + {N: "MotionThreshold", BT: "float64"}, // TODO(Scott/Ella): define bounds. + {N: "Output", BT: "uint8", E: []string{"HTTP", "RTMP", "RTP", "File"}}, + {N: "OutputPath", BT: "string"}, + {N: "Outputs", BT: "[]Output", M: "Output", E: []string{"HTTP", "RTMP", "RTP", "File"}}, + {N: "PSITime", BT: "time.Duration"}, + {N: "Quantization", BT: "uint"}, + {N: "RBCapacity", BT: "uint", Min: 1000000, Max: 100000000}, + {N: "RBMaxElements", BT: "uint", Min: 0, Max: math.MaxUint32}, + {N: "RBWriteTimeout", BT: "time.Duration"}, + {N: "RTMPURL", BT: "string"}, + {N: "RTPAddress", BT: "string"}, + {N: "RecPeriod", BT: "float64"}, // TODO(Trek): bounds. + {N: "Rotation", BT: "uint", Min: 0, Max: 359}, + {N: "SampleRate", BT: "uint"}, // TODO(Trek): bounds. + {N: "Saturation", BT: "int", Min: -50, Max: 50}, + {N: "ShowWindows", BT: "bool"}, + {N: "VBRBitrate", BT: "uint", Min: 1, Max: 30}, + {N: "VBRQuality", BT: "uint8", E: []string{"Standard", "Fair", "Good", "Great", "Excellent"}}, + {N: "VerticalFlip", BT: "bool"}, + {N: "Width", BT: "uint", Min: 640, Max: 1920}, + {N: "WriteRate", BT: "float64"}, +} + +const fileHeader = ` +/* +DESCRIPTION + Code generated by "go run generate_parameters.go”; DO NOT EDIT. + + parameters.go contains implementations of the Parameter interface for all + parameter types required by the configuration struct. + +AUTHORS + Saxon Nelson-Milton + +LICENSE + Copyright (C) 2020 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 + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. +*/ + +package parameter + +import ( + "fmt" + "strconv" + "time" + "strings" +) + +type Parameter interface { + Type() string + Set(val string) error +} +` + +const paramTemplate = ` +type {{.N}} {{.BT}} +{{if and .E (not .M)}} +const ( + {{$name := .N}} + {{- range $i, $e := .E}}{{- if eq $i 0}}{{$name}}{{$e}} {{$name}} = iota{{else}}{{$name}}{{$e}}{{end}} + {{end -}} +) +{{end -}} + +{{- if .E}} +func ({{.R}} *{{.N}}) Type() string { return "enum:{{range $i, $e := .E}}{{if eq $i 0}}{{$e}}{{else}},{{$e}}{{end}}{{end}}"} +{{else}} +func ({{.R}} *{{.N}}) Type() string { return "{{.BT}}"} +{{end -}} + +func ({{.R}} *{{.N}}) Set(val string) error { + {{- if eq .BT "string"}} + *{{.R}} = {{.N}}(val) + {{else if eq .BT "bool"}} + switch val { + case "true": + *{{.R}} = true + case "false": + *{{.R}} = false + default: + return fmt.Errorf("not boolean value: %s",val) + } + {{else if eq .BT "int"}} + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w",err) + } + *{{.R}} = {{.N}}(_v) + {{else if eq .BT "uint"}} + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w",err) + } + *{{.R}} = {{.N}}(_v) + {{else if eq .BT "float64"}} + _v, err := strconv.ParseFloat(val,64) + if err != nil { + return fmt.Errorf("could not convert set string to float: %w",err) + } + *{{.R}} = {{.N}}(_v) + {{else if eq .BT "time.Duration"}} + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w",err) + } + *{{.R}} = {{.N}}(time.Duration(_v)*time.Second) + {{else if .M}} + vals := strings.Split(val, ",") + *{{.R}} = make({{.BT}}, len(vals)) + + for i, v := range vals { + switch v { + {{- $receiver := .R}} + {{- $m := .M}} + {{range .E}}case "{{ . }}": + (*{{$receiver}})[i] = {{$m}}{{ . }} + {{end -}} + default: + return fmt.Errorf("unrecognised {{.N}}: %s",val) + } + } + {{else}} + switch val { + {{- $receiver := .R}} + {{- $name := .N}} + {{range .E}}case "{{ . }}": + *{{$receiver}} = {{$name}}{{ . }} + {{end -}} + default: + return fmt.Errorf("unrecognised {{.N}}: %s",val) + } + {{end -}} + + {{- if and (or (or (eq .BT "int") (eq .BT "uint")) (eq .BT "float64")) (ne .Min .Max)}} + if *{{.R}} < {{.Min}} || *{{.R}} > {{.Max}} { + return fmt.Errorf("invalid value %v",*{{.R}}) + } + {{end -}} + + return nil +} +` + +func main() { + f, err := os.Create(fileName) + if err != nil { + panic(fmt.Sprintf("error creating %s file: %v", fileName, err)) + } + defer f.Close() + + var buf bytes.Buffer + + _, err = buf.Write([]byte(fileHeader)) + if err != nil { + panic(fmt.Sprintf("error writing header: %v", err)) + } + + param := template.Must(template.New("param").Parse(paramTemplate)) + + for _, p := range params { + // Use first letter of parameter name as receiver. + p.R = strings.ToLower(p.N[:1]) + err = param.Execute(&buf, p) + if err != nil { + panic(fmt.Sprintf("error executing template: %v", err)) + } + } + + b, err := format.Source(buf.Bytes()) + if err != nil { + f.Write(buf.Bytes()) // Useful to debug bad format. + panic(fmt.Sprintf("error formatting: %v", err)) + } + + _, err = f.Write(b) + if err != nil { + panic(fmt.Sprintf("error writing %s file: %v", fileName, err)) + } +} diff --git a/revid/config/parameter/parameters.go b/revid/config/parameter/parameters.go new file mode 100644 index 00000000..c82dad74 --- /dev/null +++ b/revid/config/parameter/parameters.go @@ -0,0 +1,903 @@ +/* +DESCRIPTION + Code generated by "go build generate_parameters.go; ./generate_parameters”; DO NOT EDIT. + + parameters.go contains implementations of the Parameter interface for all + parameter types required by the configuration struct. + +AUTHORS + Saxon Nelson-Milton + +LICENSE + Copyright (C) 2020 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 + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. +*/ + +package parameter + +import ( + "fmt" + "strconv" + "strings" + "time" +) + +type Parameter interface { + Type() string + Set(val string) error +} + +type AutoWhiteBalance uint8 + +const ( + AutoWhiteBalanceOff AutoWhiteBalance = iota + AutoWhiteBalanceAuto + AutoWhiteBalanceSun + AutoWhiteBalanceCloud + AutoWhiteBalanceShade + AutoWhiteBalanceTungsten + AutoWhiteBalanceFluorescent + AutoWhiteBalanceIncandescent + AutoWhiteBalanceFlash + AutoWhiteBalanceHorizon +) + +func (a *AutoWhiteBalance) Type() string { + return "enum:Off,Auto,Sun,Cloud,Shade,Tungsten,Fluorescent,Incandescent,Flash,Horizon" +} +func (a *AutoWhiteBalance) Set(val string) error { + switch val { + case "Off": + *a = AutoWhiteBalanceOff + case "Auto": + *a = AutoWhiteBalanceAuto + case "Sun": + *a = AutoWhiteBalanceSun + case "Cloud": + *a = AutoWhiteBalanceCloud + case "Shade": + *a = AutoWhiteBalanceShade + case "Tungsten": + *a = AutoWhiteBalanceTungsten + case "Fluorescent": + *a = AutoWhiteBalanceFluorescent + case "Incandescent": + *a = AutoWhiteBalanceIncandescent + case "Flash": + *a = AutoWhiteBalanceFlash + case "Horizon": + *a = AutoWhiteBalanceHorizon + default: + return fmt.Errorf("unrecognised AutoWhiteBalance: %s", val) + } + return nil +} + +type BitDepth uint + +func (b *BitDepth) Type() string { return "uint" } +func (b *BitDepth) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *b = BitDepth(_v) + return nil +} + +type Bitrate uint + +func (b *Bitrate) Type() string { return "uint" } +func (b *Bitrate) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *b = Bitrate(_v) + + if *b < 1000 || *b > 10000000 { + return fmt.Errorf("invalid value %v", *b) + } + return nil +} + +type Brightness uint + +func (b *Brightness) Type() string { return "uint" } +func (b *Brightness) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *b = Brightness(_v) + + if *b < 0 || *b > 100 { + return fmt.Errorf("invalid value %v", *b) + } + return nil +} + +type BurstPeriod time.Duration + +func (b *BurstPeriod) Type() string { return "time.Duration" } +func (b *BurstPeriod) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *b = BurstPeriod(time.Duration(_v) * time.Second) + return nil +} + +type CBR bool + +func (c *CBR) Type() string { return "bool" } +func (c *CBR) Set(val string) error { + switch val { + case "true": + *c = true + case "false": + *c = false + default: + return fmt.Errorf("not boolean value: %s", val) + } + return nil +} + +type CameraChan uint8 + +const ( + CameraChanChannel1 CameraChan = iota + CameraChanChannel2 +) + +func (c *CameraChan) Type() string { return "enum:Channel1,Channel2" } +func (c *CameraChan) Set(val string) error { + switch val { + case "Channel1": + *c = CameraChanChannel1 + case "Channel2": + *c = CameraChanChannel2 + default: + return fmt.Errorf("unrecognised CameraChan: %s", val) + } + return nil +} + +type CameraIP string + +func (c *CameraIP) Type() string { return "string" } +func (c *CameraIP) Set(val string) error { + *c = CameraIP(val) + return nil +} + +type Channels uint + +func (c *Channels) Type() string { return "uint" } +func (c *Channels) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *c = Channels(_v) + return nil +} + +type ClipDuration time.Duration + +func (c *ClipDuration) Type() string { return "time.Duration" } +func (c *ClipDuration) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *c = ClipDuration(time.Duration(_v) * time.Second) + return nil +} + +type Codec uint8 + +const ( + CodecH264 Codec = iota + CodecH265 + CodecMJPEG + CodecPCM + CodecADPCM +) + +func (c *Codec) Type() string { return "enum:H264,H265,MJPEG,PCM,ADPCM" } +func (c *Codec) Set(val string) error { + switch val { + case "H264": + *c = CodecH264 + case "H265": + *c = CodecH265 + case "MJPEG": + *c = CodecMJPEG + case "PCM": + *c = CodecPCM + case "ADPCM": + *c = CodecADPCM + default: + return fmt.Errorf("unrecognised Codec: %s", val) + } + return nil +} + +type Exposure uint8 + +const ( + ExposureAuto Exposure = iota + ExposureNight + ExposureNightPreview + ExposureBackLight + ExposureSpotLight + ExposureSports + ExposureSnow + ExposureBeach + ExposureVeryLong + ExposureFixedFPS + ExposureAntiShake + ExposureFireworks +) + +func (e *Exposure) Type() string { + return "enum:Auto,Night,NightPreview,BackLight,SpotLight,Sports,Snow,Beach,VeryLong,FixedFPS,AntiShake,Fireworks" +} +func (e *Exposure) Set(val string) error { + switch val { + case "Auto": + *e = ExposureAuto + case "Night": + *e = ExposureNight + case "NightPreview": + *e = ExposureNightPreview + case "BackLight": + *e = ExposureBackLight + case "SpotLight": + *e = ExposureSpotLight + case "Sports": + *e = ExposureSports + case "Snow": + *e = ExposureSnow + case "Beach": + *e = ExposureBeach + case "VeryLong": + *e = ExposureVeryLong + case "FixedFPS": + *e = ExposureFixedFPS + case "AntiShake": + *e = ExposureAntiShake + case "Fireworks": + *e = ExposureFireworks + default: + return fmt.Errorf("unrecognised Exposure: %s", val) + } + return nil +} + +type FileFPS uint + +func (f *FileFPS) Type() string { return "uint" } +func (f *FileFPS) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *f = FileFPS(_v) + + if *f < 1 || *f > 30 { + return fmt.Errorf("invalid value %v", *f) + } + return nil +} + +type Filter uint8 + +const ( + FilterNoOp Filter = iota + FilterMOG + FilterVariableFPS + FilterKNN + FilterDifference + FilterBasic +) + +func (f *Filter) Type() string { return "enum:NoOp,MOG,VariableFPS,KNN,Difference,Basic" } +func (f *Filter) Set(val string) error { + switch val { + case "NoOp": + *f = FilterNoOp + case "MOG": + *f = FilterMOG + case "VariableFPS": + *f = FilterVariableFPS + case "KNN": + *f = FilterKNN + case "Difference": + *f = FilterDifference + case "Basic": + *f = FilterBasic + default: + return fmt.Errorf("unrecognised Filter: %s", val) + } + return nil +} + +type FrameRate uint + +func (f *FrameRate) Type() string { return "uint" } +func (f *FrameRate) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *f = FrameRate(_v) + + if *f < 1 || *f > 30 { + return fmt.Errorf("invalid value %v", *f) + } + return nil +} + +type HTTPAddress string + +func (h *HTTPAddress) Type() string { return "string" } +func (h *HTTPAddress) Set(val string) error { + *h = HTTPAddress(val) + return nil +} + +type Height uint + +func (h *Height) Type() string { return "uint" } +func (h *Height) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *h = Height(_v) + + if *h < 360 || *h > 1080 { + return fmt.Errorf("invalid value %v", *h) + } + return nil +} + +type HorizontalFlip bool + +func (h *HorizontalFlip) Type() string { return "bool" } +func (h *HorizontalFlip) Set(val string) error { + switch val { + case "true": + *h = true + case "false": + *h = false + default: + return fmt.Errorf("not boolean value: %s", val) + } + return nil +} + +type Input uint8 + +const ( + InputFile Input = iota + InputRaspivid + InputWebcam + InputRTSP +) + +func (i *Input) Type() string { return "enum:File,Raspivid,Webcam,RTSP" } +func (i *Input) Set(val string) error { + switch val { + case "File": + *i = InputFile + case "Raspivid": + *i = InputRaspivid + case "Webcam": + *i = InputWebcam + case "RTSP": + *i = InputRTSP + default: + return fmt.Errorf("unrecognised Input: %s", val) + } + return nil +} + +type InputPath string + +func (i *InputPath) Type() string { return "string" } +func (i *InputPath) Set(val string) error { + *i = InputPath(val) + return nil +} + +type Level uint8 + +const ( + LevelDebug Level = iota + LevelInfo + LevelWarning + LevelError + LevelFatal +) + +func (l *Level) Type() string { return "enum:Debug,Info,Warning,Error,Fatal" } +func (l *Level) Set(val string) error { + switch val { + case "Debug": + *l = LevelDebug + case "Info": + *l = LevelInfo + case "Warning": + *l = LevelWarning + case "Error": + *l = LevelError + case "Fatal": + *l = LevelFatal + default: + return fmt.Errorf("unrecognised Level: %s", val) + } + return nil +} + +type MinFPS uint + +func (m *MinFPS) Type() string { return "uint" } +func (m *MinFPS) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MinFPS(_v) + + if *m < 1 || *m > 30 { + return fmt.Errorf("invalid value %v", *m) + } + return nil +} + +type MinFrames uint + +func (m *MinFrames) Type() string { return "uint" } +func (m *MinFrames) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MinFrames(_v) + + if *m < 0 || *m > 1000 { + return fmt.Errorf("invalid value %v", *m) + } + return nil +} + +type Mode uint8 + +const ( + ModeNormal Mode = iota + ModePaused + ModeBurst + ModeLoop +) + +func (m *Mode) Type() string { return "enum:Normal,Paused,Burst,Loop" } +func (m *Mode) Set(val string) error { + switch val { + case "Normal": + *m = ModeNormal + case "Paused": + *m = ModePaused + case "Burst": + *m = ModeBurst + case "Loop": + *m = ModeLoop + default: + return fmt.Errorf("unrecognised Mode: %s", val) + } + return nil +} + +type MotionDownscaling uint + +func (m *MotionDownscaling) Type() string { return "uint" } +func (m *MotionDownscaling) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MotionDownscaling(_v) + return nil +} + +type MotionHistory uint + +func (m *MotionHistory) Type() string { return "uint" } +func (m *MotionHistory) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MotionHistory(_v) + return nil +} + +type MotionInterval uint + +func (m *MotionInterval) Type() string { return "uint" } +func (m *MotionInterval) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MotionInterval(_v) + + if *m < 0 || *m > 30 { + return fmt.Errorf("invalid value %v", *m) + } + return nil +} + +type MotionKernel uint + +func (m *MotionKernel) Type() string { return "uint" } +func (m *MotionKernel) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MotionKernel(_v) + return nil +} + +type MotionMinArea float64 + +func (m *MotionMinArea) Type() string { return "float64" } +func (m *MotionMinArea) Set(val string) error { + _v, err := strconv.ParseFloat(val, 64) + if err != nil { + return fmt.Errorf("could not convert set string to float: %w", err) + } + *m = MotionMinArea(_v) + return nil +} + +type MotionPixels uint + +func (m *MotionPixels) Type() string { return "uint" } +func (m *MotionPixels) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *m = MotionPixels(_v) + return nil +} + +type MotionThreshold float64 + +func (m *MotionThreshold) Type() string { return "float64" } +func (m *MotionThreshold) Set(val string) error { + _v, err := strconv.ParseFloat(val, 64) + if err != nil { + return fmt.Errorf("could not convert set string to float: %w", err) + } + *m = MotionThreshold(_v) + return nil +} + +type Output uint8 + +const ( + OutputHTTP Output = iota + OutputRTMP + OutputRTP + OutputFile +) + +func (o *Output) Type() string { return "enum:HTTP,RTMP,RTP,File" } +func (o *Output) Set(val string) error { + switch val { + case "HTTP": + *o = OutputHTTP + case "RTMP": + *o = OutputRTMP + case "RTP": + *o = OutputRTP + case "File": + *o = OutputFile + default: + return fmt.Errorf("unrecognised Output: %s", val) + } + return nil +} + +type OutputPath string + +func (o *OutputPath) Type() string { return "string" } +func (o *OutputPath) Set(val string) error { + *o = OutputPath(val) + return nil +} + +type Outputs []Output + +func (o *Outputs) Type() string { return "enum:HTTP,RTMP,RTP,File" } +func (o *Outputs) Set(val string) error { + vals := strings.Split(val, ",") + *o = make([]Output, len(vals)) + + for i, v := range vals { + switch v { + case "HTTP": + (*o)[i] = OutputHTTP + case "RTMP": + (*o)[i] = OutputRTMP + case "RTP": + (*o)[i] = OutputRTP + case "File": + (*o)[i] = OutputFile + default: + return fmt.Errorf("unrecognised Outputs: %s", val) + } + } + return nil +} + +type PSITime time.Duration + +func (p *PSITime) Type() string { return "time.Duration" } +func (p *PSITime) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *p = PSITime(time.Duration(_v) * time.Second) + return nil +} + +type Quantization uint + +func (q *Quantization) Type() string { return "uint" } +func (q *Quantization) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *q = Quantization(_v) + return nil +} + +type RBCapacity uint + +func (r *RBCapacity) Type() string { return "uint" } +func (r *RBCapacity) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *r = RBCapacity(_v) + + if *r < 1000000 || *r > 100000000 { + return fmt.Errorf("invalid value %v", *r) + } + return nil +} + +type RBMaxElements uint + +func (r *RBMaxElements) Type() string { return "uint" } +func (r *RBMaxElements) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *r = RBMaxElements(_v) + + if *r < 0 || *r > 4294967295 { + return fmt.Errorf("invalid value %v", *r) + } + return nil +} + +type RBWriteTimeout time.Duration + +func (r *RBWriteTimeout) Type() string { return "time.Duration" } +func (r *RBWriteTimeout) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *r = RBWriteTimeout(time.Duration(_v) * time.Second) + return nil +} + +type RTMPURL string + +func (r *RTMPURL) Type() string { return "string" } +func (r *RTMPURL) Set(val string) error { + *r = RTMPURL(val) + return nil +} + +type RTPAddress string + +func (r *RTPAddress) Type() string { return "string" } +func (r *RTPAddress) Set(val string) error { + *r = RTPAddress(val) + return nil +} + +type RecPeriod float64 + +func (r *RecPeriod) Type() string { return "float64" } +func (r *RecPeriod) Set(val string) error { + _v, err := strconv.ParseFloat(val, 64) + if err != nil { + return fmt.Errorf("could not convert set string to float: %w", err) + } + *r = RecPeriod(_v) + return nil +} + +type Rotation uint + +func (r *Rotation) Type() string { return "uint" } +func (r *Rotation) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *r = Rotation(_v) + + if *r < 0 || *r > 359 { + return fmt.Errorf("invalid value %v", *r) + } + return nil +} + +type SampleRate uint + +func (s *SampleRate) Type() string { return "uint" } +func (s *SampleRate) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *s = SampleRate(_v) + return nil +} + +type Saturation int + +func (s *Saturation) Type() string { return "int" } +func (s *Saturation) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *s = Saturation(_v) + + if *s < -50 || *s > 50 { + return fmt.Errorf("invalid value %v", *s) + } + return nil +} + +type ShowWindows bool + +func (s *ShowWindows) Type() string { return "bool" } +func (s *ShowWindows) Set(val string) error { + switch val { + case "true": + *s = true + case "false": + *s = false + default: + return fmt.Errorf("not boolean value: %s", val) + } + return nil +} + +type VBRBitrate uint + +func (v *VBRBitrate) Type() string { return "uint" } +func (v *VBRBitrate) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *v = VBRBitrate(_v) + + if *v < 1 || *v > 30 { + return fmt.Errorf("invalid value %v", *v) + } + return nil +} + +type VBRQuality uint8 + +const ( + VBRQualityStandard VBRQuality = iota + VBRQualityFair + VBRQualityGood + VBRQualityGreat + VBRQualityExcellent +) + +func (v *VBRQuality) Type() string { return "enum:Standard,Fair,Good,Great,Excellent" } +func (v *VBRQuality) Set(val string) error { + switch val { + case "Standard": + *v = VBRQualityStandard + case "Fair": + *v = VBRQualityFair + case "Good": + *v = VBRQualityGood + case "Great": + *v = VBRQualityGreat + case "Excellent": + *v = VBRQualityExcellent + default: + return fmt.Errorf("unrecognised VBRQuality: %s", val) + } + return nil +} + +type VerticalFlip bool + +func (v *VerticalFlip) Type() string { return "bool" } +func (v *VerticalFlip) Set(val string) error { + switch val { + case "true": + *v = true + case "false": + *v = false + default: + return fmt.Errorf("not boolean value: %s", val) + } + return nil +} + +type Width uint + +func (w *Width) Type() string { return "uint" } +func (w *Width) Set(val string) error { + _v, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("could not convert set string to int: %w", err) + } + *w = Width(_v) + + if *w < 640 || *w > 1920 { + return fmt.Errorf("invalid value %v", *w) + } + return nil +} + +type WriteRate float64 + +func (w *WriteRate) Type() string { return "float64" } +func (w *WriteRate) Set(val string) error { + _v, err := strconv.ParseFloat(val, 64) + if err != nil { + return fmt.Errorf("could not convert set string to float: %w", err) + } + *w = WriteRate(_v) + return nil +}