github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/packet/packet.go (about) 1 package packet 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "github.com/pkg/errors" 9 ) 10 11 // TransportScrambleControl is an enum of what kind of MPEG Transport Scramble Control is to be used. 12 type TransportScrambleControl byte 13 14 // TransportScrambleControl enum values. 15 const ( 16 ScrambleNone TransportScrambleControl = iota 17 scrambleReserve 18 ScrambleEven 19 ScrambleOdd 20 ) 21 22 // Packet defines a single MPEG-TS packet. 23 type Packet struct { 24 PID uint16 25 TEI bool 26 PUSI bool 27 Priority bool 28 29 ScrambleControl TransportScrambleControl 30 *AdaptationField 31 Continuity byte 32 33 Payload []byte 34 } 35 36 func (p *Packet) String() string { 37 var out []string 38 39 out = append(out, fmt.Sprintf("PID:x%04X", p.PID), fmt.Sprintf("[%X]", p.Continuity)) 40 if p.TEI { 41 out = append(out, "TEI") 42 } 43 if p.PUSI { 44 out = append(out, "PUSI") 45 } 46 if p.Priority { 47 out = append(out, "PRI") 48 } 49 50 switch p.ScrambleControl { 51 case ScrambleNone: 52 case ScrambleEven: 53 out = append(out, "EVEN") 54 case ScrambleOdd: 55 out = append(out, "ODD") 56 } 57 58 if p.AdaptationField != nil { 59 out = append(out, fmt.Sprintf("AF:%+v", p.AdaptationField)) 60 } 61 62 if len(p.Payload) > 0 { 63 pl := fmt.Sprintf("Payload[%d]", len(p.Payload)) 64 65 if len(p.Payload) > 16 { 66 pl = fmt.Sprintf("%s{ % 2X… }", pl, p.Payload[:16]) 67 } else { 68 pl = fmt.Sprintf("%s{ % 2X }", pl, p.Payload) 69 } 70 71 out = append(out, pl) 72 } 73 74 return fmt.Sprintf("{%s}", strings.Join(out, " ")) 75 } 76 77 const ( 78 flagTEI = 0x80 79 flagPUSI = 0x40 80 flagPriority = 0x20 81 82 flagPayload = 0x10 83 flagAdaptationField = 0x20 84 85 // Length is how long an MPEG-TS packet is. 86 Length = 188 87 88 // HeaderLength is the length of an MPEG-TS packet. 89 HeaderLength = 4 90 91 // MaxPayload is the maximum length of payload that may be put into a packet. 92 MaxPayload = Length - HeaderLength 93 ) 94 95 // Bytes returns the payload of the Packet as a byte slice. 96 func (p *Packet) Bytes() []byte { 97 return p.Payload 98 } 99 100 // Unmarshal decodes a byte slice into the Packet. 101 func (p *Packet) Unmarshal(b []byte) error { 102 if len(b) != Length || b[0] != 'G' { 103 return errors.Errorf("invalid packet %v", b[:4]) 104 } 105 106 p.TEI = (b[1] & flagTEI) != 0 107 p.PUSI = (b[1] & flagPUSI) != 0 108 p.Priority = (b[1] & flagPriority) != 0 109 110 p.PID = (uint16(b[1]&0x1f) << 8) | uint16(b[2]) 111 112 p.ScrambleControl = TransportScrambleControl((b[3] >> 6) & 0x03) 113 p.Continuity = b[3] & 0x0f 114 115 start := 4 116 117 if b[3]&flagAdaptationField != 0 { 118 af := new(AdaptationField) 119 120 l, err := af.unmarshal(b[start:]) 121 if err != nil { 122 return err 123 } 124 125 p.AdaptationField = af 126 127 start += l 128 } 129 130 if b[3]&flagPayload != 0 { 131 p.Payload = append([]byte{}, b[start:]...) 132 } 133 134 return nil 135 } 136 137 var fullPadding = bytes.Repeat([]byte{0xFF}, Length) 138 139 // Marshal encodes a Packet into a byte slice. 140 func (p *Packet) Marshal() ([]byte, error) { 141 if p.PID > 0x1fff { 142 return nil, errors.Errorf("PID %d is greater than maximum 0x1fff", p.PID) 143 } 144 145 packet := make([]byte, Length) 146 147 packet[0] = 'G' 148 149 if p.TEI { 150 packet[1] |= flagTEI 151 } 152 153 if p.PUSI { 154 packet[1] |= flagPUSI 155 } 156 157 if p.Priority { 158 packet[1] |= flagPriority 159 } 160 161 packet[1] |= byte((p.PID >> 8) & 0x1f) 162 packet[2] = byte(p.PID & 0xff) 163 164 packet[3] = byte((p.ScrambleControl&0x03)<<6) | byte(p.Continuity&0x0f) 165 166 start := 4 167 if p.AdaptationField != nil { 168 packet[3] |= flagAdaptationField 169 170 b, err := p.AdaptationField.marshal() 171 if err != nil { 172 return nil, err 173 } 174 175 n := copy(packet[start:], b) 176 start += n 177 } 178 179 if len(p.Payload) > 0 { 180 packet[3] |= flagPayload 181 182 n := copy(packet[start:], p.Payload) 183 start += n 184 185 if n < len(p.Payload) { 186 return nil, errors.Errorf("short packet: %d < %d", n, len(p.Payload)) 187 } 188 } 189 190 copy(packet[start:], fullPadding) 191 192 return packet, nil 193 }