github.com/cnotch/ipchub@v1.1.0/av/format/mpegts/frame.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 "github.com/cnotch/ipchub/av/codec/aac" 11 "github.com/cnotch/ipchub/av/codec/h264" 12 ) 13 14 // the mpegts header specifed the video/audio pid. 15 const ( 16 tsVideoPid = 256 17 tsAudioPid = 257 18 ) 19 20 // the mpegts header specifed the stream id. 21 const ( 22 tsAudioAac = 0xc0 // ts aac stream id. 23 tsVideoAvc = 0xe0 // ts avc stream id. 24 ) 25 26 // Frame mpegts frame 27 type Frame struct { 28 Pid int 29 StreamID int 30 Dts int64 31 Pts int64 32 Header []byte // 1. AAC-ADTS Header; 2. aud nal [+sps nal+pps nal]+sample nal start code 33 Payload []byte // data without startcode 34 key bool 35 } 36 37 // IsVideo . 38 func (frame *Frame) IsVideo() bool { 39 return frame.Pid == tsVideoPid 40 } 41 42 // IsAudio . 43 func (frame *Frame) IsAudio() bool { 44 return frame.Pid == tsAudioPid 45 } 46 47 // IsKeyFrame 判断是否是 video key frame 48 func (frame *Frame) IsKeyFrame() bool { 49 return frame.key 50 } 51 52 func (frame *Frame) prepareAvcHeader(sps, pps []byte) { 53 // a ts sample is format as: 54 // 00 00 00 01 // header 55 // xxxxxxx // data bytes 56 // 00 00 01 // continue header 57 // xxxxxxx // data bytes. 58 // so, for each sample, we append header in aud_nal, then appends the bytes in sample. 59 // for type1/5/6, insert aud packet. 60 audNal := []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xf0} 61 62 // step 1: 63 // first, before each "real" sample, 64 // we add some packets according to the nal_unit_type, 65 // for example, when got nal_unit_type=5, insert SPS/PPS before sample. 66 67 // 5bits, 7.3.1 NAL unit syntax, 68 // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. 69 var nalUnitType uint8 70 nalUnitType = frame.Payload[0] 71 nalUnitType &= 0x1f 72 73 // 6: Supplemental enhancement information (SEI) sei_rbsp( ), page 61 74 // @see: ngx_rtmp_hls_append_aud 75 // @remark, when got type 9, we donot send aud_nal, but it will make ios unhappy, so we remove it. 76 if h264.NalSlice == nalUnitType || h264.NalIdrSlice == nalUnitType || h264.NalSei == nalUnitType { 77 frame.Header = append(frame.Header, audNal...) 78 } 79 80 // 5: Coded slice of an IDR picture. 81 // insert sps/pps before IDR or key frame is ok. 82 if h264.NalIdrSlice == nalUnitType { 83 // @see: ngx_rtmp_hls_append_sps_pps 84 if len(sps) > 0 { 85 // AnnexB prefix, for sps always 4 bytes header 86 frame.Header = append(frame.Header, audNal[:4]...) 87 // sps 88 frame.Header = append(frame.Header, sps...) 89 } 90 91 if len(pps) > 0 { 92 // AnnexB prefix, for pps always 4 bytes header 93 frame.Header = append(frame.Header, audNal[:4]...) 94 // pps 95 frame.Header = append(frame.Header, pps...) 96 } 97 } 98 99 // 7-9, ignore, @see: ngx_rtmp_hls_video 100 if nalUnitType >= h264.NalSps && nalUnitType <= h264.NalAud { 101 return 102 } 103 104 // step 2: 105 // output the "real" sample, in buf. 106 // when we output some special assist packets according to nal_unit_type 107 108 // sample start prefix, '00 00 00 01' or '00 00 01' 109 pAudnal := 0 + 1 110 endAudnal := pAudnal + 3 111 112 // first AnnexB prefix is long (4 bytes) 113 if 0 == len(frame.Header) { 114 pAudnal = 0 115 } 116 frame.Header = append(frame.Header, audNal[pAudnal:pAudnal+endAudnal-pAudnal]...) 117 118 return 119 } 120 121 func (frame *Frame) prepareAacHeader(sps *aac.RawSPS) { 122 adtsHeader := sps.ToAdtsHeader(len(frame.Payload)) 123 frame.Header = adtsHeader[:] 124 return 125 } 126 127 // FrameWriter 包装 WriteMpegtsFrame 方法的接口 128 type FrameWriter interface { 129 WriteMpegtsFrame(frame *Frame) error 130 }