diff --git a/src/main.rs b/src/main.rs
index dcf9acd48786fc637e441412fe2bfbd3cb737c33..a6715b699b1fb612732db500fe3bf3312cb7f694 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,7 @@ mod render;
 mod time;
 
 use crate::{
-	render::Renderer,
+	render::{ffmpeg::FfmpegOutputFormat, Renderer},
 	time::{parse_date, parse_time, Date, Time}
 };
 use camino::Utf8PathBuf as PathBuf;
@@ -46,7 +46,7 @@ struct Args {
 }
 
 macro_rules! resolutions {
-	($($res:ident: $width:literal x $height:literal at $bitrate:literal),+) => {
+	($($res:ident: $width:literal x $height:literal at $bitrate:literal in $format:ident),+) => {
 		#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
 		#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
 		enum Resolution {
@@ -84,6 +84,12 @@ macro_rules! resolutions {
 					$(Self::$res => $bitrate),+
 				}
 			}
+
+			fn format(self) -> FfmpegOutputFormat {
+				match self {
+					$(Self::$res => FfmpegOutputFormat::$format),+
+				}
+			}
 		}
 
 		impl FromStr for Resolution {
@@ -100,12 +106,12 @@ macro_rules! resolutions {
 }
 
 resolutions! {
-	nHD: 640 x 360 at 500_000,
-	HD: 1280 x 720 at 1_000_000,
-	FullHD: 1920 x 1080 at 2_000_000,
-	WQHD: 2560 x 1440 at 3_000_000,
+	nHD: 640 x 360 at 500_000 in AvcAac,
+	HD: 1280 x 720 at 1_000_000 in AvcAac,
+	FullHD: 1920 x 1080 at 2_000_000 in AvcAac,
+	WQHD: 2560 x 1440 at 3_000_000 in Av1Opus,
 	// TODO qsx muss mal sagen wieviel bitrate für 4k
-	UHD: 3840 x 2160 at 4_000_000
+	UHD: 3840 x 2160 at 4_000_000 in Av1Opus
 }
 
 #[derive(Deserialize, Serialize)]
@@ -234,7 +240,7 @@ fn main() {
 	println!("{}", toml::to_string(&project).unwrap());
 
 	let renderer = Renderer::new(&directory, &project).unwrap();
-	let recording = renderer.recording_mp4();
+	let recording = renderer.recording_mkv();
 
 	// preprocess the video
 	if !project.progress.preprocessed {
@@ -282,7 +288,7 @@ fn main() {
 	// render the video
 	let mut videos = Vec::new();
 	videos.push(if project.progress.rendered {
-		renderer.video_mp4(&project)
+		renderer.video_file_output()
 	} else {
 		let video = renderer.render(&mut project).unwrap();
 		project.progress.rendered = true;
@@ -302,7 +308,7 @@ fn main() {
 				continue;
 			}
 			if !project.progress.transcoded.contains(&res) {
-				videos.push(renderer.rescale(res, &project).unwrap());
+				videos.push(renderer.rescale(res).unwrap());
 				project.progress.transcoded.insert(res);
 
 				println!("{}", toml::to_string(&project).unwrap());
diff --git a/src/render/ffmpeg.rs b/src/render/ffmpeg.rs
index 2e2d174597b7c17e19b2d6e1de3acceb2d42c361..543ad7d8e00b7913729ea685d448dc2222cb737c 100644
--- a/src/render/ffmpeg.rs
+++ b/src/render/ffmpeg.rs
@@ -41,7 +41,9 @@ impl FfmpegInput {
 			cmd.arg("-r").arg(fps.to_string());
 		}
 		if let Some(start) = self.start {
-			cmd.arg("-seek_streams_individually").arg("false");
+			if self.path.ends_with(".mp4") {
+				cmd.arg("-seek_streams_individualy").arg("false");
+			}
 			cmd.arg("-ss").arg(format_time(start));
 		}
 		if let Some(duration) = self.duration {
@@ -51,18 +53,35 @@ impl FfmpegInput {
 	}
 }
 
+pub(crate) enum FfmpegOutputFormat {
+	/// AV1 / FLAC
+	Av1Flac,
+	/// AV1 / OPUS
+	Av1Opus,
+	/// AVC (H.264) / AAC
+	AvcAac
+}
+
 pub(crate) struct FfmpegOutput {
+	pub(crate) format: FfmpegOutputFormat,
+	pub(crate) audio_bitrate: Option<u64>,
+	pub(crate) video_bitrate: Option<u64>,
+
 	pub(crate) fps: Option<Rational>,
 	pub(crate) duration: Option<Time>,
 	pub(crate) time_base: Option<Rational>,
 	pub(crate) fps_mode_vfr: bool,
 	pub(crate) faststart: bool,
+
 	pub(crate) path: PathBuf
 }
 
 impl FfmpegOutput {
-	pub(crate) fn new(path: PathBuf) -> Self {
+	pub(crate) fn new(format: FfmpegOutputFormat, path: PathBuf) -> Self {
 		Self {
+			format,
+			audio_bitrate: None,
+			video_bitrate: None,
 			fps: None,
 			duration: None,
 			time_base: None,
@@ -77,7 +96,42 @@ impl FfmpegOutput {
 		self
 	}
 
-	fn append_to_cmd(self, cmd: &mut Command) {
+	fn append_to_cmd(self, cmd: &mut Command, venc: bool, _aenc: bool, vaapi: bool) {
+		// select codec and bitrate
+		const QUALITY: &str = "22";
+		if venc {
+			let mut vcodec: String = match self.format {
+				FfmpegOutputFormat::Av1Flac | FfmpegOutputFormat::Av1Opus => "av1".into(),
+				FfmpegOutputFormat::AvcAac => "h264".into()
+			};
+			if vaapi {
+				vcodec = format!("{vcodec}_vaapi");
+			}
+			cmd.arg("-c:v").arg(vcodec);
+
+			if let Some(bv) = self.video_bitrate {
+				cmd.arg("-b:v").arg(bv.to_string());
+			} else if vaapi {
+				cmd.arg("-rc_mode").arg("CQP");
+				cmd.arg("-global_quality").arg(QUALITY);
+			} else {
+				cmd.arg("-crf").arg(QUALITY);
+			}
+		} else {
+			cmd.arg("-c:v").arg("copy");
+		}
+		cmd.arg("-c:a").arg(match self.format {
+			FfmpegOutputFormat::Av1Flac => "flac",
+			FfmpegOutputFormat::Av1Opus => "libopus",
+			FfmpegOutputFormat::AvcAac => "aac"
+		});
+		if let Some(ba) = self.audio_bitrate {
+			cmd.arg("-b:a").arg(ba.to_string());
+		} else {
+			cmd.arg("-b:a").arg("128k");
+		}
+
+		// other output options
 		if let Some(fps) = self.fps {
 			cmd.arg("-r").arg(fps.to_string());
 		}
@@ -110,7 +164,6 @@ enum FfmpegFilter {
 pub(crate) struct Ffmpeg {
 	inputs: Vec<FfmpegInput>,
 	filter: FfmpegFilter,
-	video_bitrate: Option<u64>,
 	output: FfmpegOutput,
 
 	filter_idx: usize
@@ -121,7 +174,6 @@ impl Ffmpeg {
 		Self {
 			inputs: Vec::new(),
 			filter: FfmpegFilter::None,
-			video_bitrate: None,
 			output,
 
 			filter_idx: 0
@@ -182,11 +234,6 @@ impl Ffmpeg {
 		self
 	}
 
-	pub fn set_video_bitrate(&mut self, bitrate: u64) -> &mut Self {
-		self.video_bitrate = Some(bitrate);
-		self
-	}
-
 	pub fn run(mut self) -> anyhow::Result<()> {
 		let mut cmd = cmd();
 		cmd.arg("ffmpeg").arg("-hide_banner").arg("-y");
@@ -256,35 +303,7 @@ impl Ffmpeg {
 			}
 		}
 
-		// append encoding options
-		const QUALITY: &str = "22";
-		if venc {
-			if vaapi {
-				cmd.arg("-c:v").arg("h264_vaapi");
-				if self.video_bitrate.is_none() {
-					cmd.arg("-rc_mode").arg("CQP");
-					cmd.arg("-global_quality").arg(QUALITY);
-				}
-			} else {
-				cmd.arg("-c:v").arg("libx264");
-				if self.video_bitrate.is_none() {
-					cmd.arg("-crf").arg(QUALITY);
-				}
-			}
-			if self.video_bitrate.is_some() {
-				cmd.arg("-b:v").arg(self.video_bitrate.unwrap().to_string());
-			}
-		} else {
-			cmd.arg("-c:v").arg("copy");
-		}
-		if aenc {
-			cmd.arg("-c:a").arg("aac");
-			cmd.arg("-b:a").arg("128000");
-		} else {
-			cmd.arg("-c:a").arg("copy");
-		}
-
-		self.output.append_to_cmd(&mut cmd);
+		self.output.append_to_cmd(&mut cmd, venc, aenc, vaapi);
 
 		let status = cmd.status()?;
 		if status.success() {
diff --git a/src/render/mod.rs b/src/render/mod.rs
index 85ab9b28ca54c88275f439c299bcd598e23a7e27..e2576e245815bec94b66e890d8e43f3687f6ced0 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -1,7 +1,10 @@
 pub mod ffmpeg;
 mod filter;
 
-use self::{ffmpeg::FfmpegOutput, filter::Filter};
+use self::{
+	ffmpeg::{FfmpegOutput, FfmpegOutputFormat},
+	filter::Filter
+};
 use crate::{
 	iotro::{intro, outro},
 	render::ffmpeg::{Ffmpeg, FfmpegInput},
@@ -114,19 +117,17 @@ pub(crate) struct Renderer<'a> {
 	target: PathBuf
 }
 
-fn svg2mp4(
+fn svg2mkv(
 	meta: &ProjectSourceMetadata,
 	svg: PathBuf,
-	mp4: PathBuf,
+	mkv: PathBuf,
 	duration: Time
 ) -> anyhow::Result<()> {
 	let mut ffmpeg = Ffmpeg::new(FfmpegOutput {
-		fps: None,
 		duration: Some(duration),
 		time_base: Some(meta.source_tbn),
 		fps_mode_vfr: true,
-		faststart: false,
-		path: mp4
+		..FfmpegOutput::new(FfmpegOutputFormat::Av1Flac, mkv)
 	});
 	ffmpeg.add_input(FfmpegInput {
 		loop_input: true,
@@ -176,8 +177,16 @@ impl<'a> Renderer<'a> {
 		})
 	}
 
-	pub(crate) fn recording_mp4(&self) -> PathBuf {
-		self.target.join("recording.mp4")
+	pub(crate) fn recording_mkv(&self) -> PathBuf {
+		self.target.join("recording.mkv")
+	}
+
+	fn intro_mkv(&self) -> PathBuf {
+		self.target.join("intro.mkv")
+	}
+
+	fn outro_mkv(&self) -> PathBuf {
+		self.target.join("outro.mkv")
 	}
 
 	pub(crate) fn preprocess(&self, project: &mut Project) -> anyhow::Result<()> {
@@ -193,8 +202,11 @@ impl<'a> Renderer<'a> {
 		println!("\x1B[1m ==> Concatenating Video and Normalising Audio ...\x1B[0m");
 		let source_sample_rate =
 			ffprobe_audio("stream=sample_rate", &recording_txt)?.parse()?;
-		let recording_mp4 = self.recording_mp4();
-		let mut ffmpeg = Ffmpeg::new(FfmpegOutput::new(recording_mp4.clone()));
+		let recording_mkv = self.recording_mkv();
+		let mut ffmpeg = Ffmpeg::new(FfmpegOutput::new(
+			FfmpegOutputFormat::Av1Flac,
+			recording_mkv.clone()
+		));
 		ffmpeg.add_input(FfmpegInput {
 			concat: true,
 			..FfmpegInput::new(recording_txt)
@@ -202,8 +214,8 @@ impl<'a> Renderer<'a> {
 		ffmpeg.enable_loudnorm();
 		ffmpeg.run()?;
 
-		let width = ffprobe_video("stream=width", &recording_mp4)?.parse()?;
-		let height = ffprobe_video("stream=height", &recording_mp4)?.parse()?;
+		let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?;
+		let height = ffprobe_video("stream=height", &recording_mkv)?.parse()?;
 		let source_res = match (width, height) {
 			(3840, 2160) => Resolution::UHD,
 			(2560, 1440) => Resolution::WQHD,
@@ -213,9 +225,9 @@ impl<'a> Renderer<'a> {
 			(width, height) => bail!("Unknown resolution: {width}x{height}")
 		};
 		project.source.metadata = Some(ProjectSourceMetadata {
-			source_duration: ffprobe_video("format=duration", &recording_mp4)?.parse()?,
-			source_fps: ffprobe_video("stream=r_frame_rate", &recording_mp4)?.parse()?,
-			source_tbn: ffprobe_video("stream=time_base", &recording_mp4)?.parse()?,
+			source_duration: ffprobe_video("format=duration", &recording_mkv)?.parse()?,
+			source_fps: ffprobe_video("stream=r_frame_rate", &recording_mkv)?.parse()?,
+			source_tbn: ffprobe_video("stream=time_base", &recording_mkv)?.parse()?,
 			source_res,
 			source_sample_rate
 		});
@@ -231,8 +243,8 @@ impl<'a> Renderer<'a> {
 				.to_string_pretty()
 				.into_bytes()
 		)?;
-		let intro_mp4 = self.target.join("intro.mp4");
-		svg2mp4(metadata, intro_svg, intro_mp4, INTRO_LEN)?;
+		let intro_mkv = self.intro_mkv();
+		svg2mkv(metadata, intro_svg, intro_mkv, INTRO_LEN)?;
 
 		// render outro to svg then mp4
 		let outro_svg = self.target.join("outro.svg");
@@ -240,8 +252,8 @@ impl<'a> Renderer<'a> {
 			&outro_svg,
 			outro(source_res).to_string_pretty().into_bytes()
 		)?;
-		let outro_mp4 = self.target.join("outro.mp4");
-		svg2mp4(metadata, outro_svg, outro_mp4, OUTRO_LEN)?;
+		let outro_mkv = self.outro_mkv();
+		svg2mkv(metadata, outro_svg, outro_mkv, OUTRO_LEN)?;
 
 		// copy logo then render to png
 		let logo_svg = self.target.join("logo.svg");
@@ -271,25 +283,35 @@ impl<'a> Renderer<'a> {
 		Ok(())
 	}
 
-	fn video_mp4_res(&self, res: Resolution) -> PathBuf {
+	/// Get the video file for a specific resolution, completely finished.
+	fn video_file_res(&self, res: Resolution) -> PathBuf {
+		let extension = match res.format() {
+			FfmpegOutputFormat::Av1Flac => "mkv",
+			FfmpegOutputFormat::Av1Opus => "webm",
+			FfmpegOutputFormat::AvcAac => "mp4"
+		};
 		self.target
-			.join(format!("{}-{}p.mp4", self.slug, res.height()))
+			.join(format!("{}-{}p.{extension}", self.slug, res.height()))
 	}
 
-	pub(crate) fn video_mp4(&self, project: &Project) -> PathBuf {
-		self.video_mp4_res(project.source.metadata.as_ref().unwrap().source_res)
+	/// Get the video file directly outputed to further transcode.
+	pub(crate) fn video_file_output(&self) -> PathBuf {
+		self.target.join(format!("{}.mkv", self.slug))
 	}
 
 	pub(crate) fn render(&self, project: &mut Project) -> anyhow::Result<PathBuf> {
 		let source_res = project.source.metadata.as_ref().unwrap().source_res;
 
-		let output = self.video_mp4(project);
-		let mut ffmpeg = Ffmpeg::new(FfmpegOutput::new(output.clone()));
+		let output = self.video_file_output();
+		let mut ffmpeg = Ffmpeg::new(FfmpegOutput {
+			video_bitrate: Some(source_res.bitrate() * 3),
+			..FfmpegOutput::new(FfmpegOutputFormat::Av1Flac, output.clone())
+		});
 
 		// add all of our inputs
-		let intro = ffmpeg.add_input(FfmpegInput::new(self.target.join("intro.mp4")));
-		let rec_file = self.target.join("recording.mp4");
-		let outro = ffmpeg.add_input(FfmpegInput::new(self.target.join("outro.mp4")));
+		let intro = ffmpeg.add_input(FfmpegInput::new(self.intro_mkv()));
+		let rec_file = self.recording_mkv();
+		let outro = ffmpeg.add_input(FfmpegInput::new(self.outro_mkv()));
 		let logo = ffmpeg.add_input(FfmpegInput::new(self.target.join("logo.png")));
 		let ff = ffmpeg.add_input(FfmpegInput::new(self.target.join("fastforward.png")));
 
@@ -444,22 +466,22 @@ impl<'a> Renderer<'a> {
 
 		// we're done :)
 		ffmpeg.set_filter_output(overlay);
-		ffmpeg.set_video_bitrate(source_res.bitrate() * 3);
 		ffmpeg.run()?;
 
 		Ok(output)
 	}
 
-	pub fn rescale(&self, res: Resolution, project: &Project) -> anyhow::Result<PathBuf> {
-		let input = self.video_mp4(project);
-		let output = self.video_mp4_res(res);
+	pub fn rescale(&self, res: Resolution) -> anyhow::Result<PathBuf> {
+		let input = self.video_file_output();
+		let output = self.video_file_res(res);
 		println!("\x1B[1m ==> Rescaling to {}p\x1B[0m", res.height());
 
-		let mut ffmpeg =
-			Ffmpeg::new(FfmpegOutput::new(output.clone()).enable_faststart());
+		let mut ffmpeg = Ffmpeg::new(FfmpegOutput {
+			video_bitrate: Some(res.bitrate()),
+			..FfmpegOutput::new(res.format(), output.clone()).enable_faststart()
+		});
 		ffmpeg.add_input(FfmpegInput::new(input));
 		ffmpeg.rescale_video(res);
-		ffmpeg.set_video_bitrate(res.bitrate());
 		ffmpeg.run()?;
 		Ok(output)
 	}