streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

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 }