diff options
author | metamuffin <metamuffin@disroot.org> | 2025-04-21 20:36:34 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-04-21 20:36:34 +0200 |
commit | b9d8e20b6bff6b51f73106b688bd6e5d98e08215 (patch) | |
tree | 0e6a82ff9fd346d79a0879c373c838f4e2a49e8a /transcoder/src/fragment.rs | |
parent | 30c3bb552aba8794d57eb08688e0c1c751ab27a0 (diff) | |
download | jellything-b9d8e20b6bff6b51f73106b688bd6e5d98e08215.tar jellything-b9d8e20b6bff6b51f73106b688bd6e5d98e08215.tar.bz2 jellything-b9d8e20b6bff6b51f73106b688bd6e5d98e08215.tar.zst |
new transcoding args system
Diffstat (limited to 'transcoder/src/fragment.rs')
-rw-r--r-- | transcoder/src/fragment.rs | 140 |
1 files changed, 87 insertions, 53 deletions
diff --git a/transcoder/src/fragment.rs b/transcoder/src/fragment.rs index 7c5cadd..027e80f 100644 --- a/transcoder/src/fragment.rs +++ b/transcoder/src/fragment.rs @@ -4,12 +4,18 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ use crate::LOCAL_VIDEO_TRANSCODING_TASKS; +use anyhow::Result; use jellybase::{ cache::{async_cache_file, CachePath}, - common::stream::{StreamFormatInfo, TrackKind}, + common::{ + config::TranscoderConfig, + stream::{StreamFormatInfo, TrackKind}, + }, CONF, }; -use log::{debug, info}; +use jellyremuxer::metadata::MatroskaTrackEntry; +use log::info; +use std::fmt::Write; use std::process::Stdio; use tokio::{ io::copy, @@ -21,62 +27,16 @@ use tokio::{ pub async fn transcode( kind: TrackKind, + orig_metadata: &MatroskaTrackEntry, format: &StreamFormatInfo, input_key: &str, input: impl FnOnce(ChildStdin), ) -> anyhow::Result<CachePath> { - let template = match format.codec.as_str() { - "V_MPEG4/ISO/AVC" => CONF.encoders.avc.as_ref(), - "V_MPEGH/ISO/HEVC" => CONF.encoders.hevc.as_ref(), - "V_VP8" => CONF.encoders.vp8.as_ref(), - "V_VP9" => CONF.encoders.vp9.as_ref(), - "V_AV1" => CONF.encoders.av1.as_ref(), - _ => None, - } - .or(CONF.encoders.generic.as_ref()) - .cloned() - .unwrap_or("ffmpeg %a".to_owned()); - - let filter = match kind { - TrackKind::Video => "-vf scale=%w:%h", - TrackKind::Audio => "", - TrackKind::Subtitle => "", - }; - let typechar = match kind { - TrackKind::Video => "v", - TrackKind::Audio => "a", - TrackKind::Subtitle => "s", - }; - let fallback_encoder = match format.codec.as_str() { - "A_OPUS" => "libopus", - "V_VP8" => "libvpx", - "V_VP9" => "libvpx-vp9", - "V_AV1" => "libaom", // svtav1 is x86 only :( - "V_MPEG4/ISO/AVC" => "libx264", - "V_MPEGH/ISO/HEVC" => "libx265", - _ => "", - }; - - let args = template - .replace("%a", "-hide_banner %i %f %e %o") - .replace("%i", "-f matroska -i pipe:0 -copyts") - .replace("%o", "-f matroska pipe:1") - .replace("%f", &filter) - .replace("%w", &format.width.unwrap_or_default().to_string()) - .replace("%h", &format.height.unwrap_or_default().to_string()) - .replace("%e", "-c:%t %c -b:%t %r") - .replace("%t", typechar) - .replace("%c", fallback_encoder) - .replace("%r", &(format.bitrate as i64).to_string()) - .replace(" ", " "); - - async_cache_file("frag-tc", (input_key, &args), async |mut output| { + let command = transcode_command(kind, orig_metadata, format, &CONF.transcoder).unwrap(); + async_cache_file("frag-tc", (input_key, &command), async |mut output| { let _permit = LOCAL_VIDEO_TRANSCODING_TASKS.acquire().await?; - debug!("transcoding fragment with {format:?}"); - - info!("encoding with {:?}", args); - - let mut args = args.split(" "); + info!("encoding with {command:?}"); + let mut args = command.split(" "); let mut proc = Command::new(args.next().unwrap()) .stdin(Stdio::piped()) .stdout(Stdio::piped()) @@ -95,3 +55,77 @@ pub async fn transcode( }) .await } + +fn transcode_command( + kind: TrackKind, + orig_metadata: &MatroskaTrackEntry, + format: &StreamFormatInfo, + config: &TranscoderConfig, +) -> Result<String> { + let br = format.bitrate as u64; + let w = format.width.unwrap_or(0); + let h = format.height.unwrap_or(0); + let mut o = String::new(); + write!(o, "ffmpeg -hide_banner ")?; + + if kind == TrackKind::Video { + if config.enable_rkmpp { + write!(o, "-hwaccel rkmpp -hwaccel_output_format drm_prime ")?; + } + if config.enable_rkrga { + write!(o, "-afbc rga ")?; + } + + write!(o, "-f matroska -i pipe:0 -copyts ")?; + + if config.enable_rkrga { + write!(o, "-vf scale_rkrga=w={w}:h={h}:format=nv12:afbc=1 ")?; + } else { + write!(o, "-vf scale={w}:{h} ")?; + } + + match format.codec.as_str() { + "V_MPEG4/ISO/AVC" if config.enable_rkmpp => { + write!(o, "-c:v h264_rkmpp -profile:v high -b:v {br} ")? + } + "V_MPEGH/ISO/HEVC" if config.enable_rkmpp => { + write!(o, "-c:v h265_rkmpp -profile:v high -b:v {br} ")? + } + "A_AV1" if config.use_svtav1 => { + let p = config.svtav1_preset.unwrap_or(8); + write!(o, "-c:v libsvtav1 -preset {p} -b:v {br} ")? + } + "A_AV1" if config.use_rav1e => { + let p = config.rav1e_preset.unwrap_or(8); + write!(o, "-c:v librav1e -speed {p} -b:v {br} ")? + } + "V_MPEG4/ISO/AVC" => { + let p = config.x264_preset.clone().unwrap_or("fast".to_string()); + write!(o, "-c:v libx264 -preset {p} -b:v {br} ")? + } + "V_MPEGH/ISO/HEVC" => write!(o, "-c:v libx265 -b:v {br} ")?, + "V_VP8" => write!(o, "-c:v libvpx -b:v {br} ")?, + "V_VP9" => write!(o, "-c:v libvpx-vp9 -b:v {br} ")?, + "V_AV1" => { + let p = config.aom_preset.unwrap_or(1); + write!(o, "-c:v libaom -cpu-used {p} -row-mt 1 -b:v {br} ")? + } + _ => todo!(), + }; + } else if kind == TrackKind::Audio { + write!(o, "-f matroska -i pipe:0 -copyts ")?; + if format.codec == "A_OPUS" && orig_metadata.audio.as_ref().unwrap().channels > 2 { + write!(o, "-ac 2 ")?; + } + match format.codec.as_str() { + "A_OPUS" => write!(o, "-c:a libopus -b:a {br} ")?, + _ => todo!(), + } + } else { + write!(o, "-f matroska -i pipe:0 -copyts ")?; + todo!() + } + + write!(o, "-f matroska pipe:1")?; + Ok(o) +} |