/* DESCRIPTION utils.go provides general constants, structs and helper functions for use in this package. AUTHORS Saxon A. Nelson-Milton LICENSE Copyright (C) 2019 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 in gpl.txt. If not, see http://www.gnu.org/licenses. */ package gvctrl import ( "crypto/md5" "encoding/hex" "math" "net/url" "strconv" "strings" ) // The strings used in encoding the settings form to indicate resultion. const ( res256 = "4480256" // 480x256 res360 = "6400360" // 640x360 res720 = "12800720" // 1280x720 res1080 = "192001080" // 1920x1080 ) // Default values for fields in the settings struct when the newSettings // constructor is used. const ( defaultCodec = CodecH264 defaultRes = "6400360" // 360p defaultFrameRate = "25000" // 25 fps defaultVBR = "0" // Variable bitrate off defaultQuality = QualityGood defaultVBRBitrate = "250000" // 512 kbps (lowest with 360p) defaultCBRBitrate = "512000" defaultRefresh = "2000" // 2 seconds defaultChan = 2 ) // settings holds string representations required by the settings form for each // of the parameters configurable through this API. type settings struct { codec Codec res string frameRate string vbr string quality Quality vbrBitrate string cbrBitrate string refresh string ch int } // newSetting will return a settings with default values. func newSettings() settings { return settings{ codec: defaultCodec, res: defaultRes, frameRate: defaultFrameRate, vbr: defaultVBR, quality: defaultQuality, vbrBitrate: defaultVBRBitrate, cbrBitrate: defaultCBRBitrate, refresh: defaultRefresh, ch: defaultChan, } } // md5Hex returns the md5 hex string of s with alphanumerics as upper case. func md5Hex(s string) string { h := md5.New() h.Write([]byte(s)) return strings.ToUpper(hex.EncodeToString(h.Sum(nil))) } // closestValIdx will return the index of the value in l that is closest to the // value v. func closestValIdx(v int, l []int) int { var idx int for i := range l { if math.Abs(float64(l[i]-v)) < math.Abs(float64(l[idx]-v)) { idx = i } } return idx } // convRate is used to firstly find a value in l closest to the bitrate v (in // kbps), convert from kbps to bps, and the convert to string. func convRate(v int, l []int) string { return strconv.Itoa(l[closestValIdx(v, l)] * 1000) } // populateForm will populate the settings form using the passed settings struct // s and return as a url.Values. func populateForm(s settings) url.Values { f := url.Values{} f.Set("dwConnType", "5") f.Set("mpeg_type", string(s.codec)) f.Set("dwflicker_hz", "0") f.Set("szResolution", s.res) f.Set("dwFrameRate", s.frameRate) f.Set("custom_qp_init", "25") if s.codec == CodecMJPEG { f.Set("vbr_enable", "1") f.Set("dwVbrQuality", string(s.quality)) switch s.res { case res256: f.Set("vbrmaxbitrate", "250000") case res360: f.Set("vbrmaxbitrate", "500000") case res720: f.Set("vbrmaxbitrate", "750000") default: panic("invalid resolution") } } else { switch s.vbr { case "0": f.Set("vbr_enable", "0") f.Set("max_bit_rate", s.cbrBitrate) case "1": f.Set("vbr_enable", "1") f.Set("dwVbrQuality", string(s.quality)) f.Set("vbrmaxbitrate", s.vbrBitrate) default: panic("invalid vbrEnable parameter") } f.Set("custom_rate_control_type", "0") f.Set("custom_bitrate", "0") f.Set("custom_qp_min", "10") f.Set("custom_qp_max", "40") } f.Set("gop_N", s.refresh) if s.codec == CodecMJPEG { f.Set("gop_N", "1500") } if s.codec == CodecH264 || s.codec == CodecH265 { f.Set("dwEncProfile", "1") f.Set("dwEncLevel", "31") f.Set("dwEntropy", "0") } f.Set("u8PreAlarmBuf", "1") f.Set("u32PostAlarmBuf2Disk", "1") f.Set("u8SplitInterval", "5") f.Set("bEnableIO", "1") f.Set("bEbIoIn", "1") f.Set("bEbIoIn1", "1") f.Set("bOSDFontSize", "0") f.Set("bEnableOSDCameraName", "1") f.Set("bCamNamePos", "2") f.Set("bEnableOSDDate", "1") f.Set("bDatePos", "2") f.Set("bEnableOSDTime", "1") f.Set("bTimePos", "2") f.Set("szOsdCamName", "Camera") f.Set("u16PostAlarmBuf", "1") f.Set("dwCameraId", "1") // Channel=1 => cameraID=0 and chanel=2 => cameraID=1 f.Set("LangCode", "undefined") f.Set("Recflag", "0") f.Set("submit", "Apply") return f }