/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ use crate::LOCAL_VIDEO_TRANSCODING_TASKS; use jellybase::{ cache::{async_cache_file, CachePath}, common::stream::StreamFormatInfo, }; use log::{debug, info}; use std::process::Stdio; use tokio::{ io::copy, process::{ChildStdin, Command}, }; // TODO odd video resolutions can cause errors when transcoding to YUV42{0,2} // TODO with an implementation that cant handle it (SVT-AV1 is such an impl). pub async fn transcode( key: &str, enc: &StreamFormatInfo, input: impl FnOnce(ChildStdin), ) -> anyhow::Result { async_cache_file( &["frag-tc", key, &format!("{enc:?}")], move |mut output| async move { let _permit = LOCAL_VIDEO_TRANSCODING_TASKS.acquire().await?; debug!("transcoding fragment with {enc:?}"); let mut args = Vec::::new(); // match enc { // EncodingProfile::Video { // codec, // preset, // bitrate, // width, // } => { // if let Some(width) = width { // args.push("-vf".to_string()); // args.push(format!("scale={width}:-1")); // } // args.push("-c:v".to_string()); // args.push(codec.to_string()); // if let Some(preset) = preset { // args.push("-preset".to_string()); // args.push(format!("{preset}")); // } // args.push("-b:v".to_string()); // args.push(format!("{bitrate}")); // } // EncodingProfile::Audio { // codec, // bitrate, // sample_rate, // channels, // } => { // if let Some(channels) = channels { // args.push("-ac".to_string()); // args.push(format!("{channels}")) // } // if let Some(sample_rate) = sample_rate { // args.push("-ar".to_string()); // args.push(format!("{sample_rate}")) // } // args.push("-c:a".to_string()); // args.push(codec.to_string()); // args.push("-b:a".to_string()); // args.push(format!("{bitrate}")); // } // EncodingProfile::Subtitles { codec } => { // args.push("-c:s".to_string()); // args.push(codec.to_string()); // } // }; info!("encoding with {:?}", args.join(" ")); let mut proc = Command::new("ffmpeg") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .args(["-f", "matroska", "-i", "pipe:0"]) .args(args) .args(["-f", "webm", "pipe:1"]) .spawn()?; // let mut proc = Command::new("cat") // .stdin(Stdio::piped()) // .stdout(Stdio::piped()) // .spawn()?; let stdin = proc.stdin.take().unwrap(); let mut stdout = proc.stdout.take().unwrap(); input(stdin); copy(&mut stdout, &mut output).await?; proc.wait().await.unwrap().exit_ok()?; info!("done"); Ok(()) }, ) .await }