mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-05 16:46:58 +08:00
修改等待关键帧逻辑
This commit is contained in:
@@ -57,7 +57,7 @@ rec_video = func(msg *Chunk) {
|
|||||||
nalus = nalus[nalulen+nalulenSize:]
|
nalus = nalus[nalulen+nalulenSize:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(stream.WaitPub)
|
close(vt.WaitFirst)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
在填充数据之前,需要获取到SPS和PPS,然后设置好,因为订阅者需要先发送这个数据
|
在填充数据之前,需要获取到SPS和PPS,然后设置好,因为订阅者需要先发送这个数据
|
||||||
|
@@ -16,7 +16,6 @@ type AudioTrack struct {
|
|||||||
SoundSize byte //1bit
|
SoundSize byte //1bit
|
||||||
SoundType byte //1bit
|
SoundType byte //1bit
|
||||||
RtmpTag []byte //rtmp协议需要先发这个帧
|
RtmpTag []byte //rtmp协议需要先发这个帧
|
||||||
ASC []byte //audio special configure
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push 来自发布者推送的音频
|
// Push 来自发布者推送的音频
|
||||||
|
@@ -47,6 +47,11 @@ type TrackCP struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tcp *TrackCP) Play(ctx context.Context, cba func(AudioPack), cbv func(VideoPack)) {
|
func (tcp *TrackCP) Play(ctx context.Context, cba func(AudioPack), cbv func(VideoPack)) {
|
||||||
|
select {
|
||||||
|
case <-tcp.Video.WaitFirst:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
vr := tcp.Video.Buffer.SubRing(tcp.Video.FirstScreen)
|
vr := tcp.Video.Buffer.SubRing(tcp.Video.FirstScreen)
|
||||||
ar := tcp.Audio.Buffer.SubRing(tcp.Audio.Buffer.Index)
|
ar := tcp.Audio.Buffer.SubRing(tcp.Audio.Buffer.Index)
|
||||||
vr.Current.Wait()
|
vr.Current.Wait()
|
||||||
|
50
hook.go
50
hook.go
@@ -6,26 +6,35 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
Name string
|
Name string
|
||||||
Payload interface{}
|
Payload interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
HOOK_SUBSCRIBE = "Subscribe"
|
||||||
|
HOOK_UNSUBSCRIBE = "UnSubscibe"
|
||||||
|
HOOK_STREAMCLOSE = "StreamClose"
|
||||||
|
HOOK_PUBLISH = "Publish"
|
||||||
|
)
|
||||||
|
|
||||||
var Hooks = NewRing_Hook()
|
var Hooks = NewRing_Hook()
|
||||||
|
|
||||||
func AddHook(name string,channel chan interface{}) {
|
func AddHook(name string, channel chan interface{}) {
|
||||||
for hooks:= Hooks.SubRing(Hooks.Index);;hooks.GoNext(){
|
for hooks := Hooks.SubRing(Hooks.Index); ; hooks.GoNext() {
|
||||||
hooks.Current.Wait()
|
hooks.Current.Wait()
|
||||||
if name == hooks.Current.Name {
|
if name == hooks.Current.Name {
|
||||||
channel<-hooks.Current.Payload
|
channel <- hooks.Current.Payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddHookWithContext(name string,channel chan interface{},ctx context.Context) {
|
func AddHookWithContext(name string, channel chan interface{}, ctx context.Context) {
|
||||||
for hooks:= Hooks.SubRing(Hooks.Index);ctx.Err()==nil;hooks.GoNext(){
|
for hooks := Hooks.SubRing(Hooks.Index); ctx.Err() == nil; hooks.GoNext() {
|
||||||
hooks.Current.Wait()
|
hooks.Current.Wait()
|
||||||
if name == hooks.Current.Name && ctx.Err()==nil{
|
if name == hooks.Current.Name && ctx.Err() == nil {
|
||||||
channel<-hooks.Current.Payload
|
channel <- hooks.Current.Payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +44,6 @@ func TriggerHook(hook Hook) {
|
|||||||
Hooks.NextW()
|
Hooks.NextW()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type RingItem_Hook struct {
|
type RingItem_Hook struct {
|
||||||
Hook
|
Hook
|
||||||
sync.WaitGroup
|
sync.WaitGroup
|
||||||
@@ -46,20 +54,22 @@ type RingItem_Hook struct {
|
|||||||
// Ring 环形缓冲,使用数组实现
|
// Ring 环形缓冲,使用数组实现
|
||||||
type Ring_Hook struct {
|
type Ring_Hook struct {
|
||||||
Current *RingItem_Hook
|
Current *RingItem_Hook
|
||||||
buffer []RingItem_Hook
|
buffer []RingItem_Hook
|
||||||
Index byte
|
Index byte
|
||||||
}
|
}
|
||||||
func (r *Ring_Hook) SubRing(index byte) *Ring_Hook{
|
|
||||||
result:= &Ring_Hook{
|
func (r *Ring_Hook) SubRing(index byte) *Ring_Hook {
|
||||||
buffer:r.buffer,
|
result := &Ring_Hook{
|
||||||
|
buffer: r.buffer,
|
||||||
}
|
}
|
||||||
result.GoTo(index)
|
result.GoTo(index)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRing 创建Ring
|
// NewRing 创建Ring
|
||||||
func NewRing_Hook() (r *Ring_Hook) {
|
func NewRing_Hook() (r *Ring_Hook) {
|
||||||
r = &Ring_Hook{
|
r = &Ring_Hook{
|
||||||
buffer : make([]RingItem_Hook, 256),
|
buffer: make([]RingItem_Hook, 256),
|
||||||
}
|
}
|
||||||
r.GoTo(0)
|
r.GoTo(0)
|
||||||
r.Current.Add(1)
|
r.Current.Add(1)
|
||||||
@@ -92,13 +102,13 @@ func (r *Ring_Hook) GetLast() *RingItem_Hook {
|
|||||||
|
|
||||||
// GoNext 移动到下一个位置
|
// GoNext 移动到下一个位置
|
||||||
func (r *Ring_Hook) GoNext() {
|
func (r *Ring_Hook) GoNext() {
|
||||||
r.Index = r.Index+1
|
r.Index = r.Index + 1
|
||||||
r.Current = &r.buffer[r.Index]
|
r.Current = &r.buffer[r.Index]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoBack 移动到上一个位置
|
// GoBack 移动到上一个位置
|
||||||
func (r *Ring_Hook) GoBack() {
|
func (r *Ring_Hook) GoBack() {
|
||||||
r.Index = r.Index-1
|
r.Index = r.Index - 1
|
||||||
r.Current = &r.buffer[r.Index]
|
r.Current = &r.buffer[r.Index]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +122,7 @@ func (r *Ring_Hook) NextW() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NextR 读下一个
|
// NextR 读下一个
|
||||||
func (r *Ring_Hook) NextR(){
|
func (r *Ring_Hook) NextR() {
|
||||||
r.Current.Wait()
|
r.Current.Wait()
|
||||||
r.GoNext()
|
r.GoNext()
|
||||||
}
|
}
|
||||||
@@ -129,8 +139,8 @@ func (r *Ring_Hook) GetBuffer() *bytes.Buffer {
|
|||||||
// Timeout 发布者是否超时了
|
// Timeout 发布者是否超时了
|
||||||
func (r *Ring_Hook) Timeout(t time.Duration) bool {
|
func (r *Ring_Hook) Timeout(t time.Duration) bool {
|
||||||
// 如果设置为0则表示永不超时
|
// 如果设置为0则表示永不超时
|
||||||
if t==0 {
|
if t == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return time.Since(r.Current.UpdateTime) >t
|
return time.Since(r.Current.UpdateTime) > t
|
||||||
}
|
}
|
||||||
|
@@ -47,6 +47,6 @@ func (p *Publisher) Publish(streamPath string) bool {
|
|||||||
p.Publisher = p
|
p.Publisher = p
|
||||||
p.StartTime = time.Now()
|
p.StartTime = time.Now()
|
||||||
//触发钩子
|
//触发钩子
|
||||||
TriggerHook(Hook{"Publish", p.Stream})
|
TriggerHook(Hook{HOOK_PUBLISH, p.Stream})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,6 @@ func GetStream(streamPath string) (result *Stream) {
|
|||||||
HasAudio: true,
|
HasAudio: true,
|
||||||
EnableAudio: &config.EnableAudio,
|
EnableAudio: &config.EnableAudio,
|
||||||
EnableVideo: &config.EnableVideo,
|
EnableVideo: &config.EnableVideo,
|
||||||
WaitPub: make(chan struct{}),
|
|
||||||
})
|
})
|
||||||
result = item.(*Stream)
|
result = item.(*Stream)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
@@ -56,7 +55,6 @@ type Stream struct {
|
|||||||
Subscribers []*Subscriber // 订阅者
|
Subscribers []*Subscriber // 订阅者
|
||||||
VideoTracks []*VideoTrack
|
VideoTracks []*VideoTrack
|
||||||
AudioTracks []*AudioTrack
|
AudioTracks []*AudioTrack
|
||||||
WaitPub chan struct{} `json:"-"` //用于订阅和等待发布者
|
|
||||||
HasAudio bool
|
HasAudio bool
|
||||||
HasVideo bool
|
HasVideo bool
|
||||||
EnableVideo *bool
|
EnableVideo *bool
|
||||||
@@ -66,6 +64,7 @@ type Stream struct {
|
|||||||
|
|
||||||
func (r *Stream) AddVideoTrack() (vt *VideoTrack) {
|
func (r *Stream) AddVideoTrack() (vt *VideoTrack) {
|
||||||
vt = new(VideoTrack)
|
vt = new(VideoTrack)
|
||||||
|
vt.WaitFirst = make(chan struct{})
|
||||||
vt.Buffer = NewRing_Video()
|
vt.Buffer = NewRing_Video()
|
||||||
r.VideoTracks = append(r.VideoTracks, vt)
|
r.VideoTracks = append(r.VideoTracks, vt)
|
||||||
return
|
return
|
||||||
@@ -80,7 +79,7 @@ func (r *Stream) Close() {
|
|||||||
r.cancel()
|
r.cancel()
|
||||||
utils.Print(Yellow("Stream destoryed :"), BrightCyan(r.StreamPath))
|
utils.Print(Yellow("Stream destoryed :"), BrightCyan(r.StreamPath))
|
||||||
Streams.Delete(r.StreamPath)
|
Streams.Delete(r.StreamPath)
|
||||||
TriggerHook(Hook{"StreamClose", r})
|
TriggerHook(Hook{HOOK_STREAMCLOSE, r})
|
||||||
}
|
}
|
||||||
|
|
||||||
//Subscribe 订阅流
|
//Subscribe 订阅流
|
||||||
@@ -93,7 +92,7 @@ func (r *Stream) Subscribe(s *Subscriber) {
|
|||||||
r.Subscribers = append(r.Subscribers, s)
|
r.Subscribers = append(r.Subscribers, s)
|
||||||
r.subscribeMutex.Unlock()
|
r.subscribeMutex.Unlock()
|
||||||
utils.Print(Sprintf(Yellow("%s subscriber %s added remains:%d"), BrightCyan(r.StreamPath), Cyan(s.ID), Blue(len(r.Subscribers))))
|
utils.Print(Sprintf(Yellow("%s subscriber %s added remains:%d"), BrightCyan(r.StreamPath), Cyan(s.ID), Blue(len(r.Subscribers))))
|
||||||
TriggerHook(Hook{"Subscribe", s})
|
TriggerHook(Hook{HOOK_SUBSCRIBE, s})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +103,7 @@ func (r *Stream) UnSubscribe(s *Subscriber) {
|
|||||||
r.Subscribers = DeleteSliceItem_Subscriber(r.Subscribers, s)
|
r.Subscribers = DeleteSliceItem_Subscriber(r.Subscribers, s)
|
||||||
r.subscribeMutex.Unlock()
|
r.subscribeMutex.Unlock()
|
||||||
utils.Print(Sprintf(Yellow("%s subscriber %s removed remains:%d"), BrightCyan(r.StreamPath), Cyan(s.ID), Blue(len(r.Subscribers))))
|
utils.Print(Sprintf(Yellow("%s subscriber %s removed remains:%d"), BrightCyan(r.StreamPath), Cyan(s.ID), Blue(len(r.Subscribers))))
|
||||||
TriggerHook(Hook{"UnSubscribe", s})
|
TriggerHook(Hook{HOOK_UNSUBSCRIBE, s})
|
||||||
if len(r.Subscribers) == 0 && (r.Publisher == nil || r.Publisher.AutoUnPublish) {
|
if len(r.Subscribers) == 0 && (r.Publisher == nil || r.Publisher.AutoUnPublish) {
|
||||||
r.Close()
|
r.Close()
|
||||||
}
|
}
|
||||||
|
@@ -58,6 +58,5 @@ func (s *Subscriber) Subscribe(streamPath string) error {
|
|||||||
if s.Context == nil {
|
if s.Context == nil {
|
||||||
return errors.Errorf("stream not exist:%s", streamPath)
|
return errors.Errorf("stream not exist:%s", streamPath)
|
||||||
}
|
}
|
||||||
<-s.WaitPub
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package engine
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
"github.com/Monibuca/utils/v3"
|
"github.com/Monibuca/utils/v3"
|
||||||
"github.com/Monibuca/utils/v3/codec"
|
"github.com/Monibuca/utils/v3/codec"
|
||||||
)
|
)
|
||||||
@@ -27,11 +28,12 @@ type VideoPack struct {
|
|||||||
type VideoTrack struct {
|
type VideoTrack struct {
|
||||||
FirstScreen byte //最近的关键帧位置,首屏渲染
|
FirstScreen byte //最近的关键帧位置,首屏渲染
|
||||||
Track_Video
|
Track_Video
|
||||||
SPS []byte
|
SPS []byte
|
||||||
PPS []byte
|
PPS []byte
|
||||||
SPSInfo codec.SPSInfo
|
SPSInfo codec.SPSInfo
|
||||||
GOP byte //关键帧间隔
|
GOP byte //关键帧间隔
|
||||||
RtmpTag []byte //rtmp需要先发送一个序列帧,包含SPS和PPS
|
RtmpTag []byte //rtmp需要先发送一个序列帧,包含SPS和PPS
|
||||||
|
WaitFirst chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push 来自发布者推送的视频
|
// Push 来自发布者推送的视频
|
||||||
@@ -82,11 +84,13 @@ func (vt *VideoTrack) Push(timestamp uint32, payload []byte) {
|
|||||||
|
|
||||||
case codec.NALU_IDR_Picture:
|
case codec.NALU_IDR_Picture:
|
||||||
if vt.RtmpTag == nil {
|
if vt.RtmpTag == nil {
|
||||||
|
vt.FirstScreen = vbr.Index
|
||||||
vt.setRtmpTag()
|
vt.setRtmpTag()
|
||||||
|
close(vt.WaitFirst)
|
||||||
} else {
|
} else {
|
||||||
vt.GOP = vbr.Index - vt.FirstScreen
|
vt.GOP = vbr.Index - vt.FirstScreen
|
||||||
|
vt.FirstScreen = vbr.Index
|
||||||
}
|
}
|
||||||
vt.FirstScreen = vbr.Index
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case codec.NALU_Non_IDR_Picture:
|
case codec.NALU_Non_IDR_Picture:
|
||||||
video.Payload = payload
|
video.Payload = payload
|
||||||
@@ -109,6 +113,11 @@ func (vt *VideoTrack) setRtmpTag() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (vt *VideoTrack) Play(ctx context.Context, callback func(VideoPack)) {
|
func (vt *VideoTrack) Play(ctx context.Context, callback func(VideoPack)) {
|
||||||
|
select {
|
||||||
|
case <-vt.WaitFirst:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
ring := vt.Buffer.SubRing(vt.FirstScreen)
|
ring := vt.Buffer.SubRing(vt.FirstScreen)
|
||||||
ring.Current.Wait()
|
ring.Current.Wait()
|
||||||
droped := 0
|
droped := 0
|
||||||
|
Reference in New Issue
Block a user