Files
lkm/stream/source.go
DESKTOP-COJOJSE\lenovo 33ec8159f1 完善Source和Sink
2023-11-18 17:57:05 +08:00

220 lines
5.7 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 stream
import (
"github.com/yangjiechina/avformat"
"github.com/yangjiechina/avformat/utils"
"github.com/yangjiechina/live-server/transcode"
"time"
)
// SourceType Source 推流类型
type SourceType byte
// Protocol 输出协议
type Protocol uint32
const (
SourceTypeRtmp = SourceType(1)
SourceType28181 = SourceType(2)
SourceType1078 = SourceType(3)
ProtocolRtmp = Protocol(1)
ProtocolFlv = Protocol(2)
ProtocolRtsp = Protocol(3)
ProtocolHls = Protocol(4)
ProtocolRtc = Protocol(5)
)
// SessionState 推拉流Session状态
// 包含, 握手阶段、Hook授权.
type SessionState uint32
const (
SessionStateCreate = SessionState(1)
SessionStateHandshaking = SessionState(2)
SessionStateHandshakeFailure = SessionState(3)
SessionStateHandshakeDone = SessionState(4)
SessionStateTransferring = SessionState(5)
)
type ISource interface {
// Id Source的唯一ID/**
Id() string
// Input 输入推流数据
Input(data []byte)
// CreateTransDeMuxer 创建推流的解服用器
CreateTransDeMuxer() ITransDeMuxer
// CreateTranscoder 创建转码器
CreateTranscoder(src utils.AVStream, dst utils.AVStream) transcode.ITranscoder
// OriginStreams 返回推流的原始Streams
OriginStreams() []utils.AVStream
// TranscodeStreams 返回转码的Streams
TranscodeStreams() []utils.AVStream
// AddSink 添加Sink, 在此之前请确保Sink已经握手、授权通过. 如果Source还未WriteHeader将Sink添加到等待队列.
// 匹配拉流的编码器, 创建TransMuxer或向存在TransMuxer添加Sink
AddSink(sink ISink) bool
// RemoveSink 删除Sink/**
RemoveSink(tid TransStreamId, sinkId string) bool
// Close 关闭Source
// 停止一切封装和转发流以及转码工作
// 将Sink添加到等待队列
Close()
}
type onSourceHandler interface {
onDeMuxStream(stream utils.AVStream)
}
type SourceImpl struct {
Id_ string
type_ SourceType
state SessionState
deMuxer ITransDeMuxer //负责从推流协议中解析出AVStream和AVPacket
recordSink ISink //每个Source唯一的一个录制流
audioTranscoders []transcode.ITranscoder //音频解码器
videoTranscoders []transcode.ITranscoder //视频解码器
originStreams StreamManager //推流的音视频Streams
allStreams StreamManager //推流Streams+转码器获得的Streams
completed bool
probeTimer *time.Timer
//所有的输出协议, 持有Sink
transStreams map[TransStreamId]ITransStream
}
func (s *SourceImpl) Id() string {
return s.Id_
}
func (s *SourceImpl) Input(data []byte) {
s.deMuxer.Input(data)
}
func (s *SourceImpl) CreateTransDeMuxer() ITransDeMuxer {
//TODO implement me
panic("implement me")
}
func (s *SourceImpl) CreateTranscoder(src utils.AVStream, dst utils.AVStream) transcode.ITranscoder {
//TODO implement me
panic("implement me")
}
func (s *SourceImpl) OriginStreams() []utils.AVStream {
return s.originStreams.All()
}
func (s *SourceImpl) TranscodeStreams() []utils.AVStream {
return s.allStreams.All()
}
func IsSupportMux(protocol Protocol, audioCodecId, videoCodecId utils.AVCodecID) bool {
if ProtocolRtmp == protocol || ProtocolFlv == protocol {
}
return true
}
func (s *SourceImpl) AddSink(sink ISink) bool {
// 暂时不考虑多路视频流意味着只能1路视频流和多路音频流同理originStreams和allStreams里面的Stream互斥. 同时多路音频流的Codec必须一致
audioCodecId, videoCodecId := sink.DesiredAudioCodecId(), sink.DesiredVideoCodecId()
audioStream := s.originStreams.FindStreamWithType(utils.AVMediaTypeAudio)
videoStream := s.originStreams.FindStreamWithType(utils.AVMediaTypeVideo)
disableAudio := audioStream == nil
disableVideo := videoStream == nil || !sink.EnableVideo()
if disableAudio && disableVideo {
return false
}
//不支持对期望编码的流封装. 降级
if (utils.AVCodecIdNONE != audioCodecId || utils.AVCodecIdNONE != videoCodecId) && !IsSupportMux(sink.Protocol(), audioCodecId, videoCodecId) {
audioCodecId = utils.AVCodecIdNONE
videoCodecId = utils.AVCodecIdNONE
}
if !disableAudio && utils.AVCodecIdNONE == audioCodecId {
audioCodecId = audioStream.CodecId()
}
if !disableVideo && utils.AVCodecIdNONE == videoCodecId {
videoCodecId = videoStream.CodecId()
}
//创建音频转码器
if !disableAudio && audioCodecId != audioStream.CodecId() {
avformat.Assert(false)
}
//创建视频转码器
if !disableVideo && videoCodecId != videoStream.CodecId() {
avformat.Assert(false)
}
var streams [5]utils.AVStream
var index int
for _, stream := range s.originStreams.All() {
if disableVideo && stream.Type() == utils.AVMediaTypeVideo {
continue
}
streams[index] = stream
index++
}
//transStreamId := GenerateTransStreamId(sink.Protocol(), streams[:]...)
TransStreamFactory(sink.Protocol(), streams[:])
return false
}
func (s *SourceImpl) RemoveSink(tid TransStreamId, sinkId string) bool {
//TODO implement me
panic("implement me")
}
func (s *SourceImpl) Close() {
//TODO implement me
panic("implement me")
}
func (s *SourceImpl) OnDeMuxStream(stream utils.AVStream) {
s.originStreams.Add(stream)
s.allStreams.Add(stream)
if len(s.originStreams.All()) == 1 {
s.probeTimer = time.AfterFunc(time.Duration(AppConfig.ProbeTimeout)*time.Millisecond, s.writeHeader)
}
}
// 从DeMuxer解析完Stream后, 处理等待Sinks
func (s *SourceImpl) writeHeader() {
avformat.Assert(!s.completed)
s.probeTimer.Stop()
s.completed = true
sinks := PopWaitingSinks(s.Id_)
for _, sink := range sinks {
s.AddSink(sink)
}
}
func (s *SourceImpl) OnDeMuxStreamDone() {
s.writeHeader()
}
func (s *SourceImpl) OnDeMuxPacket(index int, packet utils.AVPacket) {
}
func (s *SourceImpl) OnDeMuxDone() {
}