Skip to content

Instantly share code, notes, and snippets.

@19wintersp
Created March 27, 2022 04:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 19wintersp/bf537acdbbcbaf9d6384514722b0cfc6 to your computer and use it in GitHub Desktop.
Save 19wintersp/bf537acdbbcbaf9d6384514722b0cfc6 to your computer and use it in GitHub Desktop.
Code to generate a WebM file that will show differently depending on the player
[package]
name = "weird-discord-video"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "^1.0"
argh = "^0.1"
webm-iterable = "^0.3"
#[macro_use] extern crate anyhow;
use std::fs::File;
use std::process::Command;
use anyhow::Result;
use argh::FromArgs;
use webm_iterable::{ WebmIterator, WebmWriter };
use webm_iterable::matroska_spec::{ Master, MatroskaSpec as Spec };
/// Create videos that show differently on different platforms.
#[derive(FromArgs)]
struct Args {
/// video to show on android
#[argh(option)]
android_video: Option<String>,
/// video to show on firefox
#[argh(option)]
firefox_video: Option<String>,
/// video to show on chromium/electron app
#[argh(option)]
chromium_video: Option<String>,
/// video to show on all platforms
#[argh(option, short = 'v')]
video: Option<String>,
/// audio to play on android
#[argh(option)]
android_audio: Option<String>,
/// audio to play on firefox
#[argh(option)]
firefox_audio: Option<String>,
/// audio to play on chromium/electron app
#[argh(option)]
chromium_audio: Option<String>,
/// audio to play on all platforms
#[argh(option, short = 'a')]
audio: Option<String>,
/// path to output WEBM file
#[argh(option, short = 'o')]
output: Option<String>,
/// ffmpeg command to execute
#[argh(option)]
ffmpeg: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum Platform {
Android,
Firefox,
Chromium,
All,
}
fn main() {
if let Err(err) = kmain() {
eprintln!("error: {}", err);
std::process::exit(1);
}
}
fn kmain() -> Result<()> {
let args = argh::from_env::<Args>();
if args.video.is_some() {
if
args.android_video.is_some() ||
args.firefox_video.is_some() ||
args.chromium_video.is_some()
{
bail!("cannot have all and specific video");
}
}
if args.audio.is_some() {
if
args.android_audio.is_some() ||
args.firefox_audio.is_some() ||
args.chromium_audio.is_some()
{
bail!("cannot have all and specific audio");
}
}
let output = args.output.unwrap_or("output.webm".into());
let ffmpeg = args.ffmpeg.unwrap_or("ffmpeg".into());
// create the basic video
let temp_output = {
let mut temp = std::env::temp_dir();
temp.push("temp.webm");
if temp.exists() {
std::fs::remove_file(&temp)?;
}
temp.to_string_lossy().to_string()
};
let mut platforms = Vec::new();
let mut command = Vec::new();
if let Some(video) = args.android_video {
platforms.push(Platform::Android);
command.append(&mut vec![ "-i".into(), video ]);
}
if let Some(video) = args.firefox_video {
platforms.push(Platform::Firefox);
command.append(&mut vec![ "-i".into(), video ]);
}
if let Some(video) = args.chromium_video {
platforms.push(Platform::Chromium);
command.append(&mut vec![ "-i".into(), video ]);
}
if let Some(video) = args.video {
platforms.push(Platform::All);
command.append(&mut vec![ "-i".into(), video ]);
}
if let Some(audio) = args.android_audio {
platforms.push(Platform::Android);
command.append(&mut vec![ "-i".into(), audio ]);
}
if let Some(audio) = args.firefox_audio {
platforms.push(Platform::Firefox);
command.append(&mut vec![ "-i".into(), audio ]);
}
if let Some(audio) = args.chromium_audio {
platforms.push(Platform::Chromium);
command.append(&mut vec![ "-i".into(), audio ]);
}
if let Some(audio) = args.audio {
platforms.push(Platform::All);
command.append(&mut vec![ "-i".into(), audio ]);
}
command.append(
&mut (0..command.len() / 2)
.map(|index| vec![ "-map".into(), index.to_string() ])
.collect::<Vec<_>>()
.concat()
);
command.push(temp_output.clone());
let status = Command::new(ffmpeg)
.args(command)
.spawn()?
.wait()?;
if !status.success() {
bail!("ffmpeg exited with non-zero exit code");
}
// screw up the video
let webm_input = File::open(temp_output)?;
let webm_output = File::create(output)?;
let track_start = Spec::Tracks(Master::Start);
let tag_input = WebmIterator::new(webm_input, &[track_start]);
let mut tag_output = WebmWriter::new(webm_output);
// by god i renounce this cursèd child of mine
for tag_result in tag_input {
let tag = tag_result?;
if let Spec::Tracks(master) = tag {
if let Master::Full(tag_tracks) = master {
tag_output.write(&Spec::Tracks(Master::Start))?;
for (i, track) in tag_tracks.iter().enumerate() {
if let Spec::TrackEntry(Master::Full(tags)) = track {
tag_output.write(&Spec::TrackEntry(Master::Start))?;
for tag in tags {
match tag {
Spec::TrackType(_) => {
if
platforms[i] == Platform::All ||
platforms[i] == Platform::Chromium
{
tag_output.write(tag)?;
}
},
Spec::CodecId(id) => {
tag_output.write(tag)?;
let true_type = match &id[..2] {
"A_" => 2,
"V_" => 1,
_ => bail!("codec id is not video or audio"),
};
let track_type = match platforms[i] {
Platform::Android => 3,
Platform::Firefox => true_type,
_ => continue,
};
tag_output.write(&Spec::TrackType(track_type))?;
},
Spec::Video(_) | Spec::Audio(_) => {
tag_output.write(tag)?;
if platforms[i] == Platform::Firefox {
tag_output.write(&Spec::TrackType(3))?;
}
},
Spec::Language(_) => {
tag_output.write(tag)?;
if platforms[i] != Platform::Android {
tag_output.write(&Spec::FlagDefault(0))?;
}
},
Spec::FlagDefault(_) => (),
_ => tag_output.write(tag)?,
}
}
tag_output.write(&Spec::TrackEntry(Master::End))?;
} else {
unreachable!()
}
}
tag_output.write(&Spec::Tracks(Master::End))?;
} else {
unreachable!()
}
} else {
tag_output.write(&tag)?;
}
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment