From beda8c6578b8e32671770b8e8b77550c76926192 Mon Sep 17 00:00:00 2001 From: Quentin Renard Date: Sat, 25 Nov 2017 23:50:15 +0100 Subject: [PATCH] Added local time offset descriptor --- data_eit.go | 2 +- data_eit_test.go | 22 ++++++++--------- descriptor.go | 60 +++++++++++++++++++++++++++++++++++++++++++++- descriptor_test.go | 20 +++++++++++++++- dvb.go | 14 ++++++++--- dvb_test.go | 23 ++++++++++++------ 6 files changed, 117 insertions(+), 24 deletions(-) diff --git a/data_eit.go b/data_eit.go index 383e4bf..42d5a27 100644 --- a/data_eit.go +++ b/data_eit.go @@ -55,7 +55,7 @@ func parseEITSection(i []byte, offset *int, offsetSectionsEnd int, tableIDExtens e.StartTime = parseDVBTime(i, offset) // Duration - e.Duration = parseDVBDuration(i, offset) + e.Duration = parseDVBDurationSeconds(i, offset) // Running status e.RunningStatus = uint8(i[*offset]) >> 5 diff --git a/data_eit_test.go b/data_eit_test.go index 0775763..a7036e6 100644 --- a/data_eit_test.go +++ b/data_eit_test.go @@ -10,7 +10,7 @@ import ( var eit = &EITData{ Events: []*EITDataEvent{{ Descriptors: descriptors, - Duration: dvbDuration, + Duration: dvbDurationSeconds, EventID: 6, HasFreeCSAMode: true, RunningStatus: 7, @@ -25,16 +25,16 @@ var eit = &EITData{ func eitBytes() []byte { w := astibinary.New() - w.Write(uint16(2)) // Transport stream ID - w.Write(uint16(3)) // Original network ID - w.Write(uint8(4)) // Segment last section number - w.Write(uint8(5)) // Last table id - w.Write(uint16(6)) // Event #1 id - w.Write(dvbTimeBytes) // Event #1 start time - w.Write(dvbDurationBytes) // Event #1 duration - w.Write("111") // Event #1 running status - w.Write("1") // Event #1 free CA mode - descriptorsBytes(w) // Event #1 descriptors + w.Write(uint16(2)) // Transport stream ID + w.Write(uint16(3)) // Original network ID + w.Write(uint8(4)) // Segment last section number + w.Write(uint8(5)) // Last table id + w.Write(uint16(6)) // Event #1 id + w.Write(dvbTimeBytes) // Event #1 start time + w.Write(dvbDurationSecondsBytes) // Event #1 duration + w.Write("111") // Event #1 running status + w.Write("1") // Event #1 free CA mode + descriptorsBytes(w) // Event #1 descriptors return w.Bytes() } diff --git a/descriptor.go b/descriptor.go index 3933e2b..7a0ecce 100644 --- a/descriptor.go +++ b/descriptor.go @@ -1,6 +1,8 @@ package astits import ( + "time" + "github.com/asticode/go-astilog" ) @@ -22,6 +24,7 @@ const ( DescriptorTagExtendedEvent = 0x4e DescriptorTagExtension = 0x7f DescriptorTagISO639LanguageAndAudioType = 0xa + DescriptorTagLocalTimeOffset = 0x58 DescriptorTagMaximumBitrate = 0xe DescriptorTagNetworkName = 0x40 DescriptorTagParentalRating = 0x55 @@ -65,6 +68,7 @@ type Descriptor struct { Extension *DescriptorExtension ISO639LanguageAndAudioType *DescriptorISO639LanguageAndAudioType Length uint8 + LocalTimeOffset *DescriptorLocalTimeOffset MaximumBitrate *DescriptorMaximumBitrate NetworkName *DescriptorNetworkName ParentalRating *DescriptorParentalRating @@ -421,6 +425,56 @@ func newDescriptorISO639LanguageAndAudioType(i []byte) *DescriptorISO639Language } } +// DescriptorLocalTimeOffset represents a local time offset descriptor +// Page: 84 | Link: https://www.dvb.org/resources/public/standards/a38_dvb-si_specification.pdf +type DescriptorLocalTimeOffset struct { + Items []*DescriptorLocalTimeOffsetItem +} + +// DescriptorLocalTimeOffsetItem represents a local time offset item descriptor +type DescriptorLocalTimeOffsetItem struct { + CountryCode []byte + CountryRegionID uint8 + LocalTimeOffset time.Duration + LocalTimeOffsetPolarity bool + NextTimeOffset time.Duration + TimeOfChange time.Time +} + +func newDescriptorLocalTimeOffset(i []byte) (d *DescriptorLocalTimeOffset) { + // Init + d = &DescriptorLocalTimeOffset{} + var offset int + + // Add items + for offset < len(i) { + // Init + var itm = &DescriptorLocalTimeOffsetItem{} + d.Items = append(d.Items, itm) + + // Country code + itm.CountryCode = i[offset : offset+3] + offset += 3 + + // Country region ID + itm.CountryRegionID = uint8(i[offset] >> 2) + + // Local time offset polarity + itm.LocalTimeOffsetPolarity = i[offset]&0x1 > 0 + offset += 1 + + // Local time offset + itm.LocalTimeOffset = parseDVBDurationMinutes(i, &offset) + + // Time of change + itm.TimeOfChange = parseDVBTime(i, &offset) + + // Next time offset + itm.NextTimeOffset = parseDVBDurationMinutes(i, &offset) + } + return +} + // DescriptorMaximumBitrate represents a maximum bitrate descriptor type DescriptorMaximumBitrate struct { Bitrate uint32 // In bytes/second @@ -432,7 +486,9 @@ func newDescriptorMaximumBitrate(i []byte) *DescriptorMaximumBitrate { // DescriptorNetworkName represents a network name descriptor // Page: 93 | Chapter: 6.2.27 | Link: https://www.dvb.org/resources/public/standards/a38_dvb-si_specification.pdf -type DescriptorNetworkName struct{ Name []byte } +type DescriptorNetworkName struct { + Name []byte +} func newDescriptorNetworkName(i []byte) *DescriptorNetworkName { return &DescriptorNetworkName{Name: i} @@ -627,6 +683,8 @@ func parseDescriptors(i []byte, offset *int) (o []*Descriptor) { d.Extension = newDescriptorExtension(b) case DescriptorTagISO639LanguageAndAudioType: d.ISO639LanguageAndAudioType = newDescriptorISO639LanguageAndAudioType(b) + case DescriptorTagLocalTimeOffset: + d.LocalTimeOffset = newDescriptorLocalTimeOffset(b) case DescriptorTagMaximumBitrate: d.MaximumBitrate = newDescriptorMaximumBitrate(b) case DescriptorTagNetworkName: diff --git a/descriptor_test.go b/descriptor_test.go index 69f307b..81a2de1 100644 --- a/descriptor_test.go +++ b/descriptor_test.go @@ -23,7 +23,7 @@ func descriptorsBytes(w *astibinary.Writer) { func TestParseDescriptor(t *testing.T) { // Init w := astibinary.New() - w.Write(uint16(177)) // Descriptors length + w.Write(uint16(193)) // Descriptors length // AC3 w.Write(uint8(DescriptorTagAC3)) // Tag w.Write(uint8(9)) // Length @@ -154,6 +154,16 @@ func TestParseDescriptor(t *testing.T) { w.Write(uint8(4)) // Length w.Write([]byte("cou")) // Item #1 country code w.Write(uint8(2)) // Item #1 rating + // Local time offset + w.Write(uint8(DescriptorTagLocalTimeOffset)) // Tag + w.Write(uint8(13)) // Length + w.Write([]byte("cou")) // Country code + w.Write("101010") // Country region ID + w.Write("1") // Reserved + w.Write("1") // Local time offset polarity + w.Write(dvbDurationMinutesBytes) // Local time offset + w.Write(dvbTimeBytes) // Time of change + w.Write(dvbDurationMinutesBytes) // Next time offset // Assert var offset int @@ -266,4 +276,12 @@ func TestParseDescriptor(t *testing.T) { CountryCode: []byte("cou"), Rating: 2, }}}) + assert.Equal(t, *ds[15].LocalTimeOffset, DescriptorLocalTimeOffset{Items: []*DescriptorLocalTimeOffsetItem{{ + CountryCode: []byte("cou"), + CountryRegionID: 42, + LocalTimeOffset: dvbDurationMinutes, + LocalTimeOffsetPolarity: true, + NextTimeOffset: dvbDurationMinutes, + TimeOfChange: dvbTime, + }}}) } diff --git a/dvb.go b/dvb.go index b0b45c9..e554edd 100644 --- a/dvb.go +++ b/dvb.go @@ -27,13 +27,21 @@ func parseDVBTime(i []byte, offset *int) (t time.Time) { *offset += 2 // Time - t = t.Add(parseDVBDuration(i, offset)) + t = t.Add(parseDVBDurationSeconds(i, offset)) return } -// parseDVBDuration parses a duration +// parseDVBDurationMinutes parses a minutes duration +// 16 bit field containing the duration of the event in hours, minutes. format: 4 digits, 4 - bit BCD = 18 bit +func parseDVBDurationMinutes(i []byte, offset *int) (d time.Duration) { + d = parseDVBDurationByte(i[*offset])*time.Hour + parseDVBDurationByte(i[*offset+1])*time.Minute + *offset += 2 + return +} + +// parseDVBDurationSeconds parses a seconds duration // 24 bit field containing the duration of the event in hours, minutes, seconds. format: 6 digits, 4 - bit BCD = 24 bit -func parseDVBDuration(i []byte, offset *int) (d time.Duration) { +func parseDVBDurationSeconds(i []byte, offset *int) (d time.Duration) { d = parseDVBDurationByte(i[*offset])*time.Hour + parseDVBDurationByte(i[*offset+1])*time.Minute + parseDVBDurationByte(i[*offset+2])*time.Second *offset += 3 return diff --git a/dvb_test.go b/dvb_test.go index b86abe9..186140b 100644 --- a/dvb_test.go +++ b/dvb_test.go @@ -8,10 +8,12 @@ import ( ) var ( - dvbDuration = time.Hour + 45*time.Minute + 30*time.Second - dvbDurationBytes = []byte{0x1, 0x45, 0x30} // 014530 - dvbTime, _ = time.Parse("2006-01-02 15:04:05", "1993-10-13 12:45:00") - dvbTimeBytes = []byte{0xc0, 0x79, 0x12, 0x45, 0x0} // C079124500 + dvbDurationMinutes = time.Hour + 45*time.Minute + dvbDurationMinutesBytes = []byte{0x1, 0x45} // 0145 + dvbDurationSeconds = time.Hour + 45*time.Minute + 30*time.Second + dvbDurationSecondsBytes = []byte{0x1, 0x45, 0x30} // 014530 + dvbTime, _ = time.Parse("2006-01-02 15:04:05", "1993-10-13 12:45:00") + dvbTimeBytes = []byte{0xc0, 0x79, 0x12, 0x45, 0x0} // C079124500 ) func TestParseDVBTime(t *testing.T) { @@ -21,9 +23,16 @@ func TestParseDVBTime(t *testing.T) { assert.Equal(t, 5, offset) } -func TestParseDVBDuration(t *testing.T) { +func TestParseDVBDurationMinutes(t *testing.T) { var offset int - d := parseDVBDuration(dvbDurationBytes, &offset) - assert.Equal(t, dvbDuration, d) + d := parseDVBDurationMinutes(dvbDurationMinutesBytes, &offset) + assert.Equal(t, dvbDurationMinutes, d) + assert.Equal(t, 2, offset) +} + +func TestParseDVBDurationSeconds(t *testing.T) { + var offset int + d := parseDVBDurationSeconds(dvbDurationSecondsBytes, &offset) + assert.Equal(t, dvbDurationSeconds, d) assert.Equal(t, 3, offset) }