Coverage Report

Created: 2026-03-31 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxaac/encoder/ixheaace_sbr_tran_det.c
Line
Count
Source
1
/******************************************************************************
2
 *                                                                            *
3
 * Copyright (C) 2023 The Android Open Source Project
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at:
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 *****************************************************************************
18
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19
 */
20
21
#include <math.h>
22
#include <string.h>
23
#include "ixheaac_type_def.h"
24
#include "ixheaac_constants.h"
25
#include "ixheaace_aac_constants.h"
26
#include "ixheaac_error_standards.h"
27
#include "ixheaace_error_codes.h"
28
#include "ixheaac_basic_ops32.h"
29
#include "ixheaac_basic_ops16.h"
30
#include "ixheaac_basic_ops40.h"
31
#include "ixheaac_basic_ops.h"
32
33
#include "ixheaace_common_rom.h"
34
#include "ixheaace_sbr_header.h"
35
#include "ixheaace_sbr_def.h"
36
#include "ixheaace_resampler.h"
37
#include "ixheaace_sbr_rom.h"
38
#include "ixheaace_sbr_tran_det.h"
39
#include "ixheaace_sbr_main.h"
40
#include "ixheaace_sbr_frame_info_gen.h"
41
42
static IA_ERRORCODE ixheaace_spectral_change(FLOAT32 *ptr_energies[16], FLOAT32 total_energy,
43
                                             WORD32 num_sfb, WORD32 start, WORD32 border,
44
390k
                                             WORD32 stop, WORD32 is_ld_sbr, FLOAT32 *ptr_delta) {
45
390k
  WORD32 i, j;
46
390k
  WORD32 len1 = border - start;
47
390k
  WORD32 len2 = stop - border;
48
390k
  FLOAT32 energy_1[MAXIMUM_FREQ_COEFFS] = {0};
49
390k
  FLOAT32 energy_2[MAXIMUM_FREQ_COEFFS] = {0};
50
390k
  FLOAT32 len_ratio = (FLOAT32)len1 / (FLOAT32)(len2);
51
390k
  FLOAT32 delta, delta_sum = 0.0f;
52
390k
  FLOAT32 pos_wt = (0.5f - (FLOAT32)len1 / (FLOAT32)(len1 + len2));
53
390k
  pos_wt = 1.0f - 4.0f * pos_wt * pos_wt;
54
55
390k
  if (total_energy < SBR_EPS) {
56
0
    *ptr_delta = 0.0f;
57
0
    return IA_NO_ERROR;
58
0
  }
59
60
390k
  if (!is_ld_sbr) {
61
4.61M
    for (j = 0; j < num_sfb; j++) {
62
4.27M
      energy_1[j] = 1.0e6f * len1;
63
4.27M
      energy_2[j] = 1.0e6f * len2;
64
4.27M
    }
65
339k
  }
66
67
5.37M
  for (j = 0; j < num_sfb; j++) {
68
44.8M
    for (i = start; i < border; i++) {
69
39.8M
      energy_1[j] += ptr_energies[i][j];
70
39.8M
    }
71
72
44.5M
    for (i = border; i < stop; i++) {
73
39.5M
      energy_2[j] += ptr_energies[i][j];
74
39.5M
    }
75
4.98M
    if (energy_1[j] <= EPS) {
76
2.73k
      energy_1[j] = (FLOAT32)len1;
77
2.73k
    }
78
4.98M
    if (energy_2[j] <= EPS) {
79
24.6k
      energy_2[j] = (FLOAT32)len2;
80
24.6k
    }
81
4.98M
    delta = (FLOAT32)fabs(log((energy_2[j] / energy_1[j]) * len_ratio));
82
4.98M
    delta_sum += (FLOAT32)(sqrt((energy_1[j] + energy_2[j]) / total_energy) * delta);
83
4.98M
  }
84
85
390k
  *ptr_delta = delta_sum * pos_wt;
86
390k
  return IA_NO_ERROR;
87
390k
}
88
89
FLOAT32 ixheaace_add_lowband_energies(FLOAT32 **ptr_energies, UWORD8 *ptr_freq_band_tab,
90
419k
                                      WORD32 time_slots, WORD32 is_ld_sbr, WORD32 time_step) {
91
419k
  WORD32 band, ts;
92
419k
  FLOAT32 energy = 1.0f;
93
419k
  WORD32 tran_offset = 0;
94
419k
  if (is_ld_sbr) {
95
80.6k
    tran_offset = 7;
96
80.6k
    energy = 0.0f;
97
339k
  } else {
98
339k
    tran_offset = time_slots / 2;
99
339k
  }
100
101
7.09M
  for (ts = tran_offset; ts < time_slots + tran_offset; ts++) {
102
148M
    for (band = 0; band < ptr_freq_band_tab[0]; band++) {
103
141M
      energy += ptr_energies[ts][band];
104
141M
    }
105
6.67M
  }
106
107
419k
  energy *= time_step;
108
109
419k
  return energy;
110
419k
}
111
112
static FLOAT32 ixheaace_add_highband_energies(FLOAT32 **ptr_energies, FLOAT32 *ptr_energies_m[16],
113
                                              UWORD8 *ptr_freq_band_tab, WORD32 num_sfb,
114
                                              WORD32 time_slots, WORD32 time_step,
115
419k
                                              WORD32 is_ld_sbr) {
116
419k
  WORD32 band, ts, sfb, low_band, high_band;
117
419k
  FLOAT32 energy = 1.0f, tmp;
118
419k
  if (is_ld_sbr) {
119
80.6k
    energy = 0.0f;
120
80.6k
  }
121
7.09M
  for (ts = 0; ts < time_slots; ts++) {
122
92.2M
    for (sfb = 0; sfb < num_sfb; sfb++) {
123
85.6M
      tmp = 0;
124
85.6M
      low_band = ptr_freq_band_tab[sfb];
125
85.6M
      high_band = ptr_freq_band_tab[sfb + 1];
126
85.6M
      band = low_band;
127
282M
      while (band < high_band) {
128
196M
        tmp += (ptr_energies[ts][band] * time_step);
129
196M
        band++;
130
196M
      }
131
85.6M
      ptr_energies_m[ts][sfb] = tmp;
132
85.6M
      if (is_ld_sbr || time_step == 4) {
133
31.3M
        energy += tmp;
134
54.2M
      } else {
135
54.2M
        energy += ptr_energies[ts][sfb];
136
54.2M
      }
137
85.6M
    }
138
6.67M
  }
139
419k
  return energy;
140
419k
}
141
142
IA_ERRORCODE
143
ixheaace_frame_splitter(FLOAT32 **ptr_energies,
144
                        ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_detector,
145
                        UWORD8 *ptr_freq_band_tab, WORD32 num_scf, WORD32 time_step,
146
                        WORD32 no_cols, WORD32 *ptr_tran_vector,
147
419k
                        FLOAT32 *ptr_frame_splitter_scratch, WORD32 is_ld_sbr) {
148
419k
  WORD32 border, i;
149
419k
  WORD32 num_sbr_slots = no_cols / time_step;
150
419k
  FLOAT32 *ptr_energies_m[16] = {0};
151
419k
  FLOAT32 low_band_energy, high_band_energy, total_energy;
152
419k
  FLOAT32 delta = 0.0f;
153
419k
  IA_ERRORCODE err_code = IA_NO_ERROR;
154
155
419k
  if ((num_sbr_slots <= 0) || (num_sbr_slots * time_step != no_cols)) {
156
0
    return IA_EXHEAACE_EXE_FATAL_SBR_INVALID_TIME_SLOTS;
157
0
  }
158
159
419k
  memset(ptr_frame_splitter_scratch, 0,
160
419k
         sizeof(ptr_energies_m[0][0]) * MAXIMUM_FREQ_COEFFS * num_sbr_slots);
161
162
7.09M
  for (i = 0; i < num_sbr_slots; i++) {
163
6.67M
    ptr_energies_m[i] = ptr_frame_splitter_scratch;
164
6.67M
    ptr_frame_splitter_scratch += MAXIMUM_FREQ_COEFFS;
165
6.67M
  }
166
167
419k
  low_band_energy = ixheaace_add_lowband_energies(ptr_energies, ptr_freq_band_tab, num_sbr_slots,
168
419k
                                                  is_ld_sbr, time_step);
169
170
419k
  high_band_energy =
171
419k
      ixheaace_add_highband_energies(ptr_energies, ptr_energies_m, ptr_freq_band_tab, num_scf,
172
419k
                                     num_sbr_slots, time_step, is_ld_sbr);
173
419k
  border = (num_sbr_slots + 1) >> 1;
174
175
419k
  total_energy = 0.5f * (low_band_energy + pstr_sbr_trans_detector->prev_low_band_energy);
176
419k
  total_energy += high_band_energy;
177
419k
  if ((total_energy > IXHEAACE_SBR_ENERGY_THRESHOLD) || (!is_ld_sbr)) {
178
390k
    err_code = ixheaace_spectral_change(ptr_energies_m, total_energy, num_scf, 0, border,
179
390k
                                        num_sbr_slots, is_ld_sbr, &delta);
180
390k
    if (err_code) {
181
0
      return err_code;
182
0
    }
183
390k
  } else if (is_ld_sbr) {
184
29.4k
    delta = 0;
185
29.4k
  }
186
187
419k
  if (delta > pstr_sbr_trans_detector->split_thr) {
188
38.8k
    ptr_tran_vector[0] = 1;
189
380k
  } else {
190
380k
    ptr_tran_vector[0] = 0;
191
380k
  }
192
419k
  pstr_sbr_trans_detector->prev_low_band_energy = low_band_energy;
193
419k
  return err_code;
194
419k
}
195
196
VOID ixheaace_create_sbr_transient_detector(
197
    ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_detector, WORD32 sample_freq,
198
    WORD32 total_bitrate, WORD32 codec_bitrate, WORD32 tran_thr, WORD32 mode, WORD32 tran_fc,
199
    WORD32 frame_flag_480, WORD32 is_ld_sbr, WORD32 sbr_ratio_idx,
200
8.86k
    ixheaace_sbr_codec_type sbr_codec, WORD32 start_band) {
201
8.86k
  WORD32 no_cols = 32, buffer_length = 96;
202
8.86k
  FLOAT32 br_fac;
203
8.86k
  FLOAT32 frm_dur = 2048.0f / (FLOAT32)sample_freq;
204
8.86k
  FLOAT32 split_thr_fac = frm_dur - 0.01f;
205
8.86k
  if ((sbr_codec == USAC_SBR) && (sbr_ratio_idx == USAC_SBR_RATIO_INDEX_4_1)) {
206
805
    frm_dur = frm_dur * 2;
207
805
    split_thr_fac = frm_dur - 0.01f;
208
805
    no_cols = 64;
209
805
  }
210
8.86k
  if ((1 == is_ld_sbr) && (1 == frame_flag_480)) {
211
884
    no_cols = 30;
212
884
    buffer_length = 90;
213
884
  }
214
215
8.86k
  memset(pstr_sbr_trans_detector, 0, sizeof(ixheaace_str_sbr_trans_detector));
216
217
8.86k
  br_fac = codec_bitrate ? (FLOAT32)total_bitrate / (FLOAT32)codec_bitrate : 1.0f;
218
219
8.86k
  split_thr_fac = MAX(split_thr_fac, 0.0001f);
220
8.86k
  split_thr_fac = 0.000075f / (split_thr_fac * split_thr_fac);
221
222
8.86k
  pstr_sbr_trans_detector->split_thr = split_thr_fac * br_fac;
223
224
8.86k
  if (is_ld_sbr) {
225
1.87k
    WORD32 i;
226
1.87k
    FLOAT32 ratio = ((sample_freq / 2) / IXHEAACE_QMF_CHANNELS) * 0.00075275f;
227
228
1.87k
    FLOAT32 tmp = 1024.0f / sample_freq;
229
1.87k
    tmp -= 0.01f;
230
1.87k
    tmp = MAX(tmp, 0.001f);
231
232
1.87k
    if (1 == frame_flag_480) {
233
884
      no_cols = 30;
234
884
      buffer_length = 90;
235
884
    }
236
1.87k
    pstr_sbr_trans_detector->split_thr = (br_fac * 0.000075f) / (tmp * tmp) / 2.0f;
237
1.87k
    pstr_sbr_trans_detector->look_ahead = 2;
238
1.87k
    pstr_sbr_trans_detector->time_slots = no_cols / 2;
239
1.87k
    pstr_sbr_trans_detector->buffer_size =
240
1.87k
        pstr_sbr_trans_detector->look_ahead + pstr_sbr_trans_detector->time_slots;
241
1.87k
    pstr_sbr_trans_detector->stop_band =
242
1.87k
        (WORD32)fmin(13500 / ((sample_freq >> 1) / IXHEAACE_QMF_CHANNELS), IXHEAACE_QMF_CHANNELS);
243
1.87k
    pstr_sbr_trans_detector->start_band =
244
1.87k
        (WORD32)fmin(start_band, pstr_sbr_trans_detector->stop_band - 4);
245
246
1.87k
    memset(pstr_sbr_trans_detector->energy, 0,
247
1.87k
           pstr_sbr_trans_detector->buffer_size * sizeof(pstr_sbr_trans_detector->energy[0]));
248
1.87k
    memset(pstr_sbr_trans_detector->sbr_transients, 0,
249
1.87k
           pstr_sbr_trans_detector->buffer_size *
250
1.87k
               sizeof(pstr_sbr_trans_detector->sbr_transients[0]));
251
1.87k
    memset(
252
1.87k
        pstr_sbr_trans_detector->delta_energy, 0,
253
1.87k
        pstr_sbr_trans_detector->buffer_size * sizeof(pstr_sbr_trans_detector->delta_energy[0]));
254
255
122k
    for (i = 0; i < 64; i++) {
256
120k
      pstr_sbr_trans_detector->coeff[i] = (FLOAT32)pow(2.0, ratio * (i + 1));
257
120k
    }
258
1.87k
  }
259
8.86k
  pstr_sbr_trans_detector->no_cols = no_cols;
260
8.86k
  pstr_sbr_trans_detector->tran_fc = tran_fc;
261
262
8.86k
  pstr_sbr_trans_detector->buffer_length = buffer_length;
263
264
8.86k
  pstr_sbr_trans_detector->no_rows = 64;
265
8.86k
  pstr_sbr_trans_detector->mode = mode;
266
267
8.86k
  pstr_sbr_trans_detector->prev_low_band_energy = 0;
268
8.86k
  pstr_sbr_trans_detector->tran_thr = (FLOAT32)tran_thr;
269
270
8.86k
  pstr_sbr_trans_detector->ptr_thresholds = &(pstr_sbr_trans_detector->sbr_thresholds[0]);
271
272
8.86k
  memset(pstr_sbr_trans_detector->ptr_thresholds, 0,
273
8.86k
         sizeof(pstr_sbr_trans_detector->ptr_thresholds[0]) * IXHEAACE_QMF_CHANNELS);
274
275
8.86k
  pstr_sbr_trans_detector->ptr_transients = &(pstr_sbr_trans_detector->sbr_transients[0]);
276
8.86k
  memset(pstr_sbr_trans_detector->ptr_transients, 0,
277
8.86k
         sizeof(pstr_sbr_trans_detector->ptr_transients[0]) *
278
8.86k
             pstr_sbr_trans_detector->buffer_length);
279
8.86k
}