-
Notifications
You must be signed in to change notification settings - Fork 51
/
dvb.go
130 lines (106 loc) · 3.99 KB
/
dvb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package astits
import (
"fmt"
"time"
"github.com/asticode/go-astikit"
)
// parseDVBTime parses a DVB time
// This field is coded as 16 bits giving the 16 LSBs of MJD followed by 24 bits coded as 6 digits in 4 - bit Binary
// Coded Decimal (BCD). If the start time is undefined (e.g. for an event in a NVOD reference service) all bits of the
// field are set to "1".
// I apologize for the computation which is really messy but details are given in the documentation
// Page: 160 | Annex C | Link: https://www.dvb.org/resources/public/standards/a38_dvb-si_specification.pdf
// (barbashov) the link above can be broken, alternative: https://dvb.org/wp-content/uploads/2019/12/a038_tm1217r37_en300468v1_17_1_-_rev-134_-_si_specification.pdf
func parseDVBTime(i *astikit.BytesIterator) (t time.Time, err error) {
// Get next 2 bytes
var bs []byte
if bs, err = i.NextBytesNoCopy(2); err != nil {
err = fmt.Errorf("astits: fetching next bytes failed: %w", err)
return
}
// Date
var mjd = uint16(bs[0])<<8 | uint16(bs[1])
var yt = int((float64(mjd) - 15078.2) / 365.25)
var mt = int((float64(mjd) - 14956.1 - float64(int(float64(yt)*365.25))) / 30.6001)
var d = int(float64(mjd) - 14956 - float64(int(float64(yt)*365.25)) - float64(int(float64(mt)*30.6001)))
var k int
if mt == 14 || mt == 15 {
k = 1
}
var y = 1900 + yt + k
var m = mt - 1 - k*12
t = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC)
// Time
var s time.Duration
if s, err = parseDVBDurationSeconds(i); err != nil {
err = fmt.Errorf("astits: parsing DVB duration seconds failed: %w", err)
return
}
t = t.Add(s)
return
}
// 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 *astikit.BytesIterator) (d time.Duration, err error) {
var bs []byte
if bs, err = i.NextBytesNoCopy(2); err != nil {
err = fmt.Errorf("astits: fetching next bytes failed: %w", err)
return
}
d = parseDVBDurationByte(bs[0])*time.Hour + parseDVBDurationByte(bs[1])*time.Minute
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 parseDVBDurationSeconds(i *astikit.BytesIterator) (d time.Duration, err error) {
var bs []byte
if bs, err = i.NextBytesNoCopy(3); err != nil {
err = fmt.Errorf("astits: fetching next bytes failed: %w", err)
return
}
d = parseDVBDurationByte(bs[0])*time.Hour + parseDVBDurationByte(bs[1])*time.Minute + parseDVBDurationByte(bs[2])*time.Second
return
}
// parseDVBDurationByte parses a duration byte
func parseDVBDurationByte(i byte) time.Duration {
return time.Duration(uint8(i)>>4*10 + uint8(i)&0xf)
}
func writeDVBTime(w *astikit.BitsWriter, t time.Time) (int, error) {
year := t.Year() - 1900
month := t.Month()
day := t.Day()
l := 0
if month <= time.February {
l = 1
}
mjd := 14956 + day + int(float64(year-l)*365.25) + int(float64(int(month)+1+l*12)*30.6001)
d := t.Sub(t.Truncate(24 * time.Hour))
b := astikit.NewBitsWriterBatch(w)
b.Write(uint16(mjd))
bytesWritten, err := writeDVBDurationSeconds(w, d)
if err != nil {
return 2, err
}
return bytesWritten + 2, b.Err()
}
func writeDVBDurationMinutes(w *astikit.BitsWriter, d time.Duration) (int, error) {
b := astikit.NewBitsWriterBatch(w)
hours := uint8(d.Hours())
minutes := uint8(int(d.Minutes()) % 60)
b.Write(dvbDurationByteRepresentation(hours))
b.Write(dvbDurationByteRepresentation(minutes))
return 2, b.Err()
}
func writeDVBDurationSeconds(w *astikit.BitsWriter, d time.Duration) (int, error) {
b := astikit.NewBitsWriterBatch(w)
hours := uint8(d.Hours())
minutes := uint8(int(d.Minutes()) % 60)
seconds := uint8(int(d.Seconds()) % 60)
b.Write(dvbDurationByteRepresentation(hours))
b.Write(dvbDurationByteRepresentation(minutes))
b.Write(dvbDurationByteRepresentation(seconds))
return 3, b.Err()
}
func dvbDurationByteRepresentation(n uint8) uint8 {
return (n/10)<<4 | n%10
}