ffmpeg stuff
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
/target
|
/target
|
||||||
/tmp
|
/output.mp4
|
||||||
/test.mp4
|
|
||||||
/.vscode
|
/.vscode
|
||||||
|
|
||||||
# CLion
|
# CLion
|
||||||
**/.idea
|
**/.idea
|
||||||
|
|||||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
75
src/main.rs
75
src/main.rs
@@ -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!");
|
||||||
}
|
}
|
||||||
|
|||||||
119
src/model.rs
119
src/model.rs
@@ -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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user