mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-08 18:10:09 +08:00
148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
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 {
|
||
IIO
|
||
GetConfig() *config.Publish
|
||
receive(string, IPublisher, *config.Publish) error
|
||
GetIO() *IO[config.Publish, IPublisher]
|
||
getAudioTrack() common.AudioTrack
|
||
getVideoTrack() common.VideoTrack
|
||
}
|
||
|
||
type Publisher struct {
|
||
IO[config.Publish, IPublisher]
|
||
common.AudioTrack `json:"-"`
|
||
common.VideoTrack `json:"-"`
|
||
}
|
||
|
||
func (p *Publisher) Stop() {
|
||
p.IO.Stop()
|
||
p.Stream.Receive(ACTION_PUBLISHLOST)
|
||
}
|
||
func (p *Publisher) getAudioTrack() common.AudioTrack {
|
||
return p.AudioTrack
|
||
}
|
||
func (p *Publisher) getVideoTrack() common.VideoTrack {
|
||
return p.VideoTrack
|
||
}
|
||
func (p *Publisher) Equal(p2 IPublisher) bool {
|
||
return p.GetIO() == p2.GetIO()
|
||
}
|
||
func (p *Publisher) OnEvent(event any) {
|
||
switch v := event.(type) {
|
||
case IPublisher:
|
||
if p.Equal(v) { //第一任
|
||
p.AudioTrack = p.Stream.NewAudioTrack()
|
||
p.VideoTrack = p.Stream.NewVideoTrack()
|
||
} else { // 使用前任的track,因为订阅者都挂在前任的上面
|
||
p.AudioTrack = v.getAudioTrack()
|
||
p.VideoTrack = v.getVideoTrack()
|
||
}
|
||
default:
|
||
p.IO.OnEvent(event)
|
||
}
|
||
}
|
||
|
||
type IPuller interface {
|
||
IPublisher
|
||
Connect() error
|
||
Pull()
|
||
Reconnect() bool
|
||
init(streamPath string, url string, conf *config.Pull)
|
||
}
|
||
|
||
// 用于远程拉流的发布者
|
||
type Puller struct {
|
||
Client[config.Pull]
|
||
}
|
||
|
||
// 是否需要重连
|
||
func (pub *Puller) Reconnect() (ok bool) {
|
||
ok = pub.Config.RePull == -1 || pub.ReConnectCount <= pub.Config.RePull
|
||
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)
|
||
}
|
||
}
|
||
}
|