ffmpeg stuff
This commit is contained in:
parent
68e5d9fc3a
commit
278ccafb11
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,7 +1,6 @@
|
||||
/target
|
||||
/tmp
|
||||
/test.mp4
|
||||
/output.mp4
|
||||
/.vscode
|
||||
|
||||
# CLion
|
||||
**/.idea
|
||||
**/.idea
|
||||
|
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -297,9 +297,9 @@ checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.1"
|
||||
version = "1.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
checksum = "c2806eaa3524762875e21c3dcd057bc4b7bfa01ce4da8d46be1cd43649e1cc6b"
|
||||
|
||||
[[package]]
|
||||
name = "physarum"
|
||||
|
@ -24,7 +24,7 @@ impl ThinGridData {
|
||||
pub fn new_from_grid_vec(in_grids: &[Grid]) -> Vec<Self> {
|
||||
in_grids
|
||||
.iter()
|
||||
.map(|grid| Self::new_from_grid(grid))
|
||||
.map(Self::new_from_grid)
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ mod agent;
|
||||
mod blur;
|
||||
mod buffer;
|
||||
mod grid;
|
||||
mod imgdata; // for storing image data
|
||||
pub mod imgdata; // for storing image data
|
||||
pub mod model;
|
||||
mod palette;
|
||||
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() {
|
||||
// # of iterations to go through
|
||||
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);
|
||||
|
||||
// # 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 n_particles = 1 << 22;
|
||||
let diffusivity = 1;
|
||||
|
||||
// `n_populations` is the # of types of agents
|
||||
// let n_populations = 4;
|
||||
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
|
||||
println!("Rendering all saved image data....");
|
||||
model.render_all_imgdata();
|
||||
// Generate image
|
||||
let grids = ThinGridData::new_from_grid_vec(model.population_grids());
|
||||
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!");
|
||||
}
|
||||
|
119
src/model.rs
119
src/model.rs
@ -1,15 +1,14 @@
|
||||
use crate::{
|
||||
agent::Agent,
|
||||
grid::{combine, Grid},
|
||||
imgdata::{ImgData, ThinGridData},
|
||||
palette::{random_palette, Palette},
|
||||
};
|
||||
|
||||
use indicatif::{ParallelProgressIterator, ProgressBar, ProgressStyle};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
// use rand::Rng;
|
||||
use rand_distr::{Distribution, Normal};
|
||||
use rayon::{iter::ParallelIterator, prelude::*};
|
||||
use std::{path::Path, time::Instant};
|
||||
use std::time::Instant;
|
||||
|
||||
// Top-level simulation class.
|
||||
pub struct Model {
|
||||
@ -28,8 +27,8 @@ pub struct Model {
|
||||
// Color palette
|
||||
palette: Palette,
|
||||
|
||||
// List of ImgData to be processed post-simulation into images
|
||||
img_data_vec: Vec<(usize, ImgData)>,
|
||||
time_per_agent_list: Vec<f64>,
|
||||
time_per_step_list: Vec<f64>,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
@ -89,102 +88,56 @@ impl Model {
|
||||
diffusivity,
|
||||
iteration: 0,
|
||||
palette: random_palette(),
|
||||
img_data_vec: Vec::new(),
|
||||
time_per_agent_list: Vec::new(),
|
||||
time_per_step_list: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Simulates `steps` # of steps
|
||||
#[inline]
|
||||
pub fn step(&mut self) {
|
||||
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) {
|
||||
let pb = ProgressBar::new(steps as u64);
|
||||
pb.set_style(
|
||||
ProgressStyle::default_bar()
|
||||
.template(
|
||||
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta} {percent}%, {per_sec})",
|
||||
)
|
||||
.progress_chars("#>-"),
|
||||
);
|
||||
pb.set_style(ProgressStyle::default_bar()
|
||||
.template("{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();
|
||||
let mut time_per_step_list: Vec<f64> = Vec::new();
|
||||
|
||||
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;
|
||||
for _ in 0..steps {
|
||||
self.step();
|
||||
pb.inc(1);
|
||||
});
|
||||
}
|
||||
pb.finish();
|
||||
|
||||
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 =
|
||||
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!(
|
||||
"Average time per step: {}ms\nAverage time per agent: {}ms",
|
||||
avg_per_step, avg_per_agent
|
||||
);
|
||||
}
|
||||
|
||||
fn save_image_data(&mut self) {
|
||||
let grids = ThinGridData::new_from_grid_vec(&self.population_grids);
|
||||
let img_data = ImgData::new(grids, self.palette);
|
||||
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();
|
||||
}
|
||||
// Accessors for rendering
|
||||
pub fn population_grids(&self) -> &[Grid] {
|
||||
&self.population_grids
|
||||
}
|
||||
|
||||
pub fn render_all_imgdata(&mut self) {
|
||||
if !Path::new("./tmp").exists() {
|
||||
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();
|
||||
});
|
||||
pub fn palette(&self) -> Palette {
|
||||
self.palette
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user