mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-22 17:47:11 +00:00
Update close encoder channel
This commit is contained in:
parent
5dca4000f0
commit
6ce4ef7863
4 changed files with 75 additions and 48 deletions
|
|
@ -74,6 +74,12 @@ func (h *Handler) GetWeb(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// WS handles normal traffic (from browser to host)
|
||||
func (h *Handler) WS(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println("Warn: Something wrong. Recovered in f", r)
|
||||
}
|
||||
}()
|
||||
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Print("[!] WS upgrade:", err)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func (r *Room) AddConnectionToRoom(peerconnection *webrtc.WebRTC, playerIndex in
|
|||
func (r *Room) startWebRTCSession(peerconnection *webrtc.WebRTC, playerIndex int) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Recovered when sent to close inputChannel")
|
||||
log.Println("Warn: Recovered when sent to close inputChannel")
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ func NewVpxEncoder(w, h, fps, bitrate, keyframe int) (*VpxEncoder, error) {
|
|||
v := &VpxEncoder{
|
||||
Output: make(chan []byte, 5*chanSize),
|
||||
Input: make(chan []byte, chanSize),
|
||||
|
||||
IsRunning: true,
|
||||
Done: false,
|
||||
// C
|
||||
width: C.uint(w),
|
||||
height: C.uint(h),
|
||||
|
|
@ -66,9 +69,11 @@ func NewVpxEncoder(w, h, fps, bitrate, keyframe int) (*VpxEncoder, error) {
|
|||
|
||||
// VpxEncoder yuvI420 image to vp8 video
|
||||
type VpxEncoder struct {
|
||||
started bool
|
||||
Output chan []byte // frame
|
||||
Input chan []byte // yuvI420
|
||||
Output chan []byte // frame
|
||||
Input chan []byte // yuvI420
|
||||
|
||||
IsRunning bool
|
||||
Done bool
|
||||
// C
|
||||
width C.uint
|
||||
height C.uint
|
||||
|
|
@ -109,61 +114,74 @@ func (v *VpxEncoder) init() error {
|
|||
if C.call_vpx_codec_enc_init(&v.vpxCodexCtx, encoder, &cfg) != 0 {
|
||||
return fmt.Errorf("Failed to initialize encoder")
|
||||
}
|
||||
v.started = true
|
||||
v.IsRunning = true
|
||||
go v.startLooping()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VpxEncoder) startLooping() {
|
||||
go func() {
|
||||
for {
|
||||
beginEncoding := time.Now()
|
||||
|
||||
yuv, ok := <-v.Input
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// Add Image
|
||||
v.vpxCodexIter = nil
|
||||
C.vpx_img_read(&v.vpxImage, unsafe.Pointer(&yuv[0]))
|
||||
|
||||
var flags C.int
|
||||
if v.keyFrameInterval > 0 && v.frameCount%v.keyFrameInterval == 0 {
|
||||
flags |= C.VPX_EFLAG_FORCE_KF
|
||||
}
|
||||
if C.vpx_codec_encode(&v.vpxCodexCtx, &v.vpxImage, C.vpx_codec_pts_t(v.frameCount), 1, C.vpx_enc_frame_flags_t(flags), C.VPX_DL_REALTIME) != 0 {
|
||||
fmt.Println("Failed to encode frame")
|
||||
}
|
||||
v.frameCount++
|
||||
|
||||
// Get Frame
|
||||
for {
|
||||
goBytes := C.get_frame_buffer(&v.vpxCodexCtx, &v.vpxCodexIter)
|
||||
if goBytes.bs == nil {
|
||||
break
|
||||
}
|
||||
bs := C.GoBytes(goBytes.bs, goBytes.size)
|
||||
// if buffer is full skip frame
|
||||
if len(v.Output) >= cap(v.Output) {
|
||||
continue
|
||||
}
|
||||
v.Output <- bs
|
||||
}
|
||||
|
||||
if *config.IsMonitor {
|
||||
log.Println("Encoding time: ", time.Now().Sub(beginEncoding))
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println("Warn: Recovered panic in encoding ", r)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
beginEncoding := time.Now()
|
||||
|
||||
yuv, ok := <-v.Input
|
||||
if !ok || v.Done == true {
|
||||
// The first time we see IsRunning set to false, we release and return
|
||||
v.Release()
|
||||
return
|
||||
}
|
||||
|
||||
// Add Image
|
||||
v.vpxCodexIter = nil
|
||||
C.vpx_img_read(&v.vpxImage, unsafe.Pointer(&yuv[0]))
|
||||
|
||||
var flags C.int
|
||||
if v.keyFrameInterval > 0 && v.frameCount%v.keyFrameInterval == 0 {
|
||||
flags |= C.VPX_EFLAG_FORCE_KF
|
||||
}
|
||||
if C.vpx_codec_encode(&v.vpxCodexCtx, &v.vpxImage, C.vpx_codec_pts_t(v.frameCount), 1, C.vpx_enc_frame_flags_t(flags), C.VPX_DL_REALTIME) != 0 {
|
||||
fmt.Println("Failed to encode frame")
|
||||
}
|
||||
v.frameCount++
|
||||
|
||||
// Get Frame
|
||||
for {
|
||||
goBytes := C.get_frame_buffer(&v.vpxCodexCtx, &v.vpxCodexIter)
|
||||
if goBytes.bs == nil {
|
||||
break
|
||||
}
|
||||
bs := C.GoBytes(goBytes.bs, goBytes.size)
|
||||
// if buffer is full skip frame
|
||||
if len(v.Output) >= cap(v.Output) {
|
||||
continue
|
||||
}
|
||||
v.Output <- bs
|
||||
}
|
||||
|
||||
if *config.IsMonitor {
|
||||
log.Println("Encoding time: ", time.Now().Sub(beginEncoding))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release release memory and stop loop
|
||||
func (v *VpxEncoder) Release() {
|
||||
if v.started {
|
||||
close(v.Input)
|
||||
close(v.Output)
|
||||
if v.IsRunning {
|
||||
log.Println("Releasing encoder")
|
||||
log.Println("Close output", v.Output)
|
||||
C.vpx_img_free(&v.vpxImage)
|
||||
C.vpx_codec_destroy(&v.vpxCodexCtx)
|
||||
// TODO: Check here, after close it will signal
|
||||
if v.Input != nil {
|
||||
close(v.Input)
|
||||
}
|
||||
close(v.Output)
|
||||
}
|
||||
v.started = false
|
||||
v.IsRunning = false
|
||||
// TODO: Can we merge IsRunning and Done together
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,13 +232,16 @@ func (w *WebRTC) StopClient() {
|
|||
log.Println("===StopClient===")
|
||||
w.isConnected = false
|
||||
if w.encoder != nil {
|
||||
w.encoder.Release()
|
||||
// NOTE: We signal using bool value instead of channel for better performance
|
||||
w.encoder.Done = true
|
||||
}
|
||||
if w.connection != nil {
|
||||
w.connection.Close()
|
||||
}
|
||||
w.connection = nil
|
||||
close(w.InputChannel)
|
||||
// webrtc is producer, so we close
|
||||
close(w.encoder.Input)
|
||||
// NOTE: ImageChannel is waiting for input. Close in writer is not correct for this
|
||||
close(w.ImageChannel)
|
||||
close(w.AudioChannel)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue