package srt import ( "errors" "fmt" "io" "net" srt "github.com/datarhei/gosrt" "m7s.live/v5" "m7s.live/v5/pkg" "m7s.live/v5/pkg/codec" "m7s.live/v5/pkg/task" "m7s.live/v5/pkg/util" mpegts "m7s.live/v5/plugin/hls/pkg/ts" ) type Sender struct { task.Task Subscriber *m7s.Subscriber pesAudio, pesVideo *mpegts.MpegtsPESFrame PMT util.Buffer srt.Conn allocator *util.ScalableMemoryAllocator } func (s *Sender) Start() error { s.pesAudio = &mpegts.MpegtsPESFrame{ Pid: mpegts.STREAM_ID_AUDIO, } s.pesVideo = &mpegts.MpegtsPESFrame{ Pid: mpegts.STREAM_ID_VIDEO, } s.allocator = util.NewScalableMemoryAllocator(1 << util.MinPowerOf2) var audioCodec, videoCodec codec.FourCC if s.Subscriber.Publisher.HasAudioTrack() { audioCodec = s.Subscriber.Publisher.AudioTrack.FourCC() } if s.Subscriber.Publisher.HasVideoTrack() { videoCodec = s.Subscriber.Publisher.VideoTrack.FourCC() } mpegts.WritePMTPacket(&s.PMT, videoCodec, audioCodec) s.Write(mpegts.DefaultPATPacket) s.Write(s.PMT) return nil } func (s *Sender) sendAudio(packet mpegts.MpegTsPESPacket) (err error) { packet.Header.PacketStartCodePrefix = 0x000001 packet.Header.ConstTen = 0x80 packet.Header.StreamID = mpegts.STREAM_ID_AUDIO s.pesAudio.ProgramClockReferenceBase = packet.Header.Pts packet.Header.PtsDtsFlags = 0x80 packet.Header.PesHeaderDataLength = 5 return s.WritePESPacket(s.pesAudio, packet) } func (s *Sender) sendADTS(audio *pkg.ADTS) (err error) { var packet mpegts.MpegTsPESPacket packet.Header.PesPacketLength = uint16(audio.Size + 8) packet.Buffers = audio.Buffers packet.Header.Pts = uint64(audio.DTS) return s.sendAudio(packet) } func (s *Sender) sendVideo(video *pkg.AnnexB) (err error) { var buffer net.Buffers //需要对原始数据(ES),进行一些预处理,视频需要分割nalu(H264编码),并且打上sps,pps,nalu_aud信息. if video.Hevc { buffer = append(buffer, codec.AudNalu) } else { buffer = append(buffer, codec.NALU_AUD_BYTE) } buffer = append(buffer, video.Buffers...) pktLength := util.SizeOfBuffers(buffer) + 10 + 3 if pktLength > 0xffff { pktLength = 0 } var packet mpegts.MpegTsPESPacket packet.Header.PacketStartCodePrefix = 0x000001 packet.Header.ConstTen = 0x80 packet.Header.StreamID = mpegts.STREAM_ID_VIDEO packet.Header.PesPacketLength = uint16(pktLength) packet.Header.Pts = uint64(video.PTS) s.pesVideo.ProgramClockReferenceBase = packet.Header.Pts packet.Header.Dts = uint64(video.DTS) packet.Header.PtsDtsFlags = 0xC0 packet.Header.PesHeaderDataLength = 10 packet.Buffers = buffer return s.WritePESPacket(s.pesVideo, packet) } func (s *Sender) Go() error { return m7s.PlayBlock(s.Subscriber, s.sendADTS, s.sendVideo) } func (s *Sender) WritePESPacket(frame *mpegts.MpegtsPESFrame, pesPacket mpegts.MpegTsPESPacket) (err error) { if pesPacket.Header.PacketStartCodePrefix != 0x000001 { err = errors.New("packetStartCodePrefix != 0x000001") return } var pesHeadItem util.Buffer = s.allocator.Malloc(32) _, err = mpegts.WritePESHeader(&pesHeadItem, pesPacket.Header) if err != nil { return } pesBuffers := append(net.Buffers{pesHeadItem}, pesPacket.Buffers...) defer s.allocator.Free(pesHeadItem) pesPktLength := util.SizeOfBuffers(pesBuffers) var buffer util.Buffer = s.allocator.Malloc((pesPktLength/mpegts.TS_PACKET_SIZE+1)*6 + pesPktLength) bwTsHeader := &buffer bigLen := bwTsHeader.Len() bwTsHeader.Reset() defer s.allocator.Free(buffer) var tsHeaderLength int for i := 0; len(pesBuffers) > 0; i++ { if bigLen < mpegts.TS_PACKET_SIZE { // if i == 0 { // ts.Recycle() // } var headerItem util.Buffer = s.allocator.Malloc(mpegts.TS_PACKET_SIZE) defer s.allocator.Free(headerItem) bwTsHeader = &headerItem bwTsHeader.Reset() } bigLen -= mpegts.TS_PACKET_SIZE pesPktLength = util.SizeOfBuffers(pesBuffers) tsHeader := mpegts.MpegTsHeader{ SyncByte: 0x47, TransportErrorIndicator: 0, PayloadUnitStartIndicator: 0, TransportPriority: 0, Pid: frame.Pid, TransportScramblingControl: 0, AdaptionFieldControl: 1, ContinuityCounter: frame.ContinuityCounter, } frame.ContinuityCounter++ frame.ContinuityCounter = frame.ContinuityCounter % 16 // 每一帧的开头,当含有pcr的时候,包含调整字段 if i == 0 { tsHeader.PayloadUnitStartIndicator = 1 // 当PCRFlag为1的时候,包含调整字段 if frame.IsKeyFrame { tsHeader.AdaptionFieldControl = 0x03 tsHeader.AdaptationFieldLength = 7 tsHeader.PCRFlag = 1 tsHeader.RandomAccessIndicator = 1 tsHeader.ProgramClockReferenceBase = frame.ProgramClockReferenceBase } } // 每一帧的结尾,当不满足188个字节的时候,包含调整字段 if pesPktLength < mpegts.TS_PACKET_SIZE-4 { var tsStuffingLength uint8 tsHeader.AdaptionFieldControl = 0x03 tsHeader.AdaptationFieldLength = uint8(mpegts.TS_PACKET_SIZE - 4 - 1 - pesPktLength) // TODO:如果第一个TS包也是最后一个TS包,是不是需要考虑这个情况? // MpegTsHeader最少占6个字节.(前4个走字节 + AdaptationFieldLength(1 byte) + 3个指示符5个标志位(1 byte)) if tsHeader.AdaptationFieldLength >= 1 { tsStuffingLength = tsHeader.AdaptationFieldLength - 1 } else { tsStuffingLength = 0 } // error tsHeaderLength, err = mpegts.WriteTsHeader(bwTsHeader, tsHeader) if err != nil { return } if tsStuffingLength > 0 { if _, err = bwTsHeader.Write(mpegts.Stuffing[:tsStuffingLength]); err != nil { return } } tsHeaderLength += int(tsStuffingLength) } else { tsHeaderLength, err = mpegts.WriteTsHeader(bwTsHeader, tsHeader) if err != nil { return } } tsPayloadLength := mpegts.TS_PACKET_SIZE - tsHeaderLength //fmt.Println("tsPayloadLength :", tsPayloadLength) // 这里不断的减少PES包 io.CopyN(bwTsHeader, &pesBuffers, int64(tsPayloadLength)) // tmp := tsHeaderByte[3] << 2 // tmp = tmp >> 6 // if tmp == 2 { // fmt.Println("fuck you mother.") // } tsPktByteLen := bwTsHeader.Len() _, err = s.Write(*bwTsHeader) if err != nil { return } if tsPktByteLen != (i+1)*mpegts.TS_PACKET_SIZE && tsPktByteLen != mpegts.TS_PACKET_SIZE { err = errors.New(fmt.Sprintf("%s, packet size=%d", "TS_PACKET_SIZE != 188,", tsPktByteLen)) return } } return nil }