mirror of https://bitbucket.org/ausocean/av.git
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:
commit
e35b5d72ea
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue