FFmpeg
af_headphone.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Paul B Mahol
3  * Copyright (C) 2013-2015 Andreas Fuchs, Wolfgang Hrauda
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <math.h>
22 
23 #include "libavutil/avstring.h"
25 #include "libavutil/float_dsp.h"
26 #include "libavutil/intmath.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/tx.h"
29 
30 #include "avfilter.h"
31 #include "filters.h"
32 #include "internal.h"
33 #include "audio.h"
34 
35 #define TIME_DOMAIN 0
36 #define FREQUENCY_DOMAIN 1
37 
38 #define HRIR_STEREO 0
39 #define HRIR_MULTI 1
40 
41 typedef struct HeadphoneContext {
42  const AVClass *class;
43 
44  char *map;
45  int type;
46 
48 
50  int eof_hrirs;
51 
52  int ir_len;
53  int air_len;
54 
56 
57  int nb_irs;
58 
59  float gain;
61 
62  float *ringbuffer[2];
63  int write[2];
64 
66  int n_fft;
67  int size;
68  int hrir_fmt;
69 
70  float *data_ir[2];
71  float *temp_src[2];
75 
76  AVTXContext *fft[2], *ifft[2];
79 
80  float (*scalarproduct_float)(const float *v1, const float *v2, int len);
81  struct hrir_inputs {
82  int ir_len;
83  int eof;
84  } hrir_in[64];
86  enum AVChannel mapping[64];
87  uint8_t hrir_map[64];
89 
90 static int parse_channel_name(const char *arg, enum AVChannel *rchannel)
91 {
93 
95  return AVERROR(EINVAL);
96  *rchannel = channel;
97  return 0;
98 }
99 
101 {
102  HeadphoneContext *s = ctx->priv;
103  char *arg, *tokenizer, *p;
104  uint64_t used_channels = 0;
105 
106  p = s->map;
107  while ((arg = av_strtok(p, "|", &tokenizer))) {
108  enum AVChannel out_channel;
109 
110  p = NULL;
111  if (parse_channel_name(arg, &out_channel)) {
112  av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", arg);
113  continue;
114  }
115  if (used_channels & (1ULL << out_channel)) {
116  av_log(ctx, AV_LOG_WARNING, "Ignoring duplicate channel '%s'.\n", arg);
117  continue;
118  }
119  used_channels |= (1ULL << out_channel);
120  s->mapping[s->nb_irs] = out_channel;
121  s->nb_irs++;
122  }
123  av_channel_layout_from_mask(&s->map_channel_layout, used_channels);
124 
125  if (s->hrir_fmt == HRIR_MULTI)
126  s->nb_hrir_inputs = 1;
127  else
128  s->nb_hrir_inputs = s->nb_irs;
129 }
130 
131 typedef struct ThreadData {
132  AVFrame *in, *out;
133  int *write;
134  float **ir;
136  float **ringbuffer;
137  float **temp_src;
141 } ThreadData;
142 
143 static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
144 {
145  HeadphoneContext *s = ctx->priv;
146  ThreadData *td = arg;
147  AVFrame *in = td->in, *out = td->out;
148  int offset = jobnr;
149  int *write = &td->write[jobnr];
150  const float *const ir = td->ir[jobnr];
151  int *n_clippings = &td->n_clippings[jobnr];
152  float *ringbuffer = td->ringbuffer[jobnr];
153  float *temp_src = td->temp_src[jobnr];
154  const int ir_len = s->ir_len;
155  const int air_len = s->air_len;
156  const float *src = (const float *)in->data[0];
157  float *dst = (float *)out->data[0];
158  const int in_channels = in->ch_layout.nb_channels;
159  const int buffer_length = s->buffer_length;
160  const uint32_t modulo = (uint32_t)buffer_length - 1;
161  float *buffer[64];
162  int wr = *write;
163  int read;
164  int i, l;
165 
166  dst += offset;
167  for (l = 0; l < in_channels; l++) {
168  buffer[l] = ringbuffer + l * buffer_length;
169  }
170 
171  for (i = 0; i < in->nb_samples; i++) {
172  const float *cur_ir = ir;
173 
174  *dst = 0;
175  for (l = 0; l < in_channels; l++) {
176  *(buffer[l] + wr) = src[l];
177  }
178 
179  for (l = 0; l < in_channels; cur_ir += air_len, l++) {
180  const float *const bptr = buffer[l];
181 
182  if (l == s->lfe_channel) {
183  *dst += *(buffer[s->lfe_channel] + wr) * s->gain_lfe;
184  continue;
185  }
186 
187  read = (wr - (ir_len - 1)) & modulo;
188 
189  if (read + ir_len < buffer_length) {
190  memcpy(temp_src, bptr + read, ir_len * sizeof(*temp_src));
191  } else {
192  int len = FFMIN(air_len - (read % ir_len), buffer_length - read);
193 
194  memcpy(temp_src, bptr + read, len * sizeof(*temp_src));
195  memcpy(temp_src + len, bptr, (air_len - len) * sizeof(*temp_src));
196  }
197 
198  dst[0] += s->scalarproduct_float(cur_ir, temp_src, FFALIGN(ir_len, 32));
199  }
200 
201  if (fabsf(dst[0]) > 1)
202  n_clippings[0]++;
203 
204  dst += 2;
205  src += in_channels;
206  wr = (wr + 1) & modulo;
207  }
208 
209  *write = wr;
210 
211  return 0;
212 }
213 
214 static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
215 {
216  HeadphoneContext *s = ctx->priv;
217  ThreadData *td = arg;
218  AVFrame *in = td->in, *out = td->out;
219  int offset = jobnr;
220  int *write = &td->write[jobnr];
221  AVComplexFloat *hrtf = s->data_hrtf[jobnr];
222  int *n_clippings = &td->n_clippings[jobnr];
223  float *ringbuffer = td->ringbuffer[jobnr];
224  const int ir_len = s->ir_len;
225  const float *src = (const float *)in->data[0];
226  float *dst = (float *)out->data[0];
227  const int in_channels = in->ch_layout.nb_channels;
228  const int buffer_length = s->buffer_length;
229  const uint32_t modulo = (uint32_t)buffer_length - 1;
230  AVComplexFloat *fft_out = s->out_fft[jobnr];
231  AVComplexFloat *fft_in = s->in_fft[jobnr];
232  AVComplexFloat *fft_acc = s->temp_afft[jobnr];
233  AVTXContext *ifft = s->ifft[jobnr];
234  AVTXContext *fft = s->fft[jobnr];
235  av_tx_fn tx_fn = s->tx_fn[jobnr];
236  av_tx_fn itx_fn = s->itx_fn[jobnr];
237  const int n_fft = s->n_fft;
238  const float fft_scale = 1.0f / s->n_fft;
239  AVComplexFloat *hrtf_offset;
240  int wr = *write;
241  int n_read;
242  int i, j;
243 
244  dst += offset;
245 
246  n_read = FFMIN(ir_len, in->nb_samples);
247  for (j = 0; j < n_read; j++) {
248  dst[2 * j] = ringbuffer[wr];
249  ringbuffer[wr] = 0.0;
250  wr = (wr + 1) & modulo;
251  }
252 
253  for (j = n_read; j < in->nb_samples; j++) {
254  dst[2 * j] = 0;
255  }
256 
257  memset(fft_acc, 0, sizeof(AVComplexFloat) * n_fft);
258 
259  for (i = 0; i < in_channels; i++) {
260  if (i == s->lfe_channel) {
261  for (j = 0; j < in->nb_samples; j++) {
262  dst[2 * j] += src[i + j * in_channels] * s->gain_lfe;
263  }
264  continue;
265  }
266 
267  offset = i * n_fft;
268  hrtf_offset = hrtf + s->hrir_map[i] * n_fft;
269 
270  memset(fft_in, 0, sizeof(AVComplexFloat) * n_fft);
271 
272  for (j = 0; j < in->nb_samples; j++) {
273  fft_in[j].re = src[j * in_channels + i];
274  }
275 
276  tx_fn(fft, fft_out, fft_in, sizeof(float));
277 
278  for (j = 0; j < n_fft; j++) {
279  const AVComplexFloat *hcomplex = hrtf_offset + j;
280  const float re = fft_out[j].re;
281  const float im = fft_out[j].im;
282 
283  fft_acc[j].re += re * hcomplex->re - im * hcomplex->im;
284  fft_acc[j].im += re * hcomplex->im + im * hcomplex->re;
285  }
286  }
287 
288  itx_fn(ifft, fft_out, fft_acc, sizeof(float));
289 
290  for (j = 0; j < in->nb_samples; j++) {
291  dst[2 * j] += fft_out[j].re * fft_scale;
292  if (fabsf(dst[2 * j]) > 1)
293  n_clippings[0]++;
294  }
295 
296  for (j = 0; j < ir_len - 1; j++) {
297  int write_pos = (wr + j) & modulo;
298 
299  *(ringbuffer + write_pos) += fft_out[in->nb_samples + j].re * fft_scale;
300  }
301 
302  *write = wr;
303 
304  return 0;
305 }
306 
307 static int check_ir(AVFilterLink *inlink, int input_number)
308 {
309  AVFilterContext *ctx = inlink->dst;
310  HeadphoneContext *s = ctx->priv;
311  int ir_len, max_ir_len;
312 
314  max_ir_len = 65536;
315  if (ir_len > max_ir_len) {
316  av_log(ctx, AV_LOG_ERROR, "Too big length of IRs: %d > %d.\n", ir_len, max_ir_len);
317  return AVERROR(EINVAL);
318  }
319  s->hrir_in[input_number].ir_len = ir_len;
320  s->ir_len = FFMAX(ir_len, s->ir_len);
321 
322  return 0;
323 }
324 
326 {
327  AVFilterContext *ctx = outlink->src;
328  int n_clippings[2] = { 0 };
329  ThreadData td;
330  AVFrame *out;
331 
332  out = ff_get_audio_buffer(outlink, in->nb_samples);
333  if (!out) {
334  av_frame_free(&in);
335  return AVERROR(ENOMEM);
336  }
337  out->pts = in->pts;
338 
339  td.in = in; td.out = out; td.write = s->write;
340  td.ir = s->data_ir; td.n_clippings = n_clippings;
341  td.ringbuffer = s->ringbuffer; td.temp_src = s->temp_src;
342  td.out_fft = s->out_fft;
343  td.in_fft = s->in_fft;
344  td.temp_afft = s->temp_afft;
345 
346  if (s->type == TIME_DOMAIN) {
348  } else {
350  }
351  emms_c();
352 
353  if (n_clippings[0] + n_clippings[1] > 0) {
354  av_log(ctx, AV_LOG_WARNING, "%d of %d samples clipped. Please reduce gain.\n",
355  n_clippings[0] + n_clippings[1], out->nb_samples * 2);
356  }
357 
358  av_frame_free(&in);
359  return ff_filter_frame(outlink, out);
360 }
361 
363 {
364  struct HeadphoneContext *s = ctx->priv;
365  const int ir_len = s->ir_len;
366  int nb_input_channels = ctx->inputs[0]->ch_layout.nb_channels;
367  const int nb_hrir_channels = s->nb_hrir_inputs == 1 ? ctx->inputs[1]->ch_layout.nb_channels : s->nb_hrir_inputs * 2;
368  float gain_lin = expf((s->gain - 3 * nb_input_channels) / 20 * M_LN10);
369  AVFrame *frame;
370  int ret = 0;
371  int n_fft;
372  int i, j, k;
373 
374  s->air_len = 1 << (32 - ff_clz(ir_len));
375  if (s->type == TIME_DOMAIN) {
376  s->air_len = FFALIGN(s->air_len, 32);
377  }
378  s->buffer_length = 1 << (32 - ff_clz(s->air_len));
379  s->n_fft = n_fft = 1 << (32 - ff_clz(ir_len + s->size));
380 
381  if (s->type == FREQUENCY_DOMAIN) {
382  float scale;
383 
384  ret = av_tx_init(&s->fft[0], &s->tx_fn[0], AV_TX_FLOAT_FFT, 0, s->n_fft, &scale, 0);
385  if (ret < 0)
386  goto fail;
387  ret = av_tx_init(&s->fft[1], &s->tx_fn[1], AV_TX_FLOAT_FFT, 0, s->n_fft, &scale, 0);
388  if (ret < 0)
389  goto fail;
390  ret = av_tx_init(&s->ifft[0], &s->itx_fn[0], AV_TX_FLOAT_FFT, 1, s->n_fft, &scale, 0);
391  if (ret < 0)
392  goto fail;
393  ret = av_tx_init(&s->ifft[1], &s->itx_fn[1], AV_TX_FLOAT_FFT, 1, s->n_fft, &scale, 0);
394  if (ret < 0)
395  goto fail;
396 
397  if (!s->fft[0] || !s->fft[1] || !s->ifft[0] || !s->ifft[1]) {
398  av_log(ctx, AV_LOG_ERROR, "Unable to create FFT contexts of size %d.\n", s->n_fft);
399  ret = AVERROR(ENOMEM);
400  goto fail;
401  }
402  }
403 
404  if (s->type == TIME_DOMAIN) {
405  s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
406  s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
407  } else {
408  s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float));
409  s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float));
410  s->out_fft[0] = av_calloc(s->n_fft, sizeof(AVComplexFloat));
411  s->out_fft[1] = av_calloc(s->n_fft, sizeof(AVComplexFloat));
412  s->in_fft[0] = av_calloc(s->n_fft, sizeof(AVComplexFloat));
413  s->in_fft[1] = av_calloc(s->n_fft, sizeof(AVComplexFloat));
414  s->temp_afft[0] = av_calloc(s->n_fft, sizeof(AVComplexFloat));
415  s->temp_afft[1] = av_calloc(s->n_fft, sizeof(AVComplexFloat));
416  if (!s->in_fft[0] || !s->in_fft[1] ||
417  !s->out_fft[0] || !s->out_fft[1] ||
418  !s->temp_afft[0] || !s->temp_afft[1]) {
419  ret = AVERROR(ENOMEM);
420  goto fail;
421  }
422  }
423 
424  if (!s->ringbuffer[0] || !s->ringbuffer[1]) {
425  ret = AVERROR(ENOMEM);
426  goto fail;
427  }
428 
429  if (s->type == TIME_DOMAIN) {
430  s->temp_src[0] = av_calloc(s->air_len, sizeof(float));
431  s->temp_src[1] = av_calloc(s->air_len, sizeof(float));
432 
433  s->data_ir[0] = av_calloc(nb_hrir_channels * s->air_len, sizeof(*s->data_ir[0]));
434  s->data_ir[1] = av_calloc(nb_hrir_channels * s->air_len, sizeof(*s->data_ir[1]));
435  if (!s->data_ir[0] || !s->data_ir[1] || !s->temp_src[0] || !s->temp_src[1]) {
436  ret = AVERROR(ENOMEM);
437  goto fail;
438  }
439  } else {
440  s->data_hrtf[0] = av_calloc(n_fft, sizeof(*s->data_hrtf[0]) * nb_hrir_channels);
441  s->data_hrtf[1] = av_calloc(n_fft, sizeof(*s->data_hrtf[1]) * nb_hrir_channels);
442  if (!s->data_hrtf[0] || !s->data_hrtf[1]) {
443  ret = AVERROR(ENOMEM);
444  goto fail;
445  }
446  }
447 
448  for (i = 0; i < s->nb_hrir_inputs; av_frame_free(&frame), i++) {
449  int len = s->hrir_in[i].ir_len;
450  float *ptr;
451 
452  ret = ff_inlink_consume_samples(ctx->inputs[i + 1], len, len, &frame);
453  if (ret < 0)
454  goto fail;
455  ptr = (float *)frame->extended_data[0];
456 
457  if (s->hrir_fmt == HRIR_STEREO) {
458  int idx = av_channel_layout_index_from_channel(&s->map_channel_layout,
459  s->mapping[i]);
460  if (idx < 0)
461  continue;
462 
463  s->hrir_map[i] = idx;
464  if (s->type == TIME_DOMAIN) {
465  float *data_ir_l = s->data_ir[0] + idx * s->air_len;
466  float *data_ir_r = s->data_ir[1] + idx * s->air_len;
467 
468  for (j = 0; j < len; j++) {
469  data_ir_l[j] = ptr[len * 2 - j * 2 - 2] * gain_lin;
470  data_ir_r[j] = ptr[len * 2 - j * 2 - 1] * gain_lin;
471  }
472  } else {
473  AVComplexFloat *fft_out_l = s->data_hrtf[0] + idx * n_fft;
474  AVComplexFloat *fft_out_r = s->data_hrtf[1] + idx * n_fft;
475  AVComplexFloat *fft_in_l = s->in_fft[0];
476  AVComplexFloat *fft_in_r = s->in_fft[1];
477 
478  for (j = 0; j < len; j++) {
479  fft_in_l[j].re = ptr[j * 2 ] * gain_lin;
480  fft_in_r[j].re = ptr[j * 2 + 1] * gain_lin;
481  }
482 
483  s->tx_fn[0](s->fft[0], fft_out_l, fft_in_l, sizeof(float));
484  s->tx_fn[0](s->fft[0], fft_out_r, fft_in_r, sizeof(float));
485  }
486  } else {
487  int I, N = ctx->inputs[1]->ch_layout.nb_channels;
488 
489  for (k = 0; k < N / 2; k++) {
490  int idx = av_channel_layout_index_from_channel(&inlink->ch_layout,
491  s->mapping[k]);
492  if (idx < 0)
493  continue;
494 
495  s->hrir_map[k] = idx;
496  I = k * 2;
497  if (s->type == TIME_DOMAIN) {
498  float *data_ir_l = s->data_ir[0] + idx * s->air_len;
499  float *data_ir_r = s->data_ir[1] + idx * s->air_len;
500 
501  for (j = 0; j < len; j++) {
502  data_ir_l[j] = ptr[len * N - j * N - N + I ] * gain_lin;
503  data_ir_r[j] = ptr[len * N - j * N - N + I + 1] * gain_lin;
504  }
505  } else {
506  AVComplexFloat *fft_out_l = s->data_hrtf[0] + idx * n_fft;
507  AVComplexFloat *fft_out_r = s->data_hrtf[1] + idx * n_fft;
508  AVComplexFloat *fft_in_l = s->in_fft[0];
509  AVComplexFloat *fft_in_r = s->in_fft[1];
510 
511  for (j = 0; j < len; j++) {
512  fft_in_l[j].re = ptr[j * N + I ] * gain_lin;
513  fft_in_r[j].re = ptr[j * N + I + 1] * gain_lin;
514  }
515 
516  s->tx_fn[0](s->fft[0], fft_out_l, fft_in_l, sizeof(float));
517  s->tx_fn[0](s->fft[0], fft_out_r, fft_in_r, sizeof(float));
518  }
519  }
520  }
521  }
522 
523  s->have_hrirs = 1;
524 
525 fail:
526  return ret;
527 }
528 
530 {
531  HeadphoneContext *s = ctx->priv;
532  AVFilterLink *inlink = ctx->inputs[0];
533  AVFilterLink *outlink = ctx->outputs[0];
534  AVFrame *in = NULL;
535  int i, ret;
536 
538  if (!s->eof_hrirs) {
539  int eof = 1;
540  for (i = 0; i < s->nb_hrir_inputs; i++) {
541  AVFilterLink *input = ctx->inputs[i + 1];
542 
543  if (s->hrir_in[i].eof)
544  continue;
545 
546  if ((ret = check_ir(input, i)) < 0)
547  return ret;
548 
551  av_log(ctx, AV_LOG_ERROR, "No samples provided for "
552  "HRIR stream %d.\n", i);
553  return AVERROR_INVALIDDATA;
554  }
555  s->hrir_in[i].eof = 1;
556  } else {
557  if (ff_outlink_frame_wanted(ctx->outputs[0]))
559  eof = 0;
560  }
561  }
562  if (!eof)
563  return 0;
564  s->eof_hrirs = 1;
565 
567  if (ret < 0)
568  return ret;
569  } else if (!s->have_hrirs)
570  return AVERROR_EOF;
571 
572  if ((ret = ff_inlink_consume_samples(ctx->inputs[0], s->size, s->size, &in)) > 0) {
573  ret = headphone_frame(s, in, outlink);
574  if (ret < 0)
575  return ret;
576  }
577 
578  if (ret < 0)
579  return ret;
580 
581  FF_FILTER_FORWARD_STATUS(ctx->inputs[0], ctx->outputs[0]);
582  if (ff_outlink_frame_wanted(ctx->outputs[0]))
583  ff_inlink_request_frame(ctx->inputs[0]);
584 
585  return 0;
586 }
587 
589 {
590  struct HeadphoneContext *s = ctx->priv;
593  AVFilterChannelLayouts *stereo_layout = NULL;
594  AVFilterChannelLayouts *hrir_layouts = NULL;
595  int ret, i;
596 
598  if (ret)
599  return ret;
601  if (ret)
602  return ret;
603 
605  if (!layouts)
606  return AVERROR(ENOMEM);
607 
608  ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->outcfg.channel_layouts);
609  if (ret)
610  return ret;
611 
613  if (ret)
614  return ret;
615  ret = ff_channel_layouts_ref(stereo_layout, &ctx->outputs[0]->incfg.channel_layouts);
616  if (ret)
617  return ret;
618 
619  if (s->hrir_fmt == HRIR_MULTI) {
620  hrir_layouts = ff_all_channel_counts();
621  if (!hrir_layouts)
622  return AVERROR(ENOMEM);
623  ret = ff_channel_layouts_ref(hrir_layouts, &ctx->inputs[1]->outcfg.channel_layouts);
624  if (ret)
625  return ret;
626  } else {
627  for (i = 1; i <= s->nb_hrir_inputs; i++) {
628  ret = ff_channel_layouts_ref(stereo_layout, &ctx->inputs[i]->outcfg.channel_layouts);
629  if (ret)
630  return ret;
631  }
632  }
633 
635 }
636 
638 {
639  AVFilterContext *ctx = inlink->dst;
640  HeadphoneContext *s = ctx->priv;
641 
642  if (s->nb_irs < inlink->ch_layout.nb_channels) {
643  av_log(ctx, AV_LOG_ERROR, "Number of HRIRs must be >= %d.\n", inlink->ch_layout.nb_channels);
644  return AVERROR(EINVAL);
645  }
646 
647  s->lfe_channel = av_channel_layout_index_from_channel(&inlink->ch_layout,
649  return 0;
650 }
651 
653 {
654  HeadphoneContext *s = ctx->priv;
655  int i, ret;
656 
657  AVFilterPad pad = {
658  .name = "in0",
659  .type = AVMEDIA_TYPE_AUDIO,
660  .config_props = config_input,
661  };
662  if ((ret = ff_append_inpad(ctx, &pad)) < 0)
663  return ret;
664 
665  if (!s->map) {
666  av_log(ctx, AV_LOG_ERROR, "Valid mapping must be set.\n");
667  return AVERROR(EINVAL);
668  }
669 
670  parse_map(ctx);
671 
672  for (i = 0; i < s->nb_hrir_inputs; i++) {
673  char *name = av_asprintf("hrir%d", i);
674  AVFilterPad pad = {
675  .name = name,
676  .type = AVMEDIA_TYPE_AUDIO,
677  };
678  if (!name)
679  return AVERROR(ENOMEM);
680  if ((ret = ff_append_inpad_free_name(ctx, &pad)) < 0)
681  return ret;
682  }
683 
684  if (s->type == TIME_DOMAIN) {
686  if (!fdsp)
687  return AVERROR(ENOMEM);
688  s->scalarproduct_float = fdsp->scalarproduct_float;
689  av_free(fdsp);
690  }
691 
692  return 0;
693 }
694 
695 static int config_output(AVFilterLink *outlink)
696 {
697  AVFilterContext *ctx = outlink->src;
698  HeadphoneContext *s = ctx->priv;
699  AVFilterLink *inlink = ctx->inputs[0];
700 
701  if (s->hrir_fmt == HRIR_MULTI) {
702  AVFilterLink *hrir_link = ctx->inputs[1];
703 
704  if (hrir_link->ch_layout.nb_channels < inlink->ch_layout.nb_channels * 2) {
705  av_log(ctx, AV_LOG_ERROR, "Number of channels in HRIR stream must be >= %d.\n", inlink->ch_layout.nb_channels * 2);
706  return AVERROR(EINVAL);
707  }
708  }
709 
710  s->gain_lfe = expf((s->gain - 3 * inlink->ch_layout.nb_channels + s->lfe_gain) / 20 * M_LN10);
711 
712  return 0;
713 }
714 
716 {
717  HeadphoneContext *s = ctx->priv;
718 
719  av_tx_uninit(&s->ifft[0]);
720  av_tx_uninit(&s->ifft[1]);
721  av_tx_uninit(&s->fft[0]);
722  av_tx_uninit(&s->fft[1]);
723  av_freep(&s->data_ir[0]);
724  av_freep(&s->data_ir[1]);
725  av_freep(&s->ringbuffer[0]);
726  av_freep(&s->ringbuffer[1]);
727  av_freep(&s->temp_src[0]);
728  av_freep(&s->temp_src[1]);
729  av_freep(&s->out_fft[0]);
730  av_freep(&s->out_fft[1]);
731  av_freep(&s->in_fft[0]);
732  av_freep(&s->in_fft[1]);
733  av_freep(&s->temp_afft[0]);
734  av_freep(&s->temp_afft[1]);
735  av_freep(&s->data_hrtf[0]);
736  av_freep(&s->data_hrtf[1]);
737 }
738 
739 #define OFFSET(x) offsetof(HeadphoneContext, x)
740 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
741 
742 static const AVOption headphone_options[] = {
743  { "map", "set channels convolution mappings", OFFSET(map), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
744  { "gain", "set gain in dB", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20, 40, .flags = FLAGS },
745  { "lfe", "set lfe gain in dB", OFFSET(lfe_gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20, 40, .flags = FLAGS },
746  { "type", "set processing", OFFSET(type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = FLAGS, "type" },
747  { "time", "time domain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = FLAGS, "type" },
748  { "freq", "frequency domain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = FLAGS, "type" },
749  { "size", "set frame size", OFFSET(size), AV_OPT_TYPE_INT, {.i64=1024},1024,96000, .flags = FLAGS },
750  { "hrir", "set hrir format", OFFSET(hrir_fmt), AV_OPT_TYPE_INT, {.i64=HRIR_STEREO}, 0, 1, .flags = FLAGS, "hrir" },
751  { "stereo", "hrir files have exactly 2 channels", 0, AV_OPT_TYPE_CONST, {.i64=HRIR_STEREO}, 0, 0, .flags = FLAGS, "hrir" },
752  { "multich", "single multichannel hrir file", 0, AV_OPT_TYPE_CONST, {.i64=HRIR_MULTI}, 0, 0, .flags = FLAGS, "hrir" },
753  { NULL }
754 };
755 
756 AVFILTER_DEFINE_CLASS(headphone);
757 
758 static const AVFilterPad outputs[] = {
759  {
760  .name = "default",
761  .type = AVMEDIA_TYPE_AUDIO,
762  .config_props = config_output,
763  },
764 };
765 
767  .name = "headphone",
768  .description = NULL_IF_CONFIG_SMALL("Apply headphone binaural spatialization with HRTFs in additional streams."),
769  .priv_size = sizeof(HeadphoneContext),
770  .priv_class = &headphone_class,
771  .init = init,
772  .uninit = uninit,
773  .activate = activate,
774  .inputs = NULL,
778 };
formats
formats
Definition: signature.h:48
HeadphoneContext::hrir_inputs
Definition: af_headphone.c:81
convert_coeffs
static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink)
Definition: af_headphone.c:362
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:100
FREQUENCY_DOMAIN
#define FREQUENCY_DOMAIN
Definition: af_headphone.c:36
AVFilterChannelLayouts
A list of supported channel layouts.
Definition: formats.h:85
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
td
#define td
Definition: regdef.h:70
name
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 minimum maximum flags name is the option name
Definition: writing_filters.txt:88
HeadphoneContext::gain_lfe
float gain_lfe
Definition: af_headphone.c:60
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
HeadphoneContext::data_ir
float * data_ir[2]
Definition: af_headphone.c:70
ThreadData::out_fft
AVComplexFloat ** out_fft
Definition: af_headphone.c:138
out
FILE * out
Definition: movenc.c:54
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:999
ff_channel_layouts_ref
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:591
layouts
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:330
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
HeadphoneContext::size
int size
Definition: af_headphone.c:67
HeadphoneContext::temp_afft
AVComplexFloat * temp_afft[2]
Definition: af_headphone.c:74
AVTXContext
Definition: tx_priv.h:201
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
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:116
ff_clz
#define ff_clz
Definition: intmath.h:142
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:111
ff_all_channel_counts
AVFilterChannelLayouts * ff_all_channel_counts(void)
Construct an AVFilterChannelLayouts coding for any channel layout, with known or unknown disposition.
Definition: formats.c:566
im
float im
Definition: fft.c:79
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:432
AV_CHAN_LOW_FREQUENCY
@ AV_CHAN_LOW_FREQUENCY
Definition: channel_layout.h:47
TIME_DOMAIN
#define TIME_DOMAIN
Definition: af_headphone.c:35
AVOption
AVOption.
Definition: opt.h:251
HeadphoneContext::ringbuffer
float * ringbuffer[2]
Definition: af_headphone.c:62
FILTER_QUERY_FUNC
#define FILTER_QUERY_FUNC(func)
Definition: internal.h:167
expf
#define expf(x)
Definition: libm.h:283
ff_set_common_all_samplerates
int ff_set_common_all_samplerates(AVFilterContext *ctx)
Equivalent to ff_set_common_samplerates(ctx, ff_all_samplerates())
Definition: formats.c:739
HeadphoneContext::eof_hrirs
int eof_hrirs
Definition: af_headphone.c:50
AVComplexFloat
Definition: tx.h:27
HeadphoneContext::fft
AVTXContext * fft[2]
Definition: af_headphone.c:76
AV_CHANNEL_LAYOUT_STEREO
#define AV_CHANNEL_LAYOUT_STEREO
Definition: channel_layout.h:354
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:175
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:473
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:300
ThreadData::in
AVFrame * in
Definition: af_adecorrelate.c:154
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:649
ThreadData::temp_src
float ** temp_src
Definition: af_headphone.c:137
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:346
AVFilterFormats
A list of supported formats for one end of a filter link.
Definition: formats.h:64
HeadphoneContext::data_hrtf
AVComplexFloat * data_hrtf[2]
Definition: af_headphone.c:78
HeadphoneContext::hrir_inputs::ir_len
int ir_len
Definition: af_headphone.c:82
AVComplexFloat::im
float im
Definition: tx.h:28
HeadphoneContext::air_len
int air_len
Definition: af_headphone.c:53
FF_FILTER_FORWARD_STATUS_BACK_ALL
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
Definition: filters.h:212
AVChannel
AVChannel
Definition: channel_layout.h:41
ff_append_inpad
int ff_append_inpad(AVFilterContext *f, AVFilterPad *p)
Append a new input/output pad to the filter's list of such pads.
Definition: avfilter.c:118
HeadphoneContext::ir_len
int ir_len
Definition: af_headphone.c:52
fail
#define fail()
Definition: checkasm.h:131
HeadphoneContext::scalarproduct_float
float(* scalarproduct_float)(const float *v1, const float *v2, int len)
Definition: af_headphone.c:80
activate
static int activate(AVFilterContext *ctx)
Definition: af_headphone.c:529
HeadphoneContext::hrir_inputs::eof
int eof
Definition: af_headphone.c:83
ThreadData::ringbuffer
float ** ringbuffer
Definition: af_headphone.c:136
AVFrame::ch_layout
AVChannelLayout ch_layout
Channel layout of the audio data.
Definition: frame.h:704
type
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 type
Definition: writing_filters.txt:86
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1389
AVFILTER_FLAG_DYNAMIC_INPUTS
#define AVFILTER_FLAG_DYNAMIC_INPUTS
The number of the filter inputs is not determined just by AVFilter.inputs.
Definition: avfilter.h:116
fabsf
static __device__ float fabsf(float a)
Definition: cuda_runtime.h:181
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_headphone.c:637
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:49
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
OFFSET
#define OFFSET(x)
Definition: af_headphone.c:739
ff_set_common_formats
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:749
HRIR_MULTI
#define HRIR_MULTI
Definition: af_headphone.c:39
HRIR_STEREO
#define HRIR_STEREO
Definition: af_headphone.c:38
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:111
float
float
Definition: af_crystalizer.c:122
AVFloatDSPContext::scalarproduct_float
float(* scalarproduct_float)(const float *v1, const float *v2, int len)
Calculate the scalar product of two vectors of floats.
Definition: float_dsp.h:175
ff_inlink_request_frame
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition: avfilter.c:1511
s
#define s(width, name)
Definition: cbs_vp9.c:256
HeadphoneContext::buffer_length
int buffer_length
Definition: af_headphone.c:65
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:189
filters.h
AV_TX_FLOAT_FFT
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type of AVComplexFloat, AVComplexDouble or AVComplex...
Definition: tx.h:47
ctx
AVFormatContext * ctx
Definition: movenc.c:48
HeadphoneContext::lfe_gain
float lfe_gain
Definition: af_headphone.c:60
parse_channel_name
static int parse_channel_name(const char *arg, enum AVChannel *rchannel)
Definition: af_headphone.c:90
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_headphone.c:715
arg
const char * arg
Definition: jacosubdec.c:67
if
if(ret)
Definition: filter_design.txt:179
headphone_convolute
static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_headphone.c:143
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:1413
NULL
#define NULL
Definition: coverity.c:32
FLAGS
#define FLAGS
Definition: af_headphone.c:740
parse_map
static void parse_map(AVFilterContext *ctx)
Definition: af_headphone.c:100
ff_append_inpad_free_name
int ff_append_inpad_free_name(AVFilterContext *f, AVFilterPad *p)
Definition: avfilter.c:123
outputs
static const AVFilterPad outputs[]
Definition: af_headphone.c:758
ff_add_format
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
Add fmt to the list of media formats contained in *avff.
Definition: formats.c:449
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
ThreadData::in_fft
AVComplexFloat ** in_fft
Definition: af_headphone.c:139
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: af_headphone.c:588
ff_add_channel_layout
int ff_add_channel_layout(AVFilterChannelLayouts **l, const AVChannelLayout *channel_layout)
Definition: formats.c:466
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(headphone)
float_dsp.h
headphone_frame
static int headphone_frame(HeadphoneContext *s, AVFrame *in, AVFilterLink *outlink)
Definition: af_headphone.c:325
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
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:290
HeadphoneContext::write
int write[2]
Definition: af_headphone.c:63
av_channel_from_string
enum AVChannel av_channel_from_string(const char *str)
This is the inverse function of av_channel_name().
Definition: channel_layout.c:141
size
int size
Definition: twinvq_data.h:10344
AVComplexFloat::re
float re
Definition: tx.h:28
HeadphoneContext::gain
float gain
Definition: af_headphone.c:59
AVFloatDSPContext
Definition: float_dsp.h:24
HeadphoneContext
Definition: af_headphone.c:41
offset
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 offset
Definition: writing_filters.txt:86
N
#define N
Definition: af_mcompand.c:53
ff_all_channel_layouts
AVFilterChannelLayouts * ff_all_channel_layouts(void)
Construct an empty AVFilterChannelLayouts/AVFilterFormats struct – representing any channel layout (w...
Definition: formats.c:557
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
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:251
headphone_options
static const AVOption headphone_options[]
Definition: af_headphone.c:742
HeadphoneContext::have_hrirs
int have_hrirs
Definition: af_headphone.c:49
internal.h
AV_OPT_TYPE_FLOAT
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:228
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:405
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
HeadphoneContext::map
char * map
Definition: af_headphone.c:44
HeadphoneContext::tx_fn
av_tx_fn tx_fn[2]
Definition: af_headphone.c:77
init
static av_cold int init(AVFilterContext *ctx)
Definition: af_headphone.c:652
ThreadData
Used for passing data between threads.
Definition: dsddec.c:68
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
HeadphoneContext::hrir_fmt
int hrir_fmt
Definition: af_headphone.c:68
ThreadData::n_clippings
int * n_clippings
Definition: af_headphone.c:135
HeadphoneContext::mapping
enum AVChannel mapping[64]
Definition: af_headphone.c:86
len
int len
Definition: vorbis_enc_data.h:426
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:55
ff_inlink_queued_samples
int ff_inlink_queued_samples(AVFilterLink *link)
Definition: avfilter.c:1373
av_channel_layout_index_from_channel
int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, enum AVChannel channel)
Get the index of a given channel in a channel layout.
Definition: channel_layout.c:834
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:272
HeadphoneContext::in_fft
AVComplexFloat * in_fft[2]
Definition: af_headphone.c:73
AVFilter
Filter definition.
Definition: avfilter.h:171
HeadphoneContext::hrir_map
uint8_t hrir_map[64]
Definition: af_headphone.c:87
av_channel_layout_from_mask
FF_ENABLE_DEPRECATION_WARNINGS int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask)
Initialize a native channel layout from a bitmask indicating which channels are present.
Definition: channel_layout.c:389
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
ThreadData::write
int * write
Definition: af_headphone.c:133
ThreadData::temp_afft
AVComplexFloat ** temp_afft
Definition: af_headphone.c:140
HeadphoneContext::map_channel_layout
AVChannelLayout map_channel_layout
Definition: af_headphone.c:85
channel_layout.h
HeadphoneContext::nb_hrir_inputs
int nb_hrir_inputs
Definition: af_headphone.c:55
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
HeadphoneContext::ifft
AVTXContext * ifft[2]
Definition: af_headphone.c:76
HeadphoneContext::itx_fn
av_tx_fn itx_fn[2]
Definition: af_headphone.c:77
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
avfilter.h
headphone_fast_convolute
static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_headphone.c:214
ff_outlink_get_status
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
Definition: avfilter.c:1534
AVFilterContext
An instance of a filter.
Definition: avfilter.h:408
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:127
audio.h
M_LN10
#define M_LN10
Definition: mathematics.h:43
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
FF_FILTER_FORWARD_STATUS
FF_FILTER_FORWARD_STATUS(inlink, outlink)
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:191
ff_af_headphone
const AVFilter ff_af_headphone
Definition: af_headphone.c:766
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
avpriv_float_dsp_alloc
av_cold AVFloatDSPContext * avpriv_float_dsp_alloc(int bit_exact)
Allocate a float DSP context.
Definition: float_dsp.c:135
ThreadData::ir
float ** ir
Definition: af_headphone.c:134
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
HeadphoneContext::temp_src
float * temp_src[2]
Definition: af_headphone.c:71
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
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:229
HeadphoneContext::type
int type
Definition: af_headphone.c:45
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:142
HeadphoneContext::lfe_channel
int lfe_channel
Definition: af_headphone.c:47
HeadphoneContext::hrir_in
struct HeadphoneContext::hrir_inputs hrir_in[64]
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
HeadphoneContext::nb_irs
int nb_irs
Definition: af_headphone.c:57
config_output
static int config_output(AVFilterLink *outlink)
Definition: af_headphone.c:695
HeadphoneContext::n_fft
int n_fft
Definition: af_headphone.c:66
AV_SAMPLE_FMT_FLT
@ AV_SAMPLE_FMT_FLT
float
Definition: samplefmt.h:60
HeadphoneContext::out_fft
AVComplexFloat * out_fft[2]
Definition: af_headphone.c:72
channel
channel
Definition: ebur128.h:39
tx.h
re
float re
Definition: fft.c:79
check_ir
static int check_ir(AVFilterLink *inlink, int input_number)
Definition: af_headphone.c:307
intmath.h