Skip to content
Snippets Groups Projects
Select Git revision
  • c55906f70ad65c69e1b03f022ae313c6f3cc7ca5
  • main default protected
  • overlay_vaapi
  • graph2dot
  • 240926-1
  • 240926
  • 240701-2
  • 240701-3
  • 240701-4
  • 240701-5
  • 240701-6
  • 240701-7
  • 240701-8
  • 240702
  • 240624
  • 240527
  • 240517
  • 231212
  • 231114
  • 231031
  • 231030
21 results

ffmpeg.rs

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ffmpeg.rs 3.09 KiB
    use super::cmd;
    use crate::time::{format_time, Time};
    use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
    use rational::Rational;
    use std::{borrow::Cow, process::Command};
    
    pub(crate) struct FfmpegInput {
    	pub(crate) concat: bool,
    	pub(crate) loop_input: bool,
    	pub(crate) fps: Option<Rational>,
    	pub(crate) start: Option<Time>,
    	pub(crate) duration: Option<Time>,
    	pub(crate) path: PathBuf
    }
    
    impl FfmpegInput {
    	pub(crate) fn new(path: PathBuf) -> Self {
    		Self {
    			concat: false,
    			loop_input: false,
    			fps: None,
    			start: None,
    			duration: None,
    			path
    		}
    	}
    
    	fn append_to_cmd(self, cmd: &mut Command) {
    		if self.concat {
    			cmd.arg("-f").arg("concat").arg("-safe").arg("0");
    		}
    		if self.loop_input {
    			cmd.arg("-loop").arg("1");
    		}
    		if let Some(fps) = self.fps {
    			cmd.arg("-r").arg(fps.to_string());
    		}
    		if let Some(start) = self.start {
    			cmd.arg("-ss").arg(format_time(start));
    		}
    		if let Some(duration) = self.duration {
    			cmd.arg("-t").arg(format_time(duration));
    		}
    		cmd.arg("-i").arg(self.path);
    	}
    }
    
    pub(crate) enum Filter {
    	Concat {
    		inputs: Vec<Cow<'static, str>>,
    		n: usize,
    		output: Cow<'static, str>
    	},
    
    	FadeIn {
    		input: Cow<'static, str>,
    		start: Time,
    		duration: Time,
    		output: Cow<'static, str>
    	},
    
    	FadeOut {
    		input: Cow<'static, str>,
    		start: Time,
    		duration: Time,
    		output: Cow<'static, str>
    	},
    
    	Overlay {
    		video_input: Cow<'static, str>,
    		overlay_input: Cow<'static, str>,
    		x: Cow<'static, str>,
    		y: Cow<'static, str>,
    		output: Cow<'static, str>
    	},
    
    	GenerateSilence {
    		output: Cow<'static, str>
    	}
    }
    
    impl Filter {
    	fn is_video_filter(&self) -> bool {
    		matches!(
    			self,
    			Self::Concat { .. }
    				| Self::FadeIn { .. }
    				| Self::FadeOut { .. }
    				| Self::Overlay { .. }
    		)
    	}
    
    	fn is_audio_filter(&self) -> bool {
    		matches!(
    			self,
    			Self::Concat { .. }
    				| Self::FadeIn { .. }
    				| Self::FadeOut { .. }
    				| Self::GenerateSilence { .. }
    		)
    	}
    }
    
    pub(crate) struct Ffmpeg {
    	inputs: Vec<FfmpegInput>,
    	filters: Vec<Filter>,
    	output: PathBuf
    }
    
    impl Ffmpeg {
    	pub fn new(output: PathBuf) -> Self {
    		Self {
    			inputs: Vec::new(),
    			filters: Vec::new(),
    			output
    		}
    	}
    
    	pub fn run(self) -> anyhow::Result<()> {
    		let mut cmd = cmd();
    		cmd.arg("ffmpeg").arg("-hide_banner");
    
    		// determine whether the video need to be re-encoded
    		let venc = self.filters.iter().any(|f| f.is_video_filter());
    		let aenc = self.filters.iter().any(|f| f.is_audio_filter());
    
    		// initialise a vaapi device if one exists
    		let vaapi_device: PathBuf = "/dev/dri/renderD128".into();
    		let vaapi = venc && vaapi_device.exists();
    		if vaapi {
    			cmd.arg("-vaapi_device").arg(&vaapi_device);
    		}
    
    		// append all the inputs
    		for i in self.inputs {
    			i.append_to_cmd(&mut cmd);
    		}
    
    		// always try to synchronise audio
    		cmd.arg("-async").arg("1");
    
    		// TODO apply filters
    
    		// append encoding options
    		if vaapi {
    			cmd.arg("-c:v").arg("h264_vaapi");
    			cmd.arg("-rc_mode").arg("CQP");
    			cmd.arg("-global_quality").arg("22");
    		} else if venc {
    			cmd.arg("-c:v").arg("libx264");
    			cmd.arg("-crf").arg("22");
    		} else {
    			cmd.arg("-c:v").arg("copy");
    		}
    
    		unimplemented!()
    	}
    }