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
3762Default is 256. Allowed range is from 2 to 131072.3762Default is 256. Allowed range is from 2 to 131072.
3763 3763
3764@item algo3764@item algo
3765Set algorithm for cross-correlation. Can be @code{slow} or @code{fast}.3765Set algorithm for cross-correlation. Can be @code{slow} or @code{fast} or @code{best}.
3766Default is @code{slow}. Fast algorithm assumes mean values over any given segment3766Default is @code{best}. Fast algorithm assumes mean values over any given segment
3767are always zero and thus need much less calculations to make.3767are always zero and thus need much less calculations to make.
3768This is generally not true, but is valid for typical audio streams.3768This is generally not true, but is valid for typical audio streams.
3769@end table3769@end table
libavfilter/af_axcorrelate.c+112−31
@@ -110,7 +110,7 @@ static int xcorrelate_slow_##suffix(AVFilterContext *ctx, \ · 109 unmodified lines
110 AVFrame *out, int available) \110 AVFrame *out, int available) \
111{ \111{ \
112 AudioXCorrelateContext *s = ctx->priv; \112 AudioXCorrelateContext *s = ctx->priv; \
113 const int size = FFMIN(available, s->size); \113 const int size = s->size; \
114 int used; \114 int used; \
115 \115 \
116 for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) { \116 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
127 used = 1; \127 used = 1; \
128 } \128 } \
129 \129 \
130 for (int n = 0; n < out->nb_samples; n++) { \130 for (int n = 0; n < out->nb_samples; n++) { \
131 const int idx = available <= s->size ? out->nb_samples - n - 1 : n + size; \131 const int idx = n + size; \
132 \132 \
133 dst[n] = xcorrelate_##suffix(x + n, y + n, \133 dst[n] = xcorrelate_##suffix(x + n, y + n, \
134 sumx[0], sumy[0], \134 sumx[0], sumy[0],\
135 size); \135 size); \
136 \136 \
137 sumx[0] -= x[n]; \137 sumx[0] -= x[n]; \
138 sumx[0] += x[idx]; \138 sumx[0] += x[idx]; \
139 sumy[0] -= y[n]; \139 sumy[0] -= y[n]; \
@@ -147,12 +147,15 @@ static int xcorrelate_slow_##suffix(AVFilterContext *ctx, \ · 7 unmodified lines
147XCORRELATE_SLOW(f, float)147XCORRELATE_SLOW(f, float)
148XCORRELATE_SLOW(d, double)148XCORRELATE_SLOW(d, double)
149 149
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) \
151static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out, \154static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out, \
152 int available) \155 int available) \
153{ \156{ \
154 AudioXCorrelateContext *s = ctx->priv; \157 AudioXCorrelateContext *s = ctx->priv; \
155 const int size = FFMIN(available, s->size); \158 const int size = s->size; \
156 int used; \159 int used; \
157 \160 \
158 for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) { \161 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
171 used = 1; \174 used = 1; \
172 } \175 } \
173 \176 \
174 for (int n = 0; n < out->nb_samples; n++) { \177 for (int n = 0; n < out->nb_samples; n++) { \
175 const int idx = available <= s->size ? out->nb_samples - n - 1 : n + size; \178 const int idx = n + size; \
176 type num, den; \179 type num, den; \
177 \180 \
178 num = num_sum[0] / size; \181 num = num_sum[0] / size; \
179 den = sqrtfun((den_sumx[0] * den_sumy[0]) / size / size); \182 den = sqrtfun((den_sumx[0] * den_sumy[0]) / size / size); \
180 \183 \
181 dst[n] = den <= small ? zero : num / den; \184 dst[n] = den <= small ? zero : CLIP(num / den); \
182 \185 \
183 num_sum[0] -= x[n] * y[n]; \186 num_sum[0] -= x[n] * y[n]; \
184 num_sum[0] += x[idx] * y[idx]; \187 num_sum[0] += x[idx] * y[idx]; \
@@ -194,20 +197,82 @@ static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out, \ · 9 unmodified lines
194 return used; \197 return used; \
195}198}
196 199
197XCORRELATE_FAST(f, float, 0.f, 1e-6f, sqrtf)200XCORRELATE_FAST(f, float, 0.f, 1e-6f, sqrtf, clipf)
198XCORRELATE_FAST(d, double, 0.0, 1e-9, sqrt)201XCORRELATE_FAST(d, double, 0.0, 1e-9, sqrt, clipd)
202
203#define XCORRELATE_BEST(suffix, type, zero, small, sqrtfun, FMAX, CLIP) \
204static 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
261XCORRELATE_BEST(f, float, 0.f, 1e-6f, sqrtf, fmaxf, clipf)
262XCORRELATE_BEST(d, double, 0.0, 1e-9, sqrt, fmax, clipd)
199 263
200static int activate(AVFilterContext *ctx)264static int activate(AVFilterContext *ctx)
201{265{
202 AudioXCorrelateContext *s = ctx->priv;266 AudioXCorrelateContext *s = ctx->priv;
267 AVFilterLink *outlink = ctx->outputs[0];
203 AVFrame *frame = NULL;268 AVFrame *frame = NULL;
204 int ret, status;269 int ret, status;
205 int available;270 int available;
206 int64_t pts;271 int64_t pts;
207 272
208 FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);273 FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
209 274
210 for (int i = 0; i < 2; i++) {275 for (int i = 0; i < 2 && !s->eof; i++) {
211 ret = ff_inlink_consume_frame(ctx->inputs[i], &frame);276 ret = ff_inlink_consume_frame(ctx->inputs[i], &frame);
212 if (ret > 0) {277 if (ret > 0) {
213 if (s->pts == AV_NOPTS_VALUE)278 if (s->pts == AV_NOPTS_VALUE)
@@ -221,20 +286,20 @@ static int activate(AVFilterContext *ctx) · 7 unmodified lines
221 }286 }
222 287
223 available = FFMIN(av_audio_fifo_size(s->fifo[0]), av_audio_fifo_size(s->fifo[1]));288 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)) {289 if (available > s->size) {
225 const int out_samples = s->eof ? available : available - s->size;290 const int out_samples = available - s->size;
226 AVFrame *out;291 AVFrame *out;
227 292
228 if (!s->cache[0] || s->cache[0]->nb_samples < available) {293 if (!s->cache[0] || s->cache[0]->nb_samples < available) {
229 av_frame_free(&s->cache[0]);294 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);
231 if (!s->cache[0])296 if (!s->cache[0])
232 return AVERROR(ENOMEM);297 return AVERROR(ENOMEM);
233 }298 }
234 299
235 if (!s->cache[1] || s->cache[1]->nb_samples < available) {300 if (!s->cache[1] || s->cache[1]->nb_samples < available) {
236 av_frame_free(&s->cache[1]);301 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);
238 if (!s->cache[1])303 if (!s->cache[1])
239 return AVERROR(ENOMEM);304 return AVERROR(ENOMEM);
240 }305 }
@@ -247,7 +312,7 @@ static int activate(AVFilterContext *ctx) · 6 unmodified lines
247 if (ret < 0)312 if (ret < 0)
248 return ret;313 return ret;
249 314
250 out = ff_get_audio_buffer(ctx->outputs[0], out_samples);315 out = ff_get_audio_buffer(outlink, out_samples);
251 if (!out)316 if (!out)
252 return AVERROR(ENOMEM);317 return AVERROR(ENOMEM);
253 318
@@ -259,18 +324,31 @@ static int activate(AVFilterContext *ctx) · 5 unmodified lines
259 av_audio_fifo_drain(s->fifo[0], out_samples);324 av_audio_fifo_drain(s->fifo[0], out_samples);
260 av_audio_fifo_drain(s->fifo[1], out_samples);325 av_audio_fifo_drain(s->fifo[1], out_samples);
261 326
262 return ff_filter_frame(ctx->outputs[0], out);327 return ff_filter_frame(outlink, out);
263 }328 }
264 329
265 for (int i = 0; i < 2 && !s->eof; i++) {330 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
267 s->eof = 1;334 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 }
268 }346 }
269 347
270 if (s->eof &&348 if (s->eof &&
271 (av_audio_fifo_size(s->fifo[0]) <= 0 ||349 (av_audio_fifo_size(s->fifo[0]) <= s->size ||
272 av_audio_fifo_size(s->fifo[1]) <= 0)) {350 av_audio_fifo_size(s->fifo[1]) <= s->size)) {
273 ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, s->pts);351 ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
274 return 0;352 return 0;
275 }353 }
276 354
@@ -280,7 +358,7 @@ static int activate(AVFilterContext *ctx) · 3 unmodified lines
280 return 0;358 return 0;
281 }359 }
282 360
283 if (ff_outlink_frame_wanted(ctx->outputs[0]) && !s->eof) {361 if (ff_outlink_frame_wanted(outlink) && !s->eof) {
284 for (int i = 0; i < 2; i++) {362 for (int i = 0; i < 2; i++) {
285 if (av_audio_fifo_size(s->fifo[i]) > s->size)363 if (av_audio_fifo_size(s->fifo[i]) > s->size)
286 continue;364 continue;
@@ -316,12 +394,14 @@ static int config_output(AVFilterLink *outlink) · 29 unmodified lines
316 switch (s->algo) {394 switch (s->algo) {
317 case 0: s->xcorrelate = xcorrelate_slow_f; break;395 case 0: s->xcorrelate = xcorrelate_slow_f; break;
318 case 1: s->xcorrelate = xcorrelate_fast_f; break;396 case 1: s->xcorrelate = xcorrelate_fast_f; break;
397 case 2: s->xcorrelate = xcorrelate_best_f; break;
319 }398 }
320 399
321 if (outlink->format == AV_SAMPLE_FMT_DBLP) {400 if (outlink->format == AV_SAMPLE_FMT_DBLP) {
322 switch (s->algo) {401 switch (s->algo) {
323 case 0: s->xcorrelate = xcorrelate_slow_d; break;402 case 0: s->xcorrelate = xcorrelate_slow_d; break;
324 case 1: s->xcorrelate = xcorrelate_fast_d; break;403 case 1: s->xcorrelate = xcorrelate_fast_d; break;
404 case 2: s->xcorrelate = xcorrelate_best_d; break;
325 }405 }
326 }406 }
327 407
@@ -366,10 +446,11 @@ static const AVFilterPad outputs[] = { · 38 unmodified lines
366#define OFFSET(x) offsetof(AudioXCorrelateContext, x)446#define OFFSET(x) offsetof(AudioXCorrelateContext, x)
367 447
368static const AVOption axcorrelate_options[] = {448static const AVOption axcorrelate_options[] = {
369 { "size", "set segment size", OFFSET(size), AV_OPT_TYPE_INT, {.i64=256}, 2, 131072, AF },449 { "size", "set the 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" },450 { "algo", "set the algorithm", OFFSET(algo), AV_OPT_TYPE_INT, {.i64=2}, 0, 2, AF, "algo" },
371 { "slow", "slow algorithm", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "algo" },451 { "slow", "slow algorithm", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "algo" },
372 { "fast", "fast algorithm", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "algo" },452 { "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" },
373 { NULL }454 { NULL }
374};455};
375 456

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