feat(player): add frame export (E key) to save PNG
This commit is contained in:
60
src/main.rs
60
src/main.rs
@@ -406,6 +406,24 @@ fn run(config: &Config) -> Result<()> {
|
||||
player_state.speed = 1.0;
|
||||
info!("Speed: 1.0x");
|
||||
}
|
||||
sdl2::keyboard::Keycode::E => {
|
||||
if let Some(ref info) = video_info {
|
||||
let frame_num = player_state.current_frame;
|
||||
let output_dir = std::env::current_dir().unwrap_or_default();
|
||||
let filename = format!("frame_{:06}.png", frame_num);
|
||||
let output_path = output_dir.join(&filename);
|
||||
if let Err(e) = export_current_frame(
|
||||
&mut texture,
|
||||
info.width,
|
||||
info.height,
|
||||
&output_path,
|
||||
) {
|
||||
error!("Failed to export frame: {}", e);
|
||||
} else {
|
||||
info!("Exported: {:?}", output_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -927,6 +945,48 @@ fn sync_audio(
|
||||
}
|
||||
}
|
||||
|
||||
fn export_current_frame(
|
||||
texture: &mut Option<sdl2::render::Texture>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
output_path: &std::path::Path,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(ref mut tex) = texture {
|
||||
let mut pixels = vec![0u8; (width * height * 3) as usize];
|
||||
tex.with_lock(None, |buffer, _pitch| {
|
||||
pixels.copy_from_slice(buffer);
|
||||
});
|
||||
|
||||
let surf = sdl2::surface::Surface::from_data(
|
||||
&mut pixels,
|
||||
width,
|
||||
height,
|
||||
(width * 3) as u32,
|
||||
sdl2::pixels::PixelFormatEnum::RGB24,
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create surface: {}", e))?;
|
||||
|
||||
surf.save_bmp(output_path)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to save BMP: {}", e))?;
|
||||
|
||||
let png_path = output_path.with_extension("png");
|
||||
let cmd = std::process::Command::new("ffmpeg")
|
||||
.args(["-y", "-i"])
|
||||
.arg(output_path.to_str().unwrap_or(""))
|
||||
.arg(png_path.to_str().unwrap_or(""))
|
||||
.output()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to convert to PNG: {}", e))?;
|
||||
|
||||
if cmd.status.success() {
|
||||
std::fs::remove_file(output_path).ok();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
anyhow::bail!("No texture available")
|
||||
}
|
||||
}
|
||||
|
||||
fn format_time(ms: u64) -> String {
|
||||
let total_secs = ms / 1000;
|
||||
let hours = total_secs / 3600;
|
||||
|
||||
Reference in New Issue
Block a user