mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-12-24 13:48:04 +08:00
216 lines
6.3 KiB
Go
216 lines
6.3 KiB
Go
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
|
|
}
|