//! 编码基准:1080p 噪声帧(最恶劣压缩工况)对比单线程与 4 线程 openh264。 //! 运行:cargo run --release -p agent --bin encbench use openh264::encoder::{ BitRate, Encoder, EncoderConfig, FrameRate, IntraFramePeriod, RateControlMode, UsageType, }; use openh264::formats::{BgraSliceU8, YUVBuffer}; use openh264::OpenH264API; use std::time::Instant; fn bench(threads: u16, frames: usize) -> f64 { let mut enc = Encoder::with_api_config( OpenH264API::from_source(), EncoderConfig::new() .bitrate(BitRate::from_bps(5_000_000)) .max_frame_rate(FrameRate::from_hz(30.0)) .rate_control_mode(RateControlMode::Bitrate) .usage_type(UsageType::ScreenContentRealTime) .intra_frame_period(IntraFramePeriod::from_num_frames(300)) .num_threads(threads), ) .expect("encoder"); // 预生成 10 张不同噪声帧轮换(保证每帧 P 帧都真实编码,避免运动估计空转) let mut frames_in = Vec::with_capacity(10); for f in 0..10u32 { let mut frame = vec![0u8; 1920 * 1080 * 4]; let mut seed = 12345u32.wrapping_add(f * 7919); for px in frame.chunks_exact_mut(4) { seed = seed.wrapping_mul(1103515245).wrapping_add(12345); px.copy_from_slice(&seed.to_le_bytes()); } frames_in.push(YUVBuffer::from_bgra8_source(BgraSliceU8::new(&frame, (1920, 1080)))); } // 预热 5 帧(首帧 IDR、线程池初始化) for (i, y) in frames_in.iter().enumerate().take(5) { let _ = enc.encode(y).unwrap_or_else(|_| panic!("frame {i}")); } let t = Instant::now(); for (i, y) in frames_in.iter().cycle().take(frames).enumerate() { let _ = enc.encode(y).unwrap_or_else(|_| panic!("frame {i}")); } t.elapsed().as_millis() as f64 / frames as f64 } fn main() { println!("1080p 噪声帧编码基准(含 BGRA→YUV 转换)"); let t = Instant::now(); let _ = YUVBuffer::from_bgra8_source(BgraSliceU8::new( &vec![7u8; 1920 * 1080 * 4], (1920, 1080), )); println!("BGRA→YUV 转换: {}ms/帧", t.elapsed().as_millis()); let s = bench(1, 20); println!("单线程: {s:.1}ms/帧 → {}fps", (1000.0 / s) as u32); let m = bench(4, 20); println!("4 线程: {m:.1}ms/帧 → {}fps", (1000.0 / m) as u32); }