Skip to main content

mediadecode_ffmpeg/
codec_id.rs

1//! `CodecId` newtype wrapping FFmpeg's `AVCodecID` discriminant.
2//!
3//! Constructed from hardcoded `AVCodecID` enum variants in our build's
4//! bindgen-generated bindings, so we never cast an arbitrary `i32` into
5//! the bindgen enum (that cast is UB when the value isn't in the enum's
6//! discriminant set — the same hazard `crate::pix_fmt` documents). The
7//! raw `i32` stored inside is what ends up passed to FFmpeg's C API
8//! (which declares the codec id as `c_int`), so the boundary is sound.
9
10use core::fmt;
11
12use ffmpeg_next::ffi::AVCodecID;
13
14/// Codec identifier. Wraps the integer value of an `AVCodecID` enum
15/// variant; comparisons and storage work without ever transmuting back
16/// into the bindgen enum.
17#[repr(transparent)]
18#[derive(Copy, Clone, Eq, PartialEq, Hash)]
19pub struct CodecId(i32);
20
21impl CodecId {
22  /// Constructs a `CodecId` from the raw integer FFmpeg uses for
23  /// `AVCodecContext::codec_id` etc. Use this only when you have a
24  /// value that came from FFmpeg or that you know maps to a real
25  /// codec; arbitrary integers are still legal but `Debug` will fall
26  /// back to printing the raw value.
27  #[inline]
28  pub const fn from_raw(raw: i32) -> Self {
29    Self(raw)
30  }
31
32  /// Returns the underlying integer.
33  #[inline]
34  pub const fn raw(self) -> i32 {
35    self.0
36  }
37
38  // --- Sentinels -------------------------------------------------------
39
40  /// `AV_CODEC_ID_NONE` — sentinel for "no codec."
41  pub const NONE: Self = Self(AVCodecID::AV_CODEC_ID_NONE as i32);
42
43  // --- Video codecs ----------------------------------------------------
44
45  /// H.264 / AVC (ITU-T H.264 / ISO/IEC 14496-10).
46  pub const H264: Self = Self(AVCodecID::AV_CODEC_ID_H264 as i32);
47  /// H.265 / HEVC (ITU-T H.265 / ISO/IEC 23008-2).
48  pub const HEVC: Self = Self(AVCodecID::AV_CODEC_ID_HEVC as i32);
49  /// AV1 (Alliance for Open Media).
50  pub const AV1: Self = Self(AVCodecID::AV_CODEC_ID_AV1 as i32);
51  /// VP9 (Google).
52  pub const VP9: Self = Self(AVCodecID::AV_CODEC_ID_VP9 as i32);
53  /// VP8 (Google).
54  pub const VP8: Self = Self(AVCodecID::AV_CODEC_ID_VP8 as i32);
55  /// MPEG-2 Video (ITU-T H.262 / ISO/IEC 13818-2).
56  pub const MPEG2VIDEO: Self = Self(AVCodecID::AV_CODEC_ID_MPEG2VIDEO as i32);
57  /// MPEG-4 Part 2 Visual (ISO/IEC 14496-2).
58  pub const MPEG4: Self = Self(AVCodecID::AV_CODEC_ID_MPEG4 as i32);
59  /// Apple ProRes.
60  pub const PRORES: Self = Self(AVCodecID::AV_CODEC_ID_PRORES as i32);
61  /// Avid DNxHD / DNxHR (SMPTE VC-3).
62  pub const DNXHD: Self = Self(AVCodecID::AV_CODEC_ID_DNXHD as i32);
63  /// FFV1 — lossless intra-frame.
64  pub const FFV1: Self = Self(AVCodecID::AV_CODEC_ID_FFV1 as i32);
65  /// JPEG 2000.
66  pub const JPEG2000: Self = Self(AVCodecID::AV_CODEC_ID_JPEG2000 as i32);
67  /// MJPEG.
68  pub const MJPEG: Self = Self(AVCodecID::AV_CODEC_ID_MJPEG as i32);
69  /// VC-1 (SMPTE 421M, Microsoft Windows Media Video 9).
70  pub const VC1: Self = Self(AVCodecID::AV_CODEC_ID_VC1 as i32);
71  /// VVC / H.266 (ITU-T H.266).
72  pub const VVC: Self = Self(AVCodecID::AV_CODEC_ID_VVC as i32);
73
74  // --- Audio codecs ----------------------------------------------------
75
76  /// AAC (ISO/IEC 14496-3).
77  pub const AAC: Self = Self(AVCodecID::AV_CODEC_ID_AAC as i32);
78  /// MP3 (MPEG-1/2 Audio Layer III).
79  pub const MP3: Self = Self(AVCodecID::AV_CODEC_ID_MP3 as i32);
80  /// Opus (RFC 6716).
81  pub const OPUS: Self = Self(AVCodecID::AV_CODEC_ID_OPUS as i32);
82  /// FLAC — Free Lossless Audio Codec.
83  pub const FLAC: Self = Self(AVCodecID::AV_CODEC_ID_FLAC as i32);
84  /// AC-3 (ATSC A/52, Dolby Digital).
85  pub const AC3: Self = Self(AVCodecID::AV_CODEC_ID_AC3 as i32);
86  /// E-AC-3 (Dolby Digital Plus).
87  pub const EAC3: Self = Self(AVCodecID::AV_CODEC_ID_EAC3 as i32);
88  /// Apple Lossless Audio Codec.
89  pub const ALAC: Self = Self(AVCodecID::AV_CODEC_ID_ALAC as i32);
90  /// DTS / DTS-HD.
91  pub const DTS: Self = Self(AVCodecID::AV_CODEC_ID_DTS as i32);
92  /// Vorbis.
93  pub const VORBIS: Self = Self(AVCodecID::AV_CODEC_ID_VORBIS as i32);
94  /// PCM signed 16-bit little-endian.
95  pub const PCM_S16LE: Self = Self(AVCodecID::AV_CODEC_ID_PCM_S16LE as i32);
96  /// PCM signed 16-bit big-endian.
97  pub const PCM_S16BE: Self = Self(AVCodecID::AV_CODEC_ID_PCM_S16BE as i32);
98  /// PCM signed 24-bit little-endian.
99  pub const PCM_S24LE: Self = Self(AVCodecID::AV_CODEC_ID_PCM_S24LE as i32);
100  /// PCM signed 32-bit little-endian.
101  pub const PCM_S32LE: Self = Self(AVCodecID::AV_CODEC_ID_PCM_S32LE as i32);
102  /// PCM 32-bit float little-endian.
103  pub const PCM_F32LE: Self = Self(AVCodecID::AV_CODEC_ID_PCM_F32LE as i32);
104  /// PCM 64-bit float little-endian.
105  pub const PCM_F64LE: Self = Self(AVCodecID::AV_CODEC_ID_PCM_F64LE as i32);
106
107  // --- Subtitle codecs -------------------------------------------------
108
109  /// SubRip (.srt).
110  pub const SUBRIP: Self = Self(AVCodecID::AV_CODEC_ID_SUBRIP as i32);
111  /// Advanced SubStation Alpha (.ass / .ssa).
112  pub const ASS: Self = Self(AVCodecID::AV_CODEC_ID_ASS as i32);
113  /// WebVTT (.vtt).
114  pub const WEBVTT: Self = Self(AVCodecID::AV_CODEC_ID_WEBVTT as i32);
115  /// 3GPP Timed Text / MOV text track.
116  pub const MOV_TEXT: Self = Self(AVCodecID::AV_CODEC_ID_MOV_TEXT as i32);
117  /// DVB subtitle (bitmap).
118  pub const DVB_SUBTITLE: Self = Self(AVCodecID::AV_CODEC_ID_DVB_SUBTITLE as i32);
119  /// HDMV / Blu-ray PGS subtitle (bitmap).
120  pub const HDMV_PGS_SUBTITLE: Self = Self(AVCodecID::AV_CODEC_ID_HDMV_PGS_SUBTITLE as i32);
121  /// DVD VOBSUB subtitle (bitmap).
122  pub const DVD_SUBTITLE: Self = Self(AVCodecID::AV_CODEC_ID_DVD_SUBTITLE as i32);
123}
124
125impl fmt::Debug for CodecId {
126  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127    let name = match *self {
128      Self::NONE => "NONE",
129      Self::H264 => "H264",
130      Self::HEVC => "HEVC",
131      Self::AV1 => "AV1",
132      Self::VP9 => "VP9",
133      Self::VP8 => "VP8",
134      Self::MPEG2VIDEO => "MPEG2VIDEO",
135      Self::MPEG4 => "MPEG4",
136      Self::PRORES => "PRORES",
137      Self::DNXHD => "DNXHD",
138      Self::FFV1 => "FFV1",
139      Self::JPEG2000 => "JPEG2000",
140      Self::MJPEG => "MJPEG",
141      Self::VC1 => "VC1",
142      Self::VVC => "VVC",
143      Self::AAC => "AAC",
144      Self::MP3 => "MP3",
145      Self::OPUS => "OPUS",
146      Self::FLAC => "FLAC",
147      Self::AC3 => "AC3",
148      Self::EAC3 => "EAC3",
149      Self::ALAC => "ALAC",
150      Self::DTS => "DTS",
151      Self::VORBIS => "VORBIS",
152      Self::PCM_S16LE => "PCM_S16LE",
153      Self::PCM_S16BE => "PCM_S16BE",
154      Self::PCM_S24LE => "PCM_S24LE",
155      Self::PCM_S32LE => "PCM_S32LE",
156      Self::PCM_F32LE => "PCM_F32LE",
157      Self::PCM_F64LE => "PCM_F64LE",
158      Self::SUBRIP => "SUBRIP",
159      Self::ASS => "ASS",
160      Self::WEBVTT => "WEBVTT",
161      Self::MOV_TEXT => "MOV_TEXT",
162      Self::DVB_SUBTITLE => "DVB_SUBTITLE",
163      Self::HDMV_PGS_SUBTITLE => "HDMV_PGS_SUBTITLE",
164      Self::DVD_SUBTITLE => "DVD_SUBTITLE",
165      _ => return write!(f, "CodecId({})", self.0),
166    };
167    write!(f, "CodecId::{name}")
168  }
169}
170
171#[cfg(test)]
172mod tests {
173  use super::*;
174
175  #[test]
176  fn from_raw_round_trips() {
177    let id = CodecId::from_raw(27);
178    assert_eq!(id.raw(), 27);
179  }
180
181  #[test]
182  fn known_constants_match_av_values() {
183    assert_eq!(CodecId::H264.raw(), AVCodecID::AV_CODEC_ID_H264 as i32);
184    assert_eq!(CodecId::AAC.raw(), AVCodecID::AV_CODEC_ID_AAC as i32);
185    assert_eq!(CodecId::SUBRIP.raw(), AVCodecID::AV_CODEC_ID_SUBRIP as i32);
186  }
187
188  #[test]
189  fn debug_uses_name_for_known_codecs() {
190    assert_eq!(format!("{:?}", CodecId::H264), "CodecId::H264");
191    assert_eq!(format!("{:?}", CodecId::AAC), "CodecId::AAC");
192  }
193
194  #[test]
195  fn debug_falls_back_to_raw_for_unknown() {
196    let unknown = CodecId::from_raw(-99_999);
197    assert_eq!(format!("{:?}", unknown), "CodecId(-99999)");
198  }
199
200  #[test]
201  fn equality_is_value_based() {
202    assert_eq!(CodecId::H264, CodecId::from_raw(CodecId::H264.raw()));
203    assert_ne!(CodecId::H264, CodecId::HEVC);
204  }
205}