feat: screen capture scaling / downsampling
Add a Scale option (1.0 native, 0.5 half, etc.) that downsamples the captured BGRA frame with bilinear interpolation before JPEG encoding. Config carries the scale factor; the GUI exposes a Scale dropdown (100%/75%/50%/25%) that applies live via SetConfig. Verified: OBS displays the image at the reduced resolution matching the selected scale, without restarting the stream.
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"teleportfling/internal/capture"
|
||||
)
|
||||
|
||||
// TestEnginePatternStartStop runs the engine with the synthetic pattern source
|
||||
@@ -186,6 +188,59 @@ func TestFormatBitrate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestScaleBGRA verifies downsampling produces the expected dimensions and
|
||||
// preserves the dominant colour of a solid frame.
|
||||
func TestScaleBGRA(t *testing.T) {
|
||||
src := &capture.VideoFrame{
|
||||
Pix: make([]byte, 100*80*4),
|
||||
Width: 100,
|
||||
Height: 80,
|
||||
Stride: 100 * 4,
|
||||
}
|
||||
// Fill with solid red (BGRA: B=0, G=0, R=255).
|
||||
for i := 0; i+4 <= len(src.Pix); i += 4 {
|
||||
src.Pix[i], src.Pix[i+1], src.Pix[i+2], src.Pix[i+3] = 0, 0, 255, 255
|
||||
}
|
||||
|
||||
dst := &capture.VideoFrame{
|
||||
Pix: make([]byte, 50*40*4),
|
||||
Width: 50,
|
||||
Height: 40,
|
||||
Stride: 50 * 4,
|
||||
}
|
||||
scaleBGRA(src, dst)
|
||||
|
||||
if dst.Width != 50 || dst.Height != 40 {
|
||||
t.Errorf("dst dims = %dx%d, want 50x40", dst.Width, dst.Height)
|
||||
}
|
||||
// Check a few pixels are solid red.
|
||||
for _, idx := range []int{0, 4, 100, 200} {
|
||||
if dst.Pix[idx] != 0 || dst.Pix[idx+1] != 0 || dst.Pix[idx+2] != 255 {
|
||||
t.Errorf("pixel %d not red: B=%d G=%d R=%d", idx, dst.Pix[idx], dst.Pix[idx+1], dst.Pix[idx+2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestEngineScalePreservesNative verifies scaleFrame returns the original
|
||||
// frame at scale 1.0.
|
||||
func TestEngineScalePreservesNative(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
cfg.Source = "pattern"
|
||||
cfg.Port = 19760
|
||||
eng, err := New(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("New: %v", err)
|
||||
}
|
||||
|
||||
frame := &capture.VideoFrame{Pix: make([]byte, 4*4*4), Width: 4, Height: 4, Stride: 16}
|
||||
if got := eng.scaleFrame(frame, 1.0); got != frame {
|
||||
t.Error("scale 1.0 should return the original frame")
|
||||
}
|
||||
if got := eng.scaleFrame(frame, 0.5); got == frame {
|
||||
t.Error("scale 0.5 should return a new frame")
|
||||
}
|
||||
}
|
||||
|
||||
func itoa(v int) string {
|
||||
if v == 0 {
|
||||
return "0"
|
||||
|
||||
Reference in New Issue
Block a user