diff --git a/go.mod b/go.mod index d87cebd..f5d2698 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,16 @@ module github.com/krishpranav/remote-desktop go 1.19 -require github.com/gen2brain/x264-go v0.2.4 +require ( + github.com/gen2brain/x264-go v0.2.4 + github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 +) require ( + github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect github.com/gen2brain/x264-go/x264c v0.0.0-20221204084822-82ee2951dea2 // indirect github.com/gen2brain/x264-go/yuv v0.0.0-20221204084822-82ee2951dea2 // indirect + github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect + github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect + golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 // indirect ) diff --git a/go.sum b/go.sum index cd3c43c..2a74321 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,16 @@ +github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY= +github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo= github.com/gen2brain/x264-go v0.2.4 h1:/+a2NpTOzek4JtM6TQfodqv/b+vUgR/RzP+REcDBWlY= github.com/gen2brain/x264-go v0.2.4/go.mod h1:E8NzifRRlIjgPiHeBrd2gDNl0aajri6uNc117BROuwA= github.com/gen2brain/x264-go/x264c v0.0.0-20221204084822-82ee2951dea2 h1:4GzTsZK/uG+tHvWR2ORcTCGTC4+mgOPhkUdz/Ro9alg= github.com/gen2brain/x264-go/x264c v0.0.0-20221204084822-82ee2951dea2/go.mod h1:MUMv+ZURlTO3qH8QAt2gxiIY5X4NMaxObz2ImZOMvyA= github.com/gen2brain/x264-go/yuv v0.0.0-20221204084822-82ee2951dea2 h1:lihaRUKRj94EWVZRp1jTmEiIxmvjEiSb9fJl2xftrXY= github.com/gen2brain/x264-go/yuv v0.0.0-20221204084822-82ee2951dea2/go.mod h1:PzzJntdOaVt4Gc37fNaEXpqmhKkUgd/xqyPMUfx+FQc= +github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 h1:dy+DS31tGEGCsZzB45HmJJNHjur8GDgtRNX9U7HnSX4= +github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240/go.mod h1:3P4UH/k22rXyHIJD2w4h2XMqPX4Of/eySEZq9L6wqc4= +github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o= +github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 h1:5jaG59Zhd+8ZXe8C+lgiAGqkOaZBruqrWclLkgAww34= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/rdisplay/screenshot.go b/rdisplay/screenshot.go new file mode 100644 index 0000000..b3c6225 --- /dev/null +++ b/rdisplay/screenshot.go @@ -0,0 +1,83 @@ +package rdisplay + +import ( + "image" + "time" + + "github.com/kbinani/screenshot" +) + +type XVideoProvider struct{} + +type XScreenGrabber struct { + fps int + screen Screen + frames chan *image.RGBA + stop chan struct{} +} + +func (*XVideoProvider) CreateScreenGrabber(screen Screen, fps int) (ScreenGrabber, error) { + return &XScreenGrabber{ + screen: screen, + fps: fps, + frames: make(chan *image.RGBA), + stop: make(chan struct{}), + }, nil +} + +func (x *XVideoProvider) Screens() ([]Screen, error) { + numScreens := screenshot.NumActiveDisplays() + screens := make([]Screen, numScreens) + for i := 0; i < numScreens; i++ { + screens[i] = Screen{ + Index: i, + Bounds: screenshot.GetDisplayBounds(i), + } + } + return screens, nil +} + +func (g *XScreenGrabber) Frames() <-chan *image.RGBA { + return g.frames +} + +func (g *XScreenGrabber) Start() { + delta := time.Duration(1000/g.fps) * time.Millisecond + go func() { + for { + startedAt := time.Now() + select { + case <-g.stop: + close(g.frames) + return + default: + img, err := screenshot.CaptureRect(g.screen.Bounds) + if err != nil { + return + } + g.frames <- img + ellapsed := time.Now().Sub(startedAt) + sleepDuration := delta - ellapsed + if sleepDuration > 0 { + time.Sleep(sleepDuration) + } + } + } + }() +} + +func (g *XScreenGrabber) Stop() { + close(g.stop) +} + +func (g *XScreenGrabber) Screen() *Screen { + return &g.screen +} + +func (g *XScreenGrabber) Fps() int { + return g.fps +} + +func NewVideoProvider() (Service, error) { + return &XVideoProvider{}, nil +}