History

avfilter/af_axcorrelate: add another algorithm for calculation

Rewrite EOF logic while here.

Paul B Mahol committed 3 years ago

Commit c183f841 parent f0322342 files · +114 −33Browse files

Unified · Split

2 files
  1. doc/filters.texi +2 −2
  2. libavfilter/af_axcorrelate.c +112 −31
doc/filters.texi+2−2
@@ -3762,8 +3762,8 @@ Set size of segment over which cross-correlation is calculated. · 3761 unmodified lines
37623762 Default is 256. Allowed range is from 2 to 131072.
37633763
37643764 @item algo
3765−Set algorithm for cross-correlation. Can be @code{slow} or @code{fast}.
3766−Default is @code{slow}. Fast algorithm assumes mean values over any given segment
3765+Set algorithm for cross-correlation. Can be @code{slow} or @code{fast} or @code{best}.
3766+Default is @code{best}. Fast algorithm assumes mean values over any given segment
37673767 are always zero and thus need much less calculations to make.
37683768 This is generally not true, but is valid for typical audio streams.
37693769 @end table
libavfilter/af_axcorrelate.c+112−31
@@ -110,7 +110,7 @@ static int xcorrelate_slow_##suffix(AVFilterContext *ctx, \ · 109 unmodified lines
110110 AVFrame *out, int available) \
111111 { \
112112 AudioXCorrelateContext *s = ctx->priv; \
113− const int size = FFMIN(available, s->size); \
113+ const int size = s->size; \
114114 int used; \
115115 \
116116 for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) { \
@@ -127,13 +127,13 @@ static int xcorrelate_slow_##suffix(AVFilterContext *ctx, \ · 10 unmodified lines
127127 used = 1; \
128128 } \
129129 \
130− for (int n = 0; n < out->nb_samples; n++) { \
131− const int idx = available <= s->size ? out->nb_samples - n - 1 : n + size; \
132− \
133− dst[n] = xcorrelate_##suffix(x + n, y + n, \
134− sumx[0], sumy[0], \
135− size); \
136− \
130+ for (int n = 0; n < out->nb_samples; n++) { \
131+ const int idx = n + size; \
132+ \
133+ dst[n] = xcorrelate_##suffix(x + n, y + n, \
134+ sumx[0], sumy[0],\
135+ size); \
136+ \
137137 sumx[0] -= x[n]; \
138138 sumx[0] += x[idx]; \
139139 sumy[0] -= y[n]; \
@@ -147,12 +147,15 @@ static int xcorrelate_slow_##suffix(AVFilterContext *ctx, \ · 7 unmodified lines
147147 XCORRELATE_SLOW(f, float)
148148 XCORRELATE_SLOW(d, double)
149149
150−#define XCORRELATE_FAST(suffix, type, zero, small, sqrtfun) \
150+#define clipf(x) (av_clipf(x, -1.f, 1.f))
151+#define clipd(x) (av_clipd(x, -1.0, 1.0))
152+
153+#define XCORRELATE_FAST(suffix, type, zero, small, sqrtfun, CLIP) \
151154 static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out, \
152155 int available) \
153156 { \
154157 AudioXCorrelateContext *s = ctx->priv; \
155− const int size = FFMIN(available, s->size); \
158+ const int size = s->size; \
156159 int used; \
157160 \
158161 for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) { \
@@ -171,14 +174,14 @@ static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out, \ · 12 unmodified lines
171174 used = 1; \
172175 } \
173176 \
174− for (int n = 0; n < out->nb_samples; n++) { \
175− const int idx = available <= s->size ? out->nb_samples - n - 1 : n + size; \
176− type num, den; \
177+ for (int n = 0; n < out->nb_samples; n++) { \
178+ const int idx = n + size; \
179+ type num, den; \
177180 \
178181 num = num_sum[0] / size; \
179182 den = sqrtfun((den_sumx[0] * den_sumy[0]) / size / size); \
180183 \
181− dst[n] = den <= small ? zero : num / den; \
184+ dst[n] = den <= small ? zero : CLIP(num / den); \
182185 \
183186 num_sum[0] -= x[n] * y[n]; \
184187 num_sum[0] += x[idx] * y[idx]; \
@@ -194,20 +197,82 @@ static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out, \ · 9 unmodified lines
194197 return used; \
195198 }
196199
197−XCORRELATE_FAST(f, float, 0.f, 1e-6f, sqrtf)
198−XCORRELATE_FAST(d, double, 0.0, 1e-9, sqrt)
200+XCORRELATE_FAST(f, float, 0.f, 1e-6f, sqrtf, clipf)
201+XCORRELATE_FAST(d, double, 0.0, 1e-9, sqrt, clipd)
202+
203+#define XCORRELATE_BEST(suffix, type, zero, small, sqrtfun, FMAX, CLIP) \
204+static int xcorrelate_best_##suffix(AVFilterContext *ctx, AVFrame *out, \
205+ int available) \
206+{ \
207+ AudioXCorrelateContext *s = ctx->priv; \
208+ const int size = s->size; \
209+ int used; \
210+ \
211+ for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) { \
212+ const type *x = (const type *)s->cache[0]->extended_data[ch]; \
213+ const type *y = (const type *)s->cache[1]->extended_data[ch]; \
214+ type *mean_sumx = (type *)s->mean_sum[0]->extended_data[ch]; \
215+ type *mean_sumy = (type *)s->mean_sum[1]->extended_data[ch]; \
216+ type *num_sum = (type *)s->num_sum->extended_data[ch]; \
217+ type *den_sumx = (type *)s->den_sum[0]->extended_data[ch]; \
218+ type *den_sumy = (type *)s->den_sum[1]->extended_data[ch]; \
219+ type *dst = (type *)out->extended_data[ch]; \
220+ \
221+ used = s->used; \
222+ if (!used) { \
223+ num_sum[0] = square_sum_##suffix(x, y, size); \
224+ den_sumx[0] = square_sum_##suffix(x, x, size); \
225+ den_sumy[0] = square_sum_##suffix(y, y, size); \
226+ mean_sumx[0] = mean_sum_##suffix(x, size); \
227+ mean_sumy[0] = mean_sum_##suffix(y, size); \
228+ used = 1; \
229+ } \
230+ \
231+ for (int n = 0; n < out->nb_samples; n++) { \
232+ const int idx = n + size; \
233+ type num, den, xm, ym; \
234+ \
235+ xm = mean_sumx[0] / size; \
236+ ym = mean_sumy[0] / size; \
237+ num = num_sum[0] - size * xm * ym; \
238+ den = sqrtfun(FMAX(den_sumx[0] - size * xm * xm, zero)) * \
239+ sqrtfun(FMAX(den_sumy[0] - size * ym * ym, zero)); \
240+ \
241+ dst[n] = den <= small ? zero : CLIP(num / den); \
242+ \
243+ mean_sumx[0]-= x[n]; \
244+ mean_sumx[0]+= x[idx]; \
245+ mean_sumy[0]-= y[n]; \
246+ mean_sumy[0]+= y[idx]; \
247+ num_sum[0] -= x[n] * y[n]; \
248+ num_sum[0] += x[idx] * y[idx]; \
249+ den_sumx[0] -= x[n] * x[n]; \
250+ den_sumx[0] += x[idx] * x[idx]; \
251+ den_sumx[0] = FMAX(den_sumx[0], zero); \
252+ den_sumy[0] -= y[n] * y[n]; \
253+ den_sumy[0] += y[idx] * y[idx]; \
254+ den_sumy[0] = FMAX(den_sumy[0], zero); \
255+ } \
256+ } \
257+ \
258+ return used; \
259+}
260+
261+XCORRELATE_BEST(f, float, 0.f, 1e-6f, sqrtf, fmaxf, clipf)
262+XCORRELATE_BEST(d, double, 0.0, 1e-9, sqrt, fmax, clipd)
199263
200264 static int activate(AVFilterContext *ctx)
201265 {
202266 AudioXCorrelateContext *s = ctx->priv;
267+ AVFilterLink *outlink = ctx->outputs[0];
203268 AVFrame *frame = NULL;
204269 int ret, status;
205270 int available;
206271 int64_t pts;
207272
208− FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
273+ FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
209274
210− for (int i = 0; i < 2; i++) {
275+ for (int i = 0; i < 2 && !s->eof; i++) {
211276 ret = ff_inlink_consume_frame(ctx->inputs[i], &frame);
212277 if (ret > 0) {
213278 if (s->pts == AV_NOPTS_VALUE)
@@ -221,20 +286,20 @@ static int activate(AVFilterContext *ctx) · 7 unmodified lines
221286 }
222287
223288 available = FFMIN(av_audio_fifo_size(s->fifo[0]), av_audio_fifo_size(s->fifo[1]));
224− if (available > s->size || (s->eof && available > 0)) {
225− const int out_samples = s->eof ? available : available - s->size;
289+ if (available > s->size) {
290+ const int out_samples = available - s->size;
226291 AVFrame *out;
227292
228293 if (!s->cache[0] || s->cache[0]->nb_samples < available) {
229294 av_frame_free(&s->cache[0]);
230− s->cache[0] = ff_get_audio_buffer(ctx->outputs[0], available);
295+ s->cache[0] = ff_get_audio_buffer(outlink, available);
231296 if (!s->cache[0])
232297 return AVERROR(ENOMEM);
233298 }
234299
235300 if (!s->cache[1] || s->cache[1]->nb_samples < available) {
236301 av_frame_free(&s->cache[1]);
237− s->cache[1] = ff_get_audio_buffer(ctx->outputs[0], available);
302+ s->cache[1] = ff_get_audio_buffer(outlink, available);
238303 if (!s->cache[1])
239304 return AVERROR(ENOMEM);
240305 }
@@ -247,7 +312,7 @@ static int activate(AVFilterContext *ctx) · 6 unmodified lines
247312 if (ret < 0)
248313 return ret;
249314
250− out = ff_get_audio_buffer(ctx->outputs[0], out_samples);
315+ out = ff_get_audio_buffer(outlink, out_samples);
251316 if (!out)
252317 return AVERROR(ENOMEM);
253318
@@ -259,18 +324,31 @@ static int activate(AVFilterContext *ctx) · 5 unmodified lines
259324 av_audio_fifo_drain(s->fifo[0], out_samples);
260325 av_audio_fifo_drain(s->fifo[1], out_samples);
261326
262− return ff_filter_frame(ctx->outputs[0], out);
327+ return ff_filter_frame(outlink, out);
263328 }
264329
265330 for (int i = 0; i < 2 && !s->eof; i++) {
266− if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts))
331+ if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
332+ AVFrame *silence = ff_get_audio_buffer(outlink, s->size);
333+
267334 s->eof = 1;
335+ if (!silence)
336+ return AVERROR(ENOMEM);
337+
338+ av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data,
339+ silence->nb_samples);
340+
341+ av_audio_fifo_write(s->fifo[1], (void **)silence->extended_data,
342+ silence->nb_samples);
343+
344+ av_frame_free(&silence);
345+ }
268346 }
269347
270348 if (s->eof &&
271− (av_audio_fifo_size(s->fifo[0]) <= 0 ||
272− av_audio_fifo_size(s->fifo[1]) <= 0)) {
273− ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, s->pts);
349+ (av_audio_fifo_size(s->fifo[0]) <= s->size ||
350+ av_audio_fifo_size(s->fifo[1]) <= s->size)) {
351+ ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
274352 return 0;
275353 }
276354
@@ -280,7 +358,7 @@ static int activate(AVFilterContext *ctx) · 3 unmodified lines
280358 return 0;
281359 }
282360
283− if (ff_outlink_frame_wanted(ctx->outputs[0]) && !s->eof) {
361+ if (ff_outlink_frame_wanted(outlink) && !s->eof) {
284362 for (int i = 0; i < 2; i++) {
285363 if (av_audio_fifo_size(s->fifo[i]) > s->size)
286364 continue;
@@ -316,12 +394,14 @@ static int config_output(AVFilterLink *outlink) · 29 unmodified lines
316394 switch (s->algo) {
317395 case 0: s->xcorrelate = xcorrelate_slow_f; break;
318396 case 1: s->xcorrelate = xcorrelate_fast_f; break;
397+ case 2: s->xcorrelate = xcorrelate_best_f; break;
319398 }
320399
321400 if (outlink->format == AV_SAMPLE_FMT_DBLP) {
322401 switch (s->algo) {
323402 case 0: s->xcorrelate = xcorrelate_slow_d; break;
324403 case 1: s->xcorrelate = xcorrelate_fast_d; break;
404+ case 2: s->xcorrelate = xcorrelate_best_d; break;
325405 }
326406 }
327407
@@ -366,10 +446,11 @@ static const AVFilterPad outputs[] = { · 38 unmodified lines
366446 #define OFFSET(x) offsetof(AudioXCorrelateContext, x)
367447
368448 static const AVOption axcorrelate_options[] = {
369− { "size", "set segment size", OFFSET(size), AV_OPT_TYPE_INT, {.i64=256}, 2, 131072, AF },
370− { "algo", "set algorithm", OFFSET(algo), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AF, "algo" },
449+ { "size", "set the segment size", OFFSET(size), AV_OPT_TYPE_INT, {.i64=256}, 2, 131072, AF },
450+ { "algo", "set the algorithm", OFFSET(algo), AV_OPT_TYPE_INT, {.i64=2}, 0, 2, AF, "algo" },
371451 { "slow", "slow algorithm", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "algo" },
372452 { "fast", "fast algorithm", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "algo" },
453+ { "best", "best algorithm", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "algo" },
373454 { NULL }
374455 };
375456

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