pub mod media;
use std::path::{Path, PathBuf};
use thiserror::Error;
use crate::detect::MediaKind;
use crate::options::{AudioChoice, AudioCodec, FpsOpt, QualityPreset, ResolutionOpt, VideoCodec};
use crate::size::Preset;
#[derive(Debug, Clone, PartialEq)]
pub struct MediaInfo {
pub path: PathBuf,
pub kind: MediaKind,
pub duration_sec: f64,
pub size_bytes: u64,
pub width: Option<u32>,
pub height: Option<u32>,
pub fps: Option<f64>,
pub video_codec: Option<String>,
pub audio_codec: Option<String>,
pub audio_channels: Option<u32>,
}
impl MediaInfo {
pub fn has_audio(&self) -> bool {
self.audio_codec.is_some()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum SizeGoal {
Target(u64),
Reduce(f64),
Preset(Preset),
Quality,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ShrinkOpts {
pub goal: SizeGoal,
pub video_codec: VideoCodec,
pub audio: AudioChoice,
pub resolution: ResolutionOpt,
pub fps: FpsOpt,
pub quality: QualityPreset,
pub audio_codec: AudioCodec,
pub mono: bool,
pub sample_rate: Option<u32>,
pub vbr: bool,
pub target_vmaf: Option<f64>,
pub output: Option<PathBuf>,
}
impl Default for ShrinkOpts {
fn default() -> Self {
Self {
goal: SizeGoal::Quality,
video_codec: VideoCodec::H264,
audio: AudioChoice::Keep,
resolution: ResolutionOpt::Auto,
fps: FpsOpt::Auto,
quality: QualityPreset::Balanced,
audio_codec: AudioCodec::Aac,
mono: false,
sample_rate: None,
vbr: false,
target_vmaf: None,
output: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct VideoSpec {
pub codec: VideoCodec,
pub bitrate_bps: Option<u64>,
pub crf: Option<u8>,
pub height: Option<u32>,
pub fps: Option<u32>,
pub preset: QualityPreset,
}
#[derive(Debug, Clone, PartialEq)]
pub struct AudioSpec {
pub codec: AudioCodec,
pub bitrate_bps: u64,
pub mono: bool,
pub sample_rate: Option<u32>,
pub vbr: bool,
}
impl AudioSpec {
pub fn cbr(codec: AudioCodec, bitrate_bps: u64) -> Self {
Self {
codec,
bitrate_bps,
mono: false,
sample_rate: None,
vbr: false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct EncodeSpec {
pub video: VideoSpec,
pub audio: Option<AudioSpec>,
pub faststart: bool,
pub two_pass: bool,
pub passthrough: bool,
pub audio_only: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EncodePlan {
pub input: PathBuf,
pub output: PathBuf,
pub summary: String,
pub expected_bytes: Option<u64>,
pub target_bytes: Option<u64>,
pub target_vmaf: Option<f64>,
pub source_duration_sec: f64,
pub source_width: Option<u32>,
pub source_height: Option<u32>,
pub source_fps: Option<f64>,
pub spec: EncodeSpec,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Outcome {
pub output: PathBuf,
pub final_bytes: u64,
pub vmaf: Option<f64>,
}
#[derive(Debug, Error)]
pub enum EngineError {
#[error("input not supported by this engine: {0}")]
Unsupported(String),
#[error("cannot reach target size at a reasonable quality")]
Infeasible,
#[error("not yet implemented: {0}")]
NotImplemented(&'static str),
#[error(transparent)]
Ffmpeg(#[from] deepshrink_ffmpeg::FfmpegError),
#[error(transparent)]
Io(#[from] std::io::Error),
}
pub trait Engine {
fn supports(&self, input: &Path) -> bool;
fn probe(&self, input: &Path) -> Result<MediaInfo, EngineError>;
fn plan(&self, info: &MediaInfo, opts: &ShrinkOpts) -> Result<EncodePlan, EngineError>;
fn run(&self, plan: &EncodePlan) -> Result<Outcome, EngineError>;
}