99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
// Package capture provides screen capture from various sources.
|
|
//
|
|
// Supports capturing from:
|
|
// - Local window (by title or handle)
|
|
// - VM display (VNC, Spice, or VM window on host)
|
|
// - Full screen / monitor region
|
|
//
|
|
// The capture interface is source-agnostic — the engine doesn't care
|
|
// where the frames come from.
|
|
package capture
|
|
|
|
import (
|
|
"image"
|
|
"time"
|
|
)
|
|
|
|
// Region defines a rectangular area to capture.
|
|
type Region struct {
|
|
X, Y, Width, Height int
|
|
}
|
|
|
|
// Source represents a capture source (window, VM, screen, etc.)
|
|
type Source interface {
|
|
// Name returns a human-readable description of the source.
|
|
Name() string
|
|
|
|
// Capture grabs a single frame.
|
|
Capture() (image.Image, error)
|
|
|
|
// CaptureRegion grabs a sub-region of the source.
|
|
CaptureRegion(r Region) (image.Image, error)
|
|
|
|
// Size returns the source dimensions.
|
|
Size() (width, height int)
|
|
|
|
// Close releases resources.
|
|
Close() error
|
|
}
|
|
|
|
// Stats tracks capture performance metrics.
|
|
type Stats struct {
|
|
FrameCount uint64
|
|
AvgCaptureMs float64
|
|
FPS float64
|
|
LastCapture time.Time
|
|
}
|
|
|
|
// Manager handles screen capture with performance tracking.
|
|
type Manager struct {
|
|
source Source
|
|
stats Stats
|
|
}
|
|
|
|
// NewManager creates a capture manager with the given source.
|
|
func NewManager(source Source) *Manager {
|
|
return &Manager{source: source}
|
|
}
|
|
|
|
// Capture grabs a frame and updates performance stats.
|
|
func (m *Manager) Capture() (image.Image, error) {
|
|
start := time.Now()
|
|
frame, err := m.source.Capture()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
elapsed := time.Since(start)
|
|
m.stats.FrameCount++
|
|
m.stats.LastCapture = start
|
|
|
|
// Rolling average
|
|
alpha := 0.1
|
|
ms := float64(elapsed.Microseconds()) / 1000.0
|
|
if m.stats.FrameCount == 1 {
|
|
m.stats.AvgCaptureMs = ms
|
|
} else {
|
|
m.stats.AvgCaptureMs = m.stats.AvgCaptureMs*(1-alpha) + ms*alpha
|
|
}
|
|
if m.stats.AvgCaptureMs > 0 {
|
|
m.stats.FPS = 1000.0 / m.stats.AvgCaptureMs
|
|
}
|
|
|
|
return frame, nil
|
|
}
|
|
|
|
// CaptureRegion grabs a sub-region.
|
|
func (m *Manager) CaptureRegion(r Region) (image.Image, error) {
|
|
return m.source.CaptureRegion(r)
|
|
}
|
|
|
|
// Stats returns current capture performance stats.
|
|
func (m *Manager) Stats() Stats {
|
|
return m.stats
|
|
}
|
|
|
|
// Close releases the capture source.
|
|
func (m *Manager) Close() error {
|
|
return m.source.Close()
|
|
}
|