feat: add periodic image saving
This commit is contained in:
parent
6da19152ca
commit
0502f3dacb
6 changed files with 1085 additions and 6 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
.direnv/
|
||||
recordings/
|
||||
|
|
|
|||
1030
Cargo.lock
generated
1030
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,6 +7,8 @@ edition = "2021"
|
|||
async-trait = "0.1.83"
|
||||
atoi_radix10 = "0.0.1"
|
||||
bytes = "1.6.0"
|
||||
chrono = "0.4.38"
|
||||
image = "0.25.2"
|
||||
tokio = { version = "1.38", features = ["full"] }
|
||||
tokio-test = "*"
|
||||
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@ To set a pixel using RGB, use ({SET_PX_RGB_BIN:02X}) (u8 canvas) (x as u16_le) (
|
|||
writer.write_all(help_text.as_bytes()).await
|
||||
}
|
||||
Response::Size(x, y) => {
|
||||
writer.write_u16_le(x).await?;
|
||||
writer.write_u16_le(y).await
|
||||
writer.write_u16(x).await?;
|
||||
writer.write_u16(y).await
|
||||
}
|
||||
Response::GetPixel(_, _, c) => {
|
||||
writer.write_u8(c[0]).await?;
|
||||
|
|
|
|||
17
src/grid.rs
17
src/grid.rs
|
|
@ -1,5 +1,7 @@
|
|||
use std::cell::SyncUnsafeCell;
|
||||
|
||||
use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, Pixel, Rgb, Rgba};
|
||||
|
||||
use crate::Coordinate;
|
||||
|
||||
pub trait Grid<I, V> {
|
||||
|
|
@ -63,6 +65,21 @@ impl<T> Grid<Coordinate, T> for Flut<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl GenericImageView for Flut<u32> {
|
||||
type Pixel = Rgb<u8>;
|
||||
|
||||
fn dimensions(&self) -> (u32, u32) {
|
||||
let (x, y) = self.get_size();
|
||||
(x as u32, y as u32)
|
||||
}
|
||||
|
||||
fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
|
||||
let pixel = self.get_unchecked(x as u16, y as u16);
|
||||
let [r, g, b, _a] = pixel.to_be_bytes();
|
||||
Rgb::from([r, g, b])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::needless_return)]
|
||||
mod tests {
|
||||
|
|
|
|||
37
src/main.rs
37
src/main.rs
|
|
@ -7,17 +7,24 @@ mod grid;
|
|||
mod text_protocol;
|
||||
|
||||
use std::{
|
||||
alloc::System,
|
||||
fmt::Debug,
|
||||
fs::{create_dir_all, File},
|
||||
io::{self, Error, ErrorKind},
|
||||
path::Path,
|
||||
sync::{atomic::AtomicU64, Arc},
|
||||
time::Duration,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use binary_protocol::BinaryParser;
|
||||
use chrono::Local;
|
||||
use grid::{Flut, Grid};
|
||||
use image::{codecs::jpeg::JpegEncoder, save_buffer, DynamicImage, GenericImageView, SubImage};
|
||||
use text_protocol::TextParser;
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
|
||||
net::TcpListener,
|
||||
time::{interval, Instant},
|
||||
};
|
||||
|
||||
extern crate test;
|
||||
|
|
@ -261,6 +268,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
async fn save_image_frames(grids: Arc<[grid::Flut<u32>]>) -> io::Result<()> {
|
||||
let base_dir = Path::new("./recordings");
|
||||
let mut timer = interval(Duration::from_secs(5));
|
||||
create_dir_all(base_dir)?;
|
||||
loop {
|
||||
timer.tick().await;
|
||||
for grid in grids.as_ref() {
|
||||
let p = base_dir.join(format!("{}", Local::now().format("%Y-%m-%d %H:%M:%S")));
|
||||
println!("timer ticked, grid writing to {:?}", p);
|
||||
let mut file_writer = File::create(p)?;
|
||||
|
||||
let encoder = JpegEncoder::new_with_quality(&mut file_writer, 50);
|
||||
grid.view(0, 0, grid.width(), grid.height()).to_image();
|
||||
|
||||
let sub_image = SubImage::new(grid, 0, 0, grid.width(), grid.height());
|
||||
let image = sub_image.to_image();
|
||||
match image.write_with_encoder(encoder) {
|
||||
Ok(_) => {}
|
||||
Err(err) => eprintln!("{}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_flut(flut_listener: TcpListener, grids: Arc<[grid::Flut<u32>]>) -> io::Result<()> {
|
||||
let mut handles = Vec::new();
|
||||
loop {
|
||||
|
|
@ -293,8 +324,10 @@ async fn main() {
|
|||
let handles = vec![
|
||||
// log the amount of changed pixels each second
|
||||
(tokio::spawn(listen_handle())),
|
||||
// save frames every 5 seconds
|
||||
(tokio::spawn(save_image_frames(grids.clone()))),
|
||||
// accept and handle flut connections
|
||||
(tokio::spawn(handle_flut(flut_listener, grids))),
|
||||
(tokio::spawn(handle_flut(flut_listener, grids.clone()))),
|
||||
];
|
||||
|
||||
for handle in handles {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue