revid: revid config to update geovision configuration using gvctrl

Added required new params to config structure, and therefore also added new defaults and validation checking.
Also updated revid's update func so that we can control new parameters using vars. Now using gvctrl in
startRTSPCamera function and interpreting revid config to configure camera.
This commit is contained in:
Saxon 2019-10-22 14:54:38 +10:30
parent ce6c12cce8
commit 8c1c192218
4 changed files with 120 additions and 19 deletions

View File

@ -109,7 +109,7 @@ func handleFlags() revid.Config {
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
inputCodecPtr = flag.String("InputCodec", "H264", "The codec of the input: H264, Mjpeg, PCM, ADPCM")
inputPtr = flag.String("Input", "", "The input type: Raspivid, File, v4l, Audio, RTSP")
rtspURLPtr = flag.String("RTSPURL", "", "The URL for an RTSP server.")
cameraIPPtr = flag.String("CameraIP", "", "The the IP of the RTSP server")
verbosityPtr = flag.String("Verbosity", "Info", "Verbosity: Debug, Info, Warning, Error, Fatal")
rtpAddrPtr = flag.String("RtpAddr", "", "Rtp destination address: <IP>:<port> (port is generally 6970-6999)")
logPathPtr = flag.String("LogPath", defaultLogPath, "The log path")
@ -231,7 +231,7 @@ func handleFlags() revid.Config {
netsender.ConfigFile = *configFilePtr
}
cfg.RTSPURL = *rtspURLPtr
cfg.CameraIP = *cameraIPPtr
cfg.Rotation = *rotationPtr
cfg.FlipHorizontal = *horizontalFlipPtr
cfg.FlipVertical = *verticalFlipPtr

View File

@ -63,6 +63,19 @@ var AutoWhiteBalanceModes = [...]string{
"horizon",
}
// quality represents video quality.
type quality int
// The different video qualities that can be used for variable bitrate when
// using the GeoVision camera.
const (
qualityStandard quality = iota
qualityFair
qualityGood
qualityGreat
qualityExcellent
)
// Enums to define inputs, outputs and codecs.
const (
// Indicates no option has been set.
@ -100,8 +113,11 @@ const (
defaultInputCodec = codecutil.H264
defaultVerbosity = logger.Error
defaultRtpAddr = "localhost:6970"
defaultRTSPURL = "rtsp://admin:admin@192.168.1.50:8554/CH001.sdp"
defaultBurstPeriod = 10 // Seconds
defaultCameraIP = "192.168.1.50"
defaultVBR = false
defaultVBRQuality = qualityStandard
defaultBurstPeriod = 10 // Seconds
defaultVBRBitrate = 500 // kbps
// Raspivid video defaults.
defaultBrightness = 50
@ -113,7 +129,7 @@ const (
defaultMinFrames = 100
defaultClipDuration = 0
defaultQuantization = 30
defaultBitrate = 400000
defaultBitrate = 400
// Audio defaults.
defaultAudioInputCodec = codecutil.ADPCM
@ -152,7 +168,7 @@ type Config struct {
// File:
// Location must be specified in InputPath field.
// RTSP:
// RTSPURL must also be defined.
// CameraIP should also be defined.
Input uint8
// InputCodec defines the input codec we wish to use, and therefore defines the
@ -181,9 +197,9 @@ type Config struct {
// RTMP is to be used as an output.
RTMPURL string
// RTSPURL specifies the RTSP server URL for RTSP input. This must be defined
// when Input is RTSP.
RTSPURL string
// CameraIP is the IP address of the camera in the case of the input camera
// being an IP camera.
CameraIP string
// OutputPath defines the output destination for File output. This must be
// defined if File output is to be used.
@ -204,11 +220,27 @@ type Config struct {
// defined in /etc/netsender.conf.
HTTPAddress string
// Quantization defines the quantization level, which may be a value between
// 0-40. This will only take effect if the Quantize field is true and if we
// are using Raspivid input.
// VBR indicates whether we wish to use constant or variable bitrate. If VBR
// is true then we will use variable bitrate, and constant bitrate otherwise.
// In the case of the Pi camera, variable bitrate quality is controlled by
// the Quantization parameter below. In the case of the GeoVision camera,
// variable bitrate quality is controlled by firstly the VBRQuality parameter
// and second the VBRBitrate parameter.
VBR bool
// Quantization defines the quantization level, which will determine variable
// bitrate quality in the case of input from the Pi Camera.
Quantization uint
// VBRQuality describes the general quality of video from the GeoVision camera
// under variable bitrate. VBRQuality can be one 5 consts defined:
// qualityStandard, qualityFair, qualityGood, qualityGreat and qualityExcellent.
VBRQuality quality
// VBRBitrate describes maximal bitrate for the GeoVision camera when under
// variable bitrate.
VBRBitrate int
// MinFrames defines the frequency of key NAL units SPS, PPS and IDR in
// number of NAL units. This will also determine the frequency of PSI if the
// output container is MPEG-TS. If ClipDuration is less than MinFrames,
@ -251,7 +283,7 @@ type Config struct {
Rotation uint // Rotation defines the video rotation angle in degrees Raspivid input.
Height uint // Height defines the input video height Raspivid input.
Width uint // Width defines the input video width Raspivid input.
Bitrate uint // Bitrate specifies the input bitrate for Raspivid input.
Bitrate uint // Bitrate specifies the bitrate for constant bitrate in kbps.
FlipHorizontal bool // FlipHorizontal flips video horizontally for Raspivid input.
FlipVertical bool // FlipVertial flips video vertically for Raspivid input.
@ -288,9 +320,9 @@ func (c *Config) Validate() error {
switch c.Input {
case Raspivid, V4L, File, Audio:
case RTSP:
if c.RTSPURL == "" {
c.Logger.Log(logger.Info, pkg+"no RTSPURL defined, defaulting", "RTSPURL", defaultRTSPURL)
c.RTSPURL = defaultRTSPURL
if c.CameraIP == "" {
c.Logger.Log(logger.Info, pkg+"no CameraIP defined, defaulting", "CameraIP", defaultCameraIP)
c.CameraIP = defaultCameraIP
}
case NothingDefined:
c.Logger.Log(logger.Info, pkg+"no input type defined, defaulting", "input", defaultInput)
@ -481,6 +513,18 @@ func (c *Config) Validate() error {
c.MTSRBWriteTimeout = defaultMTSRBWriteTimeout
}
switch c.VBRQuality {
case qualityStandard, qualityFair, qualityGood, qualityGreat, qualityExcellent:
default:
c.Logger.Log(logger.Info, pkg+"VBRQuality bad or unset, defaulting", "VBRQuality", defaultVBRQuality)
c.VBRQuality = defaultVBRQuality
}
if c.VBRBitrate <= 0 {
c.Logger.Log(logger.Info, pkg+"VBRBitrate bad or unset, defaulting", "VBRBitrate", defaultVBRBitrate)
c.VBRBitrate = defaultVBRBitrate
}
return nil
}

View File

@ -40,12 +40,19 @@ import (
"time"
"bitbucket.org/ausocean/av/codec/codecutil"
"bitbucket.org/ausocean/av/input/gvctrl"
"bitbucket.org/ausocean/av/protocol/rtcp"
"bitbucket.org/ausocean/av/protocol/rtp"
"bitbucket.org/ausocean/av/protocol/rtsp"
"bitbucket.org/ausocean/utils/logger"
)
// TODO: remove this when gvctrl has configurable user and pass.
const (
ipCamUser = "admin"
ipCamPass = "pass"
)
// startRaspivid sets up things for input from raspivid i.e. starts
// a raspivid process and pipes it's data output.
func (r *Revid) startRaspivid() (func() error, error) {
@ -58,7 +65,7 @@ func (r *Revid) startRaspivid() (func() error, error) {
"--timeout", disabled,
"--width", fmt.Sprint(r.config.Width),
"--height", fmt.Sprint(r.config.Height),
"--bitrate", fmt.Sprint(r.config.Bitrate),
"--bitrate", fmt.Sprint(r.config.Bitrate * 1000), // Convert from kbps to bps.
"--framerate", fmt.Sprint(r.config.FrameRate),
"--rotation", fmt.Sprint(r.config.Rotation),
"--brightness", fmt.Sprint(r.config.Brightness),
@ -87,7 +94,7 @@ func (r *Revid) startRaspivid() (func() error, error) {
"--inline",
"--intra", fmt.Sprint(r.config.MinFrames),
)
if r.config.Quantization != 0 {
if r.config.VBR {
args = append(args, "-qp", fmt.Sprint(r.config.Quantization))
}
case codecutil.MJPEG:
@ -173,7 +180,36 @@ func (r *Revid) setupInputForFile() (func() error, error) {
// client is created from which RTP packets containing either h264/h265 can be
// read by the selected lexer.
func (r *Revid) startRTSPCamera() (func() error, error) {
rtspClt, local, remote, err := rtsp.NewClient(r.config.RTSPURL)
err := gvctrl.Set(
r.config.CameraIP,
gvctrl.CodecOut(
map[uint8]gvctrl.Codec{
codecutil.H264: gvctrl.CodecH264,
codecutil.H265: gvctrl.CodecH265,
codecutil.MJPEG: gvctrl.CodecMJPEG,
}[r.config.InputCodec],
),
gvctrl.Height(int(r.config.Height)),
gvctrl.FrameRate(int(r.config.FrameRate)),
gvctrl.VariableBitrate(r.config.VBR),
gvctrl.VBRQuality(
map[quality]gvctrl.Quality{
qualityStandard: gvctrl.QualityStandard,
qualityFair: gvctrl.QualityFair,
qualityGood: gvctrl.QualityGood,
qualityGreat: gvctrl.QualityGreat,
qualityExcellent: gvctrl.QualityExcellent,
}[r.config.VBRQuality],
),
gvctrl.VBRBitrate(r.config.VBRBitrate),
gvctrl.CBRBitrate(int(r.config.Bitrate)/1000),
gvctrl.Refresh(float64(r.config.MinFrames)/float64(r.config.FrameRate)),
)
if err != nil {
return nil, fmt.Errorf("could not set IPCamera settings: %w", err)
}
rtspClt, local, remote, err := rtsp.NewClient("rtsp://" + ipCamUser + ":" + ipCamPass + "@" + r.config.CameraIP + ":8554/" + "CH002.sdp")
if err != nil {
return nil, err
}

View File

@ -618,6 +618,27 @@ func (r *Revid) Update(vars map[string]string) error {
break
}
r.config.MTSRBWriteTimeout = v
case "VBR":
v, ok := map[string]bool{"true": true, "false": false}[strings.ToLower(value)]
if !ok {
r.config.Logger.Log(logger.Warning, pkg+"invalid VBR var", "value", value)
break
}
r.config.VBR = v
case "VBRQuality":
v, ok := map[string]quality{"standard": qualityStandard, "fair": qualityFair, "good": qualityGood, "great": qualityGreat, "excellent": qualityExcellent}[strings.ToLower(value)]
if !ok {
r.config.Logger.Log(logger.Warning, pkg+"invalid VBRQuality var", "value", value)
break
}
r.config.VBRQuality = v
case "VBRBitrate":
v, err := strconv.Atoi(value)
if err != nil || v <= 0 {
r.config.Logger.Log(logger.Warning, pkg+"invalid VBRBitrate var", "value", value)
break
}
r.config.VBRBitrate = v
}
}
r.config.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.config))