From 31ed3eb99528fc92cd71b336ba320b68ab6f250e Mon Sep 17 00:00:00 2001 From: Sergey Stepanov Date: Tue, 17 Oct 2023 14:04:15 +0300 Subject: [PATCH] Allow changing video resolution during the stream --- pkg/worker/caged/libretro/caged.go | 10 ++++++++ pkg/worker/caged/libretro/frontend.go | 2 ++ .../caged/libretro/nanoarch/nanoarch.go | 15 ++++++++---- pkg/worker/coordinatorhandlers.go | 9 +++++++ pkg/worker/media/media.go | 24 ++++++++++++++++--- pkg/worker/room/room.go | 2 ++ 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/pkg/worker/caged/libretro/caged.go b/pkg/worker/caged/libretro/caged.go index de0ba038d..2260b4c0c 100644 --- a/pkg/worker/caged/libretro/caged.go +++ b/pkg/worker/caged/libretro/caged.go @@ -15,6 +15,8 @@ type Caged struct { conf CagedConf log *logger.Logger w, h int + + OnSysInfoChange func() } type CagedConf struct { @@ -44,6 +46,14 @@ func (c *Caged) ReloadFrontend() { c.base = frontend } +func (c *Caged) HandleOnSystemAvInfo(fn func()) { + c.base.SetOnAV(func() { + w, h := c.ViewportCalc() + c.SetViewport(w, h) + fn() + }) +} + func (c *Caged) Load(game games.GameMetadata, path string) error { c.Emulator.LoadCore(game.System) if err := c.Emulator.LoadGame(game.FullPath(path)); err != nil { diff --git a/pkg/worker/caged/libretro/frontend.go b/pkg/worker/caged/libretro/frontend.go index 63d323201..052756a69 100644 --- a/pkg/worker/caged/libretro/frontend.go +++ b/pkg/worker/caged/libretro/frontend.go @@ -211,6 +211,8 @@ func (f *Frontend) linkNano(nano *nanoarch.Nanoarch) { f.nano.OnAudio = f.handleAudio } +func (f *Frontend) SetOnAV(fn func()) { f.nano.OnSystemAvInfo = fn } + func (f *Frontend) Start() { f.log.Debug().Msgf("Frontend start") diff --git a/pkg/worker/caged/libretro/nanoarch/nanoarch.go b/pkg/worker/caged/libretro/nanoarch/nanoarch.go index b601aadea..1b6612015 100644 --- a/pkg/worker/caged/libretro/nanoarch/nanoarch.go +++ b/pkg/worker/caged/libretro/nanoarch/nanoarch.go @@ -73,10 +73,11 @@ type Nanoarch struct { } type Handlers struct { - OnDpad func(port uint, axis uint) (shift int16) - OnKeyPress func(port uint, key int) int - OnAudio func(ptr unsafe.Pointer, frames int) - OnVideo func(data []byte, delta int32, fi FrameInfo) + OnDpad func(port uint, axis uint) (shift int16) + OnKeyPress func(port uint, key int) int + OnAudio func(ptr unsafe.Pointer, frames int) + OnVideo func(data []byte, delta int32, fi FrameInfo) + OnSystemAvInfo func() } type FrameInfo struct { @@ -689,6 +690,12 @@ func coreEnvironment(cmd C.unsigned, data unsafe.Pointer) C.bool { case C.RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: av := *(*C.struct_retro_system_av_info)(data) Nan0.log.Info().Msgf(">>> SET SYS AV INFO: %v", av) + Nan0.sysAvInfo = av + go func() { + if Nan0.OnSystemAvInfo != nil { + Nan0.OnSystemAvInfo() + } + }() return true case C.RETRO_ENVIRONMENT_SET_GEOMETRY: geom := *(*C.struct_retro_game_geometry)(data) diff --git a/pkg/worker/coordinatorhandlers.go b/pkg/worker/coordinatorhandlers.go index 2a791c1b6..f061f1594 100644 --- a/pkg/worker/coordinatorhandlers.go +++ b/pkg/worker/coordinatorhandlers.go @@ -137,6 +137,15 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest[com.Uid], w *Worke m.SetPixFmt(app.PixFormat()) m.SetRot(app.Rotation()) + app.HandleOnSystemAvInfo(func() { + m.VideoW, m.VideoH = app.ViewportSize() + m.VideoScale = app.Scale() + err := m.Reinit() + if err != nil { + c.log.Error().Err(err).Msgf("av reinit fail") + } + }) + r.BindAppMedia() r.StartApp() } diff --git a/pkg/worker/media/media.go b/pkg/worker/media/media.go index 5b33404e6..7c9a242eb 100644 --- a/pkg/worker/media/media.go +++ b/pkg/worker/media/media.go @@ -116,6 +116,11 @@ type WebrtcMediaPipe struct { AudioFrame int VideoW, VideoH int VideoScale float64 + + // keep the old settings for reinit + oldPf uint32 + oldRot uint + oldFlip bool } func NewWebRtcMediaPipe(ac config.Audio, vc config.Video, log *logger.Logger) *WebrtcMediaPipe { @@ -200,6 +205,19 @@ func round(x int, scale float64) int { return (int(float64(x)*scale) + 1) & ^1 } func (wmp *WebrtcMediaPipe) ProcessVideo(v app.Video) []byte { return wmp.v.Encode(encoder.InFrame(v.Frame)) } -func (wmp *WebrtcMediaPipe) SetPixFmt(f uint32) { wmp.v.SetPixFormat(f) } -func (wmp *WebrtcMediaPipe) SetVideoFlip(b bool) { wmp.v.SetFlip(b) } -func (wmp *WebrtcMediaPipe) SetRot(r uint) { wmp.v.SetRot(r) } + +func (wmp *WebrtcMediaPipe) Reinit() error { + wmp.v.Stop() + if err := wmp.initVideo(wmp.VideoW, wmp.VideoH, wmp.VideoScale, wmp.vConf); err != nil { + return err + } + // restore old + wmp.SetPixFmt(wmp.oldPf) + wmp.SetRot(wmp.oldRot) + wmp.SetVideoFlip(wmp.oldFlip) + return nil +} + +func (wmp *WebrtcMediaPipe) SetPixFmt(f uint32) { wmp.oldPf = f; wmp.v.SetPixFormat(f) } +func (wmp *WebrtcMediaPipe) SetVideoFlip(b bool) { wmp.oldFlip = b; wmp.v.SetFlip(b) } +func (wmp *WebrtcMediaPipe) SetRot(r uint) { wmp.oldRot = r; wmp.v.SetRot(r) } diff --git a/pkg/worker/room/room.go b/pkg/worker/room/room.go index b2341b4e8..6e777e806 100644 --- a/pkg/worker/room/room.go +++ b/pkg/worker/room/room.go @@ -11,6 +11,8 @@ type MediaPipe interface { Destroy() // Init initializes the pipe: allocates needed resources. Init() error + // Reinit initializes video and audio pipes with the new settings. + Reinit() error // PushAudio pushes the 16bit PCM audio frames into an encoder. // Because we need to fill the buffer, the SetAudioCb should be // used in order to get the result.