Skip to main content

rivet/spec/
rung.rs

1//! Rung and quality types — one rendition of the output ladder plus the encoder
2//! quality knobs that control it.
3
4use codec::encode::tuning::{QualityTarget, SpeedTier};
5use codec::encode::{AUTO_FROM_TARGET, EncoderConfig};
6
7/// Encoder quality knobs for a rung.
8#[derive(Debug, Clone)]
9pub struct Quality {
10    /// Constant rate factor in the encoder-native scale (rav1e/NVENC 0..=255).
11    /// `None` derives the quantizer from [`Quality::target`].
12    pub crf: Option<u8>,
13    /// Encoder-native speed preset. `None` derives it from [`Quality::tier`].
14    pub speed_preset: Option<u8>,
15    /// Perceptual quality target (used when `crf` is `None`).
16    pub target: QualityTarget,
17    /// Speed/efficiency tier (used when `speed_preset` is `None`).
18    pub tier: SpeedTier,
19    /// GOP length in frames. `None` → `2 × frame_rate` (a 2-second GOP).
20    pub keyframe_interval: Option<u32>,
21}
22
23impl Default for Quality {
24    fn default() -> Self {
25        Self {
26            crf: None,
27            speed_preset: None,
28            target: QualityTarget::Standard,
29            tier: SpeedTier::Standard,
30            keyframe_interval: None,
31        }
32    }
33}
34
35impl Quality {
36    /// A constant-rate-factor quality.
37    pub fn crf(crf: u8) -> Self {
38        Self {
39            crf: Some(crf),
40            ..Default::default()
41        }
42    }
43
44    /// A perceptual-target quality.
45    pub fn target(target: QualityTarget) -> Self {
46        Self {
47            target,
48            ..Default::default()
49        }
50    }
51
52    /// Apply these knobs onto an [`EncoderConfig`] for a given frame rate.
53    pub(crate) fn apply(&self, cfg: &mut EncoderConfig, frame_rate: f64) {
54        cfg.target = self.target;
55        cfg.tier = self.tier;
56        cfg.quality = self.crf.unwrap_or(AUTO_FROM_TARGET);
57        cfg.speed_preset = self.speed_preset.unwrap_or(AUTO_FROM_TARGET);
58        cfg.keyframe_interval = self
59            .keyframe_interval
60            .unwrap_or_else(|| (frame_rate * 2.0).round().max(1.0) as u32);
61    }
62}
63
64/// One rendition of the output ladder.
65#[derive(Debug, Clone)]
66pub struct Rung {
67    /// Target width in pixels (even).
68    pub width: u32,
69    /// Target height in pixels (even).
70    pub height: u32,
71    /// Human label, e.g. `"720p"` (short side). Auto-derived by [`Rung::new`].
72    pub label: String,
73    /// Per-rung encoder quality.
74    pub quality: Quality,
75}
76
77impl Rung {
78    /// A rung at `width × height` with default quality and an auto label
79    /// (`"<short-side>p"`).
80    pub fn new(width: u32, height: u32) -> Self {
81        Self {
82            width,
83            height,
84            label: format!("{}p", width.min(height)),
85            quality: Quality::default(),
86        }
87    }
88
89    /// Override the per-rung quality.
90    pub fn with_quality(mut self, quality: Quality) -> Self {
91        self.quality = quality;
92        self
93    }
94
95    /// Override the label.
96    pub fn with_label(mut self, label: impl Into<String>) -> Self {
97        self.label = label.into();
98        self
99    }
100
101    /// Short side (the "p" number).
102    pub fn short_side(&self) -> u32 {
103        self.width.min(self.height)
104    }
105}