Merged in meta-str (pull request #457)

mts, codecutils: string consts for metadata keys and codecs

Approved-by: Saxon Milton
This commit is contained in:
Trek Hopton 2021-02-22 06:17:57 +00:00
commit e35b5d72ea
13 changed files with 83 additions and 90 deletions

View File

@ -24,20 +24,23 @@ LICENSE
package codecutil
// A global list containing all available codecs for reference in any application.
// When adding or removing a codec from this list, the numCodecs const must be updated.
// All available codecs for reference in any application.
// When adding or removing a codec from this list, the IsValid function below must be updated.
const (
Undef = iota
PCM
ADPCM
H264
H265
MJPEG
JPEG
maxCodec
PCM = "pcm"
ADPCM = "adpcm"
H264 = "h264"
H265 = "h265"
MJPEG = "mjpeg"
JPEG = "jpeg"
)
// IsValid recieves an int representing a codec and checks if it is valid.
func IsValid(codec uint8) bool {
return 0 < codec && codec < maxCodec
// IsValid checks if a string is a known and valid codec in the right format.
func IsValid(s string) bool {
switch s {
case PCM, ADPCM, H264, H265, MJPEG, JPEG:
return true
default:
return false
}
}

View File

@ -101,13 +101,20 @@ const (
defaultMediaPID = PIDVideo
)
// Used to consistently read and write MTS metadata entries.
const (
WriteRateKey = "writeRate"
TimestampKey = "ts"
LocationKey = "loc"
)
// Meta allows addition of metadata to encoded mts from outside of this pkg.
// See meta pkg for usage.
//
// TODO: make this not global.
var Meta *meta.Data
// This will help us obtain a realtime for timestamp meta encoding.
// RealTime will help us obtain a realtime for timestamp meta encoding.
var RealTime = realtime.NewRealTime()
// Encoder encapsulates properties of an MPEG-TS generator.
@ -164,7 +171,7 @@ func NewEncoder(dst io.WriteCloser, log logger.LoggerIF, options ...func(*Encode
}
log.Debug("encoder options applied")
Meta.Add("writeRate", fmt.Sprintf("%f", 1/float64(e.writePeriod.Seconds())))
Meta.Add(WriteRateKey, fmt.Sprintf("%f", 1/float64(e.writePeriod.Seconds())))
e.pmt.SyntaxSection.SpecificData.(*psi.PMT).StreamSpecificData.StreamType = e.streamID
e.pmt.SyntaxSection.SpecificData.(*psi.PMT).StreamSpecificData.PID = e.mediaPID
@ -332,7 +339,7 @@ func updateMeta(b []byte, log logger.LoggerIF) ([]byte, error) {
p := psi.PSIBytes(b)
if RealTime.IsSet() {
t := strconv.Itoa(int(RealTime.Get().Unix()))
Meta.Add("ts", t)
Meta.Add(TimestampKey, t)
log.Debug("latest time added to meta", "time", t)
}
err := p.AddDescriptor(psi.MetadataTag, Meta.Encode())

View File

@ -276,7 +276,7 @@ func TestMetaEncode1(t *testing.T) {
t.Fatalf("could not create encoder, failed with error: %v", err)
}
Meta.Add("ts", "12345678")
Meta.Add(TimestampKey, "12345678")
if err := e.writePSI(); err != nil {
t.Errorf("unexpected error: %v\n", err.Error())
}
@ -289,12 +289,9 @@ func TestMetaEncode1(t *testing.T) {
0x23, // Length of bytes to follow
0x00, 0x10, 0x00, 0x1f,
}
rate := "writeRate=" + fmt.Sprintf("%f", float64(defaultRate))
want = append(want, []byte(rate)...) // writeRate
want = append(want, []byte{
'\t', 't', 's', '=', '1', '2', '3', '4', '5', '6', '7', '8', // timestamp
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}...)
rate := WriteRateKey + "=" + fmt.Sprintf("%f", float64(defaultRate)) + "\t" + TimestampKey + "=12345678" // timestamp
want = append(want, []byte(rate)...) // writeRate
want = append(want, []byte{0x1b, 0xe1, 0x00, 0xf0, 0x00}...)
want = psi.AddCRC(want)
want = psi.AddPadding(want)
if !bytes.Equal(got, want) {
@ -313,8 +310,8 @@ func TestMetaEncode2(t *testing.T) {
t.Fatalf("could not create MTS encoder, failed with error: %v", err)
}
Meta.Add("ts", "12345678")
Meta.Add("loc", "1234,4321,1234")
Meta.Add(TimestampKey, "12345678")
Meta.Add(LocationKey, "1234,4321,1234")
if err := e.writePSI(); err != nil {
t.Errorf("did not expect error: %v from writePSI", err.Error())
}
@ -326,13 +323,10 @@ func TestMetaEncode2(t *testing.T) {
0x36, // Length of bytes to follow
0x00, 0x10, 0x00, 0x32,
}
rate := "writeRate=" + fmt.Sprintf("%f", float64(defaultRate))
want = append(want, []byte(rate)...) // writeRate
want = append(want, []byte{
'\t', 't', 's', '=', '1', '2', '3', '4', '5', '6', '7', '8', '\t', // timestamp
'l', 'o', 'c', '=', '1', '2', '3', '4', ',', '4', '3', '2', '1', ',', '1', '2', '3', '4', // location
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}...)
s := WriteRateKey + "=" + fmt.Sprintf("%f", float64(defaultRate)) + "\t" +
TimestampKey + "=12345678\t" + LocationKey + "=1234,4321,1234"
want = append(want, []byte(s)...)
want = append(want, []byte{0x1b, 0xe1, 0x00, 0xf0, 0x00}...)
want = psi.AddCRC(want)
want = psi.AddPadding(want)
if !bytes.Equal(got, want) {
@ -350,8 +344,8 @@ func TestExtractMeta(t *testing.T) {
t.Fatalf("could not create MTS encoder, failed with error: %v", err)
}
Meta.Add("ts", "12345678")
Meta.Add("loc", "1234,4321,1234")
Meta.Add(TimestampKey, "12345678")
Meta.Add(LocationKey, "1234,4321,1234")
if err := e.writePSI(); err != nil {
t.Errorf("did not expect error: %v", err.Error())
}
@ -362,9 +356,9 @@ func TestExtractMeta(t *testing.T) {
}
rate := fmt.Sprintf("%f", float64(defaultRate))
want := map[string]string{
"ts": "12345678",
"loc": "1234,4321,1234",
"writeRate": rate,
TimestampKey: "12345678",
LocationKey: "1234,4321,1234",
WriteRateKey: rate,
}
if !reflect.DeepEqual(got, want) {
t.Errorf("did not get expected result.\ngot: %v\nwant: %v\n", got, want)

View File

@ -58,7 +58,7 @@ var (
ErrUnexpectedMetaFormat = errors.New("Unexpected meta format")
)
// Metadata provides functionality for the storage and encoding of metadata
// Data provides functionality for the storage and encoding of metadata
// using a map.
type Data struct {
mu sync.RWMutex

View File

@ -32,11 +32,13 @@ import (
)
const (
tstKey1 = "loc"
tstData1 = "a,b,c"
tstKey2 = "ts"
tstData2 = "12345678"
tstData3 = "d,e,f"
TimestampKey = "ts"
LocationKey = "loc"
tstKey1 = LocationKey
tstData1 = "a,b,c"
tstKey2 = TimestampKey
tstData2 = "12345678"
tstData3 = "d,e,f"
)
// TestAddAndGet ensures that we can add metadata and then successfully get it.
@ -69,7 +71,7 @@ func TestUpdate(t *testing.T) {
if data, ok := meta.Get(tstKey1); !ok {
t.Errorf("Could not get data for key: %v\n", tstKey1)
if data != tstData2 {
t.Error(`Data did not correctly update for key "loc"`)
t.Errorf("Data did not correctly update for key: %v\n", tstKey1)
}
}
}
@ -143,11 +145,11 @@ func TestGetFrom(t *testing.T) {
want string
}{
{
"loc",
LocationKey,
"a,b,c",
},
{
"ts",
TimestampKey,
"12345",
},
}
@ -169,11 +171,11 @@ func TestGetAll(t *testing.T) {
tstMeta := append([]byte{0x00, 0x10, 0x00, 0x12}, "loc=a,b,c\tts=12345"...)
want := [][2]string{
{
"loc",
LocationKey,
"a,b,c",
},
{
"ts",
TimestampKey,
"12345",
},
}
@ -191,8 +193,8 @@ func TestGetAll(t *testing.T) {
func TestGetAllAsMap(t *testing.T) {
tstMeta := append([]byte{0x00, 0x10, 0x00, 0x12}, "loc=a,b,c\tts=12345"...)
want := map[string]string{
"loc": "a,b,c",
"ts": "12345",
LocationKey: "a,b,c",
TimestampKey: "12345",
}
got, err := GetAllAsMap(tstMeta)
if err != nil {
@ -207,7 +209,7 @@ func TestGetAllAsMap(t *testing.T) {
// the meta.Keys method.
func TestKeys(t *testing.T) {
tstMeta := append([]byte{0x00, 0x10, 0x00, 0x12}, "loc=a,b,c\tts=12345"...)
want := []string{"loc", "ts"}
want := []string{LocationKey, TimestampKey}
got, err := Keys(tstMeta)
if err != nil {
t.Errorf("Unexpected error: %v\n", err)
@ -220,8 +222,8 @@ func TestKeys(t *testing.T) {
// TestNewFromMap checks that we can successfully create a new data struct from a map.
func TestNewFromMap(t *testing.T) {
want := map[string]string{
"loc": "a,b,c",
"ts": "12345",
LocationKey: "a,b,c",
TimestampKey: "12345",
}
meta := NewFromMap(want)
@ -236,8 +238,8 @@ func TestNewFromMap(t *testing.T) {
// TestEncodeAsString checks that metadata is correctly encoded as a string.
func TestEncodeAsString(t *testing.T) {
meta := NewFromMap(map[string]string{
"loc": "a,b,c",
"ts": "12345",
LocationKey: "a,b,c",
TimestampKey: "12345",
})
got := meta.EncodeAsString()

View File

@ -95,7 +95,7 @@ type Config struct {
Channels uint
BitDepth uint
RecPeriod float64
Codec uint8
Codec string
}
// Logger enables any implementation of a logger to be used.

View File

@ -173,7 +173,7 @@ func (g *GeoVision) Set(c avconfig.Config) error {
g.cfg.CameraIP,
gvconfig.Channel(g.cfg.CameraChan),
gvconfig.CodecOut(
map[uint8]gvconfig.Codec{
map[string]gvconfig.Codec{
codecutil.H264: gvconfig.CodecH264,
codecutil.H265: gvconfig.CodecH265,
codecutil.MJPEG: gvconfig.CodecMJPEG,

View File

@ -36,6 +36,15 @@ import (
"bitbucket.org/ausocean/utils/logger"
)
// Used to reliably read, write, and test audio metadata entry keys.
const (
SampleRateKey = "sampleRate"
ChannelsKey = "channels"
PeriodKey = "period"
BitDepthKey = "bitDepth"
CodecKey = "codec"
)
func (r *Revid) setupAudio() error {
// Create new ALSA device.
d := alsa.New(r.cfg.Logger)
@ -59,19 +68,11 @@ func (r *Revid) setupAudio() error {
r.lexTo = l.Lex
// Add metadata.
mts.Meta.Add("sampleRate", strconv.Itoa(int(r.cfg.SampleRate)))
mts.Meta.Add("channels", strconv.Itoa(int(r.cfg.Channels)))
mts.Meta.Add("period", fmt.Sprintf("%.6f", r.cfg.RecPeriod))
mts.Meta.Add("bitDepth", strconv.Itoa(int(r.cfg.BitDepth)))
switch r.cfg.InputCodec {
case codecutil.PCM:
mts.Meta.Add("codec", "pcm")
case codecutil.ADPCM:
mts.Meta.Add("codec", "adpcm")
default:
r.cfg.Logger.Log(logger.Fatal, "no audio codec set in config")
}
mts.Meta.Add(SampleRateKey, strconv.Itoa(int(r.cfg.SampleRate)))
mts.Meta.Add(ChannelsKey, strconv.Itoa(int(r.cfg.Channels)))
mts.Meta.Add(PeriodKey, fmt.Sprintf("%.6f", r.cfg.RecPeriod))
mts.Meta.Add(BitDepthKey, strconv.Itoa(int(r.cfg.BitDepth)))
mts.Meta.Add(CodecKey, r.cfg.InputCodec)
return nil
}

View File

@ -168,7 +168,7 @@ type Config struct {
// InputCodec defines the input codec we wish to use, and therefore defines the
// lexer for use in the pipeline. This defaults to H264, but H265 is also a
// valid option if we expect this from the input.
InputCodec uint8
InputCodec string
// InputPath defines the input file location for File Input. This must be
// defined if File input is to be used.

View File

@ -95,7 +95,7 @@ func TestUpdate(t *testing.T) {
"HorizontalFlip": "true",
"HTTPAddress": "http://address",
"Input": "rtsp",
"InputCodec": "MJPEG",
"InputCodec": "mjpeg",
"InputPath": "/inputpath",
"logging": "Error",
"Loop": "true",

View File

@ -299,24 +299,10 @@ var Variables = []struct {
Name: KeyInputCodec,
Type_: "enum:H264,H265,MJPEG,JPEG,PCM,ADPCM",
Update: func(c *Config, v string) {
c.InputCodec = parseEnum(
KeyInputCodec,
v,
map[string]uint8{
"h264": codecutil.H264,
"h265": codecutil.H265,
"mjpeg": codecutil.MJPEG,
"jpeg": codecutil.JPEG,
"pcm": codecutil.PCM,
"adpcm": codecutil.ADPCM,
},
c,
)
c.InputCodec = v
},
Validate: func(c *Config) {
switch c.InputCodec {
case codecutil.H264, codecutil.MJPEG, codecutil.JPEG, codecutil.PCM, codecutil.ADPCM:
default:
if !codecutil.IsValid(c.InputCodec) {
c.LogInvalidField(KeyInputCodec, defaultInputCodec)
c.InputCodec = defaultInputCodec
}

View File

@ -329,7 +329,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
// setLexer sets the revid input lexer based on input codec and whether input
// is RTSP or not, in which case an RTP/<codec> extractor is used.
func (r *Revid) setLexer(c uint8, isRTSP bool) error {
func (r *Revid) setLexer(c string, isRTSP bool) error {
switch c {
case codecutil.H264:
r.cfg.Logger.Log(logger.Debug, "using H.264 codec")

View File

@ -153,7 +153,7 @@ func extractMeta(r string, log func(lvl int8, msg string, args ...interface{}))
log(logger.Debug, "No location in reply")
} else {
log(logger.Debug, fmt.Sprintf("got location: %v", g))
mts.Meta.Add("loc", g)
mts.Meta.Add(mts.LocationKey, g)
}
return nil