Skip to main content

rskit_media/encoding/
codec.rs

1//! Codec identifiers and well-known constants.
2
3use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6
7/// An open codec identifier.
8///
9/// Use well-known constants from the submodules ([`video`], [`audio`], [`image`], [`subtitle`])
10/// or create custom identifiers.
11///
12/// # Examples
13///
14/// ```rust
15/// use rskit_media::codec::{self, Codec, CodecKind};
16///
17/// let h264 = Codec::new(codec::video::H264);
18/// let custom = Codec::new("my_proprietary_codec");
19/// ```
20#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub struct Codec(Arc<str>);
22
23impl Codec {
24    /// Create a new codec identifier.
25    pub fn new(id: impl Into<Arc<str>>) -> Self {
26        Self(id.into())
27    }
28
29    /// The codec identifier string.
30    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/// Which domain a codec belongs to.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
43pub enum CodecKind {
44    /// Video codec.
45    Video,
46    /// Audio codec.
47    Audio,
48    /// Image codec.
49    Image,
50    /// Subtitle codec.
51    Subtitle,
52    /// Unknown or unrecognized codec kind.
53    Unknown,
54}
55
56/// Well-known video codecs.
57pub mod video {
58    /// H.264 / AVC.
59    pub const H264: &str = "h264";
60    /// H.265 / HEVC.
61    pub const H265: &str = "h265";
62    /// VP8.
63    pub const VP8: &str = "vp8";
64    /// VP9.
65    pub const VP9: &str = "vp9";
66    /// AV1.
67    pub const AV1: &str = "av1";
68    /// Apple ProRes.
69    pub const PRORES: &str = "prores";
70    /// MPEG-2.
71    pub const MPEG2: &str = "mpeg2";
72    /// MPEG-4 Part 2.
73    pub const MPEG4: &str = "mpeg4";
74    /// Theora.
75    pub const THEORA: &str = "theora";
76    /// Windows Media Video 3.
77    pub const WMV3: &str = "wmv3";
78}
79
80/// Well-known audio codecs.
81pub mod audio {
82    /// Advanced Audio Coding.
83    pub const AAC: &str = "aac";
84    /// Opus.
85    pub const OPUS: &str = "opus";
86    /// MPEG Audio Layer III.
87    pub const MP3: &str = "mp3";
88    /// Free Lossless Audio Codec.
89    pub const FLAC: &str = "flac";
90    /// Vorbis.
91    pub const VORBIS: &str = "vorbis";
92    /// Pulse-code modulation (uncompressed).
93    pub const PCM: &str = "pcm";
94    /// Dolby Digital.
95    pub const AC3: &str = "ac3";
96    /// Dolby Digital Plus.
97    pub const EAC3: &str = "eac3";
98    /// Windows Media Audio.
99    pub const WMA: &str = "wma";
100    /// Apple Lossless Audio Codec.
101    pub const ALAC: &str = "alac";
102}
103
104/// Well-known image codecs.
105pub mod image {
106    /// PNG.
107    pub const PNG: &str = "png";
108    /// JPEG.
109    pub const JPEG: &str = "jpeg";
110    /// WebP.
111    pub const WEBP: &str = "webp";
112    /// GIF.
113    pub const GIF: &str = "gif";
114    /// BMP.
115    pub const BMP: &str = "bmp";
116    /// TIFF.
117    pub const TIFF: &str = "tiff";
118    /// AVIF.
119    pub const AVIF: &str = "avif";
120    /// HEIF.
121    pub const HEIF: &str = "heif";
122}
123
124/// Well-known subtitle codecs.
125pub mod subtitle {
126    /// SubRip.
127    pub const SRT: &str = "srt";
128    /// WebVTT.
129    pub const WEBVTT: &str = "webvtt";
130    /// Advanced SubStation Alpha.
131    pub const ASS: &str = "ass";
132    /// SubStation Alpha.
133    pub const SSA: &str = "ssa";
134    /// MOV text (mp4 subtitles).
135    pub const MOV_TEXT: &str = "mov_text";
136}
137
138/// Codec profile for quality/compatibility targeting.
139///
140/// Profiles define feature subsets of a codec. Higher profiles enable more features
141/// but require more processing power and may reduce compatibility.
142#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
143pub enum CodecProfile {
144    // ── H.264 / AVC ─────────────────────────────────────────────────
145    /// H.264 Baseline (mobile, video conferencing).
146    H264Baseline,
147    /// H.264 Main (broadcast, streaming).
148    H264Main,
149    /// H.264 High (Blu-ray, high-quality streaming).
150    H264High,
151    /// H.264 High 10-bit.
152    H264High10,
153    /// H.264 High 4:2:2.
154    H264High422,
155    /// H.264 High 4:4:4 Predictive.
156    H264High444,
157
158    // ── H.265 / HEVC ────────────────────────────────────────────────
159    /// HEVC Main (8-bit SDR).
160    HevcMain,
161    /// HEVC Main 10 (10-bit, HDR).
162    HevcMain10,
163    /// HEVC Main 12.
164    HevcMain12,
165    /// HEVC Main Still Picture.
166    HevcMainStillPicture,
167
168    // ── VP9 ─────────────────────────────────────────────────────────
169    /// VP9 Profile 0 (4:2:0 8-bit).
170    Vp9Profile0,
171    /// VP9 Profile 1 (4:2:2/4:4:4 8-bit).
172    Vp9Profile1,
173    /// VP9 Profile 2 (4:2:0 10/12-bit).
174    Vp9Profile2,
175    /// VP9 Profile 3 (4:2:2/4:4:4 10/12-bit).
176    Vp9Profile3,
177
178    // ── AV1 ─────────────────────────────────────────────────────────
179    /// AV1 Main (4:2:0 8/10-bit).
180    Av1Main,
181    /// AV1 High (4:4:4 8/10-bit).
182    Av1High,
183    /// AV1 Professional (4:2:2, 12-bit).
184    Av1Professional,
185
186    // ── AAC ─────────────────────────────────────────────────────────
187    /// AAC Low Complexity (most common).
188    AacLc,
189    /// AAC High Efficiency (HE-AAC v1).
190    AacHe,
191    /// AAC High Efficiency v2 (HE-AAC v2).
192    AacHeV2,
193
194    // ── ProRes ──────────────────────────────────────────────────────
195    /// ProRes 422 Proxy.
196    ProResProxy,
197    /// ProRes 422 LT.
198    ProResLt,
199    /// ProRes 422.
200    ProRes422,
201    /// ProRes 422 HQ.
202    ProResHq,
203    /// ProRes 4444.
204    ProRes4444,
205
206    /// Custom/other profile string.
207    Other(String),
208}
209
210impl CodecProfile {
211    /// Convert to FFmpeg `-profile:v` or `-profile:a` argument value.
212    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    /// Parse from ffprobe's `profile` field.
244    ///
245    /// ffprobe returns human-readable strings like "High", "Main", "Baseline", "High 10",
246    /// "High 4:4:4 Predictive", etc.
247    pub fn from_ffprobe(s: &str) -> Option<Self> {
248        // Normalize for matching
249        let lower = s.to_lowercase();
250        let trimmed = lower.trim();
251
252        match trimmed {
253            // H.264
254            "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            // H.265 / HEVC
261            "main still picture" => Some(Self::HevcMainStillPicture),
262            "main 10" | "main10" => Some(Self::HevcMain10),
263            "main 12" | "main12" => Some(Self::HevcMain12),
264            // VP9
265            "profile 0" => Some(Self::Vp9Profile0),
266            "profile 1" => Some(Self::Vp9Profile1),
267            "profile 2" => Some(Self::Vp9Profile2),
268            "profile 3" => Some(Self::Vp9Profile3),
269            // AAC
270            "lc" | "aac-lc" => Some(Self::AacLc),
271            "he-aac" | "he-aacv1" => Some(Self::AacHe),
272            "he-aacv2" => Some(Self::AacHeV2),
273            // ProRes
274            "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/// Codec level constraining resolution, bitrate, and framerate.
291///
292/// Levels are codec-specific.
293/// For H.264/H.265 they map directly to the standard levels (e.g., 3.0, 4.1, 5.1).
294#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
295pub struct CodecLevel(Arc<str>);
296
297impl CodecLevel {
298    /// Create a new codec level.
299    pub fn new(level: impl Into<Arc<str>>) -> Self {
300        Self(level.into())
301    }
302
303    /// The level string.
304    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
315/// Well-known H.264 levels.
316pub mod levels {
317    use super::CodecLevel;
318
319    /// H.264 Level 3.0 (SD video).
320    pub fn h264_3_0() -> CodecLevel {
321        CodecLevel::new("3.0")
322    }
323    /// H.264 Level 3.1 (720p30).
324    pub fn h264_3_1() -> CodecLevel {
325        CodecLevel::new("3.1")
326    }
327    /// H.264 Level 4.0 (1080p30).
328    pub fn h264_4_0() -> CodecLevel {
329        CodecLevel::new("4.0")
330    }
331    /// H.264 Level 4.1 (1080p30 + higher bitrate).
332    pub fn h264_4_1() -> CodecLevel {
333        CodecLevel::new("4.1")
334    }
335    /// H.264 Level 5.0 (1080p60 / 4K30).
336    pub fn h264_5_0() -> CodecLevel {
337        CodecLevel::new("5.0")
338    }
339    /// H.264 Level 5.1 (4K30).
340    pub fn h264_5_1() -> CodecLevel {
341        CodecLevel::new("5.1")
342    }
343    /// H.264 Level 5.2 (4K60).
344    pub fn h264_5_2() -> CodecLevel {
345        CodecLevel::new("5.2")
346    }
347}