use std::path::Path; use crate::stats::{FrameStats, PipelineMode}; pub(crate) fn output_for_mode(base: &str, mode: PipelineMode, split: bool) -> String { if !split || base.contains("null") { return base.to_string(); } let path = Path::new(base); let suffix = match mode { PipelineMode::Cpu => "cpu", PipelineMode::Gpu => "gpu", PipelineMode::Both => unreachable!(), }; let file_name = path.file_name().and_then(|s| s.to_str()).unwrap_or(base); let split_name = if let Some((stem, ext)) = file_name.rsplit_once('.') { format!("{stem}.{suffix}.{ext}") } else { format!("{file_name}.{suffix}") }; path.with_file_name(split_name) .to_string_lossy() .into_owned() } pub(crate) fn print_detailed_results( label: &str, stats: &FrameStats, src_width: u32, src_height: u32, enc_width: u32, enc_height: u32, ) { println!(); println!("=== {label} Pipeline Results ==="); println!("Capture resolution: {}x{}", src_width, src_height); println!("Encode resolution: {}x{}", enc_width, enc_height); println!("Frames encoded: {}", stats.frames_encoded); println!("Total time: {:.2}s", stats.elapsed_secs); println!("Output: {}", stats.output_path); if stats.import_failures > 0 { println!("Import failures: {}", stats.import_failures); } println!( "import avg: {:.2} ms/frame", FrameStats::avg_ms(&stats.import_us) ); if !stats.filter_us.is_empty() { println!( "filter avg: {:.2} ms/frame", FrameStats::avg_ms(&stats.filter_us) ); } println!( "transfer avg: {:.2} ms/frame", FrameStats::avg_ms(&stats.transfer_us) ); if !stats.scale_us.is_empty() { println!( "scale avg: {:.2} ms/frame", FrameStats::avg_ms(&stats.scale_us) ); } if !stats.format_us.is_empty() { println!( "format avg: {:.2} ms/frame", FrameStats::avg_ms(&stats.format_us) ); } println!( "encode ({}): {:.2} ms/frame", stats.codec_name, FrameStats::avg_ms(&stats.encode_us) ); println!("total avg: {:.2} ms/frame", stats.avg_total_ms()); println!("achieved FPS: {:.1}", stats.achieved_fps()); println!("max theoretical: {:.1} FPS", stats.theoretical_fps()); } pub(crate) fn print_comparison(cpu: Option<&FrameStats>, gpu: Option<&FrameStats>) { println!(); println!("=== Pipeline Comparison ==="); if let Some(s) = cpu { println!( "CPU: import={:.2}ms transfer={:.2}ms scale={:.2}ms encode={:.2}ms total={:.2}ms ({:.1} FPS)", FrameStats::avg_ms(&s.import_us), FrameStats::avg_ms(&s.transfer_us), FrameStats::avg_ms(&s.scale_us), FrameStats::avg_ms(&s.encode_us), s.avg_total_ms(), s.theoretical_fps(), ); } if let Some(s) = gpu { println!( "GPU: import={:.2}ms filter={:.2}ms transfer={:.2}ms format={:.2}ms encode={:.2}ms total={:.2}ms ({:.1} FPS)", FrameStats::avg_ms(&s.import_us), FrameStats::avg_ms(&s.filter_us), FrameStats::avg_ms(&s.transfer_us), FrameStats::avg_ms(&s.format_us), FrameStats::avg_ms(&s.encode_us), s.avg_total_ms(), s.theoretical_fps(), ); } }