use std::sync::Arc;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Codec(Arc<str>);
impl Codec {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
pub fn id(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for Codec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CodecKind {
Video,
Audio,
Image,
Subtitle,
Unknown,
}
pub mod video {
pub const H264: &str = "h264";
pub const H265: &str = "h265";
pub const VP8: &str = "vp8";
pub const VP9: &str = "vp9";
pub const AV1: &str = "av1";
pub const PRORES: &str = "prores";
pub const MPEG2: &str = "mpeg2";
pub const MPEG4: &str = "mpeg4";
pub const THEORA: &str = "theora";
pub const WMV3: &str = "wmv3";
}
pub mod audio {
pub const AAC: &str = "aac";
pub const OPUS: &str = "opus";
pub const MP3: &str = "mp3";
pub const FLAC: &str = "flac";
pub const VORBIS: &str = "vorbis";
pub const PCM: &str = "pcm";
pub const AC3: &str = "ac3";
pub const EAC3: &str = "eac3";
pub const WMA: &str = "wma";
pub const ALAC: &str = "alac";
}
pub mod image {
pub const PNG: &str = "png";
pub const JPEG: &str = "jpeg";
pub const WEBP: &str = "webp";
pub const GIF: &str = "gif";
pub const BMP: &str = "bmp";
pub const TIFF: &str = "tiff";
pub const AVIF: &str = "avif";
pub const HEIF: &str = "heif";
}
pub mod subtitle {
pub const SRT: &str = "srt";
pub const WEBVTT: &str = "webvtt";
pub const ASS: &str = "ass";
pub const SSA: &str = "ssa";
pub const MOV_TEXT: &str = "mov_text";
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CodecProfile {
H264Baseline,
H264Main,
H264High,
H264High10,
H264High422,
H264High444,
HevcMain,
HevcMain10,
HevcMain12,
HevcMainStillPicture,
Vp9Profile0,
Vp9Profile1,
Vp9Profile2,
Vp9Profile3,
Av1Main,
Av1High,
Av1Professional,
AacLc,
AacHe,
AacHeV2,
ProResProxy,
ProResLt,
ProRes422,
ProResHq,
ProRes4444,
Other(String),
}
impl CodecProfile {
pub fn as_ffmpeg_arg(&self) -> &str {
match self {
Self::H264Baseline => "baseline",
Self::H264Main => "main",
Self::H264High => "high",
Self::H264High10 => "high10",
Self::H264High422 => "high422",
Self::H264High444 => "high444p",
Self::HevcMain => "main",
Self::HevcMain10 => "main10",
Self::HevcMain12 => "main12",
Self::HevcMainStillPicture => "mainstillpicture",
Self::Vp9Profile0 => "0",
Self::Vp9Profile1 => "1",
Self::Vp9Profile2 => "2",
Self::Vp9Profile3 => "3",
Self::Av1Main => "0",
Self::Av1High => "1",
Self::Av1Professional => "2",
Self::AacLc => "aac_low",
Self::AacHe => "aac_he",
Self::AacHeV2 => "aac_he_v2",
Self::ProResProxy => "0",
Self::ProResLt => "1",
Self::ProRes422 => "2",
Self::ProResHq => "3",
Self::ProRes4444 => "4",
Self::Other(s) => s.as_str(),
}
}
pub fn from_ffprobe(s: &str) -> Option<Self> {
let lower = s.to_lowercase();
let trimmed = lower.trim();
match trimmed {
"constrained baseline" | "baseline" => Some(Self::H264Baseline),
"main" => Some(Self::H264Main),
"high" => Some(Self::H264High),
"high 10" | "high10" => Some(Self::H264High10),
"high 4:2:2" | "high422" => Some(Self::H264High422),
"high 4:4:4 predictive" | "high444" | "high 4:4:4" => Some(Self::H264High444),
"main still picture" => Some(Self::HevcMainStillPicture),
"main 10" | "main10" => Some(Self::HevcMain10),
"main 12" | "main12" => Some(Self::HevcMain12),
"profile 0" => Some(Self::Vp9Profile0),
"profile 1" => Some(Self::Vp9Profile1),
"profile 2" => Some(Self::Vp9Profile2),
"profile 3" => Some(Self::Vp9Profile3),
"lc" | "aac-lc" => Some(Self::AacLc),
"he-aac" | "he-aacv1" => Some(Self::AacHe),
"he-aacv2" => Some(Self::AacHeV2),
"apco" | "proxy" => Some(Self::ProResProxy),
"apcs" | "lt" => Some(Self::ProResLt),
"apcn" | "standard" | "422" => Some(Self::ProRes422),
"apch" | "hq" => Some(Self::ProResHq),
"ap4h" | "4444" => Some(Self::ProRes4444),
_ => {
if trimmed.is_empty() || trimmed == "unknown" {
None
} else {
Some(Self::Other(s.into()))
}
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct CodecLevel(Arc<str>);
impl CodecLevel {
pub fn new(level: impl Into<Arc<str>>) -> Self {
Self(level.into())
}
pub fn id(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for CodecLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
pub mod levels {
use super::CodecLevel;
pub fn h264_3_0() -> CodecLevel {
CodecLevel::new("3.0")
}
pub fn h264_3_1() -> CodecLevel {
CodecLevel::new("3.1")
}
pub fn h264_4_0() -> CodecLevel {
CodecLevel::new("4.0")
}
pub fn h264_4_1() -> CodecLevel {
CodecLevel::new("4.1")
}
pub fn h264_5_0() -> CodecLevel {
CodecLevel::new("5.0")
}
pub fn h264_5_1() -> CodecLevel {
CodecLevel::new("5.1")
}
pub fn h264_5_2() -> CodecLevel {
CodecLevel::new("5.2")
}
}