Files
engine/publisher.go
2022-05-14 23:42:57 +08:00

148 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
}
}