Skip to content
Snippets Groups Projects
Select Git revision
  • 694def3807edae997ff16a0e755b6a1b53a95ecb
  • master default protected
  • intros
  • live_sources
  • bootstrap4
  • modules
6 results

config.py.example

Blame
  • Forked from Video AG Infrastruktur / website
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    mod.rs 3.69 KiB
    #![allow(warnings)]
    
    pub mod ffmpeg;
    mod filter;
    
    use crate::{
    	iotro::intro,
    	render::ffmpeg::Ffmpeg,
    	time::{format_date, Time},
    	Project, ProjectSourceMetadata, Resolution
    };
    use anyhow::{bail, Context};
    use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
    use rational::Rational;
    use std::{
    	fs::{self, File},
    	io::Write as _,
    	process::{Command, Stdio}
    };
    
    const INTRO_LEN: Time = Time {
    	seconds: 3,
    	micros: 0
    };
    const OUTRO_LEN: Time = Time {
    	seconds: 5,
    	micros: 0
    };
    const TRANSITION: &str = "fadeblack";
    const TRANSITION_LEN: Time = Time {
    	seconds: 0,
    	micros: 200_000
    };
    
    fn cmd() -> Command {
    	let mut cmd = Command::new("busybox");
    	cmd.arg("ash")
    		.arg("-exuo")
    		.arg("pipefail")
    		.arg("-c")
    		.arg("exec");
    	cmd
    }
    
    fn ffprobe() -> Command {
    	let mut cmd = cmd();
    	cmd.arg("ffprobe")
    		.arg("-v")
    		.arg("error")
    		.arg("-of")
    		.arg("default=noprint_wrappers=1:nokey=1");
    	cmd
    }
    
    fn read_output(cmd: &mut Command) -> anyhow::Result<String> {
    	let out = cmd.stderr(Stdio::inherit()).output()?;
    	if !out.status.success() {
    		bail!(
    			"Executed command failed with exit status {:?}",
    			out.status.code()
    		);
    	}
    	String::from_utf8(out.stdout).context("Command returned non-utf8 output")
    }
    
    fn ffprobe_video(query: &str, input: &Path) -> anyhow::Result<String> {
    	read_output(
    		ffprobe()
    			.arg("-select_streams")
    			.arg("v:0")
    			.arg("-show_entries")
    			.arg(query)
    			.arg(input)
    	)
    }
    
    fn ffprobe_audio(query: &str, concat_input: &Path) -> anyhow::Result<String> {
    	read_output(
    		ffprobe()
    			.arg("-select_streams")
    			.arg("a:0")
    			.arg("-show_entries")
    			.arg(query)
    			.arg("-safe")
    			.arg("0")
    			.arg("-f")
    			.arg("concat")
    			.arg(concat_input)
    	)
    }
    
    fn ffmpeg() -> Command {
    	let mut cmd = cmd();
    	cmd.arg("ffmpeg")
    		.arg("-hide_banner")
    		.arg("-vaapi_device")
    		.arg("/dev/dri/renderD128");
    	cmd
    }
    
    fn render_svg(fps: Rational, tbn: u32, input: &Path, duration: Time, output: &Path) {
    	let mut cmd = ffmpeg();
    	cmd.arg("-framerate").arg(fps.to_string());
    	cmd.arg("-loop").arg("1");
    	cmd.arg("-i").arg(input);
    	cmd.arg("-c:v").arg("libx264");
    }
    
    pub(crate) struct Renderer<'a> {
    	/// The directory with all the sources.
    	directory: &'a Path,
    
    	/// The slug (i.e. 23ws-malo2-231016).
    	slug: String,
    	/// The target directory.
    	target: PathBuf
    }
    
    impl<'a> Renderer<'a> {
    	pub(crate) fn new(directory: &'a Path, project: &Project) -> anyhow::Result<Self> {
    		let slug = format!(
    			"{}-{}",
    			project.lecture.course,
    			format_date(project.lecture.date)
    		);
    		let target = directory.join(&slug);
    
    		Ok(Self {
    			directory,
    			slug,
    			target
    		})
    	}
    
    	pub(crate) fn preprocess(&self, project: &mut Project) -> anyhow::Result<()> {
    		assert!(!project.progress.preprocessed);
    
    		let logo = self.target.join("logo.svg");
    		fs::write(
    			&logo,
    			include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/logo.svg"))
    		)?;
    		let fastforward = self.target.join("fastforward.svg");
    		fs::write(
    			&fastforward,
    			include_bytes!(concat!(
    				env!("CARGO_MANIFEST_DIR"),
    				"/assets/fastforward.svg"
    			))
    		)?;
    
    		let recording_txt = self.target.join("recording.txt");
    		let mut file = File::create(recording_txt)?;
    		for filename in &project.source.files {
    			writeln!(file, "file {:?}", self.directory.join(filename).to_string());
    		}
    		drop(file);
    
    		println!("\x1B[1m ==> Concatenating Video and Normalising Audio ...");
    		let recording_mp4 = self.target.join("recording.mp4");
    		let mut ffmpeg = Ffmpeg::new(recording_mp4);
    
    		// project.source.metadata = Some(ProjectSourceMetadata {
    		// 	source_duration: ffprobe_video("format=duration", input)?.parse()?
    		// });
    
    		let intro_svg = self.target.join("intro.svg");
    		// fs::write(&intro_svg, intro(res, date));
    		let intro_mp4 = self.target.join("intro.mp4");
    
    		Ok(())
    	}
    }