1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Lambda calculation for rate-distortion optimization.
//!
//! Lambda values control the rate-distortion trade-off in mode selection.
//! Higher lambda = prefer lower rate (smaller files).
//! Lower lambda = prefer lower distortion (better quality).
//!
//! These formulas are ported from libwebp's RefineUsingDistortion.
use ;
//------------------------------------------------------------------------------
// Fixed lambda constants (from libwebp)
/// Fixed lambda for Intra16 mode selection (distortion method)
pub const LAMBDA_I16: u32 = 106;
/// Fixed lambda for Intra4 mode selection (distortion method)
pub const LAMBDA_I4: u32 = 11;
/// Fixed lambda for UV mode selection (distortion method)
pub const LAMBDA_UV: u32 = 120;
/// Default SNS strength value (matches libwebp default)
pub const DEFAULT_SNS_STRENGTH: u32 = 50;
//------------------------------------------------------------------------------
// Dynamic lambda calculation (based on quantizer)
/// Calculate lambda_i4 based on quantization: (3 * q²) >> 7
/// Calculate lambda_i16 based on quantization: 3 * q²
/// Calculate lambda_uv based on quantization: (3 * q²) >> 6
/// Calculate lambda_mode based on quantization: (1 * q²) >> 7
/// Calculate i4_penalty based on quantization: 1000 * q²
/// This penalty accounts for the extra cost of Intra4 over Intra16.
/// Calculate trellis lambda for I16 mode: (q²) >> 2
/// Calculate trellis lambda for I4 mode: (7 * q²) >> 3
/// Calculate trellis lambda for UV: (q²) << 1
/// Calculate tlambda (spectral distortion weight) based on SNS strength and quant.
///
/// tlambda = (sns_strength * q) >> 5
///
/// This controls how much weight spectral distortion (TDisto) has in mode selection.
/// Only enabled when method >= 4 and sns_strength > 0.
///
/// # Arguments
/// * `sns_strength` - Spatial noise shaping strength (0-100)
/// * `q` - Expanded quantization value (from VP8Matrix)
//------------------------------------------------------------------------------
// Filter level calculation
/// Cutoff for very small filter strengths (have close to no visual effect)
const FSTRENGTH_CUTOFF: u8 = 2;
/// Calculate filter strength from sharpness and edge delta.
/// Ported from libwebp's VP8FilterStrengthFromDelta.
/// Calculate optimal filter level based on quantizer and sharpness.
///
/// This implements libwebp's SetupFilterStrength logic:
/// 1. Compute qstep from AC quantizer
/// 2. Get base strength from delta table
/// 3. Scale by filter_strength config (default 50 = mid-filtering)
///
/// # Arguments
/// * `quant_index` - Quantizer index (0-127)
/// * `sharpness` - Sharpness level (0-7)
/// * `filter_strength` - User filter strength (0-100), default 50
/// Calculate optimal filter level with per-segment beta modulation.
///
/// This implements libwebp's SetupFilterStrength logic with per-segment complexity:
/// 1. Compute qstep from AC quantizer
/// 2. Get base strength from delta table
/// 3. Scale by filter_strength and reduce by segment beta
///
/// Segments with lower complexity (low beta) need less filtering because they have
/// fewer edges/details to preserve. High-complexity segments (high beta) get more
/// filtering to reduce artifacts.
///
/// # Arguments
/// * `quant_index` - Quantizer index (0-127)
/// * `sharpness` - Sharpness level (0-7)
/// * `filter_strength` - User filter strength (0-100), default 50
/// * `beta` - Segment complexity (0-255), where 0 = simplest, 255 = most complex