Created
November 30, 2024 13:48
-
-
Save akhildevelops/4936f32c5216b6281891a12fe15b7748 to your computer and use it in GitHub Desktop.
Stream graphic art to browser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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