feat: add PipeWire screen and system audio capture (M2)
Capture the Wayland desktop via xdg-desktop-portal + PipeWire using go2tv.app/screencast (MIT), and stream it to OBS: - internal/capture: Capture/FrameSource/AudioSource interfaces and the PipeWire backend (BGRA frames at monitor resolution, S16 48 kHz stereo system audio) - protocol: EncodeBGRA fast path producing 4:2:0 YCbCr JPEGs - cmd: --source screen|pattern, --audio, --stream-index flags; real capture feeds the existing sender - share one wall-clock reference between the audio and video loops so OBS receives aligned A/V timestamps (avoids multi-second latency) Verified end-to-end: real desktop at 30 fps renders in OBS with sub-second latency.
This commit is contained in:
@@ -120,3 +120,54 @@ func TestJPEGEncodeQualityClamp(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestJPEGEncodeBGRA checks the raw-BGRA fast path produces a decodable
|
||||
// JPEG with correct SOI/EOI markers.
|
||||
func TestJPEGEncodeBGRA(t *testing.T) {
|
||||
enc, err := NewJPEGEncoder()
|
||||
if err != nil {
|
||||
t.Fatalf("NewJPEGEncoder: %v", err)
|
||||
}
|
||||
defer enc.Close()
|
||||
|
||||
// 16x8 BGRA: top half red (R,G,B=255,0,0), bottom half blue (0,0,255).
|
||||
w, h := 16, 8
|
||||
pix := make([]byte, w*h*4)
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
off := (y*w + x) * 4
|
||||
if y < h/2 {
|
||||
pix[off], pix[off+1], pix[off+2], pix[off+3] = 0, 0, 255, 255 // B,G,R,A = blue,red
|
||||
} else {
|
||||
pix[off], pix[off+1], pix[off+2], pix[off+3] = 255, 0, 0, 255 // B,G,R,A = red,blue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf, err := enc.EncodeBGRA(pix, w, h, 85)
|
||||
if err != nil {
|
||||
t.Fatalf("EncodeBGRA: %v", err)
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
t.Fatal("empty JPEG output")
|
||||
}
|
||||
if !bytes.Equal(buf[:2], []byte{0xFF, 0xD8}) {
|
||||
t.Errorf("bad JPEG SOI marker: %x", buf[:2])
|
||||
}
|
||||
if !bytes.Equal(buf[len(buf)-2:], []byte{0xFF, 0xD9}) {
|
||||
t.Errorf("bad JPEG EOI marker")
|
||||
}
|
||||
}
|
||||
|
||||
// TestJPEGEncodeBGRAShort rejects truncated pixel buffers.
|
||||
func TestJPEGEncodeBGRAShort(t *testing.T) {
|
||||
enc, err := NewJPEGEncoder()
|
||||
if err != nil {
|
||||
t.Fatalf("NewJPEGEncoder: %v", err)
|
||||
}
|
||||
defer enc.Close()
|
||||
|
||||
if _, err := enc.EncodeBGRA(make([]byte, 10), 16, 8, 80); err == nil {
|
||||
t.Error("short BGRA buffer accepted")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user