Coverage Report

Created: 2026-09-14 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/ac_bias.c
Line
Count
Source
1
/*
2
* Copyright(c) 2024-2025 Psychovisual Experts Group
3
*
4
* This source code is subject to the terms of the BSD 2 Clause License and
5
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
* was not distributed with this source code in the LICENSE file, you can
7
* obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8
* Media Patent License 1.0 was not distributed with this source code in the
9
* PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10
*/
11
12
#include <math.h>
13
#include <stdbool.h>
14
#include "ac_bias.h"
15
#include "aom_dsp_rtcd.h"
16
#include "common_dsp_rtcd.h"
17
18
0
static int psy_energy_4x4_c(const uint8_t* src, ptrdiff_t src_stride) {
19
0
    int16_t src16[16];
20
0
    int32_t coeff[16];
21
22
0
    for (int row = 0; row < 4; ++row) {
23
0
        for (int col = 0; col < 4; ++col) {
24
0
            src16[row * 4 + col] = src[row * src_stride + col];
25
0
        }
26
0
    }
27
28
0
    svt_aom_hadamard_4x4(src16, 4, coeff);
29
30
0
    return (svt_aom_satd(coeff, 16) << 1) - coeff[0];
31
0
}
32
33
0
static int psy_energy_8x8_c(const uint8_t* src, ptrdiff_t src_stride) {
34
0
    int16_t src16[64];
35
0
    int32_t coeff[64];
36
37
0
    for (int row = 0; row < 8; ++row) {
38
0
        for (int col = 0; col < 8; ++col) {
39
0
            src16[row * 8 + col] = src[row * src_stride + col];
40
0
        }
41
0
    }
42
43
0
    svt_aom_hadamard_8x8(src16, 8, coeff);
44
45
0
    return ((svt_aom_satd(coeff, 64) + 2) >> 2) - ((coeff[0] + 2) >> 2);
46
0
}
47
48
/* Regular version of "AC Bias"
49
 *
50
 * Based on adding an "energy gap" term to each candidate block's distortion, which is the difference
51
 * of the "energy" (SATD - SAD) of the source and recon blocks
52
 */
53
uint64_t svt_psy_distortion_c(const uint8_t* input, const uint32_t input_stride, const uint8_t* recon,
54
0
                              const uint32_t recon_stride, const uint32_t width, const uint32_t height) {
55
0
    uint64_t energy_gap = 0;
56
57
0
    if (width >= 8 && height >= 8) { /* >8x8 */
58
0
        for (uint32_t j = 0; j < height; j += 8) {
59
0
            for (uint32_t i = 0; i < width; i += 8) {
60
0
                const int input_energy = psy_energy_8x8_c(input + j * input_stride + i, input_stride);
61
0
                const int recon_energy = psy_energy_8x8_c(recon + j * recon_stride + i, recon_stride);
62
63
0
                energy_gap += abs(input_energy - recon_energy);
64
0
            }
65
0
        }
66
0
    } else {
67
0
        for (uint32_t j = 0; j < height; j += 4) { /* 4x4, 4x8, 4x16, 8x4, and 16x4 */
68
0
            for (uint32_t i = 0; i < width; i += 4) {
69
0
                const int input_energy = psy_energy_4x4_c(input + j * input_stride + i, input_stride);
70
0
                const int recon_energy = psy_energy_4x4_c(recon + j * recon_stride + i, recon_stride);
71
72
0
                energy_gap += abs(input_energy - recon_energy);
73
0
            }
74
0
        }
75
0
    }
76
77
0
    return energy_gap;
78
0
}
79
80
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
81
0
static int highbd_psy_energy_4x4_c(const uint16_t* src, ptrdiff_t src_stride) {
82
0
    int32_t coeff[16];
83
84
0
    svt_aom_hadamard_4x4((const int16_t*)src, src_stride, coeff);
85
86
0
    return (svt_aom_satd(coeff, 16) << 1) - coeff[0];
87
0
}
88
89
0
static int highbd_psy_energy_8x8_c(const uint16_t* src, ptrdiff_t src_stride) {
90
0
    int32_t coeff[64];
91
92
0
    svt_aom_highbd_hadamard_8x8((const int16_t*)src, src_stride, coeff);
93
94
0
    return ((svt_aom_satd(coeff, 64) + 2) >> 2) - ((coeff[0] + 2) >> 2);
95
0
}
96
97
/* High bit-depth version of "AC Bias" */
98
uint64_t svt_psy_distortion_hbd_c(const uint16_t* input, const uint32_t input_stride, const uint16_t* recon,
99
0
                                  const uint32_t recon_stride, const uint32_t width, const uint32_t height) {
100
0
    uint64_t energy_gap = 0;
101
102
0
    if (width >= 8 && height >= 8) { /* >8x8 */
103
0
        for (uint32_t j = 0; j < height; j += 8) {
104
0
            for (uint32_t i = 0; i < width; i += 8) {
105
0
                const int input_energy = highbd_psy_energy_8x8_c(input + j * input_stride + i, input_stride);
106
0
                const int recon_energy = highbd_psy_energy_8x8_c(recon + j * recon_stride + i, recon_stride);
107
108
0
                energy_gap += abs(input_energy - recon_energy);
109
0
            }
110
0
        }
111
0
    } else {
112
0
        for (uint64_t j = 0; j < height; j += 4) { /* 4x4, 4x8, 4x16, 8x4, and 16x4 */
113
0
            for (uint64_t i = 0; i < width; i += 4) {
114
0
                const int input_energy = highbd_psy_energy_4x4_c(input + j * input_stride + i, input_stride);
115
0
                const int recon_energy = highbd_psy_energy_4x4_c(recon + j * recon_stride + i, recon_stride);
116
117
0
                energy_gap += abs(input_energy - recon_energy);
118
0
            }
119
0
        }
120
0
    }
121
122
    // Energy is scaled to approximately match equivalent 8-bit strengths
123
0
    return energy_gap << 2;
124
0
}
125
#endif
126
127
/*
128
 * Public function that mirrors the arguments of `spatial_full_dist_type_fun()`
129
 */
130
uint64_t get_svt_psy_full_dist(const void* s, const uint32_t so, const uint32_t sp, const void* r, const uint32_t ro,
131
                               const uint32_t rp, const uint32_t w, const uint32_t h, const uint8_t is_hbd,
132
0
                               const double ac_bias) {
133
0
    if (is_hbd)
134
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
135
0
        return llrint(svt_psy_distortion_hbd((const uint16_t*)s + so, sp, (uint16_t*)r + ro, rp, w, h) * ac_bias);
136
#else
137
        return 0;
138
#endif
139
0
    else {
140
0
        return llrint(svt_psy_distortion((const uint8_t*)s + so, sp, (const uint8_t*)r + ro, rp, w, h) * ac_bias);
141
0
    }
142
0
}
143
144
/*
145
 * Light version of "AC Bias", called by the Light-PD code paths
146
 *
147
 * Based on adjusting each block's rate so blocks with more energy (sum of AC coeffs) appear "cheaper" to the encoder,
148
 * thus making them more favorable to be picked by the RDO process. This tends to increase the image's total "energy"
149
 * (in contrast to `get_svt_psy_full_dist()` which tries to reduce the "energy gap" between source and recon)
150
 *
151
 * Much faster than `get_svt_psy_full_dist()` as it can re-use existing block coefficients instead of computing new
152
 * ones, but subjective visual quality benefits are significantly more modest
153
 */
154
uint64_t svt_psy_adjust_rate_light(const int32_t* coeff, uint64_t coeff_bits, const uint32_t width,
155
0
                                   const uint32_t height, const double ac_bias) {
156
0
    uint64_t       energy = 0;
157
0
    const int32_t* buf    = coeff;
158
159
0
    for (uint32_t j = 0; j < height; j++) {
160
        // Skip the DC coefficient from the calculation
161
0
        for (uint32_t i = j ? 0 : 1; i < width; i++) {
162
0
            energy += (uint64_t)llabs((int64_t)buf[i]);
163
0
        }
164
0
        buf += width;
165
0
    }
166
167
0
    if (energy > 0) {
168
0
        uint64_t coeff_bits_adj = (int)(energy * ac_bias * 100);
169
170
        // When the adjustment rate is greater than the rate, keep rate (coeff_bits) positive
171
0
        coeff_bits = (coeff_bits > coeff_bits_adj) ? (coeff_bits - coeff_bits_adj) : 1;
172
0
    }
173
174
0
    return coeff_bits;
175
0
}
176
177
901k
double get_effective_ac_bias(const double ac_bias, const bool is_islice, const uint8_t temporal_layer_index) {
178
901k
    if (is_islice) {
179
901k
        return ac_bias * 0.3;
180
901k
    }
181
18.4E
    switch (temporal_layer_index) {
182
0
    case 0:
183
0
        return ac_bias * 0.6;
184
0
    case 1:
185
0
        return ac_bias * 0.8;
186
0
    case 2:
187
0
        return ac_bias * 0.9;
188
0
    default:
189
0
        return ac_bias;
190
18.4E
    }
191
18.4E
}