FFmpeg  4.3
aacenc_tns.c
Go to the documentation of this file.
1 /*
2  * AAC encoder TNS
3  * Copyright (C) 2015 Rostislav Pehlivanov
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * AAC encoder temporal noise shaping
25  * @author Rostislav Pehlivanov ( atomnuker gmail com )
26  */
27 
28 #include "libavutil/libm.h"
29 #include "aacenc.h"
30 #include "aacenc_tns.h"
31 #include "aactab.h"
32 #include "aacenc_utils.h"
33 #include "aacenc_quantization.h"
34 
35 /* Could be set to 3 to save an additional bit at the cost of little quality */
36 #define TNS_Q_BITS 4
37 
38 /* Coefficient resolution in short windows */
39 #define TNS_Q_BITS_IS8 4
40 
41 /* We really need the bits we save here elsewhere */
42 #define TNS_ENABLE_COEF_COMPRESSION
43 
44 /* TNS will only be used if the LPC gain is within these margins */
45 #define TNS_GAIN_THRESHOLD_LOW 1.4f
46 #define TNS_GAIN_THRESHOLD_HIGH 1.16f*TNS_GAIN_THRESHOLD_LOW
47 
48 static inline int compress_coeffs(int *coef, int order, int c_bits)
49 {
50  int i;
51  const int low_idx = c_bits ? 4 : 2;
52  const int shift_val = c_bits ? 8 : 4;
53  const int high_idx = c_bits ? 11 : 5;
54 #ifndef TNS_ENABLE_COEF_COMPRESSION
55  return 0;
56 #endif /* TNS_ENABLE_COEF_COMPRESSION */
57  for (i = 0; i < order; i++)
58  if (coef[i] >= low_idx && coef[i] <= high_idx)
59  return 0;
60  for (i = 0; i < order; i++)
61  coef[i] -= (coef[i] > high_idx) ? shift_val : 0;
62  return 1;
63 }
64 
65 /**
66  * Encode TNS data.
67  * Coefficient compression is simply not lossless as it should be
68  * on any decoder tested and as such is not active.
69  */
71 {
72  TemporalNoiseShaping *tns = &sce->tns;
73  int i, w, filt, coef_compress = 0, coef_len;
74  const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
75  const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4;
76 
77  if (!sce->tns.present)
78  return;
79 
80  for (i = 0; i < sce->ics.num_windows; i++) {
81  put_bits(&s->pb, 2 - is8, sce->tns.n_filt[i]);
82  if (!tns->n_filt[i])
83  continue;
84  put_bits(&s->pb, 1, c_bits);
85  for (filt = 0; filt < tns->n_filt[i]; filt++) {
86  put_bits(&s->pb, 6 - 2 * is8, tns->length[i][filt]);
87  put_bits(&s->pb, 5 - 2 * is8, tns->order[i][filt]);
88  if (!tns->order[i][filt])
89  continue;
90  put_bits(&s->pb, 1, tns->direction[i][filt]);
91  coef_compress = compress_coeffs(tns->coef_idx[i][filt],
92  tns->order[i][filt], c_bits);
93  put_bits(&s->pb, 1, coef_compress);
94  coef_len = c_bits + 3 - coef_compress;
95  for (w = 0; w < tns->order[i][filt]; w++)
96  put_bits(&s->pb, coef_len, tns->coef_idx[i][filt][w]);
97  }
98  }
99 }
100 
101 /* Apply TNS filter */
103 {
104  TemporalNoiseShaping *tns = &sce->tns;
105  IndividualChannelStream *ics = &sce->ics;
106  int w, filt, m, i, top, order, bottom, start, end, size, inc;
107  const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb);
108  float lpc[TNS_MAX_ORDER];
109 
110  for (w = 0; w < ics->num_windows; w++) {
111  bottom = ics->num_swb;
112  for (filt = 0; filt < tns->n_filt[w]; filt++) {
113  top = bottom;
114  bottom = FFMAX(0, top - tns->length[w][filt]);
115  order = tns->order[w][filt];
116  if (order == 0)
117  continue;
118 
119  // tns_decode_coef
120  compute_lpc_coefs(tns->coef[w][filt], order, lpc, 0, 0, 0);
121 
122  start = ics->swb_offset[FFMIN(bottom, mmm)];
123  end = ics->swb_offset[FFMIN( top, mmm)];
124  if ((size = end - start) <= 0)
125  continue;
126  if (tns->direction[w][filt]) {
127  inc = -1;
128  start = end - 1;
129  } else {
130  inc = 1;
131  }
132  start += w * 128;
133 
134  /* AR filter */
135  for (m = 0; m < size; m++, start += inc) {
136  for (i = 1; i <= FFMIN(m, order); i++) {
137  sce->coeffs[start] += lpc[i-1]*sce->pcoeffs[start - i*inc];
138  }
139  }
140  }
141  }
142 }
143 
144 /*
145  * c_bits - 1 if 4 bit coefficients, 0 if 3 bit coefficients
146  */
147 static inline void quantize_coefs(double *coef, int *idx, float *lpc, int order,
148  int c_bits)
149 {
150  int i;
151  const float *quant_arr = tns_tmp2_map[c_bits];
152  for (i = 0; i < order; i++) {
153  idx[i] = quant_array_idx(coef[i], quant_arr, c_bits ? 16 : 8);
154  lpc[i] = quant_arr[idx[i]];
155  }
156 }
157 
158 /*
159  * 3 bits per coefficient with 8 short windows
160  */
162 {
163  TemporalNoiseShaping *tns = &sce->tns;
164  int w, g, count = 0;
165  double gain, coefs[MAX_LPC_ORDER];
166  const int mmm = FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb);
167  const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
168  const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4;
169  const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm);
170  const int sfb_end = av_clip(sce->ics.num_swb, 0, mmm);
171  const int order = is8 ? 7 : s->profile == FF_PROFILE_AAC_LOW ? 12 : TNS_MAX_ORDER;
172  const int slant = sce->ics.window_sequence[0] == LONG_STOP_SEQUENCE ? 1 :
173  sce->ics.window_sequence[0] == LONG_START_SEQUENCE ? 0 : 2;
174  const int sfb_len = sfb_end - sfb_start;
175  const int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start];
176 
177  if (coef_len <= 0 || sfb_len <= 0) {
178  sce->tns.present = 0;
179  return;
180  }
181 
182  for (w = 0; w < sce->ics.num_windows; w++) {
183  float en[2] = {0.0f, 0.0f};
184  int oc_start = 0, os_start = 0;
185  int coef_start = sce->ics.swb_offset[sfb_start];
186 
187  for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
188  FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
189  if (g > sfb_start + (sfb_len/2))
190  en[1] += band->energy;
191  else
192  en[0] += band->energy;
193  }
194 
195  /* LPC */
196  gain = ff_lpc_calc_ref_coefs_f(&s->lpc, &sce->coeffs[w*128 + coef_start],
197  coef_len, order, coefs);
198 
199  if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH)
200  continue;
201 
202  tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
203  for (g = 0; g < tns->n_filt[w]; g++) {
204  tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g];
205  tns->order[w][g] = g < tns->n_filt[w] ? order/tns->n_filt[w] : order - oc_start;
206  tns->length[w][g] = g < tns->n_filt[w] ? sfb_len/tns->n_filt[w] : sfb_len - os_start;
207  quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g],
208  tns->order[w][g], c_bits);
209  oc_start += tns->order[w][g];
210  os_start += tns->length[w][g];
211  }
212  count++;
213  }
214  sce->tns.present = !!count;
215 }
TNS_Q_BITS_IS8
#define TNS_Q_BITS_IS8
Definition: aacenc_tns.c:39
TemporalNoiseShaping::order
int order[8][4]
Definition: aac.h:203
libm.h
TemporalNoiseShaping::direction
int direction[8][4]
Definition: aac.h:202
TNS_GAIN_THRESHOLD_HIGH
#define TNS_GAIN_THRESHOLD_HIGH
Definition: aacenc_tns.c:46
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
TemporalNoiseShaping::coef_idx
int coef_idx[8][4][TNS_MAX_ORDER]
Definition: aac.h:204
put_bits
static void put_bits(Jpeg2000EncoderContext *s, int val, int n)
put n times val bit
Definition: j2kenc.c:208
compute_lpc_coefs
static int AAC_RENAME() compute_lpc_coefs(const LPC_TYPE *autoc, int max_order, LPC_TYPE *lpc, int lpc_stride, int fail, int normalize)
Levinson-Durbin recursion.
Definition: lpc.h:166
compress_coeffs
static int compress_coeffs(int *coef, int order, int c_bits)
Definition: aacenc_tns.c:48
TemporalNoiseShaping::present
int present
Definition: aac.h:199
SingleChannelElement::pcoeffs
INTFLOAT pcoeffs[1024]
coefficients for IMDCT, pristine
Definition: aac.h:261
IndividualChannelStream::num_swb
int num_swb
number of scalefactor window bands
Definition: aac.h:183
TNS_Q_BITS
#define TNS_Q_BITS
Definition: aacenc_tns.c:36
TemporalNoiseShaping::length
int length[8][4]
Definition: aac.h:201
SingleChannelElement::ics
IndividualChannelStream ics
Definition: aac.h:249
s
#define s(width, name)
Definition: cbs_vp9.c:257
SingleChannelElement::coeffs
INTFLOAT coeffs[1024]
coefficients for IMDCT, maybe processed
Definition: aac.h:262
g
const char * g
Definition: vf_curves.c:115
EIGHT_SHORT_SEQUENCE
@ EIGHT_SHORT_SEQUENCE
Definition: aac.h:78
isfinite
#define isfinite(x)
Definition: libm.h:359
IndividualChannelStream
Individual Channel Stream.
Definition: aac.h:174
TemporalNoiseShaping::coef
INTFLOAT coef[8][4][TNS_MAX_ORDER]
Definition: aac.h:205
IndividualChannelStream::swb_offset
const uint16_t * swb_offset
table of offsets to the lowest spectral coefficient of a scalefactor band, sfb, for a particular wind...
Definition: aac.h:181
aacenc_quantization.h
ff_aac_apply_tns
void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
Definition: aacenc_tns.c:102
FFPsyBand
single band psychoacoustic information
Definition: psymodel.h:50
aactab.h
ff_aac_encode_tns_info
void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce)
Encode TNS data.
Definition: aacenc_tns.c:70
TNS_MAX_ORDER
#define TNS_MAX_ORDER
Definition: aac.h:50
ff_lpc_calc_ref_coefs_f
double ff_lpc_calc_ref_coefs_f(LPCContext *s, const float *samples, int len, int order, double *ref)
Definition: lpc.c:171
TemporalNoiseShaping::n_filt
int n_filt[8]
Definition: aac.h:200
FF_PROFILE_AAC_LOW
#define FF_PROFILE_AAC_LOW
Definition: avcodec.h:1864
MAX_LPC_ORDER
#define MAX_LPC_ORDER
Definition: lpc.h:38
FFMAX
#define FFMAX(a, b)
Definition: common.h:94
size
int size
Definition: twinvq_data.h:11134
filt
static const int8_t filt[NUMTAPS]
Definition: af_earwax.c:39
quant_array_idx
static int quant_array_idx(const float val, const float *arr, const int num)
Definition: aacenc_utils.h:171
FFMIN
#define FFMIN(a, b)
Definition: common.h:96
tns_min_sfb
static const uint8_t *const tns_min_sfb[2]
Definition: aacenctab.h:112
SingleChannelElement
Single Channel Element - used for both SCE and LFE elements.
Definition: aac.h:248
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
IndividualChannelStream::num_windows
int num_windows
Definition: aac.h:184
ff_aac_search_for_tns
void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
Definition: aacenc_tns.c:161
LONG_STOP_SEQUENCE
@ LONG_STOP_SEQUENCE
Definition: aac.h:79
IndividualChannelStream::tns_max_bands
int tns_max_bands
Definition: aac.h:185
AACEncContext::lpc
LPCContext lpc
used by TNS
Definition: aacenc.h:388
w
FFmpeg Automated Testing Environment ************************************Introduction Using FATE from your FFmpeg source directory Submitting the results to the FFmpeg result aggregation server Uploading new samples to the fate suite FATE makefile targets and variables Makefile targets Makefile variables Examples Introduction **************FATE is an extended regression suite on the client side and a means for results aggregation and presentation on the server side The first part of this document explains how you can use FATE from your FFmpeg source directory to test your ffmpeg binary The second part describes how you can run FATE to submit the results to FFmpeg’s FATE server In any way you can have a look at the publicly viewable FATE results by visiting this as it can be seen if some test on some platform broke with their recent contribution This usually happens on the platforms the developers could not test on The second part of this document describes how you can run FATE to submit your results to FFmpeg’s FATE server If you want to submit your results be sure to check that your combination of OS and compiler is not already listed on the above mentioned website In the third part you can find a comprehensive listing of FATE makefile targets and variables Using FATE from your FFmpeg source directory **********************************************If you want to run FATE on your machine you need to have the samples in place You can get the samples via the build target fate rsync Use this command from the top level source this will cause FATE to fail NOTE To use a custom wrapper to run the pass ‘ target exec’ to ‘configure’ or set the TARGET_EXEC Make variable Submitting the results to the FFmpeg result aggregation server ****************************************************************To submit your results to the server you should run fate through the shell script ‘tests fate sh’ from the FFmpeg sources This script needs to be invoked with a configuration file as its first argument tests fate sh path to fate_config A configuration file template with comments describing the individual configuration variables can be found at ‘doc fate_config sh template’ Create a configuration that suits your based on the configuration template The ‘slot’ configuration variable can be any string that is not yet but it is suggested that you name it adhering to the following pattern ‘ARCH OS COMPILER COMPILER VERSION’ The configuration file itself will be sourced in a shell therefore all shell features may be used This enables you to setup the environment as you need it for your build For your first test runs the ‘fate_recv’ variable should be empty or commented out This will run everything as normal except that it will omit the submission of the results to the server The following files should be present in $workdir as specified in the configuration it may help to try out the ‘ssh’ command with one or more ‘ v’ options You should get detailed output concerning your SSH configuration and the authentication process The only thing left is to automate the execution of the fate sh script and the synchronisation of the samples directory Uploading new samples to the fate suite *****************************************If you need a sample uploaded send a mail to samples request This is for developers who have an account on the fate suite server If you upload new please make sure they are as small as space on each network bandwidth and so on benefit from smaller test cases Also keep in mind older checkouts use existing sample that means in practice generally do not remove or overwrite files as it likely would break older checkouts or releases Also all needed samples for a commit should be ideally before the push If you need an account for frequently uploading samples or you wish to help others by doing that send a mail to ffmpeg devel rsync vauL Duo ug o o w
Definition: fate.txt:150
LONG_START_SEQUENCE
@ LONG_START_SEQUENCE
Definition: aac.h:77
SingleChannelElement::tns
TemporalNoiseShaping tns
Definition: aac.h:250
AACEncContext
AAC encoder context.
Definition: aacenc.h:376
FFPsyBand::energy
float energy
Definition: psymodel.h:52
IndividualChannelStream::window_sequence
enum WindowSequence window_sequence[2]
Definition: aac.h:176
TemporalNoiseShaping
Temporal Noise Shaping.
Definition: aac.h:198
quantize_coefs
static void quantize_coefs(double *coef, int *idx, float *lpc, int order, int c_bits)
Definition: aacenc_tns.c:147
aacenc_tns.h
IndividualChannelStream::max_sfb
uint8_t max_sfb
number of scalefactor bands per group
Definition: aac.h:175
tns_tmp2_map
static const INTFLOAT *const tns_tmp2_map[4]
Definition: aactab.h:126
aacenc_utils.h
aacenc.h