ffmpeg stuff

This commit is contained in:
2025-03-27 13:25:45 -04:00
parent 68e5d9fc3a
commit 278ccafb11
6 changed files with 91 additions and 116 deletions

5
.gitignore vendored
View File

@@ -1,7 +1,6 @@
/target /target
/tmp /output.mp4
/test.mp4
/.vscode /.vscode
# CLion # CLion
**/.idea **/.idea

4
Cargo.lock generated
View File

@@ -297,9 +297,9 @@ checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.21.1" version = "1.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" checksum = "c2806eaa3524762875e21c3dcd057bc4b7bfa01ce4da8d46be1cd43649e1cc6b"
[[package]] [[package]]
name = "physarum" name = "physarum"

View File

@@ -24,7 +24,7 @@ impl ThinGridData {
pub fn new_from_grid_vec(in_grids: &[Grid]) -> Vec<Self> { pub fn new_from_grid_vec(in_grids: &[Grid]) -> Vec<Self> {
in_grids in_grids
.iter() .iter()
.map(|grid| Self::new_from_grid(grid)) .map(Self::new_from_grid)
.collect() .collect()
} }

View File

@@ -2,7 +2,7 @@ mod agent;
mod blur; mod blur;
mod buffer; mod buffer;
mod grid; mod grid;
mod imgdata; // for storing image data pub mod imgdata; // for storing image data
pub mod model; pub mod model;
mod palette; mod palette;
mod util; // for math things mod util; // for math things

View File

@@ -1,38 +1,61 @@
use physarum::model; use physarum::{
imgdata::{ImgData, ThinGridData},
model,
};
use std::io::Write;
fn main() { fn main() {
// # of iterations to go through
let n_iterations = 1024; let n_iterations = 1024;
// let n_iterations = 2048;
// let n_iterations = 1 << 14;
// Size of grid and pictures
// let (width, height) = (256, 256);
// let (width, height) = (512, 512);
let (width, height) = (1024, 1024); let (width, height) = (1024, 1024);
let n_particles = 1 << 22;
// # of agents
// let n_particles = 1 << 10;
// let n_particles = 1 << 16;
// let n_particles = 1 << 20;
let n_particles = 1 << 24;
println!("n_particles: {}", n_particles);
let diffusivity = 1; let diffusivity = 1;
// `n_populations` is the # of types of agents
// let n_populations = 4;
let n_populations = 1; let n_populations = 1;
// let n_populations = 1 + rng.gen_range(1..4); // make # of populations between 2 and 5
let mut model = model::Model::new(width, height, n_particles, n_populations, diffusivity); // Create the model let mut model = model::Model::new(width, height, n_particles, n_populations, diffusivity);
model.print_configurations();
model.print_configurations(); // Print config for model // Setup ffmpeg
let mut ffmpeg = std::process::Command::new("ffmpeg")
.args(&[
"-y",
"-f",
"rawvideo",
"-pix_fmt",
"rgb24",
"-s",
&format!("{}x{}", width, height),
"-r",
"30",
"-i",
"-",
"-c:v",
"libx264",
"-preset",
"fast",
"-crf",
"23",
"output.mp4",
])
.stdin(std::process::Stdio::piped())
.spawn()
.expect("Failed to start ffmpeg");
let mut stdin = ffmpeg.stdin.take().unwrap();
model.run(n_iterations); // Actually run the model for _ in 0..n_iterations {
model.step();
// export saved image data // Generate image
println!("Rendering all saved image data...."); let grids = ThinGridData::new_from_grid_vec(model.population_grids());
model.render_all_imgdata(); let img_data = ImgData::new(grids, model.palette());
let img = img_data.to_image();
let raw_data = img.into_raw();
// Write to ffmpeg
stdin.write_all(&raw_data).unwrap();
}
// Cleanup
drop(stdin);
ffmpeg.wait().unwrap();
println!("Done!"); println!("Done!");
} }

View File

@@ -1,15 +1,14 @@
use crate::{ use crate::{
agent::Agent, agent::Agent,
grid::{combine, Grid}, grid::{combine, Grid},
imgdata::{ImgData, ThinGridData},
palette::{random_palette, Palette}, palette::{random_palette, Palette},
}; };
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
// use rand::Rng; // use rand::Rng;
use rand_distr::{Distribution, Normal}; use rand_distr::{Distribution, Normal};
use rayon::{iter::ParallelIterator, prelude::*}; use rayon::{iter::ParallelIterator, prelude::*};
use std::{path::Path, time::Instant}; use std::time::Instant;
// Top-level simulation class. // Top-level simulation class.
pub struct Model { pub struct Model {
@@ -28,8 +27,8 @@ pub struct Model {
// Color palette // Color palette
palette: Palette, palette: Palette,
// List of ImgData to be processed post-simulation into images time_per_agent_list: Vec<f64>,
img_data_vec: Vec<(usize, ImgData)>, time_per_step_list: Vec<f64>,
} }
impl Model { impl Model {
@@ -89,102 +88,56 @@ impl Model {
diffusivity, diffusivity,
iteration: 0, iteration: 0,
palette: random_palette(), palette: random_palette(),
img_data_vec: Vec::new(), time_per_agent_list: Vec::new(),
time_per_step_list: Vec::new(),
} }
} }
// Simulates `steps` # of steps pub fn step(&mut self) {
#[inline] combine(&mut self.population_grids, &self.attraction_table);
let agents_tick_time = Instant::now();
self.population_grids.par_iter_mut().for_each(|grid| {
grid.tick();
grid.diffuse(self.diffusivity);
});
let agents_tick_elapsed = agents_tick_time.elapsed().as_millis() as f64;
let agents_num: usize = self.population_grids.iter().map(|g| g.agents.len()).sum();
let ms_per_agent = agents_tick_elapsed / agents_num as f64;
self.time_per_agent_list.push(ms_per_agent);
self.time_per_step_list.push(agents_tick_elapsed);
self.iteration += 1;
}
pub fn run(&mut self, steps: usize) { pub fn run(&mut self, steps: usize) {
let pb = ProgressBar::new(steps as u64); let pb = ProgressBar::new(steps as u64);
pb.set_style( pb.set_style(ProgressStyle::default_bar()
ProgressStyle::default_bar() .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta} {percent}%, {per_sec})")
.template( .progress_chars("#>-"));
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta} {percent}%, {per_sec})",
)
.progress_chars("#>-"),
);
let mut time_per_agent_list: Vec<f64> = Vec::new(); for _ in 0..steps {
let mut time_per_step_list: Vec<f64> = Vec::new(); self.step();
let agents_num: usize = self
.population_grids
.iter()
.map(|grid| grid.agents.len())
.sum();
(0..steps).for_each(|_| {
// Combine grids
combine(&mut self.population_grids, &self.attraction_table);
let agents_tick_time = Instant::now();
// Tick agents
self.population_grids.par_iter_mut().for_each(|grid| {
grid.tick();
grid.diffuse(self.diffusivity); // Diffuse + Decay
});
self.save_image_data();
let agents_tick_elapsed: f64 = agents_tick_time.elapsed().as_millis() as f64;
let ms_per_agent: f64 = agents_tick_elapsed / (agents_num as f64);
time_per_agent_list.push(ms_per_agent);
time_per_step_list.push(agents_tick_elapsed);
self.iteration += 1;
pb.inc(1); pb.inc(1);
}); }
pb.finish(); pb.finish();
let avg_per_step: f64 = let avg_per_step: f64 =
time_per_step_list.iter().sum::<f64>() / time_per_step_list.len() as f64; self.time_per_step_list.iter().sum::<f64>() / self.time_per_step_list.len() as f64;
let avg_per_agent: f64 = let avg_per_agent: f64 =
time_per_agent_list.iter().sum::<f64>() / time_per_agent_list.len() as f64; self.time_per_agent_list.iter().sum::<f64>() / self.time_per_agent_list.len() as f64;
println!( println!(
"Average time per step: {}ms\nAverage time per agent: {}ms", "Average time per step: {}ms\nAverage time per agent: {}ms",
avg_per_step, avg_per_agent avg_per_step, avg_per_agent
); );
} }
fn save_image_data(&mut self) { // Accessors for rendering
let grids = ThinGridData::new_from_grid_vec(&self.population_grids); pub fn population_grids(&self) -> &[Grid] {
let img_data = ImgData::new(grids, self.palette); &self.population_grids
self.img_data_vec.push((self.iteration + 1, img_data));
let size: usize = std::mem::size_of_val(&self.img_data_vec);
let mb = size / 1024 / 1024;
// println!("{} B | {} KB | {} MB", size, size/1024, size/1024/1024);
let max_mb = 6000;
if mb >= max_mb {
println!(
"ram usage is over {} MB (and len of {}), flushing to disk\n",
max_mb,
self.img_data_vec.len()
);
self.render_all_imgdata();
}
} }
pub fn render_all_imgdata(&mut self) { pub fn palette(&self) -> Palette {
if !Path::new("./tmp").exists() { self.palette
std::fs::create_dir("./tmp").expect("could create directory");
}
let pb = ProgressBar::new(self.img_data_vec.len() as u64);
pb.set_style(ProgressStyle::default_bar().template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] ({pos}/{len}, {percent}%, {per_sec})",
));
self.img_data_vec
.drain(..)
.collect::<Vec<_>>()
.par_iter()
.progress_with(pb)
.for_each(|(i, img)| {
img.to_image()
.save(format!("./tmp/out_{}.png", i).as_str())
.unwrap();
});
} }
} }