diff --git a/revid/revid.go b/revid/revid.go index 51a14c91..b9051a12 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -125,14 +125,11 @@ type Revid struct { isRunning bool } -var now = time.Now() -var prevTime = now - // packer takes data segments and packs them into clips // of the number frames specified in the owners config. type packer struct { - owner *Revid - + owner *Revid + lastTime time.Time packetCount uint } @@ -156,11 +153,11 @@ func (p *packer) Write(frame []byte) (int, error) { return n, err } p.packetCount++ - now = time.Now() - if (p.owner.config.Output1 != Rtmp && now.Sub(prevTime) > clipDuration && p.packetCount%7 == 0) || p.owner.config.Output1 == Rtmp { + now := time.Now() + if (p.owner.config.Output1 != Rtmp && now.Sub(p.lastTime) > clipDuration && p.packetCount%7 == 0) || p.owner.config.Output1 == Rtmp { p.owner.buffer.Flush() p.packetCount = 0 - prevTime = now + p.lastTime = now } return len(frame), nil } diff --git a/revid/senders.go b/revid/senders.go index f09d34fa..145362f5 100644 --- a/revid/senders.go +++ b/revid/senders.go @@ -144,13 +144,15 @@ func (s *httpSender) send() error { break } } + + if !send { + return nil + } var err error var reply string - if send { - reply, _, err = s.client.Send(netsender.RequestRecv, pins) - if err != nil { - return err - } + reply, _, err = s.client.Send(netsender.RequestRecv, pins) + if err != nil { + return err } return s.extractMeta(reply) @@ -169,7 +171,7 @@ func (s *httpSender) extractMeta(r string) error { s.log(logger.Warning, pkg+"No timestamp in reply") } else { s.log(logger.Debug, fmt.Sprintf("%v got timestamp: %v", pkg, t)) - mts.SetTimeStamp(uint64(t)) + mts.MetaData.SetTimeStamp(uint64(t)) } // Extract location from reply @@ -178,7 +180,7 @@ func (s *httpSender) extractMeta(r string) error { s.log(logger.Warning, pkg+"No location in reply") } else { s.log(logger.Debug, fmt.Sprintf("%v got location: %v", pkg, g)) - mts.SetLocation(g) + mts.MetaData.SetLocation(g) } return nil diff --git a/stream/mts/encoder.go b/stream/mts/encoder.go index 31fe4923..270c99e4 100644 --- a/stream/mts/encoder.go +++ b/stream/mts/encoder.go @@ -30,35 +30,146 @@ package mts import ( "io" + "sync" "time" "bitbucket.org/ausocean/av/stream/mts/pes" "bitbucket.org/ausocean/av/stream/mts/psi" ) +// Some common manifestations of PSI +var ( + // standardPat is a minimal PAT. + standardPat = psi.PSI{ + Pf: 0x00, + Tid: 0x00, + Ssi: true, + Pb: false, + Sl: 0x0d, + Tss: &psi.TSS{ + Tide: 0x01, + V: 0, + Cni: true, + Sn: 0, + Lsn: 0, + Sd: &psi.PAT{ + Pn: 0x01, + Pmpid: 0x1000, + }, + }, + } + + // standardPmt is a minimal PMT without descriptors for time and location. + standardPmt = psi.PSI{ + Pf: 0x00, + Tid: 0x02, + Ssi: true, + Sl: 0x12, + Tss: &psi.TSS{ + Tide: 0x01, + V: 0, + Cni: true, + Sn: 0, + Lsn: 0, + Sd: &psi.PMT{ + Pcrpid: 0x0100, + Pil: 0, + Essd: &psi.ESSD{ + St: 0x1b, + Epid: 0x0100, + Esil: 0x00, + }, + }, + }, + } + + // standardPmtTimeLocation is a minimal pmt with descriptors for time and location, + // time and location fields are zeroed out. + standardPmtTimeLocation = psi.PSI{ + Pf: 0x00, + Tid: 0x02, + Ssi: true, + Sl: 0x3e, + Tss: &psi.TSS{ + Tide: 0x01, + V: 0, + Cni: true, + Sn: 0, + Lsn: 0, + Sd: &psi.PMT{ + Pcrpid: 0x0100, + Pil: psi.PmtTimeLocationPil, + Pd: []psi.Desc{ + { + Dt: psi.TimeDescTag, + Dl: psi.TimeDataSize, + Dd: make([]byte, psi.TimeDataSize), + }, + { + Dt: psi.LocationDescTag, + Dl: psi.LocationDataSize, + Dd: make([]byte, psi.LocationDataSize), + }, + }, + Essd: &psi.ESSD{ + St: 0x1b, + Epid: 0x0100, + Esil: 0x00, + }, + }, + }, + } +) + const ( psiPacketSize = 184 psiSendCount = 7 ) -type MetaData struct { +// timeLocation holds time and location data +type timeLocation struct { + mu sync.RWMutex time uint64 location string } -var metaData = MetaData{time: 0, location: ""} - -func SetTimeStamp(t uint64) { - metaData.time = t +// SetTimeStamp sets the time field of a TimeLocation. +func (tl *timeLocation) SetTimeStamp(t uint64) { + tl.mu.Lock() + tl.time = t + tl.mu.Unlock() } -func SetLocation(g string) { - metaData.location = g +// GetTimeStamp returns the location of a TimeLocation. +func (tl *timeLocation) TimeStamp() uint64 { + tl.mu.RLock() + t := tl.time + tl.mu.RUnlock() + return t } +// SetLocation sets the location of a TimeLocation. +func (tl *timeLocation) SetLocation(l string) { + tl.mu.Lock() + tl.location = l + tl.mu.Unlock() +} + +// GetLocation returns the location of a TimeLocation. +func (tl *timeLocation) Location() string { + tl.mu.RLock() + l := tl.location + tl.mu.RUnlock() + return l +} + +// MetData will hold time and location data which may be set externally if +// this data is available. It is then inserted into mpegts packets outputted. +var MetaData timeLocation + var ( - patTable = psi.StdPat.Bytes() - pmtTable = psi.StdPmtTimeLocation.Bytes() + patTable = standardPat.Bytes() + pmtTable = standardPmtTimeLocation.Bytes() ) const ( @@ -72,7 +183,7 @@ const ( // Time related constants. const ( // ptsOffset is the offset added to the clock to determine - // the current presentation timestamp, + // the current presentation timestamp. ptsOffset = 700 * time.Millisecond // pcrFreq is the base Program Clock Reference frequency. @@ -119,9 +230,8 @@ const ( ) // generate handles the incoming data and generates equivalent mpegts packets - -// sending them to the output channel +// sending them to the output channel. func (e *Encoder) Encode(nalu []byte) error { - // Prepare PES data. pesPkt := pes.Packet{ StreamID: streamID, @@ -172,7 +282,7 @@ func (e *Encoder) Encode(nalu []byte) error { // writePSI creates mpegts with pat and pmt tables - with pmt table having updated // location and time data. func (e *Encoder) writePSI() error { - // Write PAT + // Write PAT. patPkt := Packet{ PUSI: true, PID: patPid, @@ -185,17 +295,17 @@ func (e *Encoder) writePSI() error { return err } - // Update pmt table time and location - err = psi.UpdateTime(pmtTable, metaData.time) + // Update pmt table time and location. + err = psi.UpdateTime(pmtTable, MetaData.TimeStamp()) if err != nil { return err } - err = psi.UpdateLocation(pmtTable, metaData.location) + err = psi.UpdateLocation(pmtTable, MetaData.Location()) if err != nil { return nil } - // Create mts packet from pmt table + // Create mts packet from pmt table. pmtPkt := Packet{ PUSI: true, PID: pmtPid, @@ -212,7 +322,7 @@ func (e *Encoder) writePSI() error { } // addPadding adds an appropriate amount of padding to a pat or pmt table for -// addition to an mpegts packet +// addition to an mpegts packet. func addPadding(d []byte) []byte { for len(d) < psiPacketSize { d = append(d, 0xff) diff --git a/stream/mts/psi/crc.go b/stream/mts/psi/crc.go new file mode 100644 index 00000000..a361307d --- /dev/null +++ b/stream/mts/psi/crc.go @@ -0,0 +1,71 @@ +/* +NAME + crc.go +DESCRIPTION + See Readme.md + +AUTHOR + Dan Kortschak + Saxon Milton + +LICENSE + crc.go is Copyright (C) 2018 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 psi + +import ( + "encoding/binary" + "hash/crc32" + "math/bits" +) + +// addCrc appends a crc table to a given psi table in bytes +func addCrc(out []byte) []byte { + t := make([]byte, len(out)+4) + copy(t, out) + updateCrc(t) + return t +} + +// updateCrc updates the crc of bytes slice, writing the checksum into the last four bytes. +func updateCrc(b []byte) { + crc32 := crc32_Update(0xffffffff, crc32_MakeTable(bits.Reverse32(crc32.IEEE)), b[1:len(b)-4]) + binary.BigEndian.PutUint32(b[len(b)-4:], crc32) +} + +func crc32_MakeTable(poly uint32) *crc32.Table { + var t crc32.Table + for i := range t { + crc := uint32(i) << 24 + for j := 0; j < 8; j++ { + if crc&0x80000000 != 0 { + crc = (crc << 1) ^ poly + } else { + crc <<= 1 + } + } + t[i] = crc + } + return &t +} + +func crc32_Update(crc uint32, tab *crc32.Table, p []byte) uint32 { + for _, v := range p { + crc = tab[byte(crc>>24)^v] ^ (crc << 8) + } + return crc +} diff --git a/stream/mts/psi/op.go b/stream/mts/psi/helpers.go similarity index 62% rename from stream/mts/psi/op.go rename to stream/mts/psi/helpers.go index e78cdac7..f49754ed 100644 --- a/stream/mts/psi/op.go +++ b/stream/mts/psi/helpers.go @@ -1,15 +1,15 @@ /* NAME - op.go + helpers.go DESCRIPTION - op.go provides functionality for editing and reading bytes slices + helpers.go provides functionality for editing and reading bytes slices directly in order to insert/read timestamp and location data in psi. AUTHOR Saxon Milton LICENSE - op.go is Copyright (C) 2018 the Australian Ocean Lab (AusOcean) + helpers.go is Copyright (C) 2018 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 @@ -31,49 +31,40 @@ import ( "bytes" "encoding/binary" "errors" - "hash/crc32" - "math/bits" ) // TimeBytes takes a timestamp as an uint64 and converts to an 8 byte slice - // allows for updating of timestamp in pmt time descriptor. func TimeBytes(t uint64) []byte { - var s [timeDataSize]byte + var s [TimeDataSize]byte binary.BigEndian.PutUint64(s[:], t) return s[:] } // HasTime takes a psi as a byte slice and checks to see if it has a time descriptor // - if so return nil, otherwise return error -func HasTime(p []byte) error { - if p[timeTagIndx] != timeDescTag { - return errors.New("PSI does not contain a time descriptor, cannot update") - } - return nil +func HasTime(p []byte) bool { + return p[TimeTagIndx] == TimeDescTag } // HasLocation takes a psi as a byte slice and checks to see if it has a location descriptor // - if so return nil, otherwise return error -func HasLocation(p []byte) error { - if p[locationTagIndx] != locationDescTag { - return errors.New("PSI does not contain a location descriptor, cannot update") - } - return nil +func HasLocation(p []byte) bool { + return p[LocationTagIndx] == LocationDescTag } // UpdateTime takes the byte slice representation of a psi-pmt as well as a time // as an integer and attempts to update the time descriptor in the pmt with the // given time if the time descriptor exists, otherwise an error is returned func UpdateTime(dst []byte, t uint64) error { - err := HasTime(dst) - if err != nil { - return err + if !HasTime(dst) { + return errors.New("pmt does not have time descriptor, cannot update") } ts := TimeBytes(uint64(t)) - for i := range dst[timeDataIndx : timeDataIndx+timeDataSize] { - dst[i+timeDataIndx] = ts[i] + for i := range dst[TimeDataIndx : TimeDataIndx+TimeDataSize] { + dst[i+TimeDataIndx] = ts[i] } - dst = updateCrc(dst) + updateCrc(dst) return nil } @@ -81,11 +72,10 @@ func UpdateTime(dst []byte, t uint64) error { // timestamp, returning as a uint64 if it exists, otherwise returning 0 and nil // if it does not exist func TimeFrom(p []byte) (t uint64, err error) { - err = HasTime(p) - if err != nil { - return 0, err + if !HasTime(p) { + return 0, errors.New("pmt does not have a time descriptor") } - t = binary.BigEndian.Uint64(p[timeDataIndx : timeDataIndx+timeDataSize]) + t = binary.BigEndian.Uint64(p[TimeDataIndx : TimeDataIndx+TimeDataSize]) return t, nil } @@ -93,11 +83,10 @@ func TimeFrom(p []byte) (t uint64, err error) { // timestamp, returning as a uint64 if it exists, otherwise returning 0 and nil // if it does not exist func LocationFrom(p []byte) (g string, err error) { - err = HasLocation(p) - if err != nil { - return "", err + if !HasLocation(p) { + return "", errors.New("pmt does not have location descriptor") } - gBytes := p[locationDataIndx : locationDataIndx+locationDataSize] + gBytes := p[LocationDataIndx : LocationDataIndx+LocationDataSize] gBytes = bytes.Trim(gBytes, "\x00") g = string(gBytes) return g, nil @@ -106,7 +95,7 @@ func LocationFrom(p []byte) (g string, err error) { // LocationStrBytes take a string of location data and converts to a 32 byte slice - // easy update of slice representation of a pmt with location descriptor func LocationStrBytes(s string) []byte { - var b [locationDataSize]byte + var b [LocationDataSize]byte copy(b[:], s) return b[:] } @@ -115,31 +104,20 @@ func LocationStrBytes(s string) []byte { // descriptor and attempts to update the location data value with the passed string. // If the psi does not contain a location descriptor, and error is returned. func UpdateLocation(d []byte, s string) error { - err := HasLocation(d) - if err != nil { - return err + if !HasLocation(d) { + return errors.New("pmt does not location descriptor, cannot update") } gb := LocationStrBytes(s) - for i := range d[locationDataIndx : locationDataIndx+locationDataSize] { - d[i+locationDataIndx] = gb[i] - } - d = updateCrc(d) + copy(d[LocationDataIndx:LocationDataIndx+LocationDataSize], gb) + updateCrc(d) return nil } -// addCrc appends a crc table to a given psi table in bytes -func addCrc(out []byte) []byte { - out = append(out, make([]byte, 4)...) - out = updateCrc(out) - return out -} - -// updateCrc updates the crc of psi bytes slice that may have been modified -func updateCrc(out []byte) []byte { - crc32 := crc32_Update(0xffffffff, crc32_MakeTable(bits.Reverse32(crc32.IEEE)), out[1:len(out)-4]) - out[len(out)-4] = byte(crc32 >> 24) - out[len(out)-3] = byte(crc32 >> 16) - out[len(out)-2] = byte(crc32 >> 8) - out[len(out)-1] = byte(crc32) - return out +func trimTo(d []byte, t byte) []byte { + for i, b := range d { + if b == t { + return d[:i] + } + } + return d } diff --git a/stream/mts/psi/psi.go b/stream/mts/psi/psi.go index 9d9763ce..55f50f78 100644 --- a/stream/mts/psi/psi.go +++ b/stream/mts/psi/psi.go @@ -26,10 +26,6 @@ LICENSE package psi -import ( - "hash/crc32" -) - // Lengths of section definitions const ( ESSDDefLen = 5 @@ -42,24 +38,24 @@ const ( // Table Type IDs const ( - PATTableID = 0x00 - PMTTableID = 0x02 + patID = 0x00 + pmtID = 0x02 ) // Consts relating to time description const ( - timeDescTag = 234 - timeTagIndx = 13 - timeDataIndx = 15 - timeDataSize = 8 // bytes, because time is stored in uint64 + TimeDescTag = 234 + TimeTagIndx = 13 + TimeDataIndx = 15 + TimeDataSize = 8 // bytes, because time is stored in uint64 ) // Consts relating to location description const ( - locationDescTag = 235 - locationTagIndx = 23 - locationDataIndx = 25 - locationDataSize = 32 // bytes + LocationDescTag = 235 + LocationTagIndx = 23 + LocationDataIndx = 25 + LocationDataSize = 32 // bytes ) // Program specific information @@ -76,26 +72,26 @@ type PSI struct { // Table syntax section type TSS struct { - Tide uint16 // Table ID extension - V byte // Version number - Cni bool // Current/next indicator - Sn byte // Section number - Lsn byte // Last section number - Sd SD // Specific data PAT/PMT + Tide uint16 // Table ID extension + V byte // Version number + Cni bool // Current/next indicator + Sn byte // Section number + Lsn byte // Last section number + Sd SpecificData // Specific data PAT/PMT } // Specific Data, (could be PAT or PMT) -type SD interface { +type SpecificData interface { Bytes() []byte } -// Program association table, implements SD +// Program association table, implements SpecificData type PAT struct { Pn uint16 // Program Number Pmpid uint16 // Program map PID } -// Program mapping table, implements SD +// Program mapping table, implements SpecificData type PMT struct { Pcrpid uint16 // Program clock reference pid Pil uint16 // Program info length @@ -138,7 +134,7 @@ func (t *TSS) Bytes() []byte { out := make([]byte, TSSDefLen) out[0] = byte(t.Tide >> 8) out[1] = byte(t.Tide) - out[2] = 0xc0 | (0x3e & (t.V << 1)) | (0x01 & boolToByte(t.Cni)) + out[2] = 0xc0 | (0x3e & (t.V << 1)) | (0x01 & asByte(t.Cni)) out[3] = t.Sn out[4] = t.Lsn out = append(out, t.Sd.Bytes()...) @@ -192,39 +188,9 @@ func (e *ESSD) Bytes() []byte { return out } -func boolToByte(b bool) (o byte) { +func asByte(b bool) byte { if b { - o = 0x01 + return 0x01 } - return -} - -func byteToBool(b byte) (o bool) { - if b != 0 { - o = true - } - return -} - -func crc32_MakeTable(poly uint32) *crc32.Table { - var t crc32.Table - for i := range t { - crc := uint32(i) << 24 - for j := 0; j < 8; j++ { - if crc&0x80000000 != 0 { - crc = (crc << 1) ^ poly - } else { - crc <<= 1 - } - } - t[i] = crc - } - return &t -} - -func crc32_Update(crc uint32, tab *crc32.Table, p []byte) uint32 { - for _, v := range p { - crc = tab[byte(crc>>24)^v] ^ (crc << 8) - } - return crc + return 0x00 } diff --git a/stream/mts/psi/psi_test.go b/stream/mts/psi/psi_test.go index 86c19f60..480f6592 100644 --- a/stream/mts/psi/psi_test.go +++ b/stream/mts/psi/psi_test.go @@ -31,10 +31,93 @@ import ( "testing" ) +// Some common manifestations of PSI +var ( + // standardPat is a minimal PAT. + standardPat = PSI{ + Pf: 0x00, + Tid: 0x00, + Ssi: true, + Pb: false, + Sl: 0x0d, + Tss: &TSS{ + Tide: 0x01, + V: 0, + Cni: true, + Sn: 0, + Lsn: 0, + Sd: &PAT{ + Pn: 0x01, + Pmpid: 0x1000, + }, + }, + } + + // standardPmt is a minimal PMT, without time and location descriptors. + standardPmt = PSI{ + Pf: 0x00, + Tid: 0x02, + Ssi: true, + Sl: 0x12, + Tss: &TSS{ + Tide: 0x01, + V: 0, + Cni: true, + Sn: 0, + Lsn: 0, + Sd: &PMT{ + Pcrpid: 0x0100, // wrong + Pil: 0, + Essd: &ESSD{ + St: 0x1b, + Epid: 0x0100, + Esil: 0x00, + }, + }, + }, + } + + // standardPmtTimeLocation is a minimal PMT with time and location descriptors. + standardPmtTimeLocation = PSI{ + Pf: 0x00, + Tid: 0x02, + Ssi: true, + Sl: 0x3e, + Tss: &TSS{ + Tide: 0x01, + V: 0, + Cni: true, + Sn: 0, + Lsn: 0, + Sd: &PMT{ + Pcrpid: 0x0100, + Pil: PmtTimeLocationPil, + Pd: []Desc{ + { + Dt: TimeDescTag, + Dl: TimeDataSize, + Dd: make([]byte, TimeDataSize), + }, + { + Dt: LocationDescTag, + Dl: LocationDataSize, + Dd: make([]byte, LocationDataSize), + }, + }, + Essd: &ESSD{ + St: 0x1b, + Epid: 0x0100, + Esil: 0x00, + }, + }, + }, + } +) + // Times as ints for testing const ( - tstTime1 = 1235367435 // 0x49A2360B - tstTime2 = 1735357535 // 0x676F745F + tstTime1 = 1235367435 // 0x49a2360b + tstTime2 = 1735357535 // 0x676f745f ) // GPS string for testing @@ -60,11 +143,11 @@ var ( var ( pmtTimeLocationBytesPart1 = []byte{ 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a, - byte(timeDescTag), // Descriptor tag for timestamp - byte(timeDataSize), // Length of bytes to follow - 0x00, 0x00, 0x00, 0x00, 0x67, 0x6F, 0x74, 0x5F, // Timestamp data - byte(locationDescTag), // Descriptor tag for location - byte(locationDataSize), // Length of bytes to follow + TimeDescTag, // Descriptor tag for timestamp + TimeDataSize, // Length of bytes to follow + 0x00, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x74, 0x5f, // Timestamp data + LocationDescTag, // Descriptor tag for location + LocationDataSize, // Length of bytes to follow } pmtTimeLocationBytesPart2 = []byte{ 0x1b, 0xe1, 0x00, 0xf0, 0x00, @@ -75,18 +158,18 @@ var ( // Bytes representing pmt with tstTime1 pmtTimeBytes1 = []byte{ 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a, - byte(timeDescTag), // Descriptor tag - byte(timeDataSize), // Length of bytes to follow - 0x00, 0x00, 0x00, 0x00, 0x49, 0xA2, 0x36, 0x0B, // timestamp + TimeDescTag, // Descriptor tag + TimeDataSize, // Length of bytes to follow + 0x00, 0x00, 0x00, 0x00, 0x49, 0xa2, 0x36, 0x0b, // timestamp 0x1b, 0xe1, 0x00, 0xf0, 0x00, } // Bytes representing pmt with tstTime 2 pmtTimeBytes2 = []byte{ 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a, - byte(timeDescTag), // Descriptor tag - byte(timeDataSize), // Length of bytes to follow - 0x00, 0x00, 0x00, 0x00, 0x67, 0x6F, 0x74, 0x5F, // timestamp + TimeDescTag, // Descriptor tag + TimeDataSize, // Length of bytes to follow + 0x00, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x74, 0x5f, // timestamp 0x1b, 0xe1, 0x00, 0xf0, 0x00, } @@ -106,15 +189,15 @@ var bytesTests = []struct { // Pat test { name: "pat Bytes()", - input: StdPat, - want: StdPatBytes, + input: standardPat, + want: StandardPatBytes, }, // Pmt test data no descriptor { name: "pmt to Bytes() without descriptors", - input: StdPmt, - want: StdPmtBytes, + input: standardPmt, + want: StandardPmtBytes, }, // Pmt with time descriptor @@ -124,9 +207,9 @@ var bytesTests = []struct { Pf: 0x00, Tid: 0x02, Ssi: true, - Sl: uint16(0x12), + Sl: 0x12, Tss: &TSS{ - Tide: uint16(0x01), + Tide: 0x01, V: 0, Cni: true, Sn: 0, @@ -135,9 +218,9 @@ var bytesTests = []struct { Pcrpid: 0x0100, // wrong Pil: 10, Pd: []Desc{ - Desc{ - Dt: byte(timeDescTag), - Dl: byte(timeDataSize), + { + Dt: TimeDescTag, + Dl: TimeDataSize, Dd: TimeBytes(tstTime1), }, }, @@ -159,9 +242,9 @@ var bytesTests = []struct { Pf: 0x00, Tid: 0x02, Ssi: true, - Sl: uint16(0x12), + Sl: 0x12, Tss: &TSS{ - Tide: uint16(0x01), + Tide: 0x01, V: 0, Cni: true, Sn: 0, @@ -170,14 +253,14 @@ var bytesTests = []struct { Pcrpid: 0x0100, // wrong Pil: 10, Pd: []Desc{ - Desc{ - Dt: byte(timeDescTag), - Dl: byte(timeDataSize), + { + Dt: TimeDescTag, + Dl: TimeDataSize, Dd: TimeBytes(tstTime2), }, - Desc{ - Dt: byte(locationDescTag), - Dl: byte(locationDataSize), + { + Dt: LocationDescTag, + Dl: LocationDataSize, Dd: LocationStrBytes(locationTstStr1), }, }, @@ -243,7 +326,7 @@ func TestTimeGet(t *testing.T) { // TestLocationGet checks that we can correctly get location data from a pmt table func TestLocationGet(t *testing.T) { - pb := StdPmtTimeLocation.Bytes() + pb := standardPmtTimeLocation.Bytes() err := UpdateLocation(pb, locationTstStr1) if err != nil { t.Errorf("Error for TestLocationGet UpdateLocation(pb, locationTstStr1): %v", err) @@ -272,6 +355,15 @@ func TestLocationUpdate(t *testing.T) { } } +func TestTrim(t *testing.T) { + test := []byte{0xa3, 0x01, 0x03, 0x00, 0xde} + want := []byte{0xa3, 0x01, 0x03} + got := trimTo(test, 0x00) + if !bytes.Equal(got, want) { + t.Errorf(errCmp, "TestTrim", want, got) + } +} + // buildPmtTimeLocationBytes is a helper function to help construct the byte slices // for pmts with time and location, as the location data field is 32 bytes, i.e. quite large // to type out diff --git a/stream/mts/psi/std.go b/stream/mts/psi/std.go index de28d44a..1ebe5ea3 100644 --- a/stream/mts/psi/std.go +++ b/stream/mts/psi/std.go @@ -27,95 +27,12 @@ LICENSE package psi const ( - pmtTimeLocationPil = 44 -) - -// Some common manifestations of PSI -var ( - // PSI struct to represent basic pat - StdPat = PSI{ - Pf: 0x00, - Tid: 0x00, - Ssi: true, - Pb: false, - Sl: uint16(0x0d), - Tss: &TSS{ - Tide: uint16(0x01), - V: 0, - Cni: true, - Sn: 0, - Lsn: 0, - Sd: &PAT{ - Pn: uint16(0x01), - Pmpid: uint16(0x1000), - }, - }, - } - - // PSI struct to represent basic pmt without descriptors for time and location - StdPmt = PSI{ - Pf: 0x00, - Tid: 0x02, - Ssi: true, - Sl: uint16(0x12), - Tss: &TSS{ - Tide: uint16(0x01), - V: 0, - Cni: true, - Sn: 0, - Lsn: 0, - Sd: &PMT{ - Pcrpid: 0x0100, // wrong - Pil: 0, - Essd: &ESSD{ - St: 0x1b, - Epid: 0x0100, - Esil: 0x00, - }, - }, - }, - } - - // Std pmt with time and location descriptors, time and location fields are zeroed out - StdPmtTimeLocation = PSI{ - Pf: 0x00, - Tid: 0x02, - Ssi: true, - Sl: uint16(0x3e), - Tss: &TSS{ - Tide: uint16(0x01), - V: 0, - Cni: true, - Sn: 0, - Lsn: 0, - Sd: &PMT{ - Pcrpid: 0x0100, - Pil: pmtTimeLocationPil, - Pd: []Desc{ - Desc{ - Dt: byte(timeDescTag), - Dl: byte(timeDataSize), - Dd: make([]byte, timeDataSize), - }, - Desc{ - Dt: byte(locationDescTag), - Dl: byte(locationDataSize), - Dd: make([]byte, locationDataSize), - }, - }, - Essd: &ESSD{ - St: 0x1b, - Epid: 0x0100, - Esil: 0x00, - }, - }, - }, - } + PmtTimeLocationPil = 44 ) // Std PSI in bytes form var ( - StdPatBytes = []byte{ + StandardPatBytes = []byte{ 0x00, // pointer // ---- section included in data sent to CRC32 during check @@ -136,7 +53,7 @@ var ( // 0x2a, 0xb1, 0x04, 0xb2, // CRC // ---- } - StdPmtBytes = []byte{ + StandardPmtBytes = []byte{ 0x00, // pointer // ---- section included in data sent to CRC32 during check