Skip to content

Instantly share code, notes, and snippets.

@akhildevelops
Created November 30, 2024 13:48
Show Gist options
  • Save akhildevelops/4936f32c5216b6281891a12fe15b7748 to your computer and use it in GitHub Desktop.
Save akhildevelops/4936f32c5216b6281891a12fe15b7748 to your computer and use it in GitHub Desktop.
Stream graphic art to browser
use image::{Rgb, RgbImage};
use minimp4::Mp4Muxer;
use openh264::{
encoder::Encoder,
formats::{RgbSliceU8, YUVBuffer},
};
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::time::Duration;
const WIDTH: u32 = 512;
const HEIGHT: u32 = 512;
const VIDEO_TIME: Duration = Duration::from_secs(10);
// const SPEED: u64 = 10;
use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_web::main]
async fn main() {
HttpServer::new(|| App::new().service(web::resource("/{speed}").to(handler)))
.bind(("127.0.0.1", 8080))
.unwrap()
.run()
.await
.unwrap()
}
async fn handler(speed: web::Path<u64>) -> HttpResponse {
let video = gen_video(speed.into_inner());
HttpResponse::Ok().content_type("video/mp4").body(video)
}
fn gen_video(speed: u64) -> Vec<u8> {
let n_frames = 60 * VIDEO_TIME.as_secs();
// let config = EncoderConfig::new(64, 64);
let mut encoder = Encoder::new().unwrap();
let mut buffer = Vec::new();
(0..n_frames).for_each(|nthframe| {
let degree = (6 * (nthframe / (60 / speed))) as f32;
let slope = degree.tan();
let mut image = RgbImage::new(WIDTH, HEIGHT);
let new_origin = (WIDTH / 2, HEIGHT / 2);
(0..HEIGHT).for_each(|row| {
(0..WIDTH).for_each(|col| {
let new_coords = (
col as i32 - new_origin.0 as i32,
row as i32 - new_origin.1 as i32,
);
if (slope - (new_coords.1 as f32 / new_coords.0 as f32)).abs() < 0.01
|| (slope - (new_coords.0 as f32 / new_coords.1 as f32)).abs() < 0.01
{
image.put_pixel(col, row, Rgb([255, 0, 0]));
} else {
image.put_pixel(col, row, Rgb([0, 0, 0]));
}
});
});
let rgb_slice =
RgbSliceU8::new(image.as_raw().as_slice(), (WIDTH as usize, HEIGHT as usize));
let yuv_buffer = YUVBuffer::from_rgb_source(rgb_slice);
let bitstream = encoder.encode(&yuv_buffer).unwrap();
bitstream.write_vec(&mut buffer);
});
let mut video = Cursor::new(Vec::new());
let mut mp4muxer = Mp4Muxer::new(&mut video);
mp4muxer.init_video(64, 64, false, "Moving circle.");
mp4muxer.write_video(&mut buffer);
mp4muxer.close();
// Some shenanigans to get the raw bytes for the video.
video.seek(SeekFrom::Start(0)).unwrap();
let mut video_bytes = Vec::new();
video.read_to_end(&mut video_bytes).unwrap();
video_bytes
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment