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;
|
player_state.speed = 1.0;
|
||||||
info!("Speed: 1.0x");
|
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 {
|
fn format_time(ms: u64) -> String {
|
||||||
let total_secs = ms / 1000;
|
let total_secs = ms / 1000;
|
||||||
let hours = total_secs / 3600;
|
let hours = total_secs / 3600;
|
||||||
|
|||||||
Reference in New Issue
Block a user