github.com/cnotch/ipchub@v1.1.0/av/format/mpegts/writer.go (about) 1 // Copyright calabashdad. https://github.com/calabashdad/seal.git 2 // 3 // Copyright (c) 2019,CAOHONGJU All rights reserved. 4 // Use of this source code is governed by a MIT-style 5 // license that can be found in the LICENSE file. 6 7 package mpegts 8 9 import ( 10 "bytes" 11 "fmt" 12 "io" 13 "sync" 14 ) 15 16 // @see: ngx_rtmp_mpegts_header 17 var mpegtsHeader = []uint8{ 18 /* TS */ 19 0x47, 0x40, 0x00, 0x10, 0x00, 20 21 /* PSI */ 22 0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00, 23 24 /* PAT */ 25 0x00, 0x01, 0xf0, 0x01, 26 27 /* CRC */ 28 0x2e, 0x70, 0x19, 0x05, 29 30 /* stuffing 167 bytes */ 31 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 35 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 36 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 37 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 38 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 39 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 42 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 44 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 45 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 46 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 47 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 48 49 /* TS */ 50 0x47, 0x50, 0x01, 0x10, 0x00, 51 52 /* PSI */ 53 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00, 54 55 /* PMT */ 56 0xe1, 0x00, 57 0xf0, 0x00, 58 0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264, pid=0x100=256 */ 59 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac, pid=0x101=257 */ 60 61 /*0x03, 0xe1, 0x01, 0xf0, 0x00,*/ /* mp3 */ 62 /* CRC */ 63 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */ 64 /*0x4e, 0x59, 0x3d, 0x1e,*/ /* crc for mp3 */ 65 66 /* stuffing 157 bytes */ 67 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 68 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 69 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 70 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 71 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 72 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 73 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 74 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 75 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 76 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 77 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 78 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 79 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 80 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 81 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 82 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 83 } 84 85 // mpegts stuff using 0xff 86 var mpegtsStuff [188]uint8 87 88 var buffers = sync.Pool{ 89 New: func() interface{} { 90 return bytes.NewBuffer(make([]byte, 0, 1024*2)) 91 }, 92 } 93 94 func init() { 95 for i := 0; i < len(mpegtsStuff); i++ { 96 mpegtsStuff[i] = 0xff 97 } 98 } 99 100 // Writer flv Writer 101 type Writer struct { 102 w io.Writer 103 videoCC int 104 audioCC int 105 } 106 107 // NewWriter . 108 func NewWriter(w io.Writer) (*Writer, error) { 109 writer := &Writer{ 110 w: w, 111 } 112 113 if err := writer.writeMpegtsHeader(); err != nil { 114 return nil, err 115 } 116 117 return writer, nil 118 } 119 120 func (w *Writer) writeMpegtsHeader() error { 121 if _, err := w.w.Write(mpegtsHeader); err != nil { 122 return fmt.Errorf("write ts file header failed,resean=%v", err) 123 } 124 return nil 125 } 126 127 // WriteMpegtsFrame write mpegts frame 128 func (w *Writer) WriteMpegtsFrame(frame *Frame) (err error) { 129 if len(frame.Payload) <= 0 { 130 return 131 } 132 133 buf := buffers.Get().(*bytes.Buffer) 134 buf.Reset() 135 defer buffers.Put(buf) 136 137 buf.Write(frame.Header) 138 buf.Write(frame.Payload) 139 140 avdata := buf.Bytes() 141 142 last := len(avdata) 143 pos := 0 144 145 first := true 146 pkt := [188]byte{} 147 cc := &w.videoCC 148 if frame.Pid == tsAudioPid { 149 cc = &w.audioCC 150 } 151 152 for { 153 if pos >= last { 154 break 155 } 156 157 // position of pkt 158 p := 0 159 160 *cc++ 161 162 // sync_byte; //8bits 163 pkt[p] = 0x47 164 p++ 165 166 // pid; //13bits 167 pkt[p] = byte((frame.Pid >> 8) & 0x1f) 168 p++ 169 170 // payload_unit_start_indicator; //1bit 171 if first { 172 pkt[p-1] |= 0x40 173 } 174 175 pkt[p] = byte(frame.Pid) 176 p++ 177 178 // transport_scrambling_control; //2bits 179 // adaption_field_control; //2bits, 0x01: PayloadOnly 180 // continuity_counter; //4bits 181 pkt[p] = byte(0x10 | (*cc & 0x0f)) 182 p++ 183 184 if first { 185 first = false 186 if frame.key { 187 pkt[p-1] |= 0x20 // Both Adaption and Payload 188 189 pkt[p] = 7 //size 190 p++ 191 192 pkt[p] = 0x50 // random access + PCR 193 p++ 194 195 writePcr(&pkt, &p, frame.Dts) 196 } 197 198 // PES header 199 // packet_start_code_prefix; //24bits, '00 00 01' 200 pkt[p] = 0x00 201 p++ 202 pkt[p] = 0x00 203 p++ 204 pkt[p] = 0x01 205 p++ 206 207 //8bits 208 pkt[p] = byte(frame.StreamID) 209 p++ 210 211 // pts(33bits) need 5bytes. 212 var headerSize uint8 = 5 213 var flags uint8 = 0x80 // pts 214 215 // dts(33bits) need 5bytes also 216 if frame.Dts != frame.Pts { 217 headerSize += 5 218 flags |= 0x40 // dts 219 } 220 221 // 3bytes: flag fields from PES_packet_length to PES_header_data_length 222 pesSize := (last - pos) + int(headerSize) + 3 223 if pesSize > 0xffff { 224 // when actual packet length > 0xffff(65535), 225 // which exceed the max u_int16_t packet length, 226 // use 0 packet length, the next unit start indicates the end of packet. 227 pesSize = 0 228 } 229 230 // PES_packet_length; //16bits 231 pkt[p] = byte(pesSize >> 8) 232 p++ 233 pkt[p] = byte(pesSize) 234 p++ 235 236 // PES_scrambling_control; //2bits, '10' 237 // PES_priority; //1bit 238 // data_alignment_indicator; //1bit 239 // copyright; //1bit 240 // original_or_copy; //1bit 241 pkt[p] = 0x80 /* H222 */ 242 p++ 243 244 // PTS_DTS_flags; //2bits 245 // ESCR_flag; //1bit 246 // ES_rate_flag; //1bit 247 // DSM_trick_mode_flag; //1bit 248 // additional_copy_info_flag; //1bit 249 // PES_CRC_flag; //1bit 250 // PES_extension_flag; //1bit 251 pkt[p] = flags 252 p++ 253 254 // PES_header_data_length; //8bits 255 pkt[p] = headerSize 256 p++ 257 258 // pts; // 33bits 259 // p = write_pts(p, flags >> 6, frame->pts); 260 writePts(&pkt, &p, flags>>6, frame.Pts) 261 262 // dts; // 33bits 263 if frame.Dts != frame.Pts { 264 writePts(&pkt, &p, 1, frame.Dts) 265 } 266 } // end of first 267 268 bodySize := 188 - p 269 inSize := last - pos 270 271 if bodySize <= inSize { 272 copy(pkt[p:], avdata[pos:pos+bodySize]) 273 pos += bodySize 274 } else { 275 fillStuff(&pkt, &p, bodySize, inSize) 276 copy(pkt[p:], avdata[pos:pos+inSize]) 277 pos = last 278 } 279 280 // write ts packet 281 if _, err = w.w.Write(pkt[:]); err != nil { 282 return fmt.Errorf("write ts ts packet failed,resean=%v", err) 283 } 284 } 285 286 return 287 288 } 289 func writePcr(pkt *[188]byte, pos *int, pcr int64) { 290 291 v := pcr 292 293 pkt[*pos] = byte(v >> 25) 294 *pos++ 295 296 pkt[*pos] = byte(v >> 17) 297 *pos++ 298 299 pkt[*pos] = byte(v >> 9) 300 *pos++ 301 302 pkt[*pos] = byte(v >> 1) 303 *pos++ 304 305 pkt[*pos] = byte(v<<7 | 0x7e) 306 *pos++ 307 308 pkt[*pos] = 0 309 *pos++ 310 } 311 312 func writePts(pkt *[188]byte, pos *int, fb uint8, pts int64) { 313 val := 0 314 315 val = int(int(fb)<<4 | int(((pts>>30)&0x07)<<1) | 1) 316 317 pkt[*pos] = byte(val) 318 *pos++ 319 320 val = ((int(pts>>15) & 0x7fff) << 1) | 1 321 pkt[*pos] = byte(val >> 8) 322 *pos++ 323 pkt[*pos] = byte(val) 324 *pos++ 325 326 val = ((int(pts) & 0x7fff) << 1) | 1 327 pkt[*pos] = byte(val >> 8) 328 *pos++ 329 pkt[*pos] = byte(val) 330 *pos++ 331 332 } 333 334 func fillStuff(pkt *[188]byte, pos *int, bodySize int, inSize int) { 335 336 // insert the stuff bytes before PES body 337 stuffSize := bodySize - inSize 338 339 // adaption_field_control; //2bits 340 if v := pkt[3] & 0x20; v != 0 { 341 // has adaptation 342 // packet[4]: adaption_field_length 343 // packet[5]: adaption field data 344 // base: start of PES body 345 346 base := 5 + int(pkt[4]) 347 348 len := *pos - base 349 copy(pkt[base+stuffSize:], pkt[base:base+len]) 350 // increase the adaption field size. 351 pkt[4] += byte(stuffSize) 352 353 *pos = base + stuffSize + len 354 355 return 356 } 357 358 // create adaption field. 359 // adaption_field_control; //2bits 360 pkt[3] |= 0x20 361 // base: start of PES body 362 base := 4 363 len := *pos - base 364 copy(pkt[base+stuffSize:], pkt[base:base+len]) 365 *pos = base + stuffSize + len 366 367 // adaption_field_length; //8bits 368 pkt[4] = byte(stuffSize - 1) 369 if stuffSize >= 2 { 370 // adaption field flags. 371 pkt[5] = 0 372 373 // adaption data. 374 if stuffSize > 2 { 375 copy(pkt[6:6+stuffSize-2], mpegtsStuff[:]) 376 } 377 } 378 }