aether_renderer_core/ffmpeg/
gif.rs1use std::fs;
2use std::process::Command;
3
4pub fn render_gif(
6 input_pattern: &str,
7 output: &str,
8 fps: u32,
9 fade_filter: Option<&str>,
10) -> Result<(), String> {
11 let palette_path = "palette.png";
12
13 let mut palette_args: Vec<String> = Vec::new();
14 if input_pattern.contains('*') {
15 palette_args.push("-pattern_type".into());
16 palette_args.push("glob".into());
17 }
18 palette_args.push("-i".into());
19 palette_args.push(input_pattern.into());
20 palette_args.push("-vf".into());
21 palette_args.push("fps=30,scale=640:-1:flags=lanczos,palettegen".into());
22 palette_args.push("-y".into());
23 palette_args.push(palette_path.into());
24
25 let palette_status = match Command::new("ffmpeg").args(&palette_args).status() {
26 Ok(s) => s,
27 Err(e) => {
28 if e.kind() == std::io::ErrorKind::NotFound {
29 return Err(
30 "❌ ffmpeg not found. Please install ffmpeg and ensure it is in your PATH."
31 .into(),
32 );
33 } else {
34 return Err(format!("❌ Failed to execute ffmpeg: {}", e));
35 }
36 }
37 };
38
39 if !palette_status.success() {
40 return Err("❌ Failed to generate palette".into());
41 }
42
43 let mut gif_filter = String::from("fps=30,scale=640:-1:flags=lanczos");
44 if let Some(filter) = fade_filter {
45 if !filter.is_empty() {
46 gif_filter.push(',');
47 gif_filter.push_str(filter);
48 }
49 }
50 let mut gif_args: Vec<String> = vec!["-framerate".into(), fps.to_string()];
51 if input_pattern.contains('*') {
52 gif_args.push("-pattern_type".into());
53 gif_args.push("glob".into());
54 }
55 gif_args.push("-i".into());
56 gif_args.push(input_pattern.into());
57 gif_args.push("-i".into());
58 gif_args.push(palette_path.into());
59 gif_args.push("-lavfi".into());
60 gif_args.push(format!("{} [x]; [x][1:v] paletteuse", gif_filter));
61 gif_args.push("-y".into());
62 gif_args.push(output.into());
63
64 let gif_status = match Command::new("ffmpeg").args(&gif_args).status() {
65 Ok(s) => s,
66 Err(e) => {
67 if e.kind() == std::io::ErrorKind::NotFound {
68 return Err(
69 "❌ ffmpeg not found. Please install ffmpeg and ensure it is in your PATH."
70 .into(),
71 );
72 } else {
73 return Err(format!("❌ Failed to execute ffmpeg: {}", e));
74 }
75 }
76 };
77
78 fs::remove_file(palette_path)
79 .unwrap_or_else(|e| eprintln!("⚠️ Failed to remove palette file: {}", e));
80
81 if gif_status.success() {
82 println!("✅ GIF exported: {}", output);
83 Ok(())
84 } else {
85 Err("❌ Failed to export GIF".into())
86 }
87}