FFmpeg
af_earwax.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Mina Nagy Zaki
3  * Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
4  * This source code is freely redistributable and may be used for any purpose.
5  * This copyright notice must be maintained. Edward Beingessner And Sundry
6  * Contributors are not responsible for the consequences of using this
7  * software.
8  *
9  * This file is part of FFmpeg.
10  *
11  * FFmpeg is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * FFmpeg is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with FFmpeg; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25 
26 /**
27  * @file
28  * Stereo Widening Effect. Adds audio cues to move stereo image in
29  * front of the listener. Adapted from the libsox earwax effect.
30  */
31 
33 #include "avfilter.h"
34 #include "audio.h"
35 #include "filters.h"
36 #include "formats.h"
37 
38 #define NUMTAPS 32
39 
40 static const int8_t filt[NUMTAPS * 2] = {
41 /* 30° 330° */
42  4, -6, /* 32 tap stereo FIR filter. */
43  4, -11, /* One side filters as if the */
44  -1, -5, /* signal was from 30 degrees */
45  3, 3, /* from the ear, the other as */
46  -2, 5, /* if 330 degrees. */
47  -5, 0,
48  9, 1,
49  6, 3, /* Input */
50  -4, -1, /* Left Right */
51  -5, -3, /* __________ __________ */
52  -2, -5, /* | | | | */
53  -7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */
54  6, -7, /* / |__________| |__________| \ */
55  30, -29, /* / \ / \ */
56  12, -3, /* / X \ */
57  -11, 4, /* / / \ \ */
58  -3, 7, /* ____V_____ __________V V__________ _____V____ */
59  -20, 23, /* | | | | | | | | */
60  2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */
61  1, -6, /* |__________| |__________| |__________| |__________| */
62  -14, -5, /* \ ___ / \ ___ / */
63  15, -18, /* \ / \ / _____ \ / \ / */
64  6, 7, /* `->| + |<--' / \ `-->| + |<-' */
65  15, -10, /* \___/ _/ \_ \___/ */
66  -14, 22, /* \ / \ / \ / */
67  -7, -2, /* `--->| | | |<---' */
68  -4, 9, /* \_/ \_/ */
69  6, -12, /* */
70  6, -6, /* Headphones */
71  0, -11,
72  0, -5,
73  4, 0};
74 
75 typedef struct EarwaxContext {
76  int16_t filter[2][NUMTAPS];
77  int16_t taps[4][NUMTAPS * 2];
78 
81 
82 static int query_formats(const AVFilterContext *ctx,
83  AVFilterFormatsConfig **cfg_in,
84  AVFilterFormatsConfig **cfg_out)
85 {
86  static const enum AVSampleFormat formats[] = {
89  };
90  static const AVChannelLayout layouts[] = {
92  { .nb_channels = 0 },
93  };
94  static const int sample_rates[] = { 44100, -1 };
95 
96  int ret;
97 
98  ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats);
99  if (ret < 0)
100  return ret;
101 
103  if (ret < 0)
104  return ret;
105 
107  if (ret < 0)
108  return ret;
109 
110  return 0;
111 }
112 
113 //FIXME: replace with DSPContext.scalarproduct_int16
114 static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin,
115  const int16_t *filt, int16_t *out)
116 {
117  int32_t sample;
118  int16_t j;
119 
120  while (in < endin) {
121  sample = 0;
122  for (j = 0; j < NUMTAPS; j++)
123  sample += in[j] * filt[j];
124  *out = av_clip_int16(sample >> 7);
125  out++;
126  in++;
127  }
128 
129  return out;
130 }
131 
133 {
134  EarwaxContext *s = inlink->dst->priv;
135 
136  for (int i = 0; i < NUMTAPS; i++) {
137  s->filter[0][i] = filt[i * 2];
138  s->filter[1][i] = filt[i * 2 + 1];
139  }
140 
141  return 0;
142 }
143 
145  int input_ch, int output_ch,
146  int filter_ch, int tap_ch)
147 {
148  EarwaxContext *s = ctx->priv;
149  int16_t *taps, *endin, *dst, *src;
150  int len;
151 
152  taps = s->taps[tap_ch];
153  dst = (int16_t *)s->frame[input_ch]->data[output_ch];
154  src = (int16_t *)in->data[input_ch];
155 
156  len = FFMIN(NUMTAPS, in->nb_samples);
157  // copy part of new input and process with saved input
158  memcpy(taps+NUMTAPS, src, len * sizeof(*taps));
159  dst = scalarproduct(taps, taps + len, s->filter[filter_ch], dst);
160 
161  // process current input
162  if (in->nb_samples >= NUMTAPS) {
163  endin = src + in->nb_samples - NUMTAPS;
164  scalarproduct(src, endin, s->filter[filter_ch], dst);
165 
166  // save part of input for next round
167  memcpy(taps, endin, NUMTAPS * sizeof(*taps));
168  } else {
169  memmove(taps, taps + in->nb_samples, NUMTAPS * sizeof(*taps));
170  }
171 }
172 
174  int output_ch, int f0, int f1, int i0, int i1)
175 {
176  EarwaxContext *s = ctx->priv;
177  const int16_t *srcl = (const int16_t *)s->frame[f0]->data[i0];
178  const int16_t *srcr = (const int16_t *)s->frame[f1]->data[i1];
179  int16_t *dst = (int16_t *)out->data[output_ch];
180 
181  for (int n = 0; n < out->nb_samples; n++)
182  dst[n] = av_clip_int16(srcl[n] + srcr[n]);
183 }
184 
186 {
187  AVFilterContext *ctx = inlink->dst;
188  EarwaxContext *s = ctx->priv;
189  AVFilterLink *outlink = ctx->outputs[0];
190  AVFrame *out = ff_get_audio_buffer(outlink, in->nb_samples);
191 
192  for (int ch = 0; ch < 2; ch++) {
193  if (!s->frame[ch] || s->frame[ch]->nb_samples < in->nb_samples) {
194  av_frame_free(&s->frame[ch]);
195  s->frame[ch] = ff_get_audio_buffer(outlink, in->nb_samples);
196  if (!s->frame[ch]) {
197  av_frame_free(&in);
198  av_frame_free(&out);
199  return AVERROR(ENOMEM);
200  }
201  }
202  }
203 
204  if (!out) {
205  av_frame_free(&in);
206  return AVERROR(ENOMEM);
207  }
209 
210  convolve(ctx, in, 0, 0, 0, 0);
211  convolve(ctx, in, 0, 1, 1, 1);
212  convolve(ctx, in, 1, 0, 0, 2);
213  convolve(ctx, in, 1, 1, 1, 3);
214 
215  mix(ctx, out, 0, 0, 1, 1, 0);
216  mix(ctx, out, 1, 0, 1, 0, 1);
217 
218  av_frame_free(&in);
219  return ff_filter_frame(outlink, out);
220 }
221 
223 {
224  EarwaxContext *s = ctx->priv;
225 
226  av_frame_free(&s->frame[0]);
227  av_frame_free(&s->frame[1]);
228 }
229 
230 static const AVFilterPad earwax_inputs[] = {
231  {
232  .name = "default",
233  .type = AVMEDIA_TYPE_AUDIO,
234  .filter_frame = filter_frame,
235  .config_props = config_input,
236  },
237 };
238 
240  .name = "earwax",
241  .description = NULL_IF_CONFIG_SMALL("Widen the stereo image."),
242  .priv_size = sizeof(EarwaxContext),
243  .uninit = uninit,
247 };
formats
formats
Definition: signature.h:47
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:98
ff_af_earwax
const AVFilter ff_af_earwax
Definition: af_earwax.c:239
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
out
FILE * out
Definition: movenc.c:55
AV_CHANNEL_LAYOUT_STEREO
#define AV_CHANNEL_LAYOUT_STEREO
Definition: channel_layout.h:393
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1061
layouts
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:335
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_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:162
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
sample_rates
static const int sample_rates[]
Definition: dcaenc.h:34
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
ff_set_common_channel_layouts_from_list2
int ff_set_common_channel_layouts_from_list2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, const AVChannelLayout *fmts)
Definition: formats.c:920
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
EarwaxContext::taps
int16_t taps[4][NUMTAPS *2]
Definition: af_earwax.c:77
earwax_inputs
static const AVFilterPad earwax_inputs[]
Definition: af_earwax.c:230
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:410
formats.h
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
av_cold
#define av_cold
Definition: attributes.h:90
scalarproduct
static int16_t * scalarproduct(const int16_t *in, const int16_t *endin, const int16_t *filt, int16_t *out)
Definition: af_earwax.c:114
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
filters.h
ff_set_common_samplerates_from_list2
int ff_set_common_samplerates_from_list2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, const int *samplerates)
Definition: formats.c:944
ctx
AVFormatContext * ctx
Definition: movenc.c:49
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
av_clip_int16
#define av_clip_int16
Definition: common.h:115
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:725
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: af_earwax.c:185
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_earwax.c:222
ff_audio_default_filterpad
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
Definition: audio.c:34
NUMTAPS
#define NUMTAPS
Definition: af_earwax.c:38
AVFilterFormatsConfig
Lists of formats / etc.
Definition: avfilter.h:111
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:94
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:317
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
EarwaxContext::frame
AVFrame * frame[2]
Definition: af_earwax.c:79
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_earwax.c:132
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:56
sample
#define sample
Definition: flacdsp_template.c:44
AV_SAMPLE_FMT_S16P
@ AV_SAMPLE_FMT_S16P
signed 16 bits, planar
Definition: samplefmt.h:64
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:469
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:55
FILTER_QUERY_FUNC2
#define FILTER_QUERY_FUNC2(func)
Definition: filters.h:239
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
query_formats
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition: af_earwax.c:82
len
int len
Definition: vorbis_enc_data.h:426
filt
static const int8_t filt[NUMTAPS *2]
Definition: af_earwax.c:40
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
mix
static void mix(AVFilterContext *ctx, AVFrame *out, int output_ch, int f0, int f1, int i0, int i1)
Definition: af_earwax.c:173
AVFilter
Filter definition.
Definition: avfilter.h:201
ret
ret
Definition: filter_design.txt:187
ff_set_common_formats_from_list2
int ff_set_common_formats_from_list2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, const int *fmts)
Definition: formats.c:1016
channel_layout.h
EarwaxContext
Definition: af_earwax.c:75
avfilter.h
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
audio.h
convolve
static void convolve(AVFilterContext *ctx, AVFrame *in, int input_ch, int output_ch, int filter_ch, int tap_ch)
Definition: af_earwax.c:144
int32_t
int32_t
Definition: audioconvert.c:56
EarwaxContext::filter
int16_t filter[2][NUMTAPS]
Definition: af_earwax.c:76
src
#define src
Definition: vp8dsp.c:248