Skip to main content

oximedia_codec/intra/
mod.rs

1//! Shared intra prediction module for AV1 and VP9 decoders.
2//!
3//! This module provides common intra prediction functionality that can be used
4//! by both AV1 and VP9 video decoders. Intra prediction generates prediction
5//! samples using only samples from the current frame.
6//!
7//! # Prediction Modes
8//!
9//! The module supports several prediction mode categories:
10//!
11//! - **DC Prediction** - Average of neighboring samples
12//! - **Directional Prediction** - Project samples along angles (0-270 degrees)
13//! - **Smooth Prediction** - Weighted interpolation (AV1)
14//! - **Paeth Prediction** - Adaptive selection (AV1)
15//! - **Palette Mode** - Index-based colors (AV1)
16//!
17//! # Architecture
18//!
19//! The prediction context ([`IntraPredContext`]) manages neighbor sample
20//! availability and provides the interface for prediction operations.
21//! Each prediction mode implements the [`IntraPredictor`] trait.
22//!
23//! # Example
24//!
25//! ```ignore
26//! use oximedia_codec::intra::{IntraPredContext, IntraMode, DcPredictor};
27//!
28//! let ctx = IntraPredContext::new(width, height, bit_depth);
29//! ctx.reconstruct_neighbors(&frame, block_x, block_y);
30//!
31//! let predictor = DcPredictor::new();
32//! predictor.predict(&ctx, &mut block);
33//! ```
34
35#![forbid(unsafe_code)]
36#![allow(dead_code)]
37#![allow(clippy::doc_markdown)]
38
39mod context;
40mod dc;
41mod directional;
42mod filter;
43mod modes;
44mod paeth;
45mod palette;
46mod smooth;
47
48// Re-export primary types
49pub use context::{IntraPredContext, LeftSamples, NeighborAvailability, TopSamples};
50pub use dc::{DcMode, DcPredictor};
51pub use directional::{
52    D113Predictor, D117Predictor, D135Predictor, D153Predictor, D157Predictor, D203Predictor,
53    D207Predictor, D45Predictor, D63Predictor, D67Predictor, DirectionalPredictor,
54    HorizontalPredictor, VerticalPredictor,
55};
56pub use filter::{apply_intra_filter, FilterStrength, IntraEdgeFilter};
57pub use modes::{AngleDelta, DirectionalMode, IntraMode, IntraPredictor, NonDirectionalMode};
58pub use paeth::{paeth_predictor, PaethPredictor};
59pub use palette::{ColorCache, PaletteInfo, PalettePredictor};
60pub use smooth::{SmoothHPredictor, SmoothPredictor, SmoothVPredictor};
61
62/// Maximum block size supported (128x128 for AV1).
63pub const MAX_BLOCK_SIZE: usize = 128;
64
65/// Maximum number of samples for neighbor arrays (2 * MAX_BLOCK_SIZE + 1).
66pub const MAX_NEIGHBOR_SAMPLES: usize = 2 * MAX_BLOCK_SIZE + 1;
67
68/// Supported bit depths.
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
70pub enum BitDepth {
71    /// 8-bit samples.
72    #[default]
73    Bits8 = 8,
74    /// 10-bit samples (AV1 HDR).
75    Bits10 = 10,
76    /// 12-bit samples (AV1 HDR).
77    Bits12 = 12,
78}
79
80impl BitDepth {
81    /// Get the maximum sample value for this bit depth.
82    #[must_use]
83    pub const fn max_value(self) -> u16 {
84        match self {
85            Self::Bits8 => 255,
86            Self::Bits10 => 1023,
87            Self::Bits12 => 4095,
88        }
89    }
90
91    /// Get the midpoint value (used for DC prediction with no neighbors).
92    #[must_use]
93    pub const fn midpoint(self) -> u16 {
94        match self {
95            Self::Bits8 => 128,
96            Self::Bits10 => 512,
97            Self::Bits12 => 2048,
98        }
99    }
100
101    /// Get the number of bits.
102    #[must_use]
103    pub const fn bits(self) -> u8 {
104        match self {
105            Self::Bits8 => 8,
106            Self::Bits10 => 10,
107            Self::Bits12 => 12,
108        }
109    }
110}
111
112/// Block dimensions.
113#[derive(Clone, Copy, Debug, PartialEq, Eq)]
114pub struct BlockDimensions {
115    /// Block width in samples.
116    pub width: usize,
117    /// Block height in samples.
118    pub height: usize,
119}
120
121impl BlockDimensions {
122    /// Create new block dimensions.
123    #[must_use]
124    pub const fn new(width: usize, height: usize) -> Self {
125        Self { width, height }
126    }
127
128    /// Get the total number of samples.
129    #[must_use]
130    pub const fn num_samples(self) -> usize {
131        self.width * self.height
132    }
133
134    /// Check if dimensions are square.
135    #[must_use]
136    pub const fn is_square(self) -> bool {
137        self.width == self.height
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_bit_depth_values() {
147        assert_eq!(BitDepth::Bits8.max_value(), 255);
148        assert_eq!(BitDepth::Bits10.max_value(), 1023);
149        assert_eq!(BitDepth::Bits12.max_value(), 4095);
150
151        assert_eq!(BitDepth::Bits8.midpoint(), 128);
152        assert_eq!(BitDepth::Bits10.midpoint(), 512);
153        assert_eq!(BitDepth::Bits12.midpoint(), 2048);
154
155        assert_eq!(BitDepth::Bits8.bits(), 8);
156        assert_eq!(BitDepth::Bits10.bits(), 10);
157        assert_eq!(BitDepth::Bits12.bits(), 12);
158    }
159
160    #[test]
161    fn test_block_dimensions() {
162        let dim = BlockDimensions::new(8, 8);
163        assert_eq!(dim.num_samples(), 64);
164        assert!(dim.is_square());
165
166        let rect = BlockDimensions::new(16, 8);
167        assert_eq!(rect.num_samples(), 128);
168        assert!(!rect.is_square());
169    }
170}