History

avfilter/af_atempo: switch to rdft from lavu/tx

Paul B Mahol committed 4 years ago

Commit 800dfd21 parent e8f43962 files · +64 −65Browse files

Unified · Split

2 files
  1. configure +0 −3
  2. libavfilter/af_atempo.c +64 −62
configure+0−3
@@ -3610,8 +3610,6 @@ amovie_filter_deps="avcodec avformat" · 3609 unmodified lines
3610aresample_filter_deps="swresample"3610aresample_filter_deps="swresample"
3611asr_filter_deps="pocketsphinx"3611asr_filter_deps="pocketsphinx"
3612ass_filter_deps="libass"3612ass_filter_deps="libass"
3613atempo_filter_deps="avcodec"
3614atempo_filter_select="rdft"
3615avgblur_opencl_filter_deps="opencl"3613avgblur_opencl_filter_deps="opencl"
3616avgblur_vulkan_filter_deps="vulkan spirv_compiler"3614avgblur_vulkan_filter_deps="vulkan spirv_compiler"
3617azmq_filter_deps="libzmq"3615azmq_filter_deps="libzmq"
@@ -7386,7 +7384,6 @@ enabled zlib && add_cppflags -DZLIB_CONST · 3768 unmodified lines
7386# conditional library dependencies, in any order7384# conditional library dependencies, in any order
7387enabled amovie_filter && prepend avfilter_deps "avformat avcodec"7385enabled amovie_filter && prepend avfilter_deps "avformat avcodec"
7388enabled aresample_filter && prepend avfilter_deps "swresample"7386enabled aresample_filter && prepend avfilter_deps "swresample"
7389enabled atempo_filter && prepend avfilter_deps "avcodec"
7390enabled bm3d_filter && prepend avfilter_deps "avcodec"7387enabled bm3d_filter && prepend avfilter_deps "avcodec"
7391enabled cover_rect_filter && prepend avfilter_deps "avformat avcodec"7388enabled cover_rect_filter && prepend avfilter_deps "avformat avcodec"
7392enabled ebur128_filter && enabled swresample && prepend avfilter_deps "swresample"7389enabled ebur128_filter && enabled swresample && prepend avfilter_deps "swresample"
libavfilter/af_atempo.c+64−62
@@ -39,13 +39,13 @@ · 38 unmodified lines
39 */39 */
40 40
41#include <float.h>41#include <float.h>
42#include "libavcodec/avfft.h"
43#include "libavutil/avassert.h"42#include "libavutil/avassert.h"
44#include "libavutil/avstring.h"43#include "libavutil/avstring.h"
45#include "libavutil/channel_layout.h"44#include "libavutil/channel_layout.h"
46#include "libavutil/eval.h"45#include "libavutil/eval.h"
47#include "libavutil/opt.h"46#include "libavutil/opt.h"
48#include "libavutil/samplefmt.h"47#include "libavutil/samplefmt.h"
48#include "libavutil/tx.h"
49#include "avfilter.h"49#include "avfilter.h"
50#include "audio.h"50#include "audio.h"
51#include "internal.h"51#include "internal.h"
@@ -67,7 +67,8 @@ typedef struct AudioFragment { · 15 unmodified lines
67 67
68 // rDFT transform of the down-mixed mono fragment, used for68 // rDFT transform of the down-mixed mono fragment, used for
69 // fast waveform alignment via correlation in frequency domain:69 // fast waveform alignment via correlation in frequency domain:
70 FFTSample *xdat;70 float *xdat_in;
71 float *xdat;
71} AudioFragment;72} AudioFragment;
72 73
73/**74/**
@@ -140,9 +141,11 @@ typedef struct ATempoContext { · 66 unmodified lines
140 FilterState state;141 FilterState state;
141 142
142 // for fast correlation calculation in frequency domain:143 // for fast correlation calculation in frequency domain:
143 RDFTContext *real_to_complex;144 AVTXContext *real_to_complex;
144 RDFTContext *complex_to_real;145 AVTXContext *complex_to_real;
145 FFTSample *correlation;146 av_tx_fn r2c_fn, c2r_fn;
147 float *correlation_in;
148 float *correlation;
146 149
147 // for managing AVFilterPad.request_frame and AVFilterPad.filter_frame150 // for managing AVFilterPad.request_frame and AVFilterPad.filter_frame
148 AVFrame *dst_buffer;151 AVFrame *dst_buffer;
@@ -228,18 +231,18 @@ static void yae_release_buffers(ATempoContext *atempo) · 79 unmodified lines
228 231
229 av_freep(&atempo->frag[0].data);232 av_freep(&atempo->frag[0].data);
230 av_freep(&atempo->frag[1].data);233 av_freep(&atempo->frag[1].data);
234 av_freep(&atempo->frag[0].xdat_in);
235 av_freep(&atempo->frag[1].xdat_in);
231 av_freep(&atempo->frag[0].xdat);236 av_freep(&atempo->frag[0].xdat);
232 av_freep(&atempo->frag[1].xdat);237 av_freep(&atempo->frag[1].xdat);
233 238
234 av_freep(&atempo->buffer);239 av_freep(&atempo->buffer);
235 av_freep(&atempo->hann);240 av_freep(&atempo->hann);
241 av_freep(&atempo->correlation_in);
236 av_freep(&atempo->correlation);242 av_freep(&atempo->correlation);
237 243
238 av_rdft_end(atempo->real_to_complex);244 av_tx_uninit(&atempo->real_to_complex);
239 atempo->real_to_complex = NULL;245 av_tx_uninit(&atempo->complex_to_real);
240
241 av_rdft_end(atempo->complex_to_real);
242 atempo->complex_to_real = NULL;
243}246}
244 247
245/* av_realloc is not aligned enough; fortunately, the data does not need to248/* av_realloc is not aligned enough; fortunately, the data does not need to
@@ -247,7 +250,7 @@ static void yae_release_buffers(ATempoContext *atempo) · 1 unmodified line
247#define RE_MALLOC_OR_FAIL(field, field_size) \250#define RE_MALLOC_OR_FAIL(field, field_size) \
248 do { \251 do { \
249 av_freep(&field); \252 av_freep(&field); \
250 field = av_malloc(field_size); \253 field = av_calloc(field_size, 1); \
251 if (!field) { \254 if (!field) { \
252 yae_release_buffers(atempo); \255 yae_release_buffers(atempo); \
253 return AVERROR(ENOMEM); \256 return AVERROR(ENOMEM); \
@@ -265,6 +268,7 @@ static int yae_reset(ATempoContext *atempo, · 11 unmodified lines
265{268{
266 const int sample_size = av_get_bytes_per_sample(format);269 const int sample_size = av_get_bytes_per_sample(format);
267 uint32_t nlevels = 0;270 uint32_t nlevels = 0;
271 float scale = 1.f, iscale = 1.f;
268 uint32_t pot;272 uint32_t pot;
269 int i;273 int i;
270 274
@@ -288,29 +292,29 @@ static int yae_reset(ATempoContext *atempo, · 17 unmodified lines
288 // initialize audio fragment buffers:292 // initialize audio fragment buffers:
289 RE_MALLOC_OR_FAIL(atempo->frag[0].data, atempo->window * atempo->stride);293 RE_MALLOC_OR_FAIL(atempo->frag[0].data, atempo->window * atempo->stride);
290 RE_MALLOC_OR_FAIL(atempo->frag[1].data, atempo->window * atempo->stride);294 RE_MALLOC_OR_FAIL(atempo->frag[1].data, atempo->window * atempo->stride);
291 RE_MALLOC_OR_FAIL(atempo->frag[0].xdat, atempo->window * sizeof(FFTComplex));295 RE_MALLOC_OR_FAIL(atempo->frag[0].xdat_in, (atempo->window + 1) * sizeof(AVComplexFloat));
292 RE_MALLOC_OR_FAIL(atempo->frag[1].xdat, atempo->window * sizeof(FFTComplex));296 RE_MALLOC_OR_FAIL(atempo->frag[1].xdat_in, (atempo->window + 1) * sizeof(AVComplexFloat));
297 RE_MALLOC_OR_FAIL(atempo->frag[0].xdat, (atempo->window + 1) * sizeof(AVComplexFloat));
298 RE_MALLOC_OR_FAIL(atempo->frag[1].xdat, (atempo->window + 1) * sizeof(AVComplexFloat));
293 299
294 // initialize rDFT contexts:300 // initialize rDFT contexts:
295 av_rdft_end(atempo->real_to_complex);301 av_tx_uninit(&atempo->real_to_complex);
296 atempo->real_to_complex = NULL;302 av_tx_uninit(&atempo->complex_to_real);
297
298 av_rdft_end(atempo->complex_to_real);
299 atempo->complex_to_real = NULL;
300 303
301 atempo->real_to_complex = av_rdft_init(nlevels + 1, DFT_R2C);304 av_tx_init(&atempo->real_to_complex, &atempo->r2c_fn, AV_TX_FLOAT_RDFT, 0, 1 << (nlevels + 1), &scale, 0);
302 if (!atempo->real_to_complex) {305 if (!atempo->real_to_complex) {
303 yae_release_buffers(atempo);306 yae_release_buffers(atempo);
304 return AVERROR(ENOMEM);307 return AVERROR(ENOMEM);
305 }308 }
306 309
307 atempo->complex_to_real = av_rdft_init(nlevels + 1, IDFT_C2R);310 av_tx_init(&atempo->complex_to_real, &atempo->c2r_fn, AV_TX_FLOAT_RDFT, 1, 1 << (nlevels + 1), &iscale, 0);
308 if (!atempo->complex_to_real) {311 if (!atempo->complex_to_real) {
309 yae_release_buffers(atempo);312 yae_release_buffers(atempo);
310 return AVERROR(ENOMEM);313 return AVERROR(ENOMEM);
311 }314 }
312 315
313 RE_MALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(FFTComplex));316 RE_MALLOC_OR_FAIL(atempo->correlation_in, (atempo->window + 1) * sizeof(AVComplexFloat));
317 RE_MALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(AVComplexFloat));
314 318
315 atempo->ring = atempo->window * 3;319 atempo->ring = atempo->window * 3;
316 RE_MALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride);320 RE_MALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride);
@@ -348,7 +352,7 @@ static int yae_update(AVFilterContext *ctx) · 31 unmodified lines
348 const uint8_t *src_end = src + \352 const uint8_t *src_end = src + \
349 frag->nsamples * atempo->channels * sizeof(scalar_type); \353 frag->nsamples * atempo->channels * sizeof(scalar_type); \
350 \354 \
351 FFTSample *xdat = frag->xdat; \355 float *xdat = frag->xdat_in; \
352 scalar_type tmp; \356 scalar_type tmp; \
353 \357 \
354 if (atempo->channels == 1) { \358 if (atempo->channels == 1) { \
@@ -356,27 +360,27 @@ static int yae_update(AVFilterContext *ctx) · 1 unmodified line
356 tmp = *(const scalar_type *)src; \360 tmp = *(const scalar_type *)src; \
357 src += sizeof(scalar_type); \361 src += sizeof(scalar_type); \
358 \362 \
359 *xdat = (FFTSample)tmp; \363 *xdat = (float)tmp; \
360 } \364 } \
361 } else { \365 } else { \
362 FFTSample s, max, ti, si; \366 float s, max, ti, si; \
363 int i; \367 int i; \
364 \368 \
365 for (; src < src_end; xdat++) { \369 for (; src < src_end; xdat++) { \
366 tmp = *(const scalar_type *)src; \370 tmp = *(const scalar_type *)src; \
367 src += sizeof(scalar_type); \371 src += sizeof(scalar_type); \
368 \372 \
369 max = (FFTSample)tmp; \373 max = (float)tmp; \
370 s = FFMIN((FFTSample)scalar_max, \374 s = FFMIN((float)scalar_max, \
371 (FFTSample)fabsf(max)); \375 (float)fabsf(max)); \
372 \376 \
373 for (i = 1; i < atempo->channels; i++) { \377 for (i = 1; i < atempo->channels; i++) { \
374 tmp = *(const scalar_type *)src; \378 tmp = *(const scalar_type *)src; \
375 src += sizeof(scalar_type); \379 src += sizeof(scalar_type); \
376 \380 \
377 ti = (FFTSample)tmp; \381 ti = (float)tmp; \
378 si = FFMIN((FFTSample)scalar_max, \382 si = FFMIN((float)scalar_max, \
379 (FFTSample)fabsf(ti)); \383 (float)fabsf(ti)); \
380 \384 \
381 if (s < si) { \385 if (s < si) { \
382 s = si; \386 s = si; \
@@ -399,7 +403,7 @@ static void yae_downmix(ATempoContext *atempo, AudioFragment *frag) · 16 unmodified lines
399 const uint8_t *src = frag->data;403 const uint8_t *src = frag->data;
400 404
401 // init complex data buffer used for FFT and Correlation:405 // init complex data buffer used for FFT and Correlation:
402 memset(frag->xdat, 0, sizeof(FFTComplex) * atempo->window);406 memset(frag->xdat_in, 0, sizeof(AVComplexFloat) * (atempo->window + 1));
403 407
404 if (atempo->format == AV_SAMPLE_FMT_U8) {408 if (atempo->format == AV_SAMPLE_FMT_U8) {
405 yae_init_xdat(uint8_t, 127);409 yae_init_xdat(uint8_t, 127);
@@ -598,32 +602,24 @@ static void yae_advance_to_next_frag(ATempoContext *atempo) · 192 unmodified lines
598 * Multiply two vectors of complex numbers (result of real_to_complex rDFT)602 * Multiply two vectors of complex numbers (result of real_to_complex rDFT)
599 * and transform back via complex_to_real rDFT.603 * and transform back via complex_to_real rDFT.
600 */604 */
601static void yae_xcorr_via_rdft(FFTSample *xcorr,605static void yae_xcorr_via_rdft(float *xcorr_in,
602 RDFTContext *complex_to_real,606 float *xcorr,
603 const FFTComplex *xa,607 AVTXContext *complex_to_real,
604 const FFTComplex *xb,608 av_tx_fn c2r_fn,
609 const AVComplexFloat *xa,
610 const AVComplexFloat *xb,
605 const int window)611 const int window)
606{612{
607 FFTComplex *xc = (FFTComplex *)xcorr;613 AVComplexFloat *xc = (AVComplexFloat *)xcorr_in;
608 int i;614 int i;
609 615
610 // NOTE: first element requires special care -- Given Y = rDFT(X),616 for (i = 0; i <= window; i++, xa++, xb++, xc++) {
611 // Im(Y[0]) and Im(Y[N/2]) are always zero, therefore av_rdft_calc
612 // stores Re(Y[N/2]) in place of Im(Y[0]).
613
614 xc->re = xa->re * xb->re;
615 xc->im = xa->im * xb->im;
616 xa++;
617 xb++;
618 xc++;
619
620 for (i = 1; i < window; i++, xa++, xb++, xc++) {
621 xc->re = (xa->re * xb->re + xa->im * xb->im);617 xc->re = (xa->re * xb->re + xa->im * xb->im);
622 xc->im = (xa->im * xb->re - xa->re * xb->im);618 xc->im = (xa->im * xb->re - xa->re * xb->im);
623 }619 }
624 620
625 // apply inverse rDFT:621 // apply inverse rDFT:
626 av_rdft_calc(complex_to_real, xcorr);622 c2r_fn(complex_to_real, xcorr, xcorr_in, sizeof(float));
627}623}
628 624
629/**625/**
@@ -637,21 +633,25 @@ static int yae_align(AudioFragment *frag, · 7 unmodified lines
637 const int window,633 const int window,
638 const int delta_max,634 const int delta_max,
639 const int drift,635 const int drift,
640 FFTSample *correlation,636 float *correlation_in,
641 RDFTContext *complex_to_real)637 float *correlation,
638 AVTXContext *complex_to_real,
639 av_tx_fn c2r_fn)
642{640{
643 int best_offset = -drift;641 int best_offset = -drift;
644 FFTSample best_metric = -FLT_MAX;642 float best_metric = -FLT_MAX;
645 FFTSample *xcorr;643 float *xcorr;
646 644
647 int i0;645 int i0;
648 int i1;646 int i1;
649 int i;647 int i;
650 648
651 yae_xcorr_via_rdft(correlation,649 yae_xcorr_via_rdft(correlation_in,
650 correlation,
652 complex_to_real,651 complex_to_real,
653 (const FFTComplex *)prev->xdat,652 c2r_fn,
654 (const FFTComplex *)frag->xdat,653 (const AVComplexFloat *)prev->xdat,
654 (const AVComplexFloat *)frag->xdat,
655 window);655 window);
656 656
657 // identify search window boundaries:657 // identify search window boundaries:
@@ -665,11 +665,11 @@ static int yae_align(AudioFragment *frag, · 7 unmodified lines
665 xcorr = correlation + i0;665 xcorr = correlation + i0;
666 666
667 for (i = i0; i < i1; i++, xcorr++) {667 for (i = i0; i < i1; i++, xcorr++) {
668 FFTSample metric = *xcorr;668 float metric = *xcorr;
669 669
670 // normalize:670 // normalize:
671 FFTSample drifti = (FFTSample)(drift + i);671 float drifti = (float)(drift + i);
672 metric *= drifti * (FFTSample)(i - i0) * (FFTSample)(i1 - i);672 metric *= drifti * (float)(i - i0) * (float)(i1 - i);
673 673
674 if (metric > best_metric) {674 if (metric > best_metric) {
675 best_metric = metric;675 best_metric = metric;
@@ -706,8 +706,10 @@ static int yae_adjust_position(ATempoContext *atempo) · 30 unmodified lines
706 atempo->window,706 atempo->window,
707 delta_max,707 delta_max,
708 drift,708 drift,
709 atempo->correlation_in,
709 atempo->correlation,710 atempo->correlation,
710 atempo->complex_to_real);711 atempo->complex_to_real,
712 atempo->c2r_fn);
711 713
712 if (correction) {714 if (correction) {
713 // adjust fragment position:715 // adjust fragment position:
@@ -833,7 +835,7 @@ yae_apply(ATempoContext *atempo, · 119 unmodified lines
833 yae_downmix(atempo, yae_curr_frag(atempo));835 yae_downmix(atempo, yae_curr_frag(atempo));
834 836
835 // apply rDFT:837 // apply rDFT:
836 av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat);838 atempo->r2c_fn(atempo->real_to_complex, yae_curr_frag(atempo)->xdat, yae_curr_frag(atempo)->xdat_in, sizeof(float));
837 839
838 // must load the second fragment before alignment can start:840 // must load the second fragment before alignment can start:
839 if (!atempo->nfrag) {841 if (!atempo->nfrag) {
@@ -865,7 +867,7 @@ yae_apply(ATempoContext *atempo, · 25 unmodified lines
865 yae_downmix(atempo, yae_curr_frag(atempo));867 yae_downmix(atempo, yae_curr_frag(atempo));
866 868
867 // apply rDFT:869 // apply rDFT:
868 av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat);870 atempo->r2c_fn(atempo->real_to_complex, yae_curr_frag(atempo)->xdat, yae_curr_frag(atempo)->xdat_in, sizeof(float));
869 871
870 atempo->state = YAE_OUTPUT_OVERLAP_ADD;872 atempo->state = YAE_OUTPUT_OVERLAP_ADD;
871 }873 }
@@ -929,7 +931,7 @@ static int yae_flush(ATempoContext *atempo, · 57 unmodified lines
929 yae_downmix(atempo, frag);931 yae_downmix(atempo, frag);
930 932
931 // apply rDFT:933 // apply rDFT:
932 av_rdft_calc(atempo->real_to_complex, frag->xdat);934 atempo->r2c_fn(atempo->real_to_complex, frag->xdat, frag->xdat_in, sizeof(float));
933 935
934 // align current fragment to previous fragment:936 // align current fragment to previous fragment:
935 if (yae_adjust_position(atempo)) {937 if (yae_adjust_position(atempo)) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t