mod compat;
mod infrastructure;
mod subtitle;
mod video;
pub(crate) use compat::PresetCommand;
pub(crate) use infrastructure::MonitorCommand;
pub(crate) use subtitle::CaptionsCommand;
pub(crate) use video::RestoreCommand;
use clap::Subcommand;
use std::path::PathBuf;
use crate::aaf_cmd;
use crate::access_cmd;
use crate::align_cmd;
use crate::archive_cmd;
use crate::archivepro_cmd;
use crate::audio_cmd;
use crate::audiopost_cmd;
use crate::auto_cmd;
use crate::batch_cmd;
use crate::calibrate_cmd;
use crate::clips_cmd;
use crate::cloud_cmd;
use crate::collab_cmd;
use crate::color_cmd;
use crate::conform_cmd;
use crate::dedup_cmd;
use crate::distributed_cmd;
use crate::dolbyvision_cmd;
use crate::drm_cmd;
use crate::edl_cmd;
use crate::farm_cmd;
use crate::filter_cmd;
use crate::gaming_cmd;
use crate::graphics_cmd;
use crate::image_cmd;
use crate::imf_cmd;
use crate::loudness_cmd;
use crate::lut_cmd;
use crate::mam_cmd;
use crate::mir_cmd;
use crate::mixer_cmd;
use crate::ml_cmd;
use crate::multicam_cmd;
use crate::ndi_cmd;
use crate::normalize_cmd;
use crate::optimize_cmd;
use crate::playlist_cmd;
use crate::playout_cmd;
use crate::plugin_cmd;
use crate::profiler_cmd;
use crate::proxy_cmd;
use crate::qc_cmd;
use crate::quality_cmd;
use crate::recommend_cmd;
use crate::renderfarm_cmd;
use crate::repair_cmd;
use crate::review_cmd;
use crate::rights_cmd;
use crate::routing_cmd;
use crate::scaling_cmd;
use crate::scene;
use crate::scopes_cmd;
use crate::search_cmd;
use crate::stream_cmd;
use crate::subtitle_cmd;
use crate::switcher_cmd;
use crate::timecode_cmd;
use crate::timeline_cmd;
use crate::timesync_cmd;
use crate::vfx_cmd;
use crate::videoip_cmd;
use crate::virtual_cmd;
use crate::watermark_cmd;
use crate::workflow_cmd;
#[derive(Subcommand)]
pub(crate) enum Commands {
Probe {
#[arg(short, long)]
input: PathBuf,
#[arg(long)]
detail: bool,
#[arg(short, long)]
streams: bool,
#[arg(long)]
hash: bool,
#[arg(long)]
quality_snapshot: bool,
#[arg(long, default_value = "text")]
format: String,
#[arg(long)]
chapters: bool,
#[arg(long)]
metadata: bool,
},
Info,
Version,
#[command(alias = "convert")]
Transcode {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: PathBuf,
#[arg(long = "preset-name", conflicts_with_all = &["video_codec", "audio_codec", "video_bitrate", "audio_bitrate"])]
preset_name: Option<String>,
#[arg(long = "codec", alias = "c:v")]
video_codec: Option<String>,
#[arg(long, alias = "c:a")]
audio_codec: Option<String>,
#[arg(long = "bitrate", alias = "b:v")]
video_bitrate: Option<String>,
#[arg(long, alias = "b:a")]
audio_bitrate: Option<String>,
#[arg(long)]
scale: Option<String>,
#[arg(long, alias = "vf")]
video_filter: Option<String>,
#[arg(long, alias = "ss")]
start_time: Option<String>,
#[arg(short = 't', long)]
duration: Option<String>,
#[arg(short = 'r', long)]
framerate: Option<String>,
#[arg(long, default_value = "medium")]
preset: String,
#[arg(long)]
two_pass: bool,
#[arg(long)]
crf: Option<u32>,
#[arg(long, default_value = "0")]
threads: usize,
#[arg(short = 'y', long)]
overwrite: bool,
#[arg(long)]
resume: bool,
#[arg(long, alias = "af")]
audio_filter: Option<String>,
#[arg(long)]
map: Vec<String>,
#[arg(long)]
normalize_audio: bool,
},
Extract {
#[arg(value_name = "INPUT")]
input: PathBuf,
#[arg(value_name = "OUTPUT_PATTERN")]
output_pattern: String,
#[arg(short, long)]
format: Option<String>,
#[arg(long, alias = "ss")]
start_time: Option<String>,
#[arg(short = 'n', long)]
frames: Option<usize>,
#[arg(long, default_value = "1")]
every: usize,
#[arg(long, default_value = "90")]
quality: u8,
},
Batch {
#[arg(value_name = "INPUT_DIR")]
input_dir: PathBuf,
#[arg(value_name = "OUTPUT_DIR")]
output_dir: PathBuf,
#[arg(value_name = "CONFIG")]
config: PathBuf,
#[arg(short, long, default_value = "0")]
jobs: usize,
#[arg(long)]
continue_on_error: bool,
#[arg(long)]
dry_run: bool,
},
Concat {
#[arg(value_name = "INPUTS", required = true, num_args = 2..)]
inputs: Vec<PathBuf>,
#[arg(short, long)]
output: PathBuf,
#[arg(long, default_value = "remux")]
method: String,
#[arg(long)]
validate: bool,
#[arg(short = 'y', long)]
overwrite: bool,
},
Thumbnail {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: PathBuf,
#[arg(long, default_value = "auto")]
mode: String,
#[arg(long)]
timestamp: Option<String>,
#[arg(long, default_value = "9")]
count: usize,
#[arg(long, default_value = "3")]
rows: usize,
#[arg(long, default_value = "3")]
cols: usize,
#[arg(long)]
width: Option<u32>,
#[arg(long)]
height: Option<u32>,
#[arg(short, long, default_value = "png")]
format: String,
#[arg(long, default_value = "90")]
quality: u8,
},
Sprite {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: PathBuf,
#[arg(long, conflicts_with = "count")]
interval: Option<String>,
#[arg(long, conflicts_with = "interval")]
count: Option<usize>,
#[arg(long, default_value = "5")]
cols: usize,
#[arg(long, default_value = "5")]
rows: usize,
#[arg(long, default_value = "160")]
width: u32,
#[arg(long, default_value = "90")]
height: u32,
#[arg(short, long, default_value = "png")]
format: String,
#[arg(long, default_value = "90")]
quality: u8,
#[arg(long, default_value = "6")]
compression: u8,
#[arg(long, default_value = "uniform")]
strategy: String,
#[arg(long, default_value = "grid")]
layout: String,
#[arg(long, default_value = "2")]
spacing: u32,
#[arg(long, default_value = "0")]
margin: u32,
#[arg(long)]
vtt: bool,
#[arg(long, requires = "vtt")]
vtt_output: Option<PathBuf>,
#[arg(long)]
manifest: bool,
#[arg(long, requires = "manifest")]
manifest_output: Option<PathBuf>,
#[arg(long)]
timestamps: bool,
#[arg(long, default_value = "true")]
aspect: bool,
},
Metadata {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: Option<PathBuf>,
#[arg(long)]
show: bool,
#[arg(long, value_parser = parse_key_val)]
set: Vec<(String, String)>,
#[arg(long)]
remove: Vec<String>,
#[arg(long)]
clear: bool,
#[arg(long)]
copy_from: Option<PathBuf>,
},
Benchmark {
#[arg(short, long)]
input: PathBuf,
#[arg(long, default_values = &["av1", "vp9"])]
codecs: Vec<String>,
#[arg(long, default_values = &["fast", "medium", "slow"])]
presets: Vec<String>,
#[arg(long)]
duration: Option<u64>,
#[arg(long, default_value = "1")]
iterations: usize,
#[arg(long)]
output_dir: Option<PathBuf>,
},
Validate {
#[arg(value_name = "INPUTS", required = true)]
inputs: Vec<PathBuf>,
#[arg(long, default_values = &["all"])]
checks: Vec<String>,
#[arg(long)]
strict: bool,
#[arg(long)]
fix: bool,
#[arg(long)]
loudness_check: bool,
#[arg(long)]
gamut_check: bool,
},
Analyze {
#[arg(short, long)]
input: PathBuf,
#[arg(long)]
reference: Option<PathBuf>,
#[arg(long, default_value = "brisque,niqe,blockiness,blur,noise")]
metrics: String,
#[arg(long, default_value = "text")]
output_format: String,
#[arg(long)]
per_frame: bool,
#[arg(long)]
summary: bool,
},
Scene {
#[command(subcommand)]
command: scene::SceneCommand,
},
Scopes {
#[command(subcommand)]
command: scopes_cmd::ScopesCommand,
},
Audio {
#[command(subcommand)]
command: audio_cmd::AudioCommand,
},
Subtitle {
#[command(subcommand)]
command: subtitle_cmd::SubtitleCommand,
},
Filter {
#[command(subcommand)]
command: filter_cmd::FilterCommand,
},
Lut {
#[command(subcommand)]
command: lut_cmd::LutCommand,
},
Denoise {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: PathBuf,
#[arg(long, default_value = "balanced")]
mode: String,
#[arg(long, default_value = "0.5")]
strength: f32,
#[arg(long)]
spatial: bool,
#[arg(long)]
temporal: bool,
#[arg(long)]
preserve_grain: bool,
},
Stabilize {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: PathBuf,
#[arg(long, default_value = "affine")]
mode: String,
#[arg(long, default_value = "balanced")]
quality: String,
#[arg(long, default_value = "30")]
smoothing: u32,
#[arg(long)]
zoom: bool,
},
Edl {
#[command(subcommand)]
command: edl_cmd::EdlCommand,
},
Package {
#[arg(short, long)]
input: PathBuf,
#[arg(short, long)]
output: PathBuf,
#[arg(long, default_value = "hls")]
format: String,
#[arg(long, default_value = "6")]
segments: u32,
#[arg(long, default_value = "auto")]
ladders: String,
#[arg(long, default_value = "none")]
encrypt: String,
#[arg(long)]
low_latency: bool,
},
Forensics {
#[arg(short, long)]
input: PathBuf,
#[arg(long)]
all: bool,
#[arg(long, default_value = "")]
tests: String,
#[arg(long, default_value = "text")]
output_format: String,
#[arg(long)]
report: Option<PathBuf>,
},
Monitor {
#[command(subcommand)]
command: MonitorCommand,
},
Restore {
#[command(subcommand)]
command: RestoreCommand,
},
Captions {
#[command(subcommand)]
command: CaptionsCommand,
},
Stream {
#[command(subcommand)]
command: stream_cmd::StreamCommand,
},
Search {
#[command(subcommand)]
command: search_cmd::SearchCommand,
},
Timecode {
#[command(subcommand)]
command: timecode_cmd::TimecodeCommand,
},
Repair {
#[command(subcommand)]
command: repair_cmd::RepairCommand,
},
Color {
#[command(subcommand)]
command: color_cmd::ColorCommand,
},
Playlist {
#[command(subcommand)]
command: playlist_cmd::PlaylistSubcommand,
},
Conform {
#[command(subcommand)]
command: conform_cmd::ConformSubcommand,
},
Archive {
#[command(subcommand)]
command: archive_cmd::ArchiveSubcommand,
},
Watermark {
#[command(subcommand)]
command: watermark_cmd::WatermarkSubcommand,
},
Image {
#[command(subcommand)]
command: image_cmd::ImageCommand,
},
Graphics {
#[command(subcommand)]
command: graphics_cmd::GraphicsCommand,
},
Multicam {
#[command(subcommand)]
command: multicam_cmd::MulticamCommand,
},
Timeline {
#[command(subcommand)]
command: timeline_cmd::TimelineCommand,
},
Vfx {
#[command(subcommand)]
command: vfx_cmd::VfxCommand,
},
#[command(alias = "ff")]
Ffcompat {
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
Tui,
Optimize {
#[command(subcommand)]
command: optimize_cmd::OptimizeCommand,
},
Preset {
#[command(subcommand)]
command: PresetCommand,
},
Mixer {
#[command(subcommand)]
command: mixer_cmd::MixerCommand,
},
Audiopost {
#[command(subcommand)]
command: audiopost_cmd::AudiopostCommand,
},
Distributed {
#[command(subcommand)]
command: distributed_cmd::DistributedCommand,
},
Farm {
#[command(subcommand)]
command: farm_cmd::FarmCommand,
},
Ndi {
#[command(subcommand)]
command: ndi_cmd::NdiCommand,
},
Videoip {
#[command(subcommand)]
command: videoip_cmd::VideoIpCommand,
},
Gaming {
#[command(subcommand)]
command: gaming_cmd::GamingCommand,
},
Mam {
#[command(subcommand)]
command: mam_cmd::MamCommand,
},
Cloud {
#[command(subcommand)]
command: cloud_cmd::CloudCommand,
},
Plugin {
#[command(subcommand)]
command: plugin_cmd::PluginCommand,
},
Mir {
#[command(subcommand)]
command: mir_cmd::MirCommand,
},
Qc {
#[command(subcommand)]
command: qc_cmd::QcCommand,
},
Imf {
#[command(subcommand)]
command: imf_cmd::ImfCommand,
},
Aaf {
#[command(subcommand)]
command: aaf_cmd::AafCommand,
},
Playout {
#[command(subcommand)]
command: playout_cmd::PlayoutCommand,
},
Switcher {
#[command(subcommand)]
command: switcher_cmd::SwitcherCommand,
},
Workflow {
#[command(subcommand)]
command: workflow_cmd::WorkflowCommand,
},
Collab {
#[command(subcommand)]
command: collab_cmd::CollabCommand,
},
Proxy {
#[command(subcommand)]
command: proxy_cmd::ProxyCommand,
},
Clips {
#[command(subcommand)]
command: clips_cmd::ClipsCommand,
},
Review {
#[command(subcommand)]
command: review_cmd::ReviewCommand,
},
Drm {
#[command(subcommand)]
command: drm_cmd::DrmCommand,
},
Dedup {
#[command(subcommand)]
command: dedup_cmd::DedupCommand,
},
#[command(name = "archive-pro")]
ArchivePro {
#[command(subcommand)]
command: archivepro_cmd::ArchiveProCommand,
},
#[command(name = "dolby-vision")]
DolbyVision {
#[command(subcommand)]
command: dolbyvision_cmd::DolbyVisionCommand,
},
#[command(name = "timesync")]
TimeSync {
#[command(subcommand)]
command: timesync_cmd::TimeSyncCommand,
},
Align {
#[command(subcommand)]
command: align_cmd::AlignCommand,
},
Routing {
#[command(subcommand)]
command: routing_cmd::RoutingCommand,
},
Calibrate {
#[command(subcommand)]
command: calibrate_cmd::CalibrateCommand,
},
Virtual {
#[command(subcommand)]
command: virtual_cmd::VirtualCommand,
},
Profiler {
#[command(subcommand)]
command: profiler_cmd::ProfilerCommand,
},
Recommend {
#[command(subcommand)]
command: recommend_cmd::RecommendCommand,
},
Scaling {
#[command(subcommand)]
command: scaling_cmd::ScalingCommand,
},
Renderfarm {
#[command(subcommand)]
command: renderfarm_cmd::RenderfarmCommand,
},
Access {
#[command(subcommand)]
command: access_cmd::AccessCommand,
},
Rights {
#[command(subcommand)]
command: rights_cmd::RightsCommand,
},
Auto {
#[command(subcommand)]
command: auto_cmd::AutoCommand,
},
Loudness {
#[command(subcommand)]
command: loudness_cmd::LoudnessCommand,
},
Quality {
#[command(subcommand)]
command: quality_cmd::QualityCommand,
},
Normalize {
#[command(subcommand)]
command: normalize_cmd::NormalizeCommand,
},
#[command(name = "batch-engine")]
BatchEngine {
#[command(subcommand)]
command: batch_cmd::BatchEngineCommand,
},
Ml {
#[command(subcommand)]
command: ml_cmd::MlCommand,
},
Completions {
shell: clap_complete::Shell,
},
#[command(name = "man-page")]
ManPage,
Doctor {
#[arg(long)]
json: bool,
#[arg(long)]
full: bool,
},
}
pub(crate) fn parse_key_val(s: &str) -> Result<(String, String), String> {
let pos = s
.find('=')
.ok_or_else(|| format!("Invalid KEY=value: no `=` found in `{}`", s))?;
Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
}