1use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub struct Codec(Arc<str>);
22
23impl Codec {
24 pub fn new(id: impl Into<Arc<str>>) -> Self {
26 Self(id.into())
27 }
28
29 pub fn id(&self) -> &str {
31 &self.0
32 }
33}
34
35impl std::fmt::Display for Codec {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.write_str(&self.0)
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
43pub enum CodecKind {
44 Video,
46 Audio,
48 Image,
50 Subtitle,
52 Unknown,
54}
55
56pub mod video {
58 pub const H264: &str = "h264";
60 pub const H265: &str = "h265";
62 pub const VP8: &str = "vp8";
64 pub const VP9: &str = "vp9";
66 pub const AV1: &str = "av1";
68 pub const PRORES: &str = "prores";
70 pub const MPEG2: &str = "mpeg2";
72 pub const MPEG4: &str = "mpeg4";
74 pub const THEORA: &str = "theora";
76 pub const WMV3: &str = "wmv3";
78}
79
80pub mod audio {
82 pub const AAC: &str = "aac";
84 pub const OPUS: &str = "opus";
86 pub const MP3: &str = "mp3";
88 pub const FLAC: &str = "flac";
90 pub const VORBIS: &str = "vorbis";
92 pub const PCM: &str = "pcm";
94 pub const AC3: &str = "ac3";
96 pub const EAC3: &str = "eac3";
98 pub const WMA: &str = "wma";
100 pub const ALAC: &str = "alac";
102}
103
104pub mod image {
106 pub const PNG: &str = "png";
108 pub const JPEG: &str = "jpeg";
110 pub const WEBP: &str = "webp";
112 pub const GIF: &str = "gif";
114 pub const BMP: &str = "bmp";
116 pub const TIFF: &str = "tiff";
118 pub const AVIF: &str = "avif";
120 pub const HEIF: &str = "heif";
122}
123
124pub mod subtitle {
126 pub const SRT: &str = "srt";
128 pub const WEBVTT: &str = "webvtt";
130 pub const ASS: &str = "ass";
132 pub const SSA: &str = "ssa";
134 pub const MOV_TEXT: &str = "mov_text";
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
143pub enum CodecProfile {
144 H264Baseline,
147 H264Main,
149 H264High,
151 H264High10,
153 H264High422,
155 H264High444,
157
158 HevcMain,
161 HevcMain10,
163 HevcMain12,
165 HevcMainStillPicture,
167
168 Vp9Profile0,
171 Vp9Profile1,
173 Vp9Profile2,
175 Vp9Profile3,
177
178 Av1Main,
181 Av1High,
183 Av1Professional,
185
186 AacLc,
189 AacHe,
191 AacHeV2,
193
194 ProResProxy,
197 ProResLt,
199 ProRes422,
201 ProResHq,
203 ProRes4444,
205
206 Other(String),
208}
209
210impl CodecProfile {
211 pub fn as_ffmpeg_arg(&self) -> &str {
213 match self {
214 Self::H264Baseline => "baseline",
215 Self::H264Main => "main",
216 Self::H264High => "high",
217 Self::H264High10 => "high10",
218 Self::H264High422 => "high422",
219 Self::H264High444 => "high444p",
220 Self::HevcMain => "main",
221 Self::HevcMain10 => "main10",
222 Self::HevcMain12 => "main12",
223 Self::HevcMainStillPicture => "mainstillpicture",
224 Self::Vp9Profile0 => "0",
225 Self::Vp9Profile1 => "1",
226 Self::Vp9Profile2 => "2",
227 Self::Vp9Profile3 => "3",
228 Self::Av1Main => "0",
229 Self::Av1High => "1",
230 Self::Av1Professional => "2",
231 Self::AacLc => "aac_low",
232 Self::AacHe => "aac_he",
233 Self::AacHeV2 => "aac_he_v2",
234 Self::ProResProxy => "0",
235 Self::ProResLt => "1",
236 Self::ProRes422 => "2",
237 Self::ProResHq => "3",
238 Self::ProRes4444 => "4",
239 Self::Other(s) => s.as_str(),
240 }
241 }
242
243 pub fn from_ffprobe(s: &str) -> Option<Self> {
248 let lower = s.to_lowercase();
250 let trimmed = lower.trim();
251
252 match trimmed {
253 "constrained baseline" | "baseline" => Some(Self::H264Baseline),
255 "main" => Some(Self::H264Main),
256 "high" => Some(Self::H264High),
257 "high 10" | "high10" => Some(Self::H264High10),
258 "high 4:2:2" | "high422" => Some(Self::H264High422),
259 "high 4:4:4 predictive" | "high444" | "high 4:4:4" => Some(Self::H264High444),
260 "main still picture" => Some(Self::HevcMainStillPicture),
262 "main 10" | "main10" => Some(Self::HevcMain10),
263 "main 12" | "main12" => Some(Self::HevcMain12),
264 "profile 0" => Some(Self::Vp9Profile0),
266 "profile 1" => Some(Self::Vp9Profile1),
267 "profile 2" => Some(Self::Vp9Profile2),
268 "profile 3" => Some(Self::Vp9Profile3),
269 "lc" | "aac-lc" => Some(Self::AacLc),
271 "he-aac" | "he-aacv1" => Some(Self::AacHe),
272 "he-aacv2" => Some(Self::AacHeV2),
273 "apco" | "proxy" => Some(Self::ProResProxy),
275 "apcs" | "lt" => Some(Self::ProResLt),
276 "apcn" | "standard" | "422" => Some(Self::ProRes422),
277 "apch" | "hq" => Some(Self::ProResHq),
278 "ap4h" | "4444" => Some(Self::ProRes4444),
279 _ => {
280 if trimmed.is_empty() || trimmed == "unknown" {
281 None
282 } else {
283 Some(Self::Other(s.into()))
284 }
285 }
286 }
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
295pub struct CodecLevel(Arc<str>);
296
297impl CodecLevel {
298 pub fn new(level: impl Into<Arc<str>>) -> Self {
300 Self(level.into())
301 }
302
303 pub fn id(&self) -> &str {
305 &self.0
306 }
307}
308
309impl std::fmt::Display for CodecLevel {
310 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311 f.write_str(&self.0)
312 }
313}
314
315pub mod levels {
317 use super::CodecLevel;
318
319 pub fn h264_3_0() -> CodecLevel {
321 CodecLevel::new("3.0")
322 }
323 pub fn h264_3_1() -> CodecLevel {
325 CodecLevel::new("3.1")
326 }
327 pub fn h264_4_0() -> CodecLevel {
329 CodecLevel::new("4.0")
330 }
331 pub fn h264_4_1() -> CodecLevel {
333 CodecLevel::new("4.1")
334 }
335 pub fn h264_5_0() -> CodecLevel {
337 CodecLevel::new("5.0")
338 }
339 pub fn h264_5_1() -> CodecLevel {
341 CodecLevel::new("5.1")
342 }
343 pub fn h264_5_2() -> CodecLevel {
345 CodecLevel::new("5.2")
346 }
347}