mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-19 07:09:56 +00:00
151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
//go:build (linux && !android) || freebsd
|
|
|
|
package server
|
|
|
|
import (
|
|
"image"
|
|
"sync"
|
|
)
|
|
|
|
// FBPoller wraps FBCapturer with the same lifecycle (ClientConnect /
|
|
// ClientDisconnect, lazy init) as X11Poller, so it slots into the same
|
|
// session plumbing without code changes upstream. The concrete
|
|
// FBCapturer is platform-specific (capture_fb_linux.go / _freebsd.go);
|
|
// this file owns the cross-platform glue.
|
|
type FBPoller struct {
|
|
mu sync.Mutex
|
|
path string
|
|
capturer *FBCapturer
|
|
w, h int
|
|
clients int32
|
|
}
|
|
|
|
// NewFBPoller returns a poller that opens path on first use. Empty path
|
|
// defaults to /dev/fb0 on Linux and /dev/ttyv0 on FreeBSD.
|
|
func NewFBPoller(path string) *FBPoller {
|
|
if path == "" {
|
|
path = defaultFBPath()
|
|
}
|
|
return &FBPoller{path: path}
|
|
}
|
|
|
|
// ClientConnect eagerly initialises the capturer on first connect.
|
|
func (p *FBPoller) ClientConnect() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.clients++
|
|
if p.clients == 1 {
|
|
_ = p.ensureCapturerLocked()
|
|
}
|
|
}
|
|
|
|
// ClientDisconnect closes the capturer when the last client leaves.
|
|
func (p *FBPoller) ClientDisconnect() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.clients--
|
|
if p.clients <= 0 && p.capturer != nil {
|
|
p.capturer.Close()
|
|
p.capturer = nil
|
|
}
|
|
}
|
|
|
|
// Width returns the framebuffer width, doing lazy init if needed.
|
|
func (p *FBPoller) Width() int {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
_ = p.ensureCapturerLocked()
|
|
return p.w
|
|
}
|
|
|
|
// Height returns the framebuffer height, doing lazy init if needed.
|
|
func (p *FBPoller) Height() int {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
_ = p.ensureCapturerLocked()
|
|
return p.h
|
|
}
|
|
|
|
// Capture takes a fresh frame.
|
|
func (p *FBPoller) Capture() (*image.RGBA, error) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if err := p.ensureCapturerLocked(); err != nil {
|
|
return nil, err
|
|
}
|
|
return p.capturer.Capture()
|
|
}
|
|
|
|
// CaptureInto fills dst directly.
|
|
func (p *FBPoller) CaptureInto(dst *image.RGBA) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if err := p.ensureCapturerLocked(); err != nil {
|
|
return err
|
|
}
|
|
return p.capturer.CaptureInto(dst)
|
|
}
|
|
|
|
// Close releases all framebuffer resources.
|
|
func (p *FBPoller) Close() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.capturer != nil {
|
|
p.capturer.Close()
|
|
p.capturer = nil
|
|
}
|
|
}
|
|
|
|
func (p *FBPoller) ensureCapturerLocked() error {
|
|
if p.capturer != nil {
|
|
return nil
|
|
}
|
|
c, err := NewFBCapturer(p.path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.capturer = c
|
|
p.w, p.h = c.Width(), c.Height()
|
|
return nil
|
|
}
|
|
|
|
|
|
var _ ScreenCapturer = (*FBPoller)(nil)
|
|
var _ captureIntoer = (*FBPoller)(nil)
|
|
|
|
// swizzleFB24 handles 24-bit packed framebuffers (B,G,R triplets).
|
|
// Shared between Linux and FreeBSD framebuffer paths.
|
|
func swizzleFB24(dst []byte, dstStride int, src []byte, srcStride, w, h int) {
|
|
for y := 0; y < h; y++ {
|
|
srcRow := src[y*srcStride : y*srcStride+w*3]
|
|
dstRow := dst[y*dstStride:]
|
|
for x := 0; x < w; x++ {
|
|
b := srcRow[x*3+0]
|
|
g := srcRow[x*3+1]
|
|
r := srcRow[x*3+2]
|
|
dstRow[x*4+0] = r
|
|
dstRow[x*4+1] = g
|
|
dstRow[x*4+2] = b
|
|
dstRow[x*4+3] = 0xff
|
|
}
|
|
}
|
|
}
|
|
|
|
// swizzleFB16RGB565 handles 16bpp RGB 565 framebuffers.
|
|
func swizzleFB16RGB565(dst []byte, dstStride int, src []byte, srcStride, w, h int) {
|
|
for y := 0; y < h; y++ {
|
|
srcRow := src[y*srcStride : y*srcStride+w*2]
|
|
dstRow := dst[y*dstStride:]
|
|
for x := 0; x < w; x++ {
|
|
pix := uint16(srcRow[x*2]) | uint16(srcRow[x*2+1])<<8
|
|
r := byte((pix >> 11) & 0x1f)
|
|
g := byte((pix >> 5) & 0x3f)
|
|
b := byte(pix & 0x1f)
|
|
dstRow[x*4+0] = (r << 3) | (r >> 2)
|
|
dstRow[x*4+1] = (g << 2) | (g >> 4)
|
|
dstRow[x*4+2] = (b << 3) | (b >> 2)
|
|
dstRow[x*4+3] = 0xff
|
|
}
|
|
}
|
|
}
|