Generating a HLS playlist through ffmpeg

I might be able to streamline the requests to cut down on the endpoints.
This also will likely take some time if the file is large and could time
out, that may be a concern for another day.
This commit is contained in:
Cameron Cordes
2020-07-13 22:39:00 -04:00
parent 78c066b7be
commit c39bf970be
2 changed files with 70 additions and 2 deletions

View File

@@ -13,10 +13,12 @@ use std::path::PathBuf;
use crate::data::{Claims, CreateAccountRequest, Token}; use crate::data::{Claims, CreateAccountRequest, Token};
use crate::database::{create_user, get_user, user_exists}; use crate::database::{create_user, get_user, user_exists};
use crate::files::list_files; use crate::files::list_files;
use crate::video::create_playlist;
mod data; mod data;
mod database; mod database;
mod files; mod files;
mod video;
#[post("/register")] #[post("/register")]
async fn register(user: Json<CreateAccountRequest>) -> impl Responder { async fn register(user: Json<CreateAccountRequest>) -> impl Responder {
@@ -119,16 +121,58 @@ async fn image(
} }
} }
#[post("/video/generate")]
async fn generate_video(_claims: Claims, body: web::Json<ThumbnailRequest>) -> impl Responder {
let filename = PathBuf::from(&body.path);
if let Some(name) = filename.file_stem() {
let filename = name.to_str().expect("Filename should conver to string");
create_playlist(&body.path, &format!("tmp/{}.m3u8", filename));
HttpResponse::Ok()
} else {
HttpResponse::BadRequest()
}
}
#[get("/video/stream")]
async fn stream_video(request: HttpRequest, path: web::Query<ThumbnailRequest>) -> impl Responder {
let playlist = &path.path;
println!("Playlist: {}", playlist);
if let Ok(file) = NamedFile::open(playlist) {
file.into_response(&request).unwrap()
} else {
HttpResponse::NotFound().finish()
}
}
#[get("/video/{path}")]
async fn get_video_part(request: HttpRequest, path: web::Path<ThumbnailRequest>) -> impl Responder {
let playlist = &path.path;
println!("Video part: {}", playlist);
if let Ok(file) = NamedFile::open(String::from("tmp/") + playlist) {
file.into_response(&request).unwrap()
} else {
HttpResponse::NotFound().finish()
}
}
#[actix_rt::main] #[actix_rt::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.service(register)
.service(login) .service(login)
.service(list_photos) .service(list_photos)
.service(register)
.service(image) .service(image)
.service(generate_video)
.service(stream_video)
.service(get_video_part)
}) })
.bind("127.0.0.1:8088")? .bind("192.168.10.23:8088")?
.bind("localhost:8088")?
.run() .run()
.await .await
} }

24
src/video.rs Normal file
View File

@@ -0,0 +1,24 @@
use std::process::Command;
// ffmpeg -i test.mp4 -c:v h264 -flags +cgop -g 30 -hls_time 3 out.m3u8
pub fn create_playlist(video_path: &str, playlist_file: &str) {
let result = Command::new("ffmpeg")
.arg("-i")
.arg(video_path)
.arg("-c:v")
.arg("h264")
.arg("-flags")
.arg("+cgop")
.arg("-g")
.arg("30")
.arg("-hls_time")
.arg("5")
.arg(playlist_file)
.output()
.expect("Expected this to work..");
println!("{:?}", result);
println!("Status: {}", String::from_utf8(result.stdout).unwrap())
}