github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/dvb/service.go (about) 1 package dvb 2 3 import ( 4 "fmt" 5 "strings" 6 7 desc "github.com/puellanivis/breton/lib/mpeg/ts/descriptor" 8 ) 9 10 // RunningStatus is an enum defining running state from the DVB standard for MPEG-TS. 11 type RunningStatus uint8 12 13 // RunningStatus enum values. 14 const ( 15 NotRunning RunningStatus = iota + 1 16 Starting 17 Pausing 18 Running 19 OffAir 20 ) 21 22 var runningStatusNames = map[RunningStatus]string{ 23 NotRunning: "NOT_RUN", 24 Starting: "START", 25 Pausing: "PAUSE", 26 Running: "RUN", 27 OffAir: "OFF_AIR", 28 } 29 30 func (rs RunningStatus) String() string { 31 if s, ok := runningStatusNames[rs]; ok { 32 return s 33 } 34 35 return fmt.Sprintf("x%X", uint8(rs)) 36 } 37 38 // Service defines a single Service from the Service Description Table from the DVB standard for MPEG-TS. 39 type Service struct { 40 ID uint16 41 EITSchedule bool 42 EITPresent bool 43 RunningStatus RunningStatus 44 FreeCA bool 45 46 Descriptors []desc.Descriptor 47 } 48 49 func (s *Service) String() string { 50 out := []string{ 51 "DVB:Service", 52 fmt.Sprintf("ID:x%04X", s.ID), 53 } 54 55 if s.EITSchedule { 56 out = append(out, "EIT_SCHED") 57 } 58 59 if s.EITPresent { 60 out = append(out, "EIT_PRES") 61 } 62 63 out = append(out, fmt.Sprint(s.RunningStatus)) 64 65 if s.FreeCA { 66 out = append(out, "FreeCA") 67 } 68 69 for _, d := range s.Descriptors { 70 out = append(out, fmt.Sprintf("Desc:%v", d)) 71 } 72 73 return fmt.Sprintf("{%s}", strings.Join(out, " ")) 74 } 75 76 const ( 77 flagEITSchedule = 0x02 78 flagEITPresent = 0x01 79 80 shiftRunningStatus = 5 81 maskRunningStatus = 0x07 82 83 flagFreeCA = 0x10 84 ) 85 86 func (s *Service) marshal() ([]byte, error) { 87 b := make([]byte, 5) 88 89 b[0] = byte((s.ID >> 8) & 0xff) 90 b[1] = byte(s.ID & 0xff) 91 b[2] = 0xFC 92 93 if s.EITSchedule { 94 b[2] |= flagEITSchedule 95 } 96 97 if s.EITPresent { 98 b[2] |= flagEITPresent 99 } 100 101 b[3] = byte((s.RunningStatus & maskRunningStatus) << shiftRunningStatus) 102 if s.FreeCA { 103 b[3] |= flagFreeCA 104 } 105 106 loopLen := 0 107 for _, d := range s.Descriptors { 108 db, err := d.Marshal() 109 if err != nil { 110 return nil, err 111 } 112 113 loopLen += len(db) 114 b = append(b, db...) 115 } 116 117 b[3] |= byte((loopLen >> 8) & 0x0F) 118 b[4] = byte(loopLen & 0xFF) 119 120 return b, nil 121 } 122 123 func (s *Service) unmarshal(b []byte) (int, error) { 124 s.ID = uint16(b[0])<<8 | uint16(b[1]) 125 s.EITSchedule = b[2]&flagEITSchedule != 0 126 s.EITPresent = b[2]&flagEITPresent != 0 127 s.RunningStatus = RunningStatus((b[3] >> shiftRunningStatus) & maskRunningStatus) 128 s.FreeCA = b[3]&flagFreeCA != 0 129 130 loopLen := int(b[3]&0x0F)<<8 | int(b[4]) 131 132 start := 0 133 b = b[5:] 134 135 for start < loopLen { 136 pd, err := desc.Unmarshal(b[start:]) 137 if err != nil { 138 return start, err 139 } 140 141 start += pd.Len() 142 s.Descriptors = append(s.Descriptors, pd) 143 } 144 145 return start + 5, nil 146 }