FFmpeg
af_apsyclip.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 - 2021 Jason Jang
3  * Copyright (c) 2021 Paul B Mahol
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 License
9  * 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
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "libavutil/opt.h"
23 #include "libavutil/tx.h"
24 #include "audio.h"
25 #include "avfilter.h"
26 #include "filters.h"
27 #include "internal.h"
28 
29 typedef struct AudioPsyClipContext {
30  const AVClass *class;
31 
32  double level_in;
33  double level_out;
34  double clip_level;
35  double adaptive;
37  int diff_only;
40  double *protections;
41 
43  int fft_size;
44  int overlap;
45  int channels;
46 
51 
60 
66 
67 #define OFFSET(x) offsetof(AudioPsyClipContext, x)
68 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM
69 
70 static const AVOption apsyclip_options[] = {
71  { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, FLAGS },
72  { "level_out", "set output level", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, FLAGS },
73  { "clip", "set clip level", OFFSET(clip_level), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 1, FLAGS },
74  { "diff", "enable difference", OFFSET(diff_only), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
75  { "adaptive", "set adaptive distortion", OFFSET(adaptive), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, FLAGS },
76  { "iterations", "set iterations", OFFSET(iterations), AV_OPT_TYPE_INT, {.i64=10}, 1, 20, FLAGS },
77  { "level", "set auto level", OFFSET(auto_level), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
78  {NULL}
79 };
80 
81 AVFILTER_DEFINE_CLASS(apsyclip);
82 
83 static void generate_hann_window(float *window, float *inv_window, int size)
84 {
85  for (int i = 0; i < size; i++) {
86  float value = 0.5f * (1.f - cosf(2.f * M_PI * i / size));
87 
88  window[i] = value;
89  // 1/window to calculate unwindowed peak.
90  inv_window[i] = value > 0.01f ? 1.f / value : 0.f;
91  }
92 }
93 
95  const int (*points)[2], int num_points, int sample_rate)
96 {
97  int j = 0;
98 
99  s->margin_curve[0] = points[0][1];
100 
101  for (int i = 0; i < num_points - 1; i++) {
102  while (j < s->fft_size / 2 + 1 && j * sample_rate / s->fft_size < points[i + 1][0]) {
103  // linearly interpolate between points
104  int binHz = j * sample_rate / s->fft_size;
105  s->margin_curve[j] = points[i][1] + (binHz - points[i][0]) * (points[i + 1][1] - points[i][1]) / (points[i + 1][0] - points[i][0]);
106  j++;
107  }
108  }
109  // handle bins after the last point
110  while (j < s->fft_size / 2 + 1) {
111  s->margin_curve[j] = points[num_points - 1][1];
112  j++;
113  }
114 
115  // convert margin curve to linear amplitude scale
116  for (j = 0; j < s->fft_size / 2 + 1; j++)
117  s->margin_curve[j] = powf(10.f, s->margin_curve[j] / 20.f);
118 }
119 
121 {
122  // Calculate tent-shape function in log-log scale.
123 
124  // As an optimization, only consider bins close to "bin"
125  // This reduces the number of multiplications needed in calculate_mask_curve
126  // The masking contribution at faraway bins is negligeable
127 
128  // Another optimization to save memory and speed up the calculation of the
129  // spread table is to calculate and store only 2 spread functions per
130  // octave, and reuse the same spread function for multiple bins.
131  int table_index = 0;
132  int bin = 0;
133  int increment = 1;
134 
135  while (bin < s->num_psy_bins) {
136  float sum = 0;
137  int base_idx = table_index * s->num_psy_bins;
138  int start_bin = bin * 3 / 4;
139  int end_bin = FFMIN(s->num_psy_bins, ((bin + 1) * 4 + 2) / 3);
140  int next_bin;
141 
142  for (int j = start_bin; j < end_bin; j++) {
143  // add 0.5 so i=0 doesn't get log(0)
144  float rel_idx_log = FFABS(logf((j + 0.5f) / (bin + 0.5f)));
145  float value;
146  if (j >= bin) {
147  // mask up
148  value = expf(-rel_idx_log * 40.f);
149  } else {
150  // mask down
151  value = expf(-rel_idx_log * 80.f);
152  }
153  // the spreading function is centred in the row
154  sum += value;
155  s->spread_table[base_idx + s->num_psy_bins / 2 + j - bin] = value;
156  }
157  // now normalize it
158  for (int j = start_bin; j < end_bin; j++) {
159  s->spread_table[base_idx + s->num_psy_bins / 2 + j - bin] /= sum;
160  }
161 
162  s->spread_table_range[table_index][0] = start_bin - bin;
163  s->spread_table_range[table_index][1] = end_bin - bin;
164 
165  if (bin <= 1) {
166  next_bin = bin + 1;
167  } else {
168  if ((bin & (bin - 1)) == 0) {
169  // power of 2
170  increment = bin / 2;
171  }
172 
173  next_bin = bin + increment;
174  }
175 
176  // set bins between "bin" and "next_bin" to use this table_index
177  for (int i = bin; i < next_bin; i++)
178  s->spread_table_index[i] = table_index;
179 
180  bin = next_bin;
181  table_index++;
182  }
183 }
184 
186 {
187  AVFilterContext *ctx = inlink->dst;
188  AudioPsyClipContext *s = ctx->priv;
189  static const int points[][2] = { {0,14}, {125,14}, {250,16}, {500,18}, {1000,20}, {2000,20}, {4000,20}, {8000,15}, {16000,5}, {20000,-10} };
190  static const int num_points = 10;
191  float scale;
192  int ret;
193 
194  s->fft_size = inlink->sample_rate > 100000 ? 1024 : inlink->sample_rate > 50000 ? 512 : 256;
195  s->overlap = s->fft_size / 4;
196 
197  // The psy masking calculation is O(n^2),
198  // so skip it for frequencies not covered by base sampling rantes (i.e. 44k)
199  if (inlink->sample_rate <= 50000) {
200  s->num_psy_bins = s->fft_size / 2;
201  } else if (inlink->sample_rate <= 100000) {
202  s->num_psy_bins = s->fft_size / 4;
203  } else {
204  s->num_psy_bins = s->fft_size / 8;
205  }
206 
207  s->window = av_calloc(s->fft_size, sizeof(*s->window));
208  s->inv_window = av_calloc(s->fft_size, sizeof(*s->inv_window));
209  if (!s->window || !s->inv_window)
210  return AVERROR(ENOMEM);
211 
212  s->in_buffer = ff_get_audio_buffer(inlink, s->fft_size * 2);
213  s->in_frame = ff_get_audio_buffer(inlink, s->fft_size * 2);
214  s->out_dist_frame = ff_get_audio_buffer(inlink, s->fft_size * 2);
215  s->windowed_frame = ff_get_audio_buffer(inlink, s->fft_size * 2);
216  s->clipping_delta = ff_get_audio_buffer(inlink, s->fft_size * 2);
217  s->spectrum_buf = ff_get_audio_buffer(inlink, s->fft_size * 2);
218  s->mask_curve = ff_get_audio_buffer(inlink, s->fft_size / 2 + 1);
219  if (!s->in_buffer || !s->in_frame ||
220  !s->out_dist_frame || !s->windowed_frame ||
221  !s->clipping_delta || !s->spectrum_buf || !s->mask_curve)
222  return AVERROR(ENOMEM);
223 
224  generate_hann_window(s->window, s->inv_window, s->fft_size);
225 
226  s->margin_curve = av_calloc(s->fft_size / 2 + 1, sizeof(*s->margin_curve));
227  if (!s->margin_curve)
228  return AVERROR(ENOMEM);
229 
230  s->spread_table_rows = av_log2(s->num_psy_bins) * 2;
231  s->spread_table = av_calloc(s->spread_table_rows * s->num_psy_bins, sizeof(*s->spread_table));
232  if (!s->spread_table)
233  return AVERROR(ENOMEM);
234 
235  s->spread_table_range = av_calloc(s->spread_table_rows * 2, sizeof(*s->spread_table_range));
236  if (!s->spread_table_range)
237  return AVERROR(ENOMEM);
238 
239  s->spread_table_index = av_calloc(s->num_psy_bins, sizeof(*s->spread_table_index));
240  if (!s->spread_table_index)
241  return AVERROR(ENOMEM);
242 
243  set_margin_curve(s, points, num_points, inlink->sample_rate);
244 
246 
247  s->channels = inlink->channels;
248 
249  s->tx_ctx = av_calloc(s->channels, sizeof(*s->tx_ctx));
250  s->itx_ctx = av_calloc(s->channels, sizeof(*s->itx_ctx));
251  if (!s->tx_ctx || !s->itx_ctx)
252  return AVERROR(ENOMEM);
253 
254  for (int ch = 0; ch < s->channels; ch++) {
255  ret = av_tx_init(&s->tx_ctx[ch], &s->tx_fn, AV_TX_FLOAT_FFT, 0, s->fft_size, &scale, 0);
256  if (ret < 0)
257  return ret;
258 
259  ret = av_tx_init(&s->itx_ctx[ch], &s->itx_fn, AV_TX_FLOAT_FFT, 1, s->fft_size, &scale, 0);
260  if (ret < 0)
261  return ret;
262  }
263 
264  return 0;
265 }
266 
268  const float *in_frame, float *out_frame, const int add_to_out_frame)
269 {
270  const float *window = s->window;
271 
272  for (int i = 0; i < s->fft_size; i++) {
273  if (add_to_out_frame) {
274  out_frame[i] += in_frame[i] * window[i];
275  } else {
276  out_frame[i] = in_frame[i] * window[i];
277  }
278  }
279 }
280 
282  const float *spectrum, float *mask_curve)
283 {
284  for (int i = 0; i < s->fft_size / 2 + 1; i++)
285  mask_curve[i] = 0;
286 
287  for (int i = 0; i < s->num_psy_bins; i++) {
288  int base_idx, start_bin, end_bin, table_idx;
289  float magnitude;
290  int range[2];
291 
292  if (i == 0) {
293  magnitude = FFABS(spectrum[0]);
294  } else if (i == s->fft_size / 2) {
295  magnitude = FFABS(spectrum[1]);
296  } else {
297  // although the negative frequencies are omitted because they are redundant,
298  // the magnitude of the positive frequencies are not doubled.
299  // Multiply the magnitude by 2 to simulate adding up the + and - frequencies.
300  magnitude = hypotf(spectrum[2 * i], spectrum[2 * i + 1]) * 2;
301  }
302 
303  table_idx = s->spread_table_index[i];
304  range[0] = s->spread_table_range[table_idx][0];
305  range[1] = s->spread_table_range[table_idx][1];
306  base_idx = table_idx * s->num_psy_bins;
307  start_bin = FFMAX(0, i + range[0]);
308  end_bin = FFMIN(s->num_psy_bins, i + range[1]);
309 
310  for (int j = start_bin; j < end_bin; j++)
311  mask_curve[j] += s->spread_table[base_idx + s->num_psy_bins / 2 + j - i] * magnitude;
312  }
313 
314  // for ultrasonic frequencies, skip the O(n^2) spread calculation and just copy the magnitude
315  for (int i = s->num_psy_bins; i < s->fft_size / 2 + 1; i++) {
316  float magnitude;
317  if (i == s->fft_size / 2) {
318  magnitude = FFABS(spectrum[1]);
319  } else {
320  // although the negative frequencies are omitted because they are redundant,
321  // the magnitude of the positive frequencies are not doubled.
322  // Multiply the magnitude by 2 to simulate adding up the + and - frequencies.
323  magnitude = hypotf(spectrum[2 * i], spectrum[2 * i + 1]) * 2;
324  }
325 
326  mask_curve[i] = magnitude;
327  }
328 
329  for (int i = 0; i < s->fft_size / 2 + 1; i++)
330  mask_curve[i] = mask_curve[i] / s->margin_curve[i];
331 }
332 
334  const float *windowed_frame, float *clipping_delta, float delta_boost)
335 {
336  const float *window = s->window;
337 
338  for (int i = 0; i < s->fft_size; i++) {
339  const float limit = s->clip_level * window[i];
340  const float effective_value = windowed_frame[i] + clipping_delta[i];
341 
342  if (effective_value > limit) {
343  clipping_delta[i] += (limit - effective_value) * delta_boost;
344  } else if (effective_value < -limit) {
345  clipping_delta[i] += (-limit - effective_value) * delta_boost;
346  }
347  }
348 }
349 
351  float *clip_spectrum, const float *mask_curve)
352 {
353  // bin 0
354  float relative_distortion_level = FFABS(clip_spectrum[0]) / mask_curve[0];
355 
356  if (relative_distortion_level > 1.f)
357  clip_spectrum[0] /= relative_distortion_level;
358 
359  // bin 1..N/2-1
360  for (int i = 1; i < s->fft_size / 2; i++) {
361  float real = clip_spectrum[i * 2];
362  float imag = clip_spectrum[i * 2 + 1];
363  // although the negative frequencies are omitted because they are redundant,
364  // the magnitude of the positive frequencies are not doubled.
365  // Multiply the magnitude by 2 to simulate adding up the + and - frequencies.
366  relative_distortion_level = hypotf(real, imag) * 2 / mask_curve[i];
367  if (relative_distortion_level > 1.0) {
368  clip_spectrum[i * 2] /= relative_distortion_level;
369  clip_spectrum[i * 2 + 1] /= relative_distortion_level;
370  }
371  }
372  // bin N/2
373  relative_distortion_level = FFABS(clip_spectrum[1]) / mask_curve[s->fft_size / 2];
374  if (relative_distortion_level > 1.f)
375  clip_spectrum[1] /= relative_distortion_level;
376 }
377 
378 static void r2c(float *buffer, int size)
379 {
380  for (int i = size - 1; i >= 0; i--)
381  buffer[2 * i] = buffer[i];
382 
383  for (int i = size - 1; i >= 0; i--)
384  buffer[2 * i + 1] = 0.f;
385 }
386 
387 static void c2r(float *buffer, int size)
388 {
389  for (int i = 0; i < size; i++)
390  buffer[i] = buffer[2 * i];
391 
392  for (int i = 0; i < size; i++)
393  buffer[i + size] = 0.f;
394 }
395 
396 static void feed(AVFilterContext *ctx, int ch,
397  const float *in_samples, float *out_samples, int diff_only,
398  float *in_frame, float *out_dist_frame,
399  float *windowed_frame, float *clipping_delta,
400  float *spectrum_buf, float *mask_curve)
401 {
402  AudioPsyClipContext *s = ctx->priv;
403  const float clip_level_inv = 1.f / s->clip_level;
404  const float level_out = s->level_out;
405  float orig_peak = 0;
406  float peak;
407 
408  // shift in/out buffers
409  for (int i = 0; i < s->fft_size - s->overlap; i++) {
410  in_frame[i] = in_frame[i + s->overlap];
411  out_dist_frame[i] = out_dist_frame[i + s->overlap];
412  }
413 
414  for (int i = 0; i < s->overlap; i++) {
415  in_frame[i + s->fft_size - s->overlap] = in_samples[i];
416  out_dist_frame[i + s->fft_size - s->overlap] = 0.f;
417  }
418 
419  apply_window(s, in_frame, windowed_frame, 0);
420  r2c(windowed_frame, s->fft_size);
421  s->tx_fn(s->tx_ctx[ch], spectrum_buf, windowed_frame, sizeof(float));
422  c2r(windowed_frame, s->fft_size);
423  calculate_mask_curve(s, spectrum_buf, mask_curve);
424 
425  // It would be easier to calculate the peak from the unwindowed input.
426  // This is just for consistency with the clipped peak calculateion
427  // because the inv_window zeros out samples on the edge of the window.
428  for (int i = 0; i < s->fft_size; i++)
429  orig_peak = FFMAX(orig_peak, FFABS(windowed_frame[i] * s->inv_window[i]));
430  orig_peak *= clip_level_inv;
431  peak = orig_peak;
432 
433  // clear clipping_delta
434  for (int i = 0; i < s->fft_size * 2; i++)
435  clipping_delta[i] = 0.f;
436 
437  // repeat clipping-filtering process a few times to control both the peaks and the spectrum
438  for (int i = 0; i < s->iterations; i++) {
439  float mask_curve_shift = 1.122f; // 1.122 is 1dB
440  // The last 1/3 of rounds have boosted delta to help reach the peak target faster
441  float delta_boost = 1.f;
442  if (i >= s->iterations - s->iterations / 3) {
443  // boosting the delta when largs peaks are still present is dangerous
444  if (peak < 2.f)
445  delta_boost = 2.f;
446  }
447 
448  clip_to_window(s, windowed_frame, clipping_delta, delta_boost);
449 
450  r2c(clipping_delta, s->fft_size);
451  s->tx_fn(s->tx_ctx[ch], spectrum_buf, clipping_delta, sizeof(float));
452 
453  limit_clip_spectrum(s, spectrum_buf, mask_curve);
454 
455  s->itx_fn(s->itx_ctx[ch], clipping_delta, spectrum_buf, sizeof(float));
456  c2r(clipping_delta, s->fft_size);
457 
458  for (int i = 0; i < s->fft_size; i++)
459  clipping_delta[i] /= s->fft_size;
460 
461  peak = 0;
462  for (int i = 0; i < s->fft_size; i++)
463  peak = FFMAX(peak, FFABS((windowed_frame[i] + clipping_delta[i]) * s->inv_window[i]));
464  peak *= clip_level_inv;
465 
466  // Automatically adjust mask_curve as necessary to reach peak target
467  if (orig_peak > 1.f && peak > 1.f) {
468  float diff_achieved = orig_peak - peak;
469  if (i + 1 < s->iterations - s->iterations / 3 && diff_achieved > 0) {
470  float diff_needed = orig_peak - 1.f;
471  float diff_ratio = diff_needed / diff_achieved;
472  // If a good amount of peak reduction was already achieved,
473  // don't shift the mask_curve by the full peak value
474  // On the other hand, if only a little peak reduction was achieved,
475  // don't shift the mask_curve by the enormous diff_ratio.
476  diff_ratio = FFMIN(diff_ratio, peak);
477  mask_curve_shift = FFMAX(mask_curve_shift, diff_ratio);
478  } else {
479  // If the peak got higher than the input or we are in the last 1/3 rounds,
480  // go back to the heavy-handed peak heuristic.
481  mask_curve_shift = FFMAX(mask_curve_shift, peak);
482  }
483  }
484 
485  mask_curve_shift = 1.f + (mask_curve_shift - 1.f) * s->adaptive;
486 
487  // Be less strict in the next iteration.
488  // This helps with peak control.
489  for (int i = 0; i < s->fft_size / 2 + 1; i++)
490  mask_curve[i] *= mask_curve_shift;
491  }
492 
493  // do overlap & add
494  apply_window(s, clipping_delta, out_dist_frame, 1);
495 
496  for (int i = 0; i < s->overlap; i++) {
497  // 4 times overlap with squared hanning window results in 1.5 time increase in amplitude
498  if (!ctx->is_disabled) {
499  out_samples[i] = out_dist_frame[i] / 1.5f;
500  if (!diff_only)
501  out_samples[i] += in_frame[i];
502  if (s->auto_level)
503  out_samples[i] *= clip_level_inv;
504  out_samples[i] *= level_out;
505  } else {
506  out_samples[i] = in_frame[i];
507  }
508  }
509 }
510 
511 static int psy_channel(AVFilterContext *ctx, AVFrame *in, AVFrame *out, int ch)
512 {
513  AudioPsyClipContext *s = ctx->priv;
514  const float *src = (const float *)in->extended_data[ch];
515  float *in_buffer = (float *)s->in_buffer->extended_data[ch];
516  float *dst = (float *)out->extended_data[ch];
517 
518  for (int n = 0; n < s->overlap; n++)
519  in_buffer[n] = src[n] * s->level_in;
520 
521  feed(ctx, ch, in_buffer, dst, s->diff_only,
522  (float *)(s->in_frame->extended_data[ch]),
523  (float *)(s->out_dist_frame->extended_data[ch]),
524  (float *)(s->windowed_frame->extended_data[ch]),
525  (float *)(s->clipping_delta->extended_data[ch]),
526  (float *)(s->spectrum_buf->extended_data[ch]),
527  (float *)(s->mask_curve->extended_data[ch]));
528 
529  return 0;
530 }
531 
532 static int psy_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
533 {
534  AudioPsyClipContext *s = ctx->priv;
535  AVFrame *out = arg;
536  const int start = (out->channels * jobnr) / nb_jobs;
537  const int end = (out->channels * (jobnr+1)) / nb_jobs;
538 
539  for (int ch = start; ch < end; ch++)
540  psy_channel(ctx, s->in, out, ch);
541 
542  return 0;
543 }
544 
546 {
547  AVFilterContext *ctx = inlink->dst;
548  AVFilterLink *outlink = ctx->outputs[0];
549  AudioPsyClipContext *s = ctx->priv;
550  AVFrame *out;
551  int ret;
552 
553  out = ff_get_audio_buffer(outlink, s->overlap);
554  if (!out) {
555  ret = AVERROR(ENOMEM);
556  goto fail;
557  }
558 
559  s->in = in;
562 
563  out->pts = in->pts;
564  out->nb_samples = in->nb_samples;
565  ret = ff_filter_frame(outlink, out);
566 fail:
567  av_frame_free(&in);
568  s->in = NULL;
569  return ret < 0 ? ret : 0;
570 }
571 
573 {
574  AVFilterLink *inlink = ctx->inputs[0];
575  AVFilterLink *outlink = ctx->outputs[0];
576  AudioPsyClipContext *s = ctx->priv;
577  AVFrame *in = NULL;
578  int ret = 0, status;
579  int64_t pts;
580 
582 
583  ret = ff_inlink_consume_samples(inlink, s->overlap, s->overlap, &in);
584  if (ret < 0)
585  return ret;
586 
587  if (ret > 0) {
588  return filter_frame(inlink, in);
589  } else if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
590  ff_outlink_set_status(outlink, status, pts);
591  return 0;
592  } else {
593  if (ff_inlink_queued_samples(inlink) >= s->overlap) {
595  } else if (ff_outlink_frame_wanted(outlink)) {
597  }
598  return 0;
599  }
600 }
601 
603 {
604  AudioPsyClipContext *s = ctx->priv;
605 
606  av_freep(&s->window);
607  av_freep(&s->inv_window);
608  av_freep(&s->spread_table);
609  av_freep(&s->spread_table_range);
610  av_freep(&s->spread_table_index);
611  av_freep(&s->margin_curve);
612 
613  av_frame_free(&s->in_buffer);
614  av_frame_free(&s->in_frame);
615  av_frame_free(&s->out_dist_frame);
616  av_frame_free(&s->windowed_frame);
617  av_frame_free(&s->clipping_delta);
618  av_frame_free(&s->spectrum_buf);
619  av_frame_free(&s->mask_curve);
620 
621  for (int ch = 0; ch < s->channels; ch++) {
622  if (s->tx_ctx)
623  av_tx_uninit(&s->tx_ctx[ch]);
624  if (s->itx_ctx)
625  av_tx_uninit(&s->itx_ctx[ch]);
626  }
627 
628  av_freep(&s->tx_ctx);
629  av_freep(&s->itx_ctx);
630 }
631 
632 static const AVFilterPad inputs[] = {
633  {
634  .name = "default",
635  .type = AVMEDIA_TYPE_AUDIO,
636  .config_props = config_input,
637  },
638 };
639 
640 static const AVFilterPad outputs[] = {
641  {
642  .name = "default",
643  .type = AVMEDIA_TYPE_AUDIO,
644  },
645 };
646 
648  .name = "apsyclip",
649  .description = NULL_IF_CONFIG_SMALL("Audio Psychoacoustic Clipper."),
650  .priv_size = sizeof(AudioPsyClipContext),
651  .priv_class = &apsyclip_class,
652  .uninit = uninit,
658  .activate = activate,
659  .process_command = ff_filter_process_command,
660 };
ff_af_apsyclip
const AVFilter ff_af_apsyclip
Definition: af_apsyclip.c:647
generate_hann_window
static void generate_hann_window(float *window, float *inv_window, int size)
Definition: af_apsyclip.c:83
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(apsyclip)
ff_get_audio_buffer
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:88
AV_SAMPLE_FMT_FLTP
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:69
status
they must not be accessed directly The fifo field contains the frames that are queued in the input for processing by the filter The status_in and status_out fields contains the queued status(EOF or error) of the link
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
set_margin_curve
static void set_margin_curve(AudioPsyClipContext *s, const int(*points)[2], int num_points, int sample_rate)
Definition: af_apsyclip.c:94
psy_channel
static int psy_channel(AVFilterContext *ctx, AVFrame *in, AVFrame *out, int ch)
Definition: af_apsyclip.c:511
out
FILE * out
Definition: movenc.c:54
limit_clip_spectrum
static void limit_clip_spectrum(AudioPsyClipContext *s, float *clip_spectrum, const float *mask_curve)
Definition: af_apsyclip.c:350
AudioPsyClipContext::protections
double * protections
Definition: af_apsyclip.c:40
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1018
AVTXContext
Definition: tx_priv.h:110
FILTER_SINGLE_SAMPLEFMT
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
Definition: internal.h:184
AudioPsyClipContext::clip_level
double clip_level
Definition: af_apsyclip.c:34
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
AudioPsyClipContext::spread_table_rows
int spread_table_rows
Definition: af_apsyclip.c:47
AudioPsyClipContext::tx_ctx
AVTXContext ** tx_ctx
Definition: af_apsyclip.c:61
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:112
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:303
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:396
AVOption
AVOption.
Definition: opt.h:247
AudioPsyClipContext::protections_str
char * protections_str
Definition: af_apsyclip.c:39
expf
#define expf(x)
Definition: libm.h:283
apsyclip_options
static const AVOption apsyclip_options[]
Definition: af_apsyclip.c:70
activate
static int activate(AVFilterContext *ctx)
Definition: af_apsyclip.c:572
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:153
FF_FILTER_FORWARD_STATUS_BACK
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition: filters.h:199
AudioPsyClipContext::window
float * window
Definition: af_apsyclip.c:50
sample_rate
sample_rate
Definition: ffmpeg_filter.c:156
av_tx_init
av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, int inv, int len, const void *scale, uint64_t flags)
Initialize a transform context with the given configuration (i)MDCTs with an odd length are currently...
Definition: tx.c:228
calculate_mask_curve
static void calculate_mask_curve(AudioPsyClipContext *s, const float *spectrum, float *mask_curve)
Definition: af_apsyclip.c:281
AudioPsyClipContext::in_frame
AVFrame * in_frame
Definition: af_apsyclip.c:54
AudioPsyClipContext
Definition: af_apsyclip.c:29
AudioPsyClipContext::itx_ctx
AVTXContext ** itx_ctx
Definition: af_apsyclip.c:63
window
static SDL_Window * window
Definition: ffplay.c:364
AudioPsyClipContext::num_psy_bins
int num_psy_bins
Definition: af_apsyclip.c:42
AudioPsyClipContext::windowed_frame
AVFrame * windowed_frame
Definition: af_apsyclip.c:56
cosf
#define cosf(x)
Definition: libm.h:78
fail
#define fail()
Definition: checkasm.h:127
apply_window
static void apply_window(AudioPsyClipContext *s, const float *in_frame, float *out_frame, const int add_to_out_frame)
Definition: af_apsyclip.c:267
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1377
pts
static int64_t pts
Definition: transcode_aac.c:653
AudioPsyClipContext::channels
int channels
Definition: af_apsyclip.c:45
FLAGS
#define FLAGS
Definition: af_apsyclip.c:68
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
av_cold
#define av_cold
Definition: attributes.h:90
AudioPsyClipContext::auto_level
int auto_level
Definition: af_apsyclip.c:36
av_tx_fn
void(* av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride)
Function pointer to a function to perform the transform.
Definition: tx.h:102
AudioPsyClipContext::inv_window
float * inv_window
Definition: af_apsyclip.c:50
ff_outlink_set_status
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition: filters.h:189
inputs
static const AVFilterPad inputs[]
Definition: af_apsyclip.c:632
AudioPsyClipContext::tx_fn
av_tx_fn tx_fn
Definition: af_apsyclip.c:62
ff_inlink_request_frame
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition: avfilter.c:1534
c2r
static void c2r(float *buffer, int size)
Definition: af_apsyclip.c:387
s
#define s(width, name)
Definition: cbs_vp9.c:257
AudioPsyClipContext::level_out
double level_out
Definition: af_apsyclip.c:33
AudioPsyClipContext::mask_curve
AVFrame * mask_curve
Definition: af_apsyclip.c:59
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:226
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
filters.h
AudioPsyClipContext::margin_curve
float * margin_curve
Definition: af_apsyclip.c:50
AV_TX_FLOAT_FFT
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type AVComplexFloat.
Definition: tx.h:45
ctx
AVFormatContext * ctx
Definition: movenc.c:48
OFFSET
#define OFFSET(x)
Definition: af_apsyclip.c:67
AudioPsyClipContext::out_dist_frame
AVFrame * out_dist_frame
Definition: af_apsyclip.c:55
f
#define f(width, name)
Definition: cbs_vp9.c:255
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:191
arg
const char * arg
Definition: jacosubdec.c:67
feed
static void feed(AVFilterContext *ctx, int ch, const float *in_samples, float *out_samples, int diff_only, float *in_frame, float *out_dist_frame, float *windowed_frame, float *clipping_delta, float *spectrum_buf, float *mask_curve)
Definition: af_apsyclip.c:396
AudioPsyClipContext::in
AVFrame * in
Definition: af_apsyclip.c:52
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:65
AudioPsyClipContext::itx_fn
av_tx_fn itx_fn
Definition: af_apsyclip.c:64
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
ff_inlink_consume_samples
int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe)
Take samples from the link's FIFO and update the link's stats.
Definition: avfilter.c:1436
NULL
#define NULL
Definition: coverity.c:32
AudioPsyClipContext::fft_size
int fft_size
Definition: af_apsyclip.c:43
AudioPsyClipContext::adaptive
double adaptive
Definition: af_apsyclip.c:35
AudioPsyClipContext::spread_table_index
int * spread_table_index
Definition: af_apsyclip.c:48
AudioPsyClipContext::level_in
double level_in
Definition: af_apsyclip.c:32
AudioPsyClipContext::spread_table_range
int(* spread_table_range)[2]
Definition: af_apsyclip.c:49
AudioPsyClipContext::clipping_delta
AVFrame * clipping_delta
Definition: af_apsyclip.c:57
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_apsyclip.c:602
r2c
static void r2c(float *buffer, int size)
Definition: af_apsyclip.c:378
src
#define src
Definition: vp8dsp.c:255
ff_inlink_acknowledge_status
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition: avfilter.c:1371
AudioPsyClipContext::in_buffer
AVFrame * in_buffer
Definition: af_apsyclip.c:53
for
for(j=16;j >0;--j)
Definition: h264pred_template.c:469
AudioPsyClipContext::iterations
int iterations
Definition: af_apsyclip.c:38
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
powf
#define powf(x, y)
Definition: libm.h:50
size
int size
Definition: twinvq_data.h:10344
clip_to_window
static void clip_to_window(AudioPsyClipContext *s, const float *windowed_frame, float *clipping_delta, float delta_boost)
Definition: af_apsyclip.c:333
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:882
outputs
static const AVFilterPad outputs[]
Definition: af_apsyclip.c:640
M_PI
#define M_PI
Definition: mathematics.h:52
av_tx_uninit
av_cold void av_tx_uninit(AVTXContext **ctx)
Frees a context and sets ctx to NULL, does nothing when ctx == NULL.
Definition: tx.c:213
internal.h
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:369
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
AVFrame::extended_data
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:350
increment
#define increment(name, min, max)
Definition: cbs_av1.c:688
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:803
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
ff_inlink_queued_samples
int ff_inlink_queued_samples(AVFilterLink *link)
Definition: avfilter.c:1396
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:271
limit
static double limit(double x)
Definition: vf_pseudocolor.c:128
AVFilter
Filter definition.
Definition: avfilter.h:149
ret
ret
Definition: filter_design.txt:187
psy_channels
static int psy_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_apsyclip.c:532
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
avfilter.h
generate_spread_table
static void generate_spread_table(AudioPsyClipContext *s)
Definition: af_apsyclip.c:120
AudioPsyClipContext::overlap
int overlap
Definition: af_apsyclip.c:44
AVFilterContext
An instance of a filter.
Definition: avfilter.h:386
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:121
audio.h
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:241
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:192
AudioPsyClipContext::spread_table
float * spread_table
Definition: af_apsyclip.c:50
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition: avfilter.h:138
AudioPsyClipContext::diff_only
int diff_only
Definition: af_apsyclip.c:37
ff_outlink_frame_wanted
the definition of that something depends on the semantic of the filter The callback must examine the status of the filter s links and proceed accordingly The status of output links is stored in the status_in and status_out fields and tested by the ff_outlink_frame_wanted() function. If this function returns true
AudioPsyClipContext::spectrum_buf
AVFrame * spectrum_buf
Definition: af_apsyclip.c:58
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:143
int
int
Definition: ffmpeg_filter.c:156
av_log2
int av_log2(unsigned v)
Definition: intmath.c:26
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_apsyclip.c:185
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: af_apsyclip.c:545
ff_filter_set_ready
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
Definition: avfilter.c:211
tx.h