mirror of
				https://github.com/Monibuca/engine.git
				synced 2025-10-31 20:02:44 +08:00 
			
		
		
		
	优化代码
This commit is contained in:
		| @@ -176,33 +176,18 @@ func (at *AudioTrack) Play(ctx context.Context, onAudio func(AudioPack)) { | |||||||
| 	streamExit := at.Stream.Context.Done() | 	streamExit := at.Stream.Context.Done() | ||||||
| 	ar := at.Clone() | 	ar := at.Clone() | ||||||
| 	ap := ar.Read().(*AudioPack) | 	ap := ar.Read().(*AudioPack) | ||||||
| 	startTimestamp := ap.Timestamp |  | ||||||
| 	droped := 0 |  | ||||||
| 	var action, send func() |  | ||||||
| 	drop := func() { |  | ||||||
| 		if at.current().Sequence-ap.Sequence < 4 { |  | ||||||
| 			action = send |  | ||||||
| 		} else { |  | ||||||
| 			droped++ |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	send = func() { |  | ||||||
| 		if onAudio(ap.Copy(startTimestamp)); at.lastTs-ap.Timestamp > 1000 { |  | ||||||
| 			action = drop |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	var extraExit <-chan struct{} | 	var extraExit <-chan struct{} | ||||||
| 	if ctx != nil { | 	if ctx != nil { | ||||||
| 		extraExit = ctx.Done() | 		extraExit = ctx.Done() | ||||||
| 	} | 	} | ||||||
| 	for action = send; at.Flag != 2; ap = ar.Read().(*AudioPack) { | 	for startTimestamp := ap.Timestamp; at.Goon(); ap = ar.Read().(*AudioPack) { | ||||||
| 		select { | 		select { | ||||||
| 		case <-extraExit: | 		case <-extraExit: | ||||||
| 			return | 			return | ||||||
| 		case <-streamExit: | 		case <-streamExit: | ||||||
| 			return | 			return | ||||||
| 		default: | 		default: | ||||||
| 			action() | 			onAudio(ap.Copy(startTimestamp)) | ||||||
| 			ar.MoveNext() | 			ar.MoveNext() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -108,16 +108,17 @@ func (ts *Tracks) WaitTrack(codecs ...string) Track { | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			go func() { | 			go ring.ReadLoop(wait) | ||||||
| 				for { | 			// go func() { | ||||||
| 					if rt, ok := ring.Read().(string); ok { | 			// 	for { | ||||||
| 						wait <- rt | 			// 		if rt, ok := ring.Read().(string); ok { | ||||||
| 						ring.MoveNext() | 			// 			wait <- rt | ||||||
| 					} else { | 			// 			ring.MoveNext() | ||||||
| 						break | 			// 		} else { | ||||||
| 					} | 			// 			break | ||||||
| 				} | 			// 		} | ||||||
| 			}() | 			// 	} | ||||||
|  | 			// }() | ||||||
| 			for { | 			for { | ||||||
| 				select { | 				select { | ||||||
| 				case t := <-wait: | 				case t := <-wait: | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								hook.go
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								hook.go
									
									
									
									
									
								
							| @@ -27,20 +27,14 @@ func AddHooks(hooks map[string]interface{}) { | |||||||
| 	for name, hook := range hooks { | 	for name, hook := range hooks { | ||||||
| 		rl, ok := Hooks[name] | 		rl, ok := Hooks[name] | ||||||
| 		if !ok { | 		if !ok { | ||||||
| 			rl = &RingBuffer{} | 			rl = NewRingBuffer(4) | ||||||
| 			rl.Init(4) |  | ||||||
| 			Hooks[name] = rl | 			Hooks[name] = rl | ||||||
| 		} | 		} | ||||||
| 		go func(hooks *RingBuffer, callback interface{}) { | 		vf := reflect.ValueOf(hook) | ||||||
| 			vf := reflect.ValueOf(callback) |  | ||||||
| 		if vf.Kind() != reflect.Func { | 		if vf.Kind() != reflect.Func { | ||||||
| 			panic("callback is not a function") | 			panic("callback is not a function") | ||||||
| 		} | 		} | ||||||
| 			for { | 		go rl.Clone().ReadLoop(vf.Call, nil) | ||||||
| 				vf.Call(hooks.Read().([]reflect.Value)) |  | ||||||
| 				hooks.MoveNext() |  | ||||||
| 			} |  | ||||||
| 		}(rl.Clone(), hook) |  | ||||||
| 	} | 	} | ||||||
| 	hookLocker.Unlock() | 	hookLocker.Unlock() | ||||||
| } | } | ||||||
| @@ -49,8 +43,7 @@ func AddHook(name string, callback interface{}) { | |||||||
| 	hookLocker.Lock() | 	hookLocker.Lock() | ||||||
| 	rl, ok := Hooks[name] | 	rl, ok := Hooks[name] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		rl = &RingBuffer{} | 		rl = NewRingBuffer(4) | ||||||
| 		rl.Init(4) |  | ||||||
| 		Hooks[name] = rl | 		Hooks[name] = rl | ||||||
| 	} | 	} | ||||||
| 	hookLocker.Unlock() | 	hookLocker.Unlock() | ||||||
| @@ -58,9 +51,10 @@ func AddHook(name string, callback interface{}) { | |||||||
| 	if vf.Kind() != reflect.Func { | 	if vf.Kind() != reflect.Func { | ||||||
| 		panic("callback is not a function") | 		panic("callback is not a function") | ||||||
| 	} | 	} | ||||||
| 	for hooks := rl.Clone(); ; hooks.MoveNext() { | 	rl.Clone().ReadLoop(vf.Call, nil) | ||||||
| 		vf.Call(hooks.Read().([]reflect.Value)) | 	// for hooks := rl.Clone(); ; hooks.MoveNext() { | ||||||
| 	} | 	// 	vf.Call(hooks.Read().([]reflect.Value)) | ||||||
|  | 	// } | ||||||
| } | } | ||||||
|  |  | ||||||
| func AddHookWithContext(ctx context.Context, name string, callback interface{}) { | func AddHookWithContext(ctx context.Context, name string, callback interface{}) { | ||||||
| @@ -75,9 +69,10 @@ func AddHookWithContext(ctx context.Context, name string, callback interface{}) | |||||||
| 	if vf.Kind() != reflect.Func { | 	if vf.Kind() != reflect.Func { | ||||||
| 		panic("callback is not a function") | 		panic("callback is not a function") | ||||||
| 	} | 	} | ||||||
| 	for hooks := rl.Clone(); ctx.Err() == nil; hooks.MoveNext() { | 	rl.Clone().ReadLoop(vf.Call, func() bool { return ctx.Err() == nil }) | ||||||
| 		vf.Call(hooks.Read().([]reflect.Value)) | 	// for hooks := rl.Clone(); ctx.Err() == nil; hooks.MoveNext() { | ||||||
| 	} | 	// 	vf.Call(hooks.Read().([]reflect.Value)) | ||||||
|  | 	// } | ||||||
| } | } | ||||||
|  |  | ||||||
| func TriggerHook(name string, payload ...interface{}) { | func TriggerHook(name string, payload ...interface{}) { | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							| @@ -17,7 +17,7 @@ import ( | |||||||
| 	. "github.com/logrusorgru/aurora" | 	. "github.com/logrusorgru/aurora" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const Version = "3.1.6" | const Version = "3.1.7" | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	config = &struct { | 	config = &struct { | ||||||
|   | |||||||
							
								
								
									
										109
									
								
								ring.go
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								ring.go
									
									
									
									
									
								
							| @@ -2,8 +2,8 @@ package engine | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"container/ring" | 	"container/ring" | ||||||
|  | 	"reflect" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"sync/atomic" |  | ||||||
| 	// "time" | 	// "time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -14,26 +14,8 @@ type RingItem struct { | |||||||
|  |  | ||||||
| type RingBuffer struct { | type RingBuffer struct { | ||||||
| 	*ring.Ring | 	*ring.Ring | ||||||
| 	// UpdateTime time.Time //更新时间,用于计算是否超时 |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // 可释放的Ring,用于音视频 |  | ||||||
| type RingDisposable struct { |  | ||||||
| 	RingBuffer |  | ||||||
| 	Flag int32 // 0:不在写入,1:正在写入,2:已销毁 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // 带锁的Ring,用于Hook |  | ||||||
| // type RingLock struct { |  | ||||||
| // 	RingBuffer |  | ||||||
| // 	sync.Mutex |  | ||||||
| // } |  | ||||||
| // func (r *RingLock) Write(value interface{}) { |  | ||||||
| // 	r.Lock() |  | ||||||
| // 	r.RingBuffer.Write(value) |  | ||||||
| // 	r.Unlock() |  | ||||||
| // } |  | ||||||
|  |  | ||||||
| // TODO: 池化,泛型 | // TODO: 池化,泛型 | ||||||
|  |  | ||||||
| func NewRingBuffer(n int) (r *RingBuffer) { | func NewRingBuffer(n int) (r *RingBuffer) { | ||||||
| @@ -44,7 +26,6 @@ func NewRingBuffer(n int) (r *RingBuffer) { | |||||||
|  |  | ||||||
| func (r *RingBuffer) Init(n int) { | func (r *RingBuffer) Init(n int) { | ||||||
| 	r.Ring = ring.New(n) | 	r.Ring = ring.New(n) | ||||||
| 	// r.UpdateTime = time.Now() |  | ||||||
| 	for x := r.Ring; x.Value == nil; x = x.Next() { | 	for x := r.Ring; x.Value == nil; x = x.Next() { | ||||||
| 		x.Value = new(RingItem) | 		x.Value = new(RingItem) | ||||||
| 	} | 	} | ||||||
| @@ -55,53 +36,22 @@ func (rb RingBuffer) Clone() *RingBuffer { | |||||||
| 	return &rb | 	return &rb | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *RingBuffer) SubRing(rr *ring.Ring) *RingBuffer { | func (r RingBuffer) SubRing(rr *ring.Ring) *RingBuffer { | ||||||
| 	r = r.Clone() |  | ||||||
| 	r.Ring = rr | 	r.Ring = rr | ||||||
| 	return r | 	return &r | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *RingBuffer) Write(value interface{}) { | func (r *RingBuffer) Write(value interface{}) { | ||||||
| 	// r.UpdateTime = time.Now() |  | ||||||
| 	last := r.Current() | 	last := r.Current() | ||||||
| 	last.Value = value | 	last.Value = value | ||||||
| 	r.GetNext().Add(1) | 	r.GetNext().Add(1) | ||||||
| 	last.Done() | 	last.Done() | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *RingDisposable) Write(value interface{}) { | func (r *RingBuffer) read() reflect.Value { | ||||||
| 	// r.UpdateTime = time.Now() |  | ||||||
| 	last := r.Current() |  | ||||||
| 	last.Value = value |  | ||||||
| 	if atomic.CompareAndSwapInt32(&r.Flag, 0, 1) { |  | ||||||
| 		current := r.GetNext() |  | ||||||
| 		current.Add(1) |  | ||||||
| 		last.Done() |  | ||||||
| 		//Flag不为1代表被Dispose了,但尚未处理Done |  | ||||||
| 		if !atomic.CompareAndSwapInt32(&r.Flag, 1, 0) { |  | ||||||
| 			current.Done() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *RingDisposable) Step() { |  | ||||||
| 	// r.UpdateTime = time.Now() |  | ||||||
| 	last := r.Current() |  | ||||||
| 	if atomic.CompareAndSwapInt32(&r.Flag, 0, 1) { |  | ||||||
| 		current := r.GetNext() |  | ||||||
| 		current.Add(1) |  | ||||||
| 		last.Done() |  | ||||||
| 		//Flag不为1代表被Dispose了,但尚未处理Done |  | ||||||
| 		if !atomic.CompareAndSwapInt32(&r.Flag, 1, 0) { |  | ||||||
| 			current.Done() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *RingBuffer) Read() interface{} { |  | ||||||
| 	current := r.Current() | 	current := r.Current() | ||||||
| 	current.Wait() | 	current.Wait() | ||||||
| 	return current.Value | 	return reflect.ValueOf(current.Value) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *RingBuffer) CurrentValue() interface{} { | func (r *RingBuffer) CurrentValue() interface{} { | ||||||
| @@ -112,7 +62,6 @@ func (r *RingBuffer) NextValue() interface{} { | |||||||
| 	return r.Next().Value.(*RingItem).Value | 	return r.Next().Value.(*RingItem).Value | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| func (r *RingBuffer) Current() *RingItem { | func (r *RingBuffer) Current() *RingItem { | ||||||
| 	return r.Ring.Value.(*RingItem) | 	return r.Ring.Value.(*RingItem) | ||||||
| } | } | ||||||
| @@ -126,22 +75,38 @@ func (r *RingBuffer) GetNext() *RingItem { | |||||||
| 	return r.Current() | 	return r.Current() | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *RingDisposable) Dispose() { | func (r *RingBuffer) Read() interface{} { | ||||||
| 	current := r.Current() | 	current := r.Current() | ||||||
| 	if atomic.CompareAndSwapInt32(&r.Flag, 0, 2) { | 	current.Wait() | ||||||
| 		current.Done() | 	return current.Value | ||||||
| 	} else if atomic.CompareAndSwapInt32(&r.Flag, 1, 2) { |  | ||||||
| 		//当前是1代表正在写入,此时变成2,但是Done的任务得交给NextW来处理 |  | ||||||
| 	} else if atomic.CompareAndSwapInt32(&r.Flag, 0, 2) { |  | ||||||
| 		current.Done() |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // // Timeout 发布者是否超时了 | func (r *RingBuffer) ReadLoop(handler interface{}, goon func() bool) { | ||||||
| // func (r *RingBuffer) Timeout(t time.Duration) bool { | 	if goon == nil { | ||||||
| // 	// 如果设置为0则表示永不超时 | 		switch t := reflect.ValueOf(handler); t.Kind() { | ||||||
| // 	if t == 0 { | 		case reflect.Chan: | ||||||
| // 		return false | 			for v := r.read(); ; v = r.read() { | ||||||
| // 	} | 				t.Send(v) | ||||||
| // 	return time.Since(r.UpdateTime) > t | 				r.MoveNext() | ||||||
| // } | 			} | ||||||
|  | 		case reflect.Func: | ||||||
|  | 			for args := []reflect.Value{r.read()}; ; args[0] = r.read() { | ||||||
|  | 				t.Call(args) | ||||||
|  | 				r.MoveNext() | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		switch t := reflect.ValueOf(handler); t.Kind() { | ||||||
|  | 		case reflect.Chan: | ||||||
|  | 			for v := r.read(); goon(); v = r.read() { | ||||||
|  | 				t.Send(v) | ||||||
|  | 				r.MoveNext() | ||||||
|  | 			} | ||||||
|  | 		case reflect.Func: | ||||||
|  | 			for args := []reflect.Value{r.read()}; goon(); args[0] = r.read() { | ||||||
|  | 				t.Call(args) | ||||||
|  | 				r.MoveNext() | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								ring_disposable.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								ring_disposable.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | package engine | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"container/ring" | ||||||
|  | 	"sync/atomic" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // 可释放的Ring,用于音视频 | ||||||
|  | type RingDisposable struct { | ||||||
|  | 	RingBuffer | ||||||
|  | 	Flag *int32 // 0:不在写入,1:正在写入,2:已销毁 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rb *RingDisposable) Init(n int) { | ||||||
|  | 	var flag int32 | ||||||
|  | 	rb.RingBuffer.Init(n) | ||||||
|  | 	rb.Flag = &flag | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rb RingDisposable) Clone() *RingDisposable { | ||||||
|  | 	return &rb | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r RingDisposable) SubRing(rr *ring.Ring) *RingDisposable { | ||||||
|  | 	r.Ring = rr | ||||||
|  | 	return &r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *RingDisposable) Write(value interface{}) { | ||||||
|  | 	last := r.Current() | ||||||
|  | 	last.Value = value | ||||||
|  | 	if atomic.CompareAndSwapInt32(r.Flag, 0, 1) { | ||||||
|  | 		current := r.GetNext() | ||||||
|  | 		current.Add(1) | ||||||
|  | 		last.Done() | ||||||
|  | 		//Flag不为1代表被Dispose了,但尚未处理Done | ||||||
|  | 		if !atomic.CompareAndSwapInt32(r.Flag, 1, 0) { | ||||||
|  | 			current.Done() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *RingDisposable) Step() { | ||||||
|  | 	last := r.Current() | ||||||
|  | 	if atomic.CompareAndSwapInt32(r.Flag, 0, 1) { | ||||||
|  | 		current := r.GetNext() | ||||||
|  | 		current.Add(1) | ||||||
|  | 		last.Done() | ||||||
|  | 		//Flag不为1代表被Dispose了,但尚未处理Done | ||||||
|  | 		if !atomic.CompareAndSwapInt32(r.Flag, 1, 0) { | ||||||
|  | 			current.Done() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func (r *RingDisposable) Dispose() { | ||||||
|  | 	current := r.Current() | ||||||
|  | 	if atomic.CompareAndSwapInt32(r.Flag, 0, 2) { | ||||||
|  | 		current.Done() | ||||||
|  | 	} else if atomic.CompareAndSwapInt32(r.Flag, 1, 2) { | ||||||
|  | 		//当前是1代表正在写入,此时变成2,但是Done的任务得交给NextW来处理 | ||||||
|  | 	} else if atomic.CompareAndSwapInt32(r.Flag, 0, 2) { | ||||||
|  | 		current.Done() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *RingDisposable) Goon() bool { | ||||||
|  | 	return *r.Flag != 2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *RingDisposable) ReadLoop(handler interface{}) { | ||||||
|  | 	r.RingBuffer.ReadLoop(handler, r.Goon) | ||||||
|  | } | ||||||
| @@ -84,11 +84,10 @@ func (s *Subscriber) Play(at *AudioTrack, vt *VideoTrack) { | |||||||
| 	} | 	} | ||||||
| 	vr := vt.SubRing(vt.IDRing) //从关键帧开始读取,首屏秒开 | 	vr := vt.SubRing(vt.IDRing) //从关键帧开始读取,首屏秒开 | ||||||
| 	ar := at.Clone() | 	ar := at.Clone() | ||||||
| 	// dropping := false //是否处于丢帧中 |  | ||||||
| 	vp := vr.Read().(*VideoPack) | 	vp := vr.Read().(*VideoPack) | ||||||
| 	ap := ar.Read().(*AudioPack) | 	ap := ar.Read().(*AudioPack) | ||||||
| 	startTimestamp := vp.Timestamp | 	vst, ast := vp.Timestamp, ap.Timestamp | ||||||
| 	for vt.Flag != 2 { | 	for vt.Goon() { | ||||||
| 		select { | 		select { | ||||||
| 		case <-extraExit: | 		case <-extraExit: | ||||||
| 			return | 			return | ||||||
| @@ -96,25 +95,11 @@ func (s *Subscriber) Play(at *AudioTrack, vt *VideoTrack) { | |||||||
| 			return | 			return | ||||||
| 		default: | 		default: | ||||||
| 			if ap.Timestamp > vp.Timestamp || ap.Timestamp == 0 { | 			if ap.Timestamp > vp.Timestamp || ap.Timestamp == 0 { | ||||||
| 				s.OnVideo(vp.Copy(startTimestamp)) | 				s.OnVideo(vp.Copy(vst)) | ||||||
| 				// if !dropping { |  | ||||||
| 				// 	s.OnVideo(vp.Copy(startTimestamp)) |  | ||||||
| 				// 	if vt.lastTs - vp.Timestamp > 1000 { |  | ||||||
| 				// 		dropping = true |  | ||||||
| 				// 	} |  | ||||||
| 				// } else if vp.IDR { |  | ||||||
| 				// 	dropping = false |  | ||||||
| 				// } |  | ||||||
| 				vr.MoveNext() | 				vr.MoveNext() | ||||||
| 				vp = vr.Read().(*VideoPack) | 				vp = vr.Read().(*VideoPack) | ||||||
| 			} else { | 			} else { | ||||||
| 				s.OnAudio(ap.Copy(startTimestamp)) | 				s.OnAudio(ap.Copy(ast)) | ||||||
| 				// if !dropping { |  | ||||||
| 				// 	s.OnAudio(ap.Copy(startTimestamp)) |  | ||||||
| 				// 	if at.CurrentValue().(AVPack).Since(ap.Timestamp) > 1000 { |  | ||||||
| 				// 		dropping = true |  | ||||||
| 				// 	} |  | ||||||
| 				// } |  | ||||||
| 				ar.MoveNext() | 				ar.MoveNext() | ||||||
| 				ap = ar.Read().(*AudioPack) | 				ap = ar.Read().(*AudioPack) | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -557,26 +557,14 @@ func (vt *VideoTrack) Play(ctx context.Context, onVideo func(VideoPack)) { | |||||||
| 	} | 	} | ||||||
| 	vr := vt.SubRing(vt.IDRing) //从关键帧开始读取,首屏秒开 | 	vr := vt.SubRing(vt.IDRing) //从关键帧开始读取,首屏秒开 | ||||||
| 	vp := vr.Read().(*VideoPack) | 	vp := vr.Read().(*VideoPack) | ||||||
| 	startTimestamp := vp.Timestamp | 	for startTimestamp := vp.Timestamp; vt.Goon(); vp = vr.Read().(*VideoPack) { | ||||||
| 	var action, send func() |  | ||||||
| 	drop := func() { |  | ||||||
| 		if vp.IDR { |  | ||||||
| 			action = send |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	send = func() { |  | ||||||
| 		if onVideo(vp.Copy(startTimestamp)); vt.lastTs-vp.Timestamp > 1000 { |  | ||||||
| 			action = drop |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	for action = send; vt.Flag != 2; vp = vr.Read().(*VideoPack) { |  | ||||||
| 		select { | 		select { | ||||||
| 		case <-extraExit: | 		case <-extraExit: | ||||||
| 			return | 			return | ||||||
| 		case <-streamExit: | 		case <-streamExit: | ||||||
| 			return | 			return | ||||||
| 		default: | 		default: | ||||||
| 			action() | 			onVideo(vp.Copy(startTimestamp)) | ||||||
| 			vr.MoveNext() | 			vr.MoveNext() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 李宇翔
					李宇翔