feat(portal): BWE-driven resolution adaptation + duplicate frame skipping
WebRTC client bandwidth estimate now drives both encoder bitrate and resolution tier selection, replacing the previous static-target encoder. - webrtc.rs: enable str0m BWE (seeded at 5 Mbps), surface EgressBitrateEstimate + KeyframeRequest events, expose get_bwe_estimate() / set_need_keyframe() - state_portal.rs: wire bitrate/resolution channels between the WebRTC thread and the encode thread; tier ladder [1440p, 1080p, 720p] with downscale at 60% budget and upscale hysteresis (120% sustained 10s) - avhw.rs: SwEncImport::poll_resolution_commands() rebuilds the import filter graph on UpdateResolution; SwEncEncode::recreate_encoder() rebuilds sws/enc_video/yuv_frame atomically; hash_sampled_y_plane() skips duplicate frames; VBV x264opts cap IDR bursts; H.264 level 4.0 (muxer) / 4.2 (WebRTC) - state.rs: sync wlr-screencopy GOP to fps*2 max 20 for parity - fix: drain bitrate_rx + resolution_rx BEFORE the stride check in encode_cpu_frame() so the new (smaller-stride) frame produced after a resolution change does not hit the stale (larger) enc_width and crash the encode thread - WebRTC GOP widened to fps*2 max 20 (was fps/2 max 10)
This commit is contained in:
+19
-11
@@ -15,9 +15,9 @@ mod backend_detect; // 截屏后端自动检测(wlroots vs Portal/PipeWire)
|
||||
mod cap_portal; // XDG Portal 屏幕捕获
|
||||
mod cap_wlr_screencopy; // wlroots wlr-screencopy 截屏协议
|
||||
mod fps_limit; // 帧率限制器
|
||||
mod stats; // 管道性能统计(卡顿诊断)
|
||||
mod state; // wlr-screencopy 后端的主状态机
|
||||
mod state_portal; // Portal/PipeWire 后端的主状态机
|
||||
mod stats; // 管道性能统计(卡顿诊断)
|
||||
mod transform; // 图像变换(旋转/翻转)
|
||||
mod webrtc; // WebRTC 传输(str0m Sans-IO)
|
||||
|
||||
@@ -46,21 +46,27 @@ fn main() -> Result<()> {
|
||||
|
||||
// 根据 verbose 模式或 RUST_LOG 环境变量设置日志级别
|
||||
// 支持 RUST_LOG 粒度控制(如 RUST_LOG=wl_webrtc::webrtc=trace)
|
||||
let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| {
|
||||
if args.verbose {
|
||||
tracing_subscriber::EnvFilter::new("debug")
|
||||
} else {
|
||||
tracing_subscriber::EnvFilter::new("info")
|
||||
}
|
||||
});
|
||||
let env_filter = tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||
if args.verbose {
|
||||
tracing_subscriber::EnvFilter::new("debug")
|
||||
} else {
|
||||
tracing_subscriber::EnvFilter::new("info")
|
||||
}
|
||||
});
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(env_filter)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
|
||||
tracing::info!("wl-webrtc starting");
|
||||
tracing::debug!("Args: output={:?} fps={} codec={} port={} verbose={}", args.output, args.fps, args.codec, args.port, args.verbose);
|
||||
tracing::debug!(
|
||||
"Args: output={:?} fps={} codec={} port={} verbose={}",
|
||||
args.output,
|
||||
args.fps,
|
||||
args.codec,
|
||||
args.port,
|
||||
args.verbose
|
||||
);
|
||||
|
||||
// MVP 阶段仅支持 H.264 编码,不支持 HEVC
|
||||
if args.codec != "h264" {
|
||||
@@ -352,7 +358,9 @@ fn run_portal_pipewire(args: Args) -> Result<()> {
|
||||
|
||||
// Portal 状态机遇到致命错误时退出
|
||||
if state.is_errored() {
|
||||
tracing::error!("Fatal error in portal state machine (check preceding error logs), exiting");
|
||||
tracing::error!(
|
||||
"Fatal error in portal state machine (check preceding error logs), exiting"
|
||||
);
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user