mirror of
https://github.com/lkmio/lkm.git
synced 2025-10-03 14:26:27 +08:00
支持GB28181三种推流
This commit is contained in:
240
stream/source.go
240
stream/source.go
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/yangjiechina/live-server/log"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/yangjiechina/avformat/stream"
|
||||
@@ -36,17 +35,11 @@ const (
|
||||
ProtocolHls = Protocol(4)
|
||||
ProtocolRtc = Protocol(5)
|
||||
|
||||
ProtocolRtmpStr = "rtmp"
|
||||
|
||||
SourceEventPlay = SourceEvent(1)
|
||||
SourceEventPlayDone = SourceEvent(2)
|
||||
SourceEventInput = SourceEvent(3)
|
||||
SourceEventClose = SourceEvent(4)
|
||||
|
||||
// TransMuxerHeaderMaxSize 传输流协议头的最大长度
|
||||
// 在解析流分配AVPacket的Data时, 如果没有开启合并写, 提前预留指定长度的字节数量.
|
||||
// 在封装传输流时, 直接在预留头中添加对应传输流的协议头,减少或免内存拷贝. 在传输flv以及转换AVCC和AnnexB格式时有显著提升.
|
||||
TransMuxerHeaderMaxSize = 30
|
||||
SourceEventPlay = SourceEvent(1)
|
||||
SourceEventPlayDone = SourceEvent(2)
|
||||
SourceEventInput = SourceEvent(3)
|
||||
SourceEventClose = SourceEvent(4)
|
||||
SourceEventProbeTimeout = SourceEvent(5)
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -59,40 +52,42 @@ const (
|
||||
SessionStateClose = SessionState(7) //关闭状态
|
||||
)
|
||||
|
||||
func sourceTypeToStr(sourceType SourceType) string {
|
||||
if SourceTypeRtmp == sourceType {
|
||||
func (s SourceType) ToString() string {
|
||||
if SourceTypeRtmp == s {
|
||||
return "rtmp"
|
||||
} else if SourceType28181 == sourceType {
|
||||
} else if SourceType28181 == s {
|
||||
return "28181"
|
||||
} else if SourceType1078 == sourceType {
|
||||
return "1078"
|
||||
} else if SourceType1078 == s {
|
||||
return "jt1078"
|
||||
}
|
||||
|
||||
return ""
|
||||
panic(fmt.Sprintf("unknown source type %d", s))
|
||||
}
|
||||
|
||||
func streamTypeToStr(protocol Protocol) string {
|
||||
if ProtocolRtmp == protocol {
|
||||
func (p Protocol) ToString() string {
|
||||
if ProtocolRtmp == p {
|
||||
return "rtmp"
|
||||
} else if ProtocolFlv == protocol {
|
||||
} else if ProtocolFlv == p {
|
||||
return "flv"
|
||||
} else if ProtocolRtsp == protocol {
|
||||
} else if ProtocolRtsp == p {
|
||||
return "rtsp"
|
||||
} else if ProtocolHls == protocol {
|
||||
} else if ProtocolHls == p {
|
||||
return "hls"
|
||||
} else if ProtocolRtc == protocol {
|
||||
} else if ProtocolRtc == p {
|
||||
return "rtc"
|
||||
}
|
||||
|
||||
return ""
|
||||
panic(fmt.Sprintf("unknown stream protocol %d", p))
|
||||
}
|
||||
|
||||
// ISource 父类Source负责, 除解析流以外的所有事情
|
||||
type ISource interface {
|
||||
// Id Source的唯一ID/**
|
||||
Id() string
|
||||
|
||||
// Input 输入推流数据
|
||||
Input(data []byte)
|
||||
//@Return bool fatal error.释放Source
|
||||
Input(data []byte) error
|
||||
|
||||
// OriginStreams 返回推流的原始Streams
|
||||
OriginStreams() []utils.AVStream
|
||||
@@ -100,8 +95,8 @@ type ISource interface {
|
||||
// TranscodeStreams 返回转码的Streams
|
||||
TranscodeStreams() []utils.AVStream
|
||||
|
||||
// AddSink 添加Sink, 在此之前请确保Sink已经握手、授权通过. 如果Source还未WriteHeader,将Sink添加到等待队列.
|
||||
// 匹配拉流的编码器, 创建TransMuxer或向存在TransMuxer添加Sink
|
||||
// AddSink 添加Sink, 在此之前请确保Sink已经握手、授权通过. 如果Source还未WriteHeader,先将Sink添加到等待队列.
|
||||
// 匹配拉流的编码器, 创建TransStream或向存在TransStream添加Sink
|
||||
AddSink(sink ISink) bool
|
||||
|
||||
// RemoveSink 删除Sink/**
|
||||
@@ -116,10 +111,34 @@ type ISource interface {
|
||||
// 将Sink添加到等待队列
|
||||
Close()
|
||||
|
||||
// Type 推流类型
|
||||
Type() SourceType
|
||||
}
|
||||
|
||||
type CreateSource func(id string, type_ SourceType, handler stream.OnDeMuxerHandler)
|
||||
// FindOrCreatePacketBuffer 查找或者创建AVPacket的内存池
|
||||
FindOrCreatePacketBuffer(index int, mediaType utils.AVMediaType) MemoryPool
|
||||
|
||||
// OnDiscardPacket GOP缓存溢出回调, 释放AVPacket
|
||||
OnDiscardPacket(pkt interface{})
|
||||
|
||||
// OnDeMuxStream 解析出AVStream回调
|
||||
OnDeMuxStream(stream utils.AVStream)
|
||||
|
||||
// IsCompleted 是否已经WireHeader
|
||||
IsCompleted() bool
|
||||
|
||||
// OnDeMuxStreamDone 所有track解析完毕, 后续的OnDeMuxStream回调不再处理
|
||||
OnDeMuxStreamDone()
|
||||
|
||||
// OnDeMuxPacket 解析出AvPacket回调
|
||||
OnDeMuxPacket(packet utils.AVPacket)
|
||||
|
||||
// OnDeMuxDone 所有流解析完毕回调
|
||||
OnDeMuxDone()
|
||||
|
||||
LoopEvent()
|
||||
|
||||
Init(input func(data []byte) error)
|
||||
}
|
||||
|
||||
var TranscoderFactory func(src utils.AVStream, dst utils.AVStream) transcode.ITranscoder
|
||||
|
||||
@@ -132,18 +151,18 @@ type SourceImpl struct {
|
||||
Conn net.Conn
|
||||
|
||||
TransDeMuxer stream.DeMuxer //负责从推流协议中解析出AVStream和AVPacket
|
||||
recordSink ISink //每个Source唯一的一个录制流
|
||||
hlsStream ITransStream //hls不等拉流,创建时直接生成
|
||||
recordSink ISink //每个Source的录制流
|
||||
hlsStream ITransStream //如果开开启HLS传输流, 不等拉流时, 创建直接生成
|
||||
audioTranscoders []transcode.ITranscoder //音频解码器
|
||||
videoTranscoders []transcode.ITranscoder //视频解码器
|
||||
originStreams StreamManager //推流的音视频Streams
|
||||
allStreams StreamManager //推流Streams+转码器获得的Streams
|
||||
buffers []StreamBuffer
|
||||
allStreams StreamManager //推流Streams+转码器获得的Stream
|
||||
gopBuffers []StreamBuffer //推流每路的GOP缓存
|
||||
pktBuffers [8]MemoryPool //推流每路的AVPacket缓存, AVPacket的data从该内存池中分配. 在GOP缓存溢出时,释放池中内存.
|
||||
|
||||
Input_ func(data []byte) //解决多态无法传递给子类的问题
|
||||
Input_ func(data []byte) error //解决多态无法传递给子类的问题
|
||||
|
||||
completed bool
|
||||
mutex sync.Mutex //只用作AddStream期间
|
||||
probeTimer *time.Timer
|
||||
|
||||
//所有的输出协议, 持有Sink
|
||||
@@ -156,21 +175,26 @@ type SourceImpl struct {
|
||||
closeEvent chan byte
|
||||
playingEventQueue chan ISink
|
||||
playingDoneEventQueue chan ISink
|
||||
probeTimoutEvent chan bool
|
||||
}
|
||||
|
||||
func (s *SourceImpl) Id() string {
|
||||
return s.Id_
|
||||
}
|
||||
|
||||
func (s *SourceImpl) Init() {
|
||||
func (s *SourceImpl) Init(input func(data []byte) error) {
|
||||
s.Input_ = input
|
||||
|
||||
//初始化事件接收缓冲区
|
||||
s.SetState(SessionStateTransferring)
|
||||
|
||||
//收流和网络断开的chan都阻塞执行
|
||||
s.inputEvent = make(chan []byte)
|
||||
s.responseEvent = make(chan byte)
|
||||
s.closeEvent = make(chan byte)
|
||||
s.playingEventQueue = make(chan ISink, 128)
|
||||
s.playingDoneEventQueue = make(chan ISink, 128)
|
||||
s.probeTimoutEvent = make(chan bool)
|
||||
|
||||
if s.transStreams == nil {
|
||||
s.transStreams = make(map[TransStreamId]ITransStream, 10)
|
||||
@@ -183,20 +207,58 @@ func (s *SourceImpl) Init() {
|
||||
|
||||
//创建HLS输出流
|
||||
if AppConfig.Hls.Enable {
|
||||
s.hlsStream = TransStreamFactory(s, ProtocolHls, nil)
|
||||
hlsStream, err := CreateTransStream(s, ProtocolHls, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s.hlsStream = hlsStream
|
||||
s.transStreams[0x100] = s.hlsStream
|
||||
}
|
||||
}
|
||||
|
||||
// FindOrCreatePacketBuffer 查找或者创建AVPacket的内存池
|
||||
func (s *SourceImpl) FindOrCreatePacketBuffer(index int, mediaType utils.AVMediaType) MemoryPool {
|
||||
if index >= cap(s.pktBuffers) {
|
||||
panic("流路数过多...")
|
||||
}
|
||||
|
||||
if s.pktBuffers[index] == nil {
|
||||
if utils.AVMediaTypeAudio == mediaType {
|
||||
s.pktBuffers[index] = NewMemoryPool(48000 * 64)
|
||||
} else if AppConfig.GOPCache {
|
||||
//开启GOP缓存
|
||||
//以每秒钟4M码率大小创建视频内存池
|
||||
s.pktBuffers[index] = NewMemoryPool(4096 * 1024)
|
||||
} else {
|
||||
//未开启GOP缓存
|
||||
//以每秒钟4M的1/8码率大小创建视频内存池
|
||||
s.pktBuffers[index] = NewMemoryPool(4096 * 1024 / 8)
|
||||
}
|
||||
}
|
||||
|
||||
return s.pktBuffers[index]
|
||||
}
|
||||
|
||||
func (s *SourceImpl) LoopEvent() {
|
||||
for {
|
||||
select {
|
||||
case data := <-s.inputEvent:
|
||||
s.Input_(data)
|
||||
if err := s.Input_(data); err != nil {
|
||||
log.Sugar.Errorf("处理输入流失败 释放source:%s err:%s", s.Id_, err.Error())
|
||||
s.Close()
|
||||
}
|
||||
|
||||
s.responseEvent <- 0
|
||||
break
|
||||
case sink := <-s.playingEventQueue:
|
||||
s.AddSink(sink)
|
||||
if !s.completed {
|
||||
AddSinkToWaitingQueue(sink.SourceId(), sink)
|
||||
} else {
|
||||
if !s.AddSink(sink) {
|
||||
sink.Close()
|
||||
}
|
||||
}
|
||||
break
|
||||
case sink := <-s.playingDoneEventQueue:
|
||||
s.RemoveSink(sink)
|
||||
@@ -204,12 +266,15 @@ func (s *SourceImpl) LoopEvent() {
|
||||
case _ = <-s.closeEvent:
|
||||
s.Close()
|
||||
return
|
||||
case _ = <-s.probeTimoutEvent:
|
||||
s.writeHeader()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SourceImpl) Input(data []byte) {
|
||||
|
||||
func (s *SourceImpl) Input(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SourceImpl) OriginStreams() []utils.AVStream {
|
||||
@@ -228,7 +293,7 @@ func IsSupportMux(protocol Protocol, audioCodecId, videoCodecId utils.AVCodecID)
|
||||
return true
|
||||
}
|
||||
|
||||
// 分发每路StreamBuffer给传输流
|
||||
// 将GOP缓存发送给TransStream
|
||||
// 按照时间戳升序发送
|
||||
func (s *SourceImpl) dispatchStreamBuffer(transStream ITransStream, streams []utils.AVStream) {
|
||||
size := len(streams)
|
||||
@@ -238,12 +303,12 @@ func (s *SourceImpl) dispatchStreamBuffer(transStream ITransStream, streams []ut
|
||||
min := int64(0xFFFFFFFF)
|
||||
|
||||
//找出最小的时间戳
|
||||
for index, stream := range streams[:size] {
|
||||
if s.buffers[stream.Index()].Size() == indexs[index] {
|
||||
for index, stream_ := range streams[:size] {
|
||||
if s.gopBuffers[stream_.Index()].Size() == indexs[index] {
|
||||
continue
|
||||
}
|
||||
|
||||
pkt := s.buffers[stream.Index()].Peek(indexs[index]).(utils.AVPacket)
|
||||
pkt := s.gopBuffers[stream_.Index()].Peek(indexs[index]).(utils.AVPacket)
|
||||
v := pkt.Dts()
|
||||
if min == 0xFFFFFFFF {
|
||||
min = v
|
||||
@@ -256,8 +321,8 @@ func (s *SourceImpl) dispatchStreamBuffer(transStream ITransStream, streams []ut
|
||||
break
|
||||
}
|
||||
|
||||
for index, stream := range streams[:size] {
|
||||
buffer := s.buffers[stream.Index()]
|
||||
for index, stream_ := range streams[:size] {
|
||||
buffer := s.gopBuffers[stream_.Index()]
|
||||
if buffer.Size() == indexs[index] {
|
||||
continue
|
||||
}
|
||||
@@ -313,12 +378,12 @@ func (s *SourceImpl) AddSink(sink ISink) bool {
|
||||
var streams [5]utils.AVStream
|
||||
var size int
|
||||
|
||||
for _, stream := range s.originStreams.All() {
|
||||
if disableVideo && stream.Type() == utils.AVMediaTypeVideo {
|
||||
for _, stream_ := range s.originStreams.All() {
|
||||
if disableVideo && stream_.Type() == utils.AVMediaTypeVideo {
|
||||
continue
|
||||
}
|
||||
|
||||
streams[size] = stream
|
||||
streams[size] = stream_
|
||||
size++
|
||||
}
|
||||
|
||||
@@ -329,9 +394,15 @@ func (s *SourceImpl) AddSink(sink ISink) bool {
|
||||
s.transStreams = make(map[TransStreamId]ITransStream, 10)
|
||||
}
|
||||
//创建一个新的传输流
|
||||
log.Sugar.Debugf("创建%s-stream", sink.ProtocolStr())
|
||||
log.Sugar.Debugf("创建%s-stream", sink.Protocol().ToString())
|
||||
|
||||
var err error
|
||||
transStream, err = CreateTransStream(s, sink.Protocol(), streams[:size])
|
||||
if err != nil {
|
||||
log.Sugar.Errorf("创建传输流失败 err:%s source:%s", err.Error(), s.Id_)
|
||||
return false
|
||||
}
|
||||
|
||||
transStream = TransStreamFactory(s, sink.Protocol(), streams[:size])
|
||||
s.transStreams[transStreamId] = transStream
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
@@ -420,53 +491,59 @@ func (s *SourceImpl) Close() {
|
||||
s.transStreams = nil
|
||||
}
|
||||
|
||||
func (s *SourceImpl) OnDeMuxStream(stream utils.AVStream) (bool, StreamBuffer) {
|
||||
//整块都受保护 确保Add的Stream 都能WriteHeader
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
func (s *SourceImpl) OnDiscardPacket(pkt interface{}) {
|
||||
packet := pkt.(utils.AVPacket)
|
||||
s.FindOrCreatePacketBuffer(packet.Index(), packet.MediaType()).FreeHead()
|
||||
}
|
||||
|
||||
func (s *SourceImpl) OnDeMuxStream(stream utils.AVStream) {
|
||||
if s.completed {
|
||||
fmt.Printf("添加Stream失败 Source: %s已经WriteHeader", s.Id_)
|
||||
return false, nil
|
||||
log.Sugar.Warnf("添加Stream失败 Source: %s已经WriteHeader", s.Id_)
|
||||
return
|
||||
}
|
||||
|
||||
s.originStreams.Add(stream)
|
||||
s.allStreams.Add(stream)
|
||||
|
||||
//启动探测超时计时器
|
||||
if len(s.originStreams.All()) == 1 && AppConfig.ProbeTimeout > 100 {
|
||||
s.probeTimer = time.AfterFunc(time.Duration(AppConfig.ProbeTimeout)*time.Millisecond, s.writeHeader)
|
||||
if len(s.originStreams.All()) == 1 {
|
||||
if AppConfig.ProbeTimeout == 0 {
|
||||
AppConfig.ProbeTimeout = 2000
|
||||
}
|
||||
|
||||
s.probeTimer = time.AfterFunc(time.Duration(AppConfig.ProbeTimeout)*time.Millisecond, func() {
|
||||
s.probeTimoutEvent <- true
|
||||
})
|
||||
}
|
||||
|
||||
//为每个Stream创建对应的Buffer
|
||||
if AppConfig.GOPCache {
|
||||
buffer := NewStreamBuffer(200)
|
||||
//OnDeMuxStream的调用顺序,就是AVStream和AVPacket的Index的递增顺序
|
||||
s.buffers = append(s.buffers, buffer)
|
||||
return true, buffer
|
||||
s.gopBuffers = append(s.gopBuffers, buffer)
|
||||
//设置GOP缓存溢出回调
|
||||
buffer.SetDiscardHandler(s.OnDiscardPacket)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 从DeMuxer解析完Stream后, 处理等待Sinks
|
||||
func (s *SourceImpl) writeHeader() {
|
||||
{
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
if s.completed {
|
||||
return
|
||||
}
|
||||
s.completed = true
|
||||
if s.completed {
|
||||
fmt.Printf("添加Stream失败 Source: %s已经WriteHeader", s.Id_)
|
||||
return
|
||||
}
|
||||
|
||||
s.completed = true
|
||||
|
||||
if s.probeTimer != nil {
|
||||
s.probeTimer.Stop()
|
||||
}
|
||||
|
||||
sinks := PopWaitingSinks(s.Id_)
|
||||
for _, sink := range sinks {
|
||||
s.AddSink(sink)
|
||||
if !s.AddSink(sink) {
|
||||
sink.Close()
|
||||
}
|
||||
}
|
||||
|
||||
if s.hlsStream != nil {
|
||||
@@ -478,20 +555,31 @@ func (s *SourceImpl) writeHeader() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SourceImpl) IsCompleted() bool {
|
||||
return s.completed
|
||||
}
|
||||
|
||||
func (s *SourceImpl) OnDeMuxStreamDone() {
|
||||
s.writeHeader()
|
||||
}
|
||||
|
||||
func (s *SourceImpl) OnDeMuxPacket(packet utils.AVPacket) {
|
||||
if AppConfig.GOPCache {
|
||||
buffer := s.buffers[packet.Index()]
|
||||
buffer := s.gopBuffers[packet.Index()]
|
||||
buffer.AddPacket(packet, packet.KeyFrame(), packet.Dts())
|
||||
}
|
||||
|
||||
//分发给各个传输流
|
||||
for _, stream := range s.transStreams {
|
||||
stream.Input(packet)
|
||||
for _, stream_ := range s.transStreams {
|
||||
stream_.Input(packet)
|
||||
}
|
||||
|
||||
if AppConfig.GOPCache {
|
||||
return
|
||||
}
|
||||
|
||||
//未开启GOP缓存,释放掉内存
|
||||
s.FindOrCreatePacketBuffer(packet.Index(), packet.MediaType()).FreeTail()
|
||||
}
|
||||
|
||||
func (s *SourceImpl) OnDeMuxDone() {
|
||||
|
Reference in New Issue
Block a user