diff --git a/src/state_portal.rs b/src/state_portal.rs index fad2075..15eb327 100644 --- a/src/state_portal.rs +++ b/src/state_portal.rs @@ -198,9 +198,13 @@ impl StatePortal { enc_height, self.args.fps, ); - // 码率:未指定时按分辨率 × 帧率动态计算 + // 码率:WebRTC 模式用保守默认(BWE 连接后立即覆盖),MP4 用公式 let actual_bitrate = self.args.bitrate.unwrap_or_else(|| { - 5 * (enc_width as u64) * (enc_height as u64) * (self.args.fps as u64) / 100 + if self.webrtc.is_some() { + webrtc_startup_bitrate_bps(enc_width, enc_height) + } else { + 5 * (enc_width as u64) * (enc_height as u64) * (self.args.fps as u64) / 100 + } }); // GOP 大小:WebRTC 模式使用较大的 GOP(fps*2,最低20),MP4 模式使用 fps let actual_gop_size = self.args.gop_size.unwrap_or_else(|| { @@ -848,6 +852,22 @@ fn resolution_bitrate_bps(width: u32, height: u32, fps: u32) -> u64 { 5 * u64::from(width) * u64::from(height) * u64::from(fps) / 100 } +/// Conservative startup bitrate for WebRTC mode, tier-based by total pixel count. +/// BWE estimate arrives within milliseconds of client connect and overrides this; +/// the startup value only affects the first IDR. See issue #21. +fn webrtc_startup_bitrate_bps(width: u32, height: u32) -> u64 { + let pixels = u64::from(width) * u64::from(height); + if pixels <= 1_000_000 { + 1_000_000 + } else if pixels <= 2_500_000 { + 2_000_000 + } else if pixels <= 4_500_000 { + 4_000_000 + } else { + 8_000_000 + } +} + /// Select resolution tier based on BWE estimate. /// Returns (width, height) for the selected tier. fn select_resolution(current_w: u32, current_h: u32, bwe_bps: u64, fps: u32) -> (u32, u32) { @@ -1026,6 +1046,14 @@ mod tests { assert_eq!(result, None); } + #[test] + fn webrtc_startup_bitrate_tiers_by_pixel_count() { + assert_eq!(webrtc_startup_bitrate_bps(1280, 720), 1_000_000); + assert_eq!(webrtc_startup_bitrate_bps(1920, 1080), 2_000_000); + assert_eq!(webrtc_startup_bitrate_bps(2560, 1440), 4_000_000); + assert_eq!(webrtc_startup_bitrate_bps(3840, 2160), 8_000_000); + } + #[test] fn select_resolution_downscales_one_tier_below_sixty_percent() { let fps = 30;