mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-07 01:22:51 +08:00
将ts解包置入引擎中
This commit is contained in:
@@ -62,6 +62,7 @@ const (
|
||||
// 0xFF Forbidden
|
||||
|
||||
STREAM_TYPE_H264 = 0x1B
|
||||
STREAM_TYPE_H265 = 0x24
|
||||
STREAM_TYPE_AAC = 0x0F
|
||||
|
||||
// 1110 xxxx
|
||||
@@ -80,23 +81,23 @@ const (
|
||||
//
|
||||
|
||||
type MpegTsStream struct {
|
||||
firstTsPkt *MpegTsPacket // 每一帧的第一个TS包
|
||||
patPkt *MpegTsPacket // 装载PAT的TS包
|
||||
pmtPkt *MpegTsPacket // 装载PMT的TS包
|
||||
pat *MpegTsPAT // PAT表信息
|
||||
pmt *MpegTsPMT // PMT表信息
|
||||
closed bool //是否已经关闭
|
||||
TsPesPktChan chan *MpegTsPesStream // TS + PES Packet Channel,将封装的每一帧ES数据,通过channel来传输
|
||||
firstTsPkt *MpegTsPacket // 每一帧的第一个TS包
|
||||
patPkt *MpegTsPacket // 装载PAT的TS包
|
||||
pmtPkt *MpegTsPacket // 装载PMT的TS包
|
||||
pat *MpegTsPAT // PAT表信息
|
||||
pmt *MpegTsPMT // PMT表信息
|
||||
closed bool //是否已经关闭
|
||||
// TsPesPktChan chan *MpegTsPesStream // TS + PES Packet Channel,将封装的每一帧ES数据,通过channel来传输
|
||||
}
|
||||
|
||||
func NewMpegTsStream(bufferLength int) (ts *MpegTsStream) {
|
||||
func NewMpegTsStream() (ts *MpegTsStream) {
|
||||
ts = new(MpegTsStream)
|
||||
ts.firstTsPkt = new(MpegTsPacket)
|
||||
ts.patPkt = new(MpegTsPacket)
|
||||
ts.pmtPkt = new(MpegTsPacket)
|
||||
ts.pat = new(MpegTsPAT)
|
||||
ts.pmt = new(MpegTsPMT)
|
||||
ts.TsPesPktChan = make(chan *MpegTsPesStream, bufferLength)
|
||||
// ts.TsPesPktChan = make(chan *MpegTsPesStream, bufferLength)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -485,7 +486,7 @@ func WriteTsHeader(w io.Writer, header MpegTsHeader) (written int, err error) {
|
||||
// return nil
|
||||
//}
|
||||
|
||||
func (s *MpegTsStream) readPAT(packet *MpegTsPacket, pr io.Reader) (err error) {
|
||||
func (s *MpegTsStream) ReadPAT(packet *MpegTsPacket, pr io.Reader) (err error) {
|
||||
// 首先找到PID==0x00的TS包(PAT)
|
||||
if PID_PAT == packet.Header.Pid {
|
||||
if len(packet.Payload) == 188 {
|
||||
@@ -501,7 +502,7 @@ func (s *MpegTsStream) readPAT(packet *MpegTsPacket, pr io.Reader) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MpegTsStream) readPMT(packet *MpegTsPacket, pr io.Reader) (err error) {
|
||||
func (s *MpegTsStream) ReadPMT(packet *MpegTsPacket, pr io.Reader) (err error) {
|
||||
// 在读取PAT中已经将所有频道节目信息(PMT_PID)保存了起来
|
||||
// 接着读取所有TS包里面的PID,找出PID==PMT_PID的TS包,就是PMT表
|
||||
for _, v := range s.pat.Program {
|
||||
@@ -521,7 +522,7 @@ func (s *MpegTsStream) readPMT(packet *MpegTsPacket, pr io.Reader) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MpegTsStream) Feed(ts io.Reader) error {
|
||||
func (s *MpegTsStream) Feed(ts io.Reader, onStream func(MpegTsPmtStream), onPES func(MpegTsPESPacket)) error {
|
||||
var frame int64
|
||||
var tsPktArr []MpegTsPacket
|
||||
for {
|
||||
@@ -532,21 +533,18 @@ func (s *MpegTsStream) Feed(ts io.Reader) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.TsPesPktChan <- &MpegTsPesStream{
|
||||
TsPkt: *s.firstTsPkt,
|
||||
PesPkt: pesPkt,
|
||||
}
|
||||
onPES(pesPkt)
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pr := bytes.NewReader(packet.Payload)
|
||||
err = s.readPAT(&packet, pr)
|
||||
err = s.ReadPAT(&packet, pr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.readPMT(&packet, pr)
|
||||
err = s.ReadPMT(&packet, pr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -560,14 +558,11 @@ func (s *MpegTsStream) Feed(ts io.Reader) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.TsPesPktChan <- &MpegTsPesStream{
|
||||
TsPkt: *s.firstTsPkt,
|
||||
PesPkt: pesPkt,
|
||||
}
|
||||
|
||||
onPES(pesPkt)
|
||||
tsPktArr = nil
|
||||
}
|
||||
s.firstTsPkt = &packet
|
||||
onStream(v)
|
||||
frame++
|
||||
}
|
||||
tsPktArr = append(tsPktArr, packet)
|
||||
|
81
publisher.go
81
publisher.go
@@ -1,8 +1,13 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"m7s.live/engine/v4/codec/mpegts"
|
||||
"m7s.live/engine/v4/common"
|
||||
"m7s.live/engine/v4/config"
|
||||
"m7s.live/engine/v4/track"
|
||||
)
|
||||
|
||||
type IPublisher interface {
|
||||
@@ -43,8 +48,9 @@ func (p *Publisher) OnEvent(event any) {
|
||||
p.AudioTrack = v.getAudioTrack()
|
||||
p.VideoTrack = v.getVideoTrack()
|
||||
}
|
||||
default:
|
||||
p.IO.OnEvent(event)
|
||||
}
|
||||
p.IO.OnEvent(event)
|
||||
}
|
||||
|
||||
type IPuller interface {
|
||||
@@ -66,3 +72,76 @@ func (pub *Puller) Reconnect() (ok bool) {
|
||||
pub.ReConnectCount++
|
||||
return
|
||||
}
|
||||
|
||||
type TSPublisher struct {
|
||||
Publisher
|
||||
*mpegts.MpegTsStream
|
||||
adts []byte
|
||||
}
|
||||
|
||||
func (t *TSPublisher) OnEvent(event any) {
|
||||
switch v := event.(type) {
|
||||
case IPublisher:
|
||||
t.MpegTsStream = mpegts.NewMpegTsStream()
|
||||
if !t.Equal(v) {
|
||||
t.AudioTrack = v.getAudioTrack()
|
||||
t.VideoTrack = v.getVideoTrack()
|
||||
}
|
||||
case io.Reader:
|
||||
t.Feed(v, t.OnPmtStream, t.OnPES)
|
||||
default:
|
||||
t.Publisher.OnEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TSPublisher) OnPmtStream(s mpegts.MpegTsPmtStream) {
|
||||
switch s.StreamType {
|
||||
case mpegts.STREAM_TYPE_H264:
|
||||
if t.VideoTrack == nil {
|
||||
t.VideoTrack = track.NewH264(t.Stream)
|
||||
}
|
||||
case mpegts.STREAM_TYPE_H265:
|
||||
if t.VideoTrack == nil {
|
||||
t.VideoTrack = track.NewH265(t.Stream)
|
||||
}
|
||||
case mpegts.STREAM_TYPE_AAC:
|
||||
if t.AudioTrack == nil {
|
||||
t.AudioTrack = track.NewAAC(t.Stream)
|
||||
}
|
||||
default:
|
||||
t.Warn("unsupport stream type:", zap.Uint8("type", s.StreamType))
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TSPublisher) OnPES(pes mpegts.MpegTsPESPacket) {
|
||||
if pes.Header.Dts == 0 {
|
||||
pes.Header.Dts = pes.Header.Pts
|
||||
}
|
||||
switch pes.Header.StreamID & 0xF0 {
|
||||
case mpegts.STREAM_ID_AUDIO:
|
||||
if t.AudioTrack != nil {
|
||||
if t.adts == nil {
|
||||
t.adts = append(t.adts, pes.Payload[:7]...)
|
||||
t.AudioTrack.WriteADTS(t.adts)
|
||||
}
|
||||
t.AudioTrack.CurrentFrame().PTS = uint32(pes.Header.Pts)
|
||||
t.AudioTrack.CurrentFrame().DTS = uint32(pes.Header.Dts)
|
||||
for remainLen := len(pes.Payload); remainLen > 0; {
|
||||
// AACFrameLength(13)
|
||||
// xx xxxxxxxx xxx
|
||||
frameLen := (int(pes.Payload[3]&3) << 11) | (int(pes.Payload[4]) << 3) | (int(pes.Payload[5]) >> 5)
|
||||
if frameLen > remainLen {
|
||||
break
|
||||
}
|
||||
t.AudioTrack.WriteSlice(pes.Payload[7:frameLen])
|
||||
pes.Payload = pes.Payload[frameLen:remainLen]
|
||||
remainLen -= frameLen
|
||||
t.AudioTrack.Flush()
|
||||
}
|
||||
}
|
||||
case mpegts.STREAM_ID_VIDEO:
|
||||
if t.VideoTrack != nil {
|
||||
t.VideoTrack.WriteAnnexB(uint32(pes.Header.Pts), uint32(pes.Header.Dts), pes.Payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -60,10 +60,11 @@ func (a *Audio) WriteADTS(adts []byte) {
|
||||
a.DecoderConfiguration = DecoderConfiguration[AudioSlice]{
|
||||
97,
|
||||
net.Buffers{avcc},
|
||||
avcc[:2],
|
||||
avcc[2:],
|
||||
net.Buffers{adcflv1, avcc, adcflv2},
|
||||
0,
|
||||
}
|
||||
a.Attach()
|
||||
}
|
||||
|
||||
func (a *Audio) Flush() {
|
||||
|
@@ -46,7 +46,7 @@ func (p *流速控制) 控制流速(绝对时间戳 uint32) {
|
||||
// }
|
||||
// 如果收到的帧的时间戳超过实际消耗的时间100ms就休息一下,100ms作为一个弹性区间防止频繁调用sleep
|
||||
if 过快毫秒 := 数据时间差 - 实际时间差; 过快毫秒 > time.Millisecond*100 {
|
||||
println("休息", 过快毫秒/time.Millisecond, 绝对时间戳, p.起始时间戳)
|
||||
// println("休息", 过快毫秒/time.Millisecond, 绝对时间戳, p.起始时间戳)
|
||||
time.Sleep(过快毫秒)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user