Skip to main content

tpt_kinetix_core/
encode.rs

1//! Shared encoder configuration types.
2//!
3//! Encoders across the Kinetix engine (currently the `rav1e`-backed AV1 encoder
4//! in `tpt-kinetix-av1`) accept their tuning parameters through the codec-agnostic
5//! [`EncodeConfig`] defined here, so that higher layers (pipeline, CLI) can
6//! express encode intent without depending on any specific codec crate.
7//!
8//! The [`RateControl`] enum captures the two rate-control strategies supported
9//! by the initial release, and [`SpeedPreset`] maps human-friendly presets onto
10//! the numeric speed knobs used by real encoders.
11
12use serde::{Deserialize, Serialize};
13
14/// How the encoder should allocate bits.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
16pub enum RateControl {
17    /// Constant-quality mode driven by a quantizer value (0 = best quality,
18    /// 255 = worst quality). This is `rav1e`'s CQP mode.
19    ConstantQuality {
20        /// Quantizer index (0..=255).
21        quantizer: u8,
22    },
23    /// Target-bitrate mode in bits per second.
24    Bitrate {
25        /// Target bitrate in bits per second.
26        bits_per_second: u32,
27    },
28}
29
30impl Default for RateControl {
31    fn default() -> Self {
32        RateControl::ConstantQuality { quantizer: 100 }
33    }
34}
35
36/// Human-friendly speed / quality trade-off preset.
37///
38/// Presets map onto a numeric speed value via [`SpeedPreset::to_speed`], where
39/// `0` is the slowest / highest quality and `10` is the fastest.
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
41pub enum SpeedPreset {
42    /// Highest quality, slowest encode (speed 0).
43    Slowest,
44    /// Balanced default (speed 6).
45    #[default]
46    Medium,
47    /// Fastest encode, lowest quality (speed 10).
48    Fastest,
49    /// An explicit numeric speed value (clamped to 0..=10).
50    Custom(u8),
51}
52
53impl SpeedPreset {
54    /// Map the preset to a numeric speed value in the range `0..=10`.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use tpt_kinetix_core::encode::SpeedPreset;
60    ///
61    /// assert_eq!(SpeedPreset::Slowest.to_speed(), 0);
62    /// assert_eq!(SpeedPreset::Medium.to_speed(), 6);
63    /// assert_eq!(SpeedPreset::Fastest.to_speed(), 10);
64    /// assert_eq!(SpeedPreset::Custom(20).to_speed(), 10); // clamped
65    /// ```
66    pub fn to_speed(self) -> u8 {
67        match self {
68            SpeedPreset::Slowest => 0,
69            SpeedPreset::Medium => 6,
70            SpeedPreset::Fastest => 10,
71            SpeedPreset::Custom(v) => v.min(10),
72        }
73    }
74}
75
76/// Codec-agnostic video encode configuration.
77///
78/// Codec-specific encoders translate this into their own configuration type.
79///
80/// # Examples
81///
82/// ```
83/// use tpt_kinetix_core::encode::{EncodeConfig, RateControl, SpeedPreset};
84///
85/// let cfg = EncodeConfig {
86///     width: 1920,
87///     height: 1080,
88///     rate_control: RateControl::Bitrate { bits_per_second: 6_000_000 },
89///     speed: SpeedPreset::Medium,
90///     keyframe_interval: 240,
91/// };
92/// assert_eq!(cfg.speed.to_speed(), 6);
93/// ```
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
95pub struct EncodeConfig {
96    /// Frame width in pixels.
97    pub width: u32,
98    /// Frame height in pixels.
99    pub height: u32,
100    /// Rate-control strategy.
101    pub rate_control: RateControl,
102    /// Speed / quality preset.
103    pub speed: SpeedPreset,
104    /// Maximum interval between keyframes, in frames.
105    pub keyframe_interval: u64,
106}
107
108impl Default for EncodeConfig {
109    fn default() -> Self {
110        Self {
111            width: 640,
112            height: 480,
113            rate_control: RateControl::default(),
114            speed: SpeedPreset::default(),
115            keyframe_interval: 240,
116        }
117    }
118}
119
120impl EncodeConfig {
121    /// Returns the quantizer to use, defaulting sensibly when in bitrate mode.
122    pub fn quantizer(&self) -> u8 {
123        match self.rate_control {
124            RateControl::ConstantQuality { quantizer } => quantizer,
125            // rav1e uses the quantizer as an upper bound in bitrate mode; a
126            // neutral mid value is a safe default.
127            RateControl::Bitrate { .. } => 100,
128        }
129    }
130
131    /// Returns the target bitrate in bits per second (0 in constant-quality mode).
132    pub fn bitrate(&self) -> u32 {
133        match self.rate_control {
134            RateControl::ConstantQuality { .. } => 0,
135            RateControl::Bitrate { bits_per_second } => bits_per_second,
136        }
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn defaults_are_constant_quality() {
146        let cfg = EncodeConfig::default();
147        assert_eq!(cfg.bitrate(), 0);
148        assert_eq!(cfg.quantizer(), 100);
149        assert_eq!(cfg.speed.to_speed(), 6);
150    }
151
152    #[test]
153    fn bitrate_mode_reports_bitrate() {
154        let cfg = EncodeConfig {
155            rate_control: RateControl::Bitrate {
156                bits_per_second: 5_000_000,
157            },
158            ..Default::default()
159        };
160        assert_eq!(cfg.bitrate(), 5_000_000);
161    }
162
163    #[test]
164    fn custom_speed_clamps() {
165        assert_eq!(SpeedPreset::Custom(255).to_speed(), 10);
166        assert_eq!(SpeedPreset::Custom(3).to_speed(), 3);
167    }
168}