use anyhow::Context;
#[derive(usage::Cli)]
#[usage(bin = "transcode", unknown_flags = "error", args_override_self = false)]
struct Args {
#[usage(long, default = "http://localhost:4443/anon")]
url: url::Url,
#[usage(long)]
source: String,
#[usage(long)]
output: Option<String>,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
moq_tokio::Log::new(tracing::Level::INFO).init()?;
let args = Args::parse();
let source_path = moq_net::PathOwned::from(args.source);
let output_path = moq_net::PathOwned::from(
args.output
.clone()
.unwrap_or_else(|| format!("{source_path}/transcode.hang")),
);
let publish = moq_tokio::origin::spawn();
let remote = moq_tokio::origin::spawn();
let client = moq_tokio::connect::Config::default().init(Default::default())?;
let session = client
.with_publisher(&publish)
.with_subscriber(remote.clone())
.connect(args.url.clone());
let consumer = remote.consume();
tokio::select! {
routed = consumer.routed(&source_path) => {
routed.context("origin closed before the source broadcast was announced")?;
}
closed = session.closed() => {
closed.context("session failed before the source broadcast was announced")?;
anyhow::bail!("session closed before the source broadcast was announced");
}
}
let source = consumer
.request_broadcast(&source_path)
.await
.context("source broadcast unavailable")?;
let mut config = moq_transcode::Config::default();
config.source = source_path.relative(&output_path).filter(|rel| !rel.is_empty());
let output = publish
.create_broadcast(&output_path)
.context("failed to create the derivative broadcast")?;
output
.announce(Default::default())
.context("failed to announce the derivative broadcast")?;
tracing::info!(source = %source_path, output = %output_path, "transcoding");
tokio::select! {
res = moq_transcode::run(source, output, config) => Ok(res?),
res = session.closed() => Ok(res?),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_defaults() {
let argv = ["transcode", "--source", "input"].map(std::ffi::OsStr::new);
let args = Args::try_parse_from(&argv).unwrap();
assert_eq!(args.url.as_str(), "http://localhost:4443/anon");
assert_eq!(args.source, "input");
assert_eq!(args.output, None);
}
#[test]
fn rejects_unknown_and_duplicate_flags() {
let unknown = ["transcode", "--source", "input", "--unknown"].map(std::ffi::OsStr::new);
assert!(Args::try_parse_from(&unknown).is_err());
let duplicate = ["transcode", "--source", "input", "--source", "other"].map(std::ffi::OsStr::new);
assert!(Args::try_parse_from(&duplicate).is_err());
}
}