dailz
|
caccfec44e
|
fix(portal): compositor stall detection + filler frames + PipeWire state logging
P0: Detect compositor frame delivery stalls (>100ms no frames) and log
stall/resume events with duration. Rate-limited to 1 warn/sec.
P1: Insert duplicate raw CpuNv12Frame filler during stalls at target fps.
Keeps WebRTC stream smooth (sent_fps 20-40 instead of 3-5 during
compositor pauses). Stops after 2s max stale. WebRTC mode only.
P2: Replace silent _ => {} in PipeWire state_changed callback with
explicit Paused/Streaming/Connecting log messages.
P4: Add PwCtrlEvent::FormatChanged for mid-stream dimension changes.
param_changed detects resolution renegotiation (skips first call).
Logs warning in poll_and_encode; full encoder reinit deferred.
Verified: cargo check 0 errors, 70/70 tests, release build, --stats live.
|
2026-06-07 17:20:54 +08:00 |
|
dailz
|
826f544569
|
feat(portal): async encode pipeline - decouple capture from encoding
Split synchronous encode pipeline so sws_scale + libx264 runs on a
dedicated thread, leaving only VAAPI import + GPU scale + GPU→CPU
transfer on the main capture thread.
Problem: encode_p95 occasionally hit 74ms, blocking the entire capture
pipeline and causing capture_gap_max=356ms stutter.
Solution:
- avhw.rs: Split SwEncState into SwEncImport (main thread: VAAPI import,
filter_graph scale, GPU→CPU transfer) and SwEncEncode (encode thread:
sws_scale NV12→YUV420P, libx264 encode). New CpuNv12Frame struct
carries owned pixel data across threads via crossbeam channel.
SwEncState wraps both for backward compat (MP4/sync path untouched).
- state_portal.rs: WebRTC portal path spawns 'wl-webrtc-encode' thread
with bounded(2) input channel (drop-newest backpressure) and separate
timing channel. Graceful shutdown: drop webrtc_rx → drop input_tx →
join encode thread → flush sync encoder.
- stats.rs: Add record_import() + record_encode_thread() for async timing.
Results: encode_p95 stable at 2.9-4.2ms (was 11-74ms), capture_fps
stable 59-60fps, cap_gap_p95 17-19ms. Remaining capture stalls traced
to PipeWire compositor frame delivery (external, not our code).
|
2026-06-07 16:55:28 +08:00 |
|
dailz
|
46367ef6b5
|
fix(state): add WebRTC support to wlr-screencopy backend
Fixes #1 -- --port mode with wlr-screencopy backend caused panic at
negotiate_format() because self.args.output is None and .expect() was
called unconditionally.
Changes:
- Introduce StreamingEncoder enum wrapping EncState (MP4) and
SwEncState (WebRTC) with unified frames_rgb/encode_frame/flush API
- Add WebRTC fields to State<S> (webrtc, webrtc_tx, webrtc_rx,
webrtc_frames_sent) matching Portal backend pattern
- State::new() returns Result<Self> for clean WebRtcState init failure
- negotiate_format() branches on webrtc_tx: WebRTC path uses
SwEncState::new_webrtc(), MP4 path unchanged (hardware VAAPI)
- Add poll_webrtc() method to drive signaling + channel drain
- Event loop calls poll_webrtc() each iteration
- Fix pre-existing test/bench Args construction (Option<String> output,
missing no_persist field)
|
2026-06-04 22:10:46 +08:00 |
|
dailz
|
d80b34f44f
|
feat: GPU-downscale + software H.264 encode pipeline (WIP)
Add SwEncState in avhw.rs: GPU pipeline using scale_vaapi to downscale
4K BGRA -> 2K NV12 on AMD iGPU, then software encode with libopenh264.
- import_dma_buf_to_vaapi: av_hwframe_map based DMA-BUF import
- SwEncState: GPU filter graph (scale_vaapi) + NV12->YUV420P + libopenh264
- state_portal.rs: integrated SwEncState, auto DRM device detection
- vaapi_import_bench.rs: CPU vs GPU pipeline benchmark
- sw_encode_bench.rs: software encode benchmark
Benchmark results: GPU pipeline ~91 FPS theoretical (10.95ms/frame)
vs CPU pipeline ~33 FPS (30.21ms/frame).
Known issue: only 1 frame encoded in production recording,
diagnostic STATS logging added to debug frame flow.
|
2026-05-29 22:04:12 +08:00 |
|