mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add transcode cmd paramters
This commit is contained in:
parent
5543bc4c9d
commit
33d212bd84
34
transcoder/Cargo.lock
generated
34
transcoder/Cargo.lock
generated
@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -203,7 +203,7 @@ dependencies = [
|
||||
"actix-router",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -398,7 +398,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -867,6 +867,20 @@ name = "serde"
|
||||
version = "1.0.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
@ -947,6 +961,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.20"
|
||||
@ -1047,6 +1072,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-web",
|
||||
"rand",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6,3 +6,6 @@ edition = "2021"
|
||||
[dependencies]
|
||||
actix-web = "4"
|
||||
actix-files = "0.6.2"
|
||||
tokio = { version = "1.27.0", features = ["process"] }
|
||||
serde = { version = "1.0.159", features = ["derive"] }
|
||||
rand = "0.8.5"
|
||||
|
@ -1,20 +1,40 @@
|
||||
use actix_files::NamedFile;
|
||||
use actix_web::{get, web, App, HttpServer, Result};
|
||||
|
||||
use crate::transcode::{Quality, TranscoderState};
|
||||
mod paths;
|
||||
mod transcode;
|
||||
|
||||
#[get("/movie/direct/{slug}")]
|
||||
async fn index(query: web::Path<String>) -> Result<NamedFile> {
|
||||
async fn get_movie_direct(query: web::Path<String>) -> Result<NamedFile> {
|
||||
let slug = query.into_inner();
|
||||
let path = paths::get_movie_path(slug);
|
||||
|
||||
Ok(NamedFile::open_async(path).await?)
|
||||
// .map(|f| (infer_content_type(f), f))
|
||||
}
|
||||
|
||||
#[get("/movie/{quality}/{slug}")]
|
||||
async fn get_movie_auto(
|
||||
query: web::Path<(String, String)>,
|
||||
state: web::Data<TranscoderState>,
|
||||
) -> Result<NamedFile> {
|
||||
let (quality, slug) = query.into_inner();
|
||||
let path = paths::get_movie_path(slug);
|
||||
|
||||
Ok(NamedFile::open_async(path).await?)
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
HttpServer::new(|| App::new().service(index))
|
||||
.bind(("0.0.0.0", 7666))?
|
||||
.run()
|
||||
.await
|
||||
let state = web::Data::new(TranscoderState::new());
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(state.clone())
|
||||
.service(get_movie_direct)
|
||||
.service(get_movie_auto)
|
||||
})
|
||||
.bind(("0.0.0.0", 7666))?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
94
transcoder/src/transcode.rs
Normal file
94
transcoder/src/transcode.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{thread_rng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::process::{Command, Child};
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
|
||||
pub struct TranscoderState {
|
||||
running: Mutex<HashMap<u32, Child>>,
|
||||
}
|
||||
|
||||
impl TranscoderState {
|
||||
pub fn new() -> TranscoderState {
|
||||
Self {
|
||||
running: Mutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Quality {
|
||||
P240,
|
||||
P360,
|
||||
P480,
|
||||
P720,
|
||||
P1080,
|
||||
P1440,
|
||||
P4k,
|
||||
P8k,
|
||||
Original,
|
||||
}
|
||||
|
||||
imhttps://sgsot3a.sic.shibaura-it.ac.jp/
|
||||
|
||||
fn get_transcode_video_quality_args(quality: Quality) -> Vec<&'static str> {
|
||||
// superfast or ultrafast would produce a file extremly big so we prever veryfast.
|
||||
let enc_base: Vec<&str> = vec![
|
||||
"-map", "0:v:0", "-c:v", "libx264", "-crf", "21", "-preset", "veryfast",
|
||||
];
|
||||
|
||||
match quality {
|
||||
Quality::Original => vec![],
|
||||
Quality::P240 => [enc_base, vec!["-vf", "scale=-1:240"]].concat(),
|
||||
Quality::P360 => [enc_base, vec!["-vf", "scale=-1:360"]].concat(),
|
||||
Quality::P480 => [enc_base, vec!["-vf", "scale=-1:480"]].concat(),
|
||||
Quality::P720 => [enc_base, vec!["-vf", "scale=-1:720"]].concat(),
|
||||
Quality::P1080 => [enc_base, vec!["-vf", "scale=-1:1080"]].concat(),
|
||||
Quality::P1440 => [enc_base, vec!["-vf", "scale=-1:1440"]].concat(),
|
||||
Quality::P4k => [enc_base, vec!["-vf", "scale=-1:2160"]].concat(),
|
||||
Quality::P8k => [enc_base, vec!["-vf", "scale=-1:4320"]].concat(),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add audios streams (and transcode them only when necesarry)
|
||||
async fn start_transcode(path: &str, quality: Quality, start_time_sec: f32) -> (String, Child) {
|
||||
// TODO: Use the out path below once cached segments can be reused.
|
||||
// let out_dir = format!("/cache/{show_hash}/{quality}");
|
||||
let uuid: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(30)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
let out_dir = format!("/cache/{uuid}");
|
||||
|
||||
let segment_time = "10";
|
||||
let child = Command::new("ffmpeg")
|
||||
.args(&["-ss", start_time_sec.to_string().as_str()])
|
||||
.args(&["-i", path])
|
||||
.args(&["-f", "segment"])
|
||||
.args(&["-segment_list_type", "m3u8"])
|
||||
// Keep all segments in the list (else only last X are presents, useful for livestreams)
|
||||
.args(&["--segment_list_size", "0"])
|
||||
.args(&["-segment_time", segment_time])
|
||||
// Force segments to be exactly segment_time (only works when transcoding)
|
||||
.args(&[
|
||||
"-force_key_frames",
|
||||
format!("expr:gte(t,n_forced*{segment_time})").as_str(),
|
||||
"-strict",
|
||||
"-2",
|
||||
"-segment_time_delta",
|
||||
"0.1",
|
||||
])
|
||||
.args(get_transcode_video_quality_args(quality))
|
||||
.args(&[
|
||||
"-segment_list".to_string(),
|
||||
format!("{out_dir}/stream.m3u8"),
|
||||
format!("{out_dir}/segments-%02d.ts"),
|
||||
])
|
||||
.spawn()
|
||||
.expect("ffmpeg failed to start");
|
||||
(uuid, child)
|
||||
}
|
||||
|
||||
pub async fn transcode(user_id: u32, path: &str, quality: Quality, start_time_sec: f32) {
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user