mirror of https://bitbucket.org/ausocean/av.git
313 lines
10 KiB
Go
313 lines
10 KiB
Go
|
// +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: "PoolCapacity", BT: "uint", Min: 1000000, Max: 100000000},
|
||
|
{N: "PoolMaxElements", BT: "uint", Min: 0, Max: math.MaxUint32},
|
||
|
{N: "PoolWriteTimeout", 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},
|
||
|
}
|
||
|
|
||
|
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 <saxon@ausocean.org>
|
||
|
|
||
|
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 is autogenerated code for config parameters - DO NOT EDIT.
|
||
|
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)
|
||
|
}
|
||
|
{{if ne .Min .Max}}
|
||
|
if _v < {{.Min}} || _v > {{.Max}} {
|
||
|
return fmt.Errorf("invalid value %v",_v)
|
||
|
}
|
||
|
{{end}}
|
||
|
*{{.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)
|
||
|
}
|
||
|
{{if ne .Min .Max}}
|
||
|
if _v < {{.Min}} || _v > {{.Max}} {
|
||
|
return fmt.Errorf("invalid value %v",_v)
|
||
|
}
|
||
|
{{end}}
|
||
|
*{{.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)
|
||
|
}
|
||
|
{{if ne .Min .Max}}
|
||
|
if _v < {{.Min}} || _v > {{.Max}} {
|
||
|
return fmt.Errorf("invalid value %v",_v)
|
||
|
}
|
||
|
{{end}}
|
||
|
*{{.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 -}}
|
||
|
|
||
|
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))
|
||
|
}
|
||
|
}
|