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  }