splice_descriptor.go (11265B)
1 package scte35 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 ) 7 8 const DescriptorIDCUEI = "CUEI" 9 10 // DescriptorIDCUEI in ASCII 11 const descriptorIDCUEI uint32 = 0x43554549 12 13 const ( 14 TagAvail uint8 = iota 15 TagDTMF 16 TagSegmentation 17 TagTime 18 TagAudio 19 ) 20 21 // SCTE 35 section 10.3.3.1 22 const ( 23 ProgramStart = 0x10 24 ProgramEnd = 0x11 25 ChapterStart = 0x20 26 ChapterEnd = 0x21 27 ProviderAdStart = 0x30 28 DistributorAdStart = 0x32 29 ProviderPlacementOppStart = 0x34 30 ProviderPlacementOppEnd = 0x35 31 DistributorPlacementOppStart = 0x36 32 ProviderOverlayPlacementOppStart = 0x38 33 DistributorOverlayPlacementOppStart = 0x3a 34 ProviderAdBlockStart = 0x44 35 DistributorAdBlockStart = 0x46 36 ) 37 38 type SpliceDescriptor interface { 39 // Tag identifies the type of descriptor. If ID is 40 // DescriptorIDCUEI, then the the values [TagAvail] et al. may be used. 41 Tag() uint8 42 // For private descriptors, this value must not be DescriptorIDCUEI. 43 ID() uint32 44 // Data is the encoded splice descriptor implementation. 45 // If Tag is one of [TagAvail] et al., then the corresponding 46 // types (AvailDescriptor, DTMFDescriptor...) may be used to 47 // decode/encode this field. 48 Data() []byte 49 } 50 51 func encodeSpliceDescriptor(sd SpliceDescriptor) []byte { 52 var buf []byte 53 buf = append(buf, byte(sd.Tag())) 54 buf = append(buf, byte(len(sd.Data())+4)) // len(sd.ID()) == 4 55 buf = binary.BigEndian.AppendUint32(buf, sd.ID()) 56 return append(buf, sd.Data()...) 57 } 58 59 // AvailDescriptor is a type of splice descriptor described in SCTE 35 section 10.3.1. 60 // Its only value is a so-called "provider avail ID". 61 type AvailDescriptor uint32 62 63 func (d AvailDescriptor) Tag() uint8 { return TagAvail } 64 func (d AvailDescriptor) ID() uint32 { return descriptorIDCUEI } 65 66 func (d AvailDescriptor) Data() []byte { 67 buf := make([]byte, 4) 68 binary.BigEndian.PutUint32(buf, uint32(d)) 69 return buf 70 } 71 72 // DTMFDescriptor is a type of a splice descriptor as described in SCTE 35 10.3.2. 73 // DTMF stands for [Dual-tone multi-frequency signaling]. 74 // 75 // [Dual-tone multi-frequency signaling]: https://en.wikipedia.org/wiki/DTMF 76 type DTMFDescriptor struct { 77 Preroll uint8 78 // Chars holds a DTMF sequence whose values may only 79 // consist of the ASCII values of '0' through '9', '*', and '#'. 80 Chars []byte 81 } 82 83 func (d DTMFDescriptor) Tag() uint8 { return TagDTMF } 84 func (d DTMFDescriptor) ID() uint32 { return descriptorIDCUEI } 85 86 func (d DTMFDescriptor) Data() []byte { 87 // preroll + char count + chars 88 b := make([]byte, 1+1+len(d.Chars)) 89 b[0] = byte(d.Preroll) 90 // set 3 bits, right-most 5 are reserved. 91 b[1] = byte(len(d.Chars)) << 5 92 copy(b[2:], d.Chars) 93 return b 94 } 95 96 func unmarshalDTMF(buf []byte) DTMFDescriptor { 97 // skip buf[1]; contains the length which we don't care about when using slices. 98 return DTMFDescriptor{ 99 Preroll: uint8(buf[0]), 100 Chars: buf[2:], 101 } 102 } 103 104 type DeliveryRestrictions uint8 105 106 const ( 107 WebDeliveryAllowed DeliveryRestrictions = 1<<4 - iota 108 NoRegionalBlackout 109 ArchiveAllowed 110 DeviceRestrictGroup0 = 0x00 111 DeviceRestrictGroup1 = 0x01 112 DeviceRestrictGroup2 = 0x02 113 DeviceRestrictionsNone = 0x03 114 ) 115 116 // SegmentationDescriptor represents the segmentation_descriptor 117 // structure defined in SCTE 35 section 10.3.3. 118 type SegmentationDescriptor struct { 119 EventID uint32 120 Cancel bool 121 Restrictions DeliveryRestrictions 122 // 40-bit integer representing the number of ticks of a 90KHz clock. 123 Duration *uint64 124 UPID UPID 125 // Valid types are specified in Table 23, SCTE 35 section 10.3.3.1. 126 Type uint8 127 // The numbered index of this descriptor in a collection of descriptors. 128 Number uint8 129 // Expected count of descriptors. 130 Expected uint8 131 // Numbered index of any subsegment of this descriptor. 132 SubNumber uint8 133 // Expected count of subsegments. 134 SubExpected uint8 135 // Indicates the event's ID is prepared in the method 136 // described in SCTE 35 section 9.3.3. 137 // TODO(otl): can we calculate this at runtime? 138 // See https://github.com/untangledco/streaming/issues/2 139 idCompliance bool 140 } 141 142 func (d SegmentationDescriptor) Tag() uint8 { return TagSegmentation } 143 func (d SegmentationDescriptor) ID() uint32 { return descriptorIDCUEI } 144 145 func (d SegmentationDescriptor) Data() []byte { 146 buf := make([]byte, 5) 147 binary.BigEndian.PutUint32(buf[:4], d.EventID) 148 if d.Cancel { 149 buf[4] |= (1 << 7) 150 } 151 if d.idCompliance { 152 buf[4] |= (1 << 6) 153 } 154 // toggle next remaining 6 reserved bits. 155 buf[4] |= 0b00111111 156 157 if !d.Cancel { 158 buf = append(buf, segDescFlags(&d)) 159 if d.Duration != nil { 160 b := make([]byte, 8) // uint64 needs 8 161 binary.BigEndian.PutUint64(b, *d.Duration<<24) // 40 bits 162 // append 40 bits (5 bytes) 163 buf = append(buf, b[:5]...) 164 } 165 166 buf = append(buf, byte(d.UPID.Type)) 167 buf = append(buf, uint8(len(d.UPID.Value))) 168 buf = append(buf, d.UPID.Value...) 169 170 buf = append(buf, byte(d.Type), byte(d.Number), byte(d.Expected)) 171 switch d.Type { 172 case ProviderAdStart, DistributorAdStart, ProviderPlacementOppStart, DistributorPlacementOppStart, ProviderOverlayPlacementOppStart, DistributorOverlayPlacementOppStart, ProviderAdBlockStart, DistributorAdBlockStart: 173 if d.SubNumber > 0 { 174 buf = append(buf, d.SubNumber) 175 } 176 if d.SubExpected > 0 { 177 buf = append(buf, d.SubExpected) 178 } 179 } 180 } 181 return buf 182 } 183 184 func unmarshalSegDescriptor(buf []byte) SegmentationDescriptor { 185 var desc SegmentationDescriptor 186 desc.EventID = binary.BigEndian.Uint32(buf[:4]) 187 desc.Cancel = buf[4]&(1<<7) > 0 188 desc.idCompliance = buf[4]&(1<<6) > 0 189 // next 6 bits are reserved 190 191 // always assume program_segmentation_flag is set at 0b10000000 192 // we don't support the deprecated component mode. 193 194 if !desc.Cancel { 195 // left-most 2 bits are flags for later. 196 desc.Restrictions = DeliveryRestrictions(buf[5] & 0b00111111) 197 198 // is segmentation duration flag set? 199 if buf[5]&0b01000000 > 0 { 200 b := make([]byte, 3) 201 b = append(b, buf[6:11]...) 202 dur := binary.BigEndian.Uint64(b) 203 desc.Duration = &dur 204 buf = buf[11:] 205 } else { 206 buf = buf[6:] 207 } 208 209 uplen := int(buf[1]) 210 desc.UPID = UPID{ 211 Type: UPIDType(buf[0]), 212 Value: buf[2 : 2+uplen], 213 } 214 buf = buf[2+uplen:] 215 216 desc.Type = uint8(buf[0]) 217 desc.Number = uint8(buf[1]) 218 desc.Expected = uint8(buf[2]) 219 switch desc.Type { 220 case ProviderAdStart, DistributorAdStart, ProviderPlacementOppStart, DistributorPlacementOppStart, ProviderOverlayPlacementOppStart, DistributorOverlayPlacementOppStart, ProviderAdBlockStart, DistributorAdBlockStart: 221 if len(buf[2:]) > 1 { 222 desc.SubNumber = uint8(buf[3]) 223 } 224 if len(buf[2:]) > 2 { 225 desc.SubExpected = uint8(buf[4]) 226 } 227 } 228 } 229 230 return desc 231 } 232 233 // UPID represents a segmentation_upid structure as specified in SCTE 35 section 10.3.3.1. 234 type UPID struct { 235 Type UPIDType 236 // Value holds the corresponding encoded contents for this UPID's Type. 237 // Possible values are given in Table 22 of section 10.3.3.1. 238 Value []byte 239 } 240 241 // UPIDType represents a Segmentation UPID type as defined in SCTE 35 section 10.3.3.1. 242 type UPIDType uint8 243 244 // Valid UPIDType values defined in Table 22, SCTE 35 section 10.3.3.1. 245 const ( 246 UPIDNone UPIDType = 0 + iota 247 _ // User Defined, deprecated, use MPU. 248 _ // ISCI, deprecated, use AdID. 249 UPIDAdID 250 UPIDUMID 251 _ // ISAN, deprecated, use ISAN. 252 UPIDISAN 253 UPIDTID 254 UPIDTI 255 UPIDADI 256 UPIDEIDR 257 UPIDATSCContentID 258 UPIDMPU 259 UPIDMID 260 UPIDADSInfo 261 UPIDURI 262 UPIDUUID 263 UPIDSCR 264 UPIDReserved 265 ) 266 267 // TimeDescriptor represents a moment in time as used in the Precision 268 // Time Protocol (PTP). PTP uses International Atomic Time (TAI) rather 269 // than UTC time as in NTP. 270 type TimeDescriptor struct { 271 // A 48-bit integer of the number of seconds since the Unix 272 // epoch according to TAI. 273 Seconds uint64 274 // Number of nanoseconds... 275 Nanoseconds uint32 276 // The current number of seconds between NTP time and 277 // TAI for a single instance of time. 278 UTCOffset uint16 279 } 280 281 func (d TimeDescriptor) Tag() uint8 { return TagTime } 282 func (d TimeDescriptor) ID() uint32 { return descriptorIDCUEI } 283 284 func (d TimeDescriptor) Data() []byte { 285 // 48 bits + 32 bits + 16 bits 286 b := make([]byte, 0, 6+4+2) 287 b = binary.BigEndian.AppendUint64(b, d.Seconds) 288 b = b[:6] // only want 48-bits 289 b = binary.BigEndian.AppendUint32(b, d.Nanoseconds) 290 return binary.BigEndian.AppendUint16(b, d.UTCOffset) 291 } 292 293 type AudioChannel struct { 294 ComponentTag uint8 295 // A language code from ISO 639-2. 296 Language [3]byte 297 // A 3-bit integer from ATSC A/52 Table 5.7. 298 BitstreamMode uint8 299 // Number of channels as a 4 bit field, from ATSC A/52 Table A4.5. 300 Count NumChannels 301 FullService bool 302 } 303 304 type NumChannels uint8 305 306 const ( 307 OneChan NumChannels = 0b10000000 + (iota << 4) 308 TwoChan 309 ThreeChan 310 FourChan 311 FiveChan 312 SixChan 313 _ // Reserved 314 _ // Reserved 315 ) 316 317 type AudioDescriptor []AudioChannel 318 319 func (d AudioDescriptor) Tag() uint8 { return TagAudio } 320 func (d AudioDescriptor) ID() uint32 { return descriptorIDCUEI } 321 322 func (d AudioDescriptor) Data() []byte { 323 var b []byte 324 count := len(d) 325 b = append(b, byte(count<<4)) // right-most 4 bits are reserved 326 for _, ch := range d { 327 b = append(b, ch.ComponentTag) 328 b = append(b, ch.Language[:]...) 329 var c byte 330 c |= (ch.BitstreamMode << 5) // set bits 0-2 331 c |= byte(ch.Count) >> 3 // set bits 3-7 332 if ch.FullService { 333 c |= 0x01 // set last bit 334 } 335 b = append(b, c) 336 } 337 return b 338 } 339 340 func decodeAllDescriptors(buf []byte) ([]SpliceDescriptor, error) { 341 var sds []SpliceDescriptor 342 for len(buf) >= 6 { 343 // first byte is tag, second is length of next descriptor. 344 dlen := uint8(buf[1]) 345 desc, err := unmarshalSpliceDescriptor(buf[:2+dlen]) 346 if err != nil { 347 return sds, err 348 } 349 sds = append(sds, desc) 350 if int(dlen) >= len(buf) { 351 break 352 } 353 buf = buf[2+dlen:] 354 } 355 return sds, nil 356 } 357 358 // UnmarshalSpliceDescriptor reads exactly one descriptor from buf. 359 func unmarshalSpliceDescriptor(buf []byte) (SpliceDescriptor, error) { 360 if len(buf) < 6 { 361 return nil, fmt.Errorf("short slice: need at least 5 bytes") 362 } 363 tag := uint8(buf[0]) 364 length := uint8(buf[1]) 365 if len(buf[2:]) != int(length) { 366 return nil, fmt.Errorf("need %d bytes, have %d", int(length), len(buf[2:])) 367 } 368 buf = buf[2 : 2+length] 369 id := binary.BigEndian.Uint32(buf[:4]) 370 buf = buf[4:] 371 if id != descriptorIDCUEI { 372 return PrivateDescriptor{tag, id, buf}, nil 373 } 374 switch tag { 375 case TagAvail: 376 return AvailDescriptor(binary.BigEndian.Uint32(buf)), nil 377 case TagSegmentation: 378 return unmarshalSegDescriptor(buf), nil 379 case TagDTMF: 380 return unmarshalDTMF(buf), nil 381 } 382 return nil, fmt.Errorf("unmarshal %d unsupported", tag) 383 } 384 385 type PrivateDescriptor struct { 386 PTag uint8 387 PID uint32 388 PData []byte 389 } 390 391 func (d PrivateDescriptor) Tag() uint8 { return d.PTag } 392 func (d PrivateDescriptor) ID() uint32 { return d.PID } 393 func (d PrivateDescriptor) Data() []byte { return d.PData } 394 395 func segDescFlags(seg *SegmentationDescriptor) uint8 { 396 var b uint8 397 // assume program_segmentation is always set; we do not support the deprecated component mode. 398 b |= (1 << 7) 399 if seg.Duration != nil { 400 b |= (1 << 6) 401 } 402 if seg.Restrictions != 0 { 403 b |= byte(seg.Restrictions) 404 } else { 405 b |= (1 << 5) 406 } 407 return b 408 }