mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-05 16:46:58 +08:00
修改命名
This commit is contained in:
@@ -17,14 +17,11 @@ type AVPacket struct {
|
|||||||
Timestamp uint32
|
Timestamp uint32
|
||||||
Type byte //8 audio,9 video
|
Type byte //8 audio,9 video
|
||||||
IsSequence bool //序列帧
|
IsSequence bool //序列帧
|
||||||
VideoFrameType byte //4bit
|
IsKeyFrame bool//是否为关键帧
|
||||||
Payload []byte
|
Payload []byte
|
||||||
Number int //编号,audio和video独立编号
|
Number int //编号,audio和video独立编号
|
||||||
}
|
}
|
||||||
|
|
||||||
func (av *AVPacket) IsKeyFrame() bool {
|
|
||||||
return av.VideoFrameType == 1 || av.VideoFrameType == 4
|
|
||||||
}
|
|
||||||
func (av *AVPacket) ADTS2ASC() (tagPacket *AVPacket) {
|
func (av *AVPacket) ADTS2ASC() (tagPacket *AVPacket) {
|
||||||
tagPacket = NewAVPacket(FLV_TAG_TYPE_AUDIO)
|
tagPacket = NewAVPacket(FLV_TAG_TYPE_AUDIO)
|
||||||
tagPacket.Payload = ADTSToAudioSpecificConfig(av.Payload)
|
tagPacket.Payload = ADTSToAudioSpecificConfig(av.Payload)
|
||||||
|
@@ -14,6 +14,7 @@ const (
|
|||||||
PLUGIN_SUBSCRIBER = 1 //订阅者插件
|
PLUGIN_SUBSCRIBER = 1 //订阅者插件
|
||||||
PLUGIN_PUBLISHER = 1 << 1 //发布者插件
|
PLUGIN_PUBLISHER = 1 << 1 //发布者插件
|
||||||
PLUGIN_HOOK = 1 << 2 //钩子插件
|
PLUGIN_HOOK = 1 << 2 //钩子插件
|
||||||
|
PLUGIN_APP = 1 << 3 //应用插件
|
||||||
)
|
)
|
||||||
|
|
||||||
// Plugins 所有的插件配置
|
// Plugins 所有的插件配置
|
||||||
@@ -53,5 +54,5 @@ type ListenerConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var config = &struct {
|
var config = &struct {
|
||||||
EnableWaitRoom bool
|
EnableWaitStream bool
|
||||||
}{true}
|
}{true}
|
||||||
|
34
hook.go
34
hook.go
@@ -18,12 +18,12 @@ func (h AuthHook) Trigger(sign string) error {
|
|||||||
|
|
||||||
var OnPublishHooks = make(OnPublishHook, 0)
|
var OnPublishHooks = make(OnPublishHook, 0)
|
||||||
|
|
||||||
type OnPublishHook []func(r *Room)
|
type OnPublishHook []func(r *Stream)
|
||||||
|
|
||||||
func (h OnPublishHook) AddHook(hook func(r *Room)) {
|
func (h OnPublishHook) AddHook(hook func(r *Stream)) {
|
||||||
OnPublishHooks = append(h, hook)
|
OnPublishHooks = append(h, hook)
|
||||||
}
|
}
|
||||||
func (h OnPublishHook) Trigger(r *Room) {
|
func (h OnPublishHook) Trigger(r *Stream) {
|
||||||
for _, f := range h {
|
for _, f := range h {
|
||||||
f(r)
|
f(r)
|
||||||
}
|
}
|
||||||
@@ -31,12 +31,12 @@ func (h OnPublishHook) Trigger(r *Room) {
|
|||||||
|
|
||||||
var OnSubscribeHooks = make(OnSubscribeHook, 0)
|
var OnSubscribeHooks = make(OnSubscribeHook, 0)
|
||||||
|
|
||||||
type OnSubscribeHook []func(s *OutputStream)
|
type OnSubscribeHook []func(s *Subscriber)
|
||||||
|
|
||||||
func (h OnSubscribeHook) AddHook(hook func(s *OutputStream)) {
|
func (h OnSubscribeHook) AddHook(hook func(s *Subscriber)) {
|
||||||
OnSubscribeHooks = append(h, hook)
|
OnSubscribeHooks = append(h, hook)
|
||||||
}
|
}
|
||||||
func (h OnSubscribeHook) Trigger(s *OutputStream) {
|
func (h OnSubscribeHook) Trigger(s *Subscriber) {
|
||||||
for _, f := range h {
|
for _, f := range h {
|
||||||
f(s)
|
f(s)
|
||||||
}
|
}
|
||||||
@@ -44,12 +44,12 @@ func (h OnSubscribeHook) Trigger(s *OutputStream) {
|
|||||||
|
|
||||||
var OnUnSubscribeHooks = make(OnUnSubscribeHook, 0)
|
var OnUnSubscribeHooks = make(OnUnSubscribeHook, 0)
|
||||||
|
|
||||||
type OnUnSubscribeHook []func(s *OutputStream)
|
type OnUnSubscribeHook []func(s *Subscriber)
|
||||||
|
|
||||||
func (h OnUnSubscribeHook) AddHook(hook func(s *OutputStream)) {
|
func (h OnUnSubscribeHook) AddHook(hook func(s *Subscriber)) {
|
||||||
OnUnSubscribeHooks = append(h, hook)
|
OnUnSubscribeHooks = append(h, hook)
|
||||||
}
|
}
|
||||||
func (h OnUnSubscribeHook) Trigger(s *OutputStream) {
|
func (h OnUnSubscribeHook) Trigger(s *Subscriber) {
|
||||||
for _, f := range h {
|
for _, f := range h {
|
||||||
f(s)
|
f(s)
|
||||||
}
|
}
|
||||||
@@ -57,12 +57,12 @@ func (h OnUnSubscribeHook) Trigger(s *OutputStream) {
|
|||||||
|
|
||||||
var OnDropHooks = make(OnDropHook, 0)
|
var OnDropHooks = make(OnDropHook, 0)
|
||||||
|
|
||||||
type OnDropHook []func(s *OutputStream)
|
type OnDropHook []func(s *Subscriber)
|
||||||
|
|
||||||
func (h OnDropHook) AddHook(hook func(s *OutputStream)) {
|
func (h OnDropHook) AddHook(hook func(s *Subscriber)) {
|
||||||
OnDropHooks = append(h, hook)
|
OnDropHooks = append(h, hook)
|
||||||
}
|
}
|
||||||
func (h OnDropHook) Trigger(s *OutputStream) {
|
func (h OnDropHook) Trigger(s *Subscriber) {
|
||||||
for _, f := range h {
|
for _, f := range h {
|
||||||
f(s)
|
f(s)
|
||||||
}
|
}
|
||||||
@@ -81,14 +81,14 @@ func (h OnSummaryHook) Trigger(v bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var OnRoomClosedHooks = make(OnRoomClosedHook, 0)
|
var OnStreamClosedHooks = make(OnStreamClosedHook, 0)
|
||||||
|
|
||||||
type OnRoomClosedHook []func(*Room)
|
type OnStreamClosedHook []func(*Stream)
|
||||||
|
|
||||||
func (h OnRoomClosedHook) AddHook(hook func(*Room)) {
|
func (h OnStreamClosedHook) AddHook(hook func(*Stream)) {
|
||||||
OnRoomClosedHooks = append(h, hook)
|
OnStreamClosedHooks = append(h, hook)
|
||||||
}
|
}
|
||||||
func (h OnRoomClosedHook) Trigger(v *Room) {
|
func (h OnStreamClosedHook) Trigger(v *Stream) {
|
||||||
for _, f := range h {
|
for _, f := range h {
|
||||||
f(v)
|
f(v)
|
||||||
}
|
}
|
||||||
|
35
publisher.go
35
publisher.go
@@ -1,51 +1,36 @@
|
|||||||
package engine
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Publisher 发布者接口
|
// Publisher 发布者实体定义
|
||||||
type Publisher interface {
|
type Publisher struct {
|
||||||
OnClosed()
|
*Stream
|
||||||
}
|
|
||||||
|
|
||||||
// InputStream 发布者实体定义
|
|
||||||
type InputStream struct {
|
|
||||||
*Room
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close 关闭发布者
|
// Close 关闭发布者
|
||||||
func (p *InputStream) Close() {
|
func (p *Publisher) Close() {
|
||||||
if p.Running() {
|
if p.Running() {
|
||||||
p.Cancel()
|
p.Cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Running 发布者是否正在发布
|
// Running 发布者是否正在发布
|
||||||
func (p *InputStream) Running() bool {
|
func (p *Publisher) Running() bool {
|
||||||
return p.Room != nil && p.Err() == nil
|
return p.Stream != nil && p.Err() == nil
|
||||||
}
|
|
||||||
|
|
||||||
// OnClosed 发布者关闭事件,用于回收资源
|
|
||||||
func (p *InputStream) OnClosed() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish 发布者进行发布操作
|
// Publish 发布者进行发布操作
|
||||||
func (p *InputStream) Publish(streamPath string, publisher Publisher) bool {
|
func (p *Publisher) Publish(streamPath string) bool {
|
||||||
p.Room = AllRoom.Get(streamPath)
|
p.Stream = GetStream(streamPath)
|
||||||
//检查是否已存在发布者
|
//检查是否已存在发布者
|
||||||
if p.Publisher != nil {
|
if p.Publisher != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
p.Publisher = publisher
|
p.Publisher = p
|
||||||
//反射获取发布者类型信息
|
|
||||||
p.Type = reflect.ValueOf(publisher).Elem().Type().Name()
|
|
||||||
log.Printf("publish set :%s", p.Type)
|
|
||||||
p.StartTime = time.Now()
|
p.StartTime = time.Now()
|
||||||
//触发钩子
|
//触发钩子
|
||||||
OnPublishHooks.Trigger(p.Room)
|
OnPublishHooks.Trigger(p.Stream)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
11
ring.go
11
ring.go
@@ -43,6 +43,17 @@ func (r *Ring) GoBack() {
|
|||||||
r.Index--
|
r.Index--
|
||||||
r.RingItem = r.buffer[r.Index]
|
r.RingItem = r.buffer[r.Index]
|
||||||
}
|
}
|
||||||
|
func (r *Ring) NextW() {
|
||||||
|
r.Index++
|
||||||
|
item := r.RingItem
|
||||||
|
r.RingItem = r.buffer[r.Index]
|
||||||
|
r.RingItem.Lock()
|
||||||
|
item.UnLock()
|
||||||
|
}
|
||||||
|
func (r *Ring) NextR() {
|
||||||
|
r.RingItem.RUnlock()
|
||||||
|
r.GoNext()
|
||||||
|
}
|
||||||
func (r Ring) Clone() *Ring {
|
func (r Ring) Clone() *Ring {
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
|
@@ -11,54 +11,54 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
AllRoom = RoomCollection{}
|
streamCollection = Collection{}
|
||||||
roomCtxBg = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collection 对sync.Map的包装
|
// Collection 对sync.Map的包装
|
||||||
type RoomCollection struct {
|
type Collection struct {
|
||||||
sync.Map
|
sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 根据流名称获取房间
|
//GetStream 根据流路径获取流,如果不存在则创建一个新的
|
||||||
func (c *RoomCollection) Get(name string) (result *Room) {
|
func GetStream(streamPath string) (result *Stream) {
|
||||||
item, loaded := AllRoom.LoadOrStore(name, &Room{
|
item, loaded := streamCollection.LoadOrStore(name, &Stream{
|
||||||
Subscribers: make(map[string]*OutputStream),
|
Subscribers: make(map[string]*Subscriber),
|
||||||
Control: make(chan interface{}),
|
Control: make(chan interface{}),
|
||||||
AVRing: NewRing(),
|
AVRing: NewRing(),
|
||||||
WaitingMutex: new(sync.RWMutex),
|
WaitingMutex: new(sync.RWMutex),
|
||||||
RoomInfo: RoomInfo{
|
StreamInfo: StreamInfo{
|
||||||
StreamPath: name,
|
StreamPath: streamPath,
|
||||||
SubscriberInfo: make([]*SubscriberInfo, 0),
|
SubscriberInfo: make([]*SubscriberInfo, 0),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
result = item.(*Room)
|
result = item.(*Stream)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
result.Context, result.Cancel = context.WithCancel(roomCtxBg)
|
Summary.Streams = append(Summary.Streams, &result.StreamInfo)
|
||||||
|
result.Context, result.Cancel = context.WithCancel(context.Background())
|
||||||
result.WaitingMutex.Lock() //等待发布者
|
result.WaitingMutex.Lock() //等待发布者
|
||||||
go result.Run()
|
go result.Run()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Room 房间定义
|
// Stream 流定义
|
||||||
type Room struct {
|
type Stream struct {
|
||||||
context.Context
|
context.Context
|
||||||
Publisher
|
Publisher
|
||||||
RoomInfo //可序列化,供后台查看的数据
|
StreamInfo //可序列化,供后台查看的数据
|
||||||
Control chan interface{}
|
Control chan interface{}
|
||||||
Cancel context.CancelFunc
|
Cancel context.CancelFunc
|
||||||
Subscribers map[string]*OutputStream // 订阅者
|
Subscribers map[string]*Subscriber // 订阅者
|
||||||
VideoTag *avformat.AVPacket // 每个视频包都是这样的结构,区别在于Payload的大小.FMS在发送AVC sequence header,需要加上 VideoTags,这个tag 1个字节(8bits)的数据
|
VideoTag *avformat.AVPacket // 每个视频包都是这样的结构,区别在于Payload的大小.FMS在发送AVC sequence header,需要加上 VideoTags,这个tag 1个字节(8bits)的数据
|
||||||
AudioTag *avformat.AVPacket // 每个音频包都是这样的结构,区别在于Payload的大小.FMS在发送AAC sequence header,需要加上 AudioTags,这个tag 1个字节(8bits)的数据
|
AudioTag *avformat.AVPacket // 每个音频包都是这样的结构,区别在于Payload的大小.FMS在发送AAC sequence header,需要加上 AudioTags,这个tag 1个字节(8bits)的数据
|
||||||
FirstScreen *Ring //最近的关键帧位置,首屏渲染
|
FirstScreen *Ring //最近的关键帧位置,首屏渲染
|
||||||
AVRing *Ring //数据环
|
AVRing *Ring //数据环
|
||||||
WaitingMutex *sync.RWMutex //用于订阅和等待发布者
|
WaitingMutex *sync.RWMutex //用于订阅和等待发布者
|
||||||
UseTimestamp bool //是否采用数据包中的时间戳
|
UseTimestamp bool //是否采用数据包中的时间戳
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomInfo 房间可序列化信息,用于控制台显示
|
// StreamInfo 流可序列化信息,用于控制台显示
|
||||||
type RoomInfo struct {
|
type StreamInfo struct {
|
||||||
StreamPath string
|
StreamPath string
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
SubscriberInfo []*SubscriberInfo
|
SubscriberInfo []*SubscriberInfo
|
||||||
@@ -82,50 +82,47 @@ type RoomInfo struct {
|
|||||||
|
|
||||||
// UnSubscribeCmd 取消订阅命令
|
// UnSubscribeCmd 取消订阅命令
|
||||||
type UnSubscribeCmd struct {
|
type UnSubscribeCmd struct {
|
||||||
*OutputStream
|
*Subscriber
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeCmd 订阅房间命令
|
// SubscribeCmd 订阅流命令
|
||||||
type SubscribeCmd struct {
|
type SubscribeCmd struct {
|
||||||
*OutputStream
|
*Subscriber
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeRoomCmd 切换房间命令
|
// ChangeStreamCmd 切换流命令
|
||||||
type ChangeRoomCmd struct {
|
type ChangeStreamCmd struct {
|
||||||
*OutputStream
|
*Subscriber
|
||||||
NewRoom *Room
|
NewStream *Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Room) onClosed() {
|
func (r *Stream) onClosed() {
|
||||||
Print(Yellow("room destoryed :"), BrightCyan(r.StreamPath))
|
Print(Yellow("Stream destoryed :"), BrightCyan(r.StreamPath))
|
||||||
AllRoom.Delete(r.StreamPath)
|
streamCollection.Delete(r.StreamPath)
|
||||||
OnRoomClosedHooks.Trigger(r)
|
OnStreamClosedHooks.Trigger(r)
|
||||||
if r.Publisher != nil {
|
|
||||||
r.OnClosed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Subscribe 订阅房间
|
//Subscribe 订阅流
|
||||||
func (r *Room) Subscribe(s *OutputStream) {
|
func (r *Stream) Subscribe(s *Subscriber) {
|
||||||
s.Room = r
|
s.Stream = r
|
||||||
if r.Err() == nil {
|
if r.Err() == nil {
|
||||||
s.SubscribeTime = time.Now()
|
s.SubscribeTime = time.Now()
|
||||||
Print(Sprintf(Yellow("subscribe :%s %s,to room %s"), Blue(s.Type), Cyan(s.ID), BrightCyan(r.StreamPath)))
|
Print(Sprintf(Yellow("subscribe :%s %s,to Stream %s"), Blue(s.Type), Cyan(s.ID), BrightCyan(r.StreamPath)))
|
||||||
s.Context, s.Cancel = context.WithCancel(r)
|
s.Context, s.Cancel = context.WithCancel(r)
|
||||||
s.Control <- &SubscribeCmd{s}
|
s.Control <- &SubscribeCmd{s}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//UnSubscribe 取消订阅房间
|
//UnSubscribe 取消订阅流
|
||||||
func (r *Room) UnSubscribe(s *OutputStream) {
|
func (r *Stream) UnSubscribe(s *Subscriber) {
|
||||||
if r.Err() == nil {
|
if r.Err() == nil {
|
||||||
r.Control <- &UnSubscribeCmd{s}
|
r.Control <- &UnSubscribeCmd{s}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run 房间运行,转发逻辑
|
// Run 流运行
|
||||||
func (r *Room) Run() {
|
func (r *Stream) Run() {
|
||||||
Print(Green("room create:"), BrightCyan(r.StreamPath))
|
Print(Green("Stream create:"), BrightCyan(r.StreamPath))
|
||||||
defer r.onClosed()
|
defer r.onClosed()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -145,7 +142,7 @@ func (r *Room) Run() {
|
|||||||
}
|
}
|
||||||
copy(r.SubscriberInfo[hole:], r.SubscriberInfo[hole+1:])
|
copy(r.SubscriberInfo[hole:], r.SubscriberInfo[hole+1:])
|
||||||
r.SubscriberInfo = r.SubscriberInfo[:len(r.SubscriberInfo)-1]
|
r.SubscriberInfo = r.SubscriberInfo[:len(r.SubscriberInfo)-1]
|
||||||
OnUnSubscribeHooks.Trigger(v.OutputStream)
|
OnUnSubscribeHooks.Trigger(v.Subscriber)
|
||||||
Print(Sprintf(Yellow("%s subscriber %s removed remains:%d"), BrightCyan(r.StreamPath), Cyan(v.ID), Blue(len(r.SubscriberInfo))))
|
Print(Sprintf(Yellow("%s subscriber %s removed remains:%d"), BrightCyan(r.StreamPath), Cyan(v.ID), Blue(len(r.SubscriberInfo))))
|
||||||
if len(r.SubscriberInfo) == 0 && r.Publisher == nil {
|
if len(r.SubscriberInfo) == 0 && r.Publisher == nil {
|
||||||
r.Cancel()
|
r.Cancel()
|
||||||
@@ -154,15 +151,15 @@ func (r *Room) Run() {
|
|||||||
case *SubscribeCmd:
|
case *SubscribeCmd:
|
||||||
//防止重复添加
|
//防止重复添加
|
||||||
if _, ok := r.Subscribers[v.ID]; !ok {
|
if _, ok := r.Subscribers[v.ID]; !ok {
|
||||||
r.Subscribers[v.ID] = v.OutputStream
|
r.Subscribers[v.ID] = v.Subscriber
|
||||||
r.SubscriberInfo = append(r.SubscriberInfo, &v.SubscriberInfo)
|
r.SubscriberInfo = append(r.SubscriberInfo, &v.SubscriberInfo)
|
||||||
Print(Sprintf(Yellow("%s subscriber %s added remains:%d"), BrightCyan(r.StreamPath), Cyan(v.ID), Blue(len(r.SubscriberInfo))))
|
Print(Sprintf(Yellow("%s subscriber %s added remains:%d"), BrightCyan(r.StreamPath), Cyan(v.ID), Blue(len(r.SubscriberInfo))))
|
||||||
OnSubscribeHooks.Trigger(v.OutputStream)
|
OnSubscribeHooks.Trigger(v.Subscriber)
|
||||||
}
|
}
|
||||||
case *ChangeRoomCmd:
|
case *ChangeStreamCmd:
|
||||||
if _, ok := v.NewRoom.Subscribers[v.ID]; !ok {
|
if _, ok := v.NewStream.Subscribers[v.ID]; !ok {
|
||||||
delete(r.Subscribers, v.ID)
|
delete(r.Subscribers, v.ID)
|
||||||
v.NewRoom.Subscribe(v.OutputStream)
|
v.NewStream.Subscribe(v.Subscriber)
|
||||||
if len(r.SubscriberInfo) == 0 && r.Publisher == nil {
|
if len(r.SubscriberInfo) == 0 && r.Publisher == nil {
|
||||||
r.Cancel()
|
r.Cancel()
|
||||||
}
|
}
|
||||||
@@ -173,13 +170,13 @@ func (r *Room) Run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PushAudio 来自发布者推送的音频
|
// PushAudio 来自发布者推送的音频
|
||||||
func (r *Room) PushAudio(timestamp uint32, payload []byte) {
|
func (r *Stream) PushAudio(timestamp uint32, payload []byte) {
|
||||||
payloadLen := len(payload)
|
payloadLen := len(payload)
|
||||||
audio := r.AVRing
|
audio := r.AVRing
|
||||||
audio.Type = avformat.FLV_TAG_TYPE_AUDIO
|
audio.Type = avformat.FLV_TAG_TYPE_AUDIO
|
||||||
audio.Timestamp = timestamp
|
audio.Timestamp = timestamp
|
||||||
audio.Payload = payload
|
audio.Payload = payload
|
||||||
audio.VideoFrameType = 0
|
audio.IsKeyFrame = false
|
||||||
audio.IsSequence = false
|
audio.IsSequence = false
|
||||||
if audio.GetLast().Timestamp > 0 {
|
if audio.GetLast().Timestamp > 0 {
|
||||||
r.AudioInfo.BPS = payloadLen * 1000 / int(timestamp-audio.GetLast().Timestamp)
|
r.AudioInfo.BPS = payloadLen * 1000 / int(timestamp-audio.GetLast().Timestamp)
|
||||||
@@ -228,11 +225,9 @@ func (r *Room) PushAudio(timestamp uint32, payload []byte) {
|
|||||||
}
|
}
|
||||||
r.AudioInfo.PacketCount++
|
r.AudioInfo.PacketCount++
|
||||||
audio.Number = r.AudioInfo.PacketCount
|
audio.Number = r.AudioInfo.PacketCount
|
||||||
audio.GoNext()
|
audio.NextW()
|
||||||
audio.Lock()
|
|
||||||
audio.GetLast().Unlock()
|
|
||||||
}
|
}
|
||||||
func (r *Room) setH264Info(video *Ring) {
|
func (r *Stream) setH264Info(video *Ring) {
|
||||||
r.VideoTag = video.AVPacket.Clone()
|
r.VideoTag = video.AVPacket.Clone()
|
||||||
if r.VideoInfo.CodecID != 7 {
|
if r.VideoInfo.CodecID != 7 {
|
||||||
return
|
return
|
||||||
@@ -245,7 +240,7 @@ func (r *Room) setH264Info(video *Ring) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PushVideo 来自发布者推送的视频
|
// PushVideo 来自发布者推送的视频
|
||||||
func (r *Room) PushVideo(timestamp uint32, payload []byte) {
|
func (r *Stream) PushVideo(timestamp uint32, payload []byte) {
|
||||||
payloadLen := len(payload)
|
payloadLen := len(payload)
|
||||||
video := r.AVRing
|
video := r.AVRing
|
||||||
video.Type = avformat.FLV_TAG_TYPE_VIDEO
|
video.Type = avformat.FLV_TAG_TYPE_VIDEO
|
||||||
@@ -257,9 +252,10 @@ func (r *Room) PushVideo(timestamp uint32, payload []byte) {
|
|||||||
if payloadLen < 3 {
|
if payloadLen < 3 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
video.VideoFrameType = payload[0] >> 4 // 帧类型 4Bit, H264一般为1或者2
|
videoFrameType := payload[0] >> 4 // 帧类型 4Bit, H264一般为1或者2
|
||||||
r.VideoInfo.CodecID = payload[0] & 0x0f // 编码类型ID 4Bit, JPEG, H263, AVC...
|
r.VideoInfo.CodecID = payload[0] & 0x0f // 编码类型ID 4Bit, JPEG, H263, AVC...
|
||||||
video.IsSequence = video.VideoFrameType == 1 && payload[1] == 0
|
video.IsSequence = videoFrameType == 1 && payload[1] == 0
|
||||||
|
video.IsKeyFrame = videoFrameType == 1 || videoFrameType == 4
|
||||||
if r.VideoTag == nil {
|
if r.VideoTag == nil {
|
||||||
if video.IsSequence {
|
if video.IsSequence {
|
||||||
r.setH264Info(video)
|
r.setH264Info(video)
|
||||||
@@ -271,7 +267,7 @@ func (r *Room) PushVideo(timestamp uint32, payload []byte) {
|
|||||||
if video.IsSequence {
|
if video.IsSequence {
|
||||||
r.setH264Info(video)
|
r.setH264Info(video)
|
||||||
}
|
}
|
||||||
if video.IsKeyFrame() {
|
if video.IsKeyFrame {
|
||||||
if r.FirstScreen == nil {
|
if r.FirstScreen == nil {
|
||||||
defer r.WaitingMutex.Unlock()
|
defer r.WaitingMutex.Unlock()
|
||||||
r.FirstScreen = video.Clone()
|
r.FirstScreen = video.Clone()
|
||||||
@@ -287,8 +283,6 @@ func (r *Room) PushVideo(timestamp uint32, payload []byte) {
|
|||||||
}
|
}
|
||||||
r.VideoInfo.PacketCount++
|
r.VideoInfo.PacketCount++
|
||||||
video.Number = r.VideoInfo.PacketCount
|
video.Number = r.VideoInfo.PacketCount
|
||||||
video.GoNext()
|
video.NextW()
|
||||||
video.Lock()
|
|
||||||
video.GetLast().Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,11 +9,6 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Subscriber 订阅者
|
|
||||||
// type Subscriber interface {
|
|
||||||
// Send(*avformat.SendPacket) error
|
|
||||||
// }
|
|
||||||
|
|
||||||
// SubscriberInfo 订阅者可序列化信息,用于控制台输出
|
// SubscriberInfo 订阅者可序列化信息,用于控制台输出
|
||||||
type SubscriberInfo struct {
|
type SubscriberInfo struct {
|
||||||
ID string
|
ID string
|
||||||
@@ -25,51 +20,50 @@ type SubscriberInfo struct {
|
|||||||
SubscribeTime time.Time
|
SubscribeTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutputStream 订阅者实体定义
|
// Subscriber 订阅者实体定义
|
||||||
type OutputStream struct {
|
type Subscriber struct {
|
||||||
context.Context
|
context.Context
|
||||||
*Room
|
*Stream
|
||||||
SubscriberInfo
|
SubscriberInfo
|
||||||
SendHandler func(*avformat.SendPacket) error
|
OnData func(*avformat.SendPacket) error
|
||||||
Cancel context.CancelFunc
|
Cancel context.CancelFunc
|
||||||
Sign string
|
Sign string
|
||||||
OffsetTime uint32
|
OffsetTime uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsClosed 检查订阅者是否已经关闭
|
// IsClosed 检查订阅者是否已经关闭
|
||||||
func (s *OutputStream) IsClosed() bool {
|
func (s *Subscriber) IsClosed() bool {
|
||||||
return s.Context != nil && s.Err() != nil
|
return s.Context != nil && s.Err() != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close 关闭订阅者
|
// Close 关闭订阅者
|
||||||
func (s *OutputStream) Close() {
|
func (s *Subscriber) Close() {
|
||||||
if s.Cancel != nil {
|
if s.Cancel != nil {
|
||||||
s.Cancel()
|
s.Cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Play 开始订阅
|
//Subscribe 开始订阅
|
||||||
func (s *OutputStream) Play(streamPath string) (err error) {
|
func (s *Subscriber) Subscribe(streamPath string) (err error) {
|
||||||
if !config.EnableWaitRoom {
|
if !config.EnableWaitStream {
|
||||||
if _, ok := AllRoom.Load(streamPath); !ok {
|
if _, ok := streamCollection.Load(streamPath); !ok {
|
||||||
return errors.New(fmt.Sprintf("Stream not found:%s", streamPath))
|
return errors.New(fmt.Sprintf("Stream not found:%s", streamPath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AllRoom.Get(streamPath).Subscribe(s)
|
GetStream(streamPath).Subscribe(s)
|
||||||
defer s.UnSubscribe(s)
|
defer s.UnSubscribe(s)
|
||||||
//加锁解锁的目的是等待发布者首屏数据,如果发布者尚为发布,则会等待,否则就会往下执行
|
//加锁解锁的目的是等待发布者首屏数据,如果发布者尚为发布,则会等待,否则就会往下执行
|
||||||
s.WaitingMutex.RLock()
|
s.WaitingMutex.RLock()
|
||||||
s.WaitingMutex.RUnlock()
|
s.WaitingMutex.RUnlock()
|
||||||
sendPacket := avformat.NewSendPacket(s.VideoTag, 0)
|
sendPacket := avformat.NewSendPacket(s.VideoTag, 0)
|
||||||
defer sendPacket.Recycle()
|
defer sendPacket.Recycle()
|
||||||
s.SendHandler(sendPacket)
|
s.OnData(sendPacket)
|
||||||
packet := s.FirstScreen.Clone()
|
packet := s.FirstScreen.Clone()
|
||||||
startTime := packet.Timestamp
|
startTime := packet.Timestamp
|
||||||
packet.RLock()
|
packet.RLock()
|
||||||
sendPacket.AVPacket = packet.AVPacket
|
sendPacket.AVPacket = packet.AVPacket
|
||||||
s.SendHandler(sendPacket)
|
s.OnData(sendPacket)
|
||||||
packet.RUnlock()
|
packet.NextR()
|
||||||
packet.GoNext()
|
|
||||||
atsent := false
|
atsent := false
|
||||||
dropping := false
|
dropping := false
|
||||||
droped := 0
|
droped := 0
|
||||||
@@ -84,19 +78,18 @@ func (s *OutputStream) Play(streamPath string) (err error) {
|
|||||||
if packet.Type == avformat.FLV_TAG_TYPE_AUDIO && !atsent {
|
if packet.Type == avformat.FLV_TAG_TYPE_AUDIO && !atsent {
|
||||||
sendPacket.AVPacket = s.AudioTag
|
sendPacket.AVPacket = s.AudioTag
|
||||||
sendPacket.Timestamp = 0
|
sendPacket.Timestamp = 0
|
||||||
s.SendHandler(sendPacket)
|
s.OnData(sendPacket)
|
||||||
atsent = true
|
atsent = true
|
||||||
}
|
}
|
||||||
sendPacket.AVPacket = packet.AVPacket
|
sendPacket.AVPacket = packet.AVPacket
|
||||||
sendPacket.Timestamp = packet.Timestamp - startTime
|
sendPacket.Timestamp = packet.Timestamp - startTime
|
||||||
s.SendHandler(sendPacket)
|
s.OnData(sendPacket)
|
||||||
if s.checkDrop(packet) {
|
if s.checkDrop(packet) {
|
||||||
dropping = true
|
dropping = true
|
||||||
droped = 0
|
droped = 0
|
||||||
}
|
}
|
||||||
packet.RUnlock()
|
packet.NextR()
|
||||||
packet.GoNext()
|
} else if packet.IsKeyFrame {
|
||||||
} else if packet.AVPacket.IsKeyFrame() {
|
|
||||||
//遇到关键帧则退出丢帧
|
//遇到关键帧则退出丢帧
|
||||||
dropping = false
|
dropping = false
|
||||||
//fmt.Println("drop package ", droped)
|
//fmt.Println("drop package ", droped)
|
||||||
@@ -104,8 +97,7 @@ func (s *OutputStream) Play(streamPath string) (err error) {
|
|||||||
packet.RUnlock()
|
packet.RUnlock()
|
||||||
} else {
|
} else {
|
||||||
droped++
|
droped++
|
||||||
packet.RUnlock()
|
packet.NextR()
|
||||||
packet.GoNext()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ type ServerSummary struct {
|
|||||||
Usage float64
|
Usage float64
|
||||||
}
|
}
|
||||||
NetWork []NetWorkInfo
|
NetWork []NetWorkInfo
|
||||||
Rooms []*RoomInfo
|
Streams []*StreamInfo
|
||||||
lastNetWork []NetWorkInfo
|
lastNetWork []NetWorkInfo
|
||||||
ref int
|
ref int
|
||||||
control chan bool
|
control chan bool
|
||||||
@@ -144,10 +144,5 @@ func (s *ServerSummary) collect() {
|
|||||||
//fmt.Printf(" HD : %v GB Free: %v GB Usage:%f%%\n", d.Total/1024/1024/1024, d.Free/1024/1024/1024, d.UsedPercent)
|
//fmt.Printf(" HD : %v GB Free: %v GB Usage:%f%%\n", d.Total/1024/1024/1024, d.Free/1024/1024/1024, d.UsedPercent)
|
||||||
//fmt.Printf(" OS : %v(%v) %v \n", n.Platform, n.PlatformFamily, n.PlatformVersion)
|
//fmt.Printf(" OS : %v(%v) %v \n", n.Platform, n.PlatformFamily, n.PlatformVersion)
|
||||||
//fmt.Printf(" Hostname : %v \n", n.Hostname)
|
//fmt.Printf(" Hostname : %v \n", n.Hostname)
|
||||||
s.Rooms = nil
|
|
||||||
AllRoom.Range(func(key interface{}, v interface{}) bool {
|
|
||||||
s.Rooms = append(s.Rooms, &v.(*Room).RoomInfo)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user