1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-02 03:06:28 +02:00
FFmpeg/libavfilter/af_earwax.c
Michael Niedermayer f8911b987d Merge remote-tracking branch 'qatar/master'
* qatar/master:
  mss3: use standard zigzag table
  mss3: split DSP functions that are used in MTS2(MSS4) into separate file
  motion-test: do not use getopt()
  tcp: add initial timeout limit for incoming connections
  configure: Change the rdtsc check to a linker check
  avconv: propagate fatal errors from lavfi.
  lavfi: add error handling to filter_samples().
  fate-run: make avconv() properly deal with multiple inputs.
  asplit: don't leak the input buffer.
  af_resample: fix request_frame() behavior.
  af_asyncts: fix request_frame() behavior.
  libx264: support aspect ratio switching
  matroskadec: honor error_recognition when encountering unknown elements.
  lavr: resampling: add support for s32p, fltp, and dblp internal sample formats
  lavr: resampling: add filter type and Kaiser window beta to AVOptions
  lavr: Use AV_SAMPLE_FMT_NONE to auto-select the internal sample format
  lavr: mix: validate internal sample format in ff_audio_mix_init()

Conflicts:
	ffmpeg.c
	ffplay.c
	libavcodec/libx264.c
	libavfilter/audio.c
	libavfilter/split.c
	libavformat/tcp.c
	tests/fate-run.sh

Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-07-09 22:40:12 +02:00

170 lines
6.4 KiB
C

/*
* Copyright (c) 2011 Mina Nagy Zaki
* Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
* This source code is freely redistributable and may be used for any purpose.
* This copyright notice must be maintained. Edward Beingessner And Sundry
* Contributors are not responsible for the consequences of using this
* software.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Stereo Widening Effect. Adds audio cues to move stereo image in
* front of the listener. Adapted from the libsox earwax effect.
*/
#include "libavutil/audioconvert.h"
#include "avfilter.h"
#include "audio.h"
#include "formats.h"
#define NUMTAPS 64
static const int8_t filt[NUMTAPS] = {
/* 30° 330° */
4, -6, /* 32 tap stereo FIR filter. */
4, -11, /* One side filters as if the */
-1, -5, /* signal was from 30 degrees */
3, 3, /* from the ear, the other as */
-2, 5, /* if 330 degrees. */
-5, 0,
9, 1,
6, 3, /* Input */
-4, -1, /* Left Right */
-5, -3, /* __________ __________ */
-2, -5, /* | | | | */
-7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */
6, -7, /* / |__________| |__________| \ */
30, -29, /* / \ / \ */
12, -3, /* / X \ */
-11, 4, /* / / \ \ */
-3, 7, /* ____V_____ __________V V__________ _____V____ */
-20, 23, /* | | | | | | | | */
2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */
1, -6, /* |__________| |__________| |__________| |__________| */
-14, -5, /* \ ___ / \ ___ / */
15, -18, /* \ / \ / _____ \ / \ / */
6, 7, /* `->| + |<--' / \ `-->| + |<-' */
15, -10, /* \___/ _/ \_ \___/ */
-14, 22, /* \ / \ / \ / */
-7, -2, /* `--->| | | |<---' */
-4, 9, /* \_/ \_/ */
6, -12, /* */
6, -6, /* Headphones */
0, -11,
0, -5,
4, 0};
typedef struct {
int16_t taps[NUMTAPS * 2];
} EarwaxContext;
static int query_formats(AVFilterContext *ctx)
{
int sample_rates[] = { 44100, -1 };
AVFilterFormats *formats = NULL;
AVFilterChannelLayouts *layout = NULL;
ff_add_format(&formats, AV_SAMPLE_FMT_S16);
ff_set_common_formats(ctx, formats);
ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
ff_set_common_channel_layouts(ctx, layout);
ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
return 0;
}
static int config_input(AVFilterLink *inlink)
{
if (inlink->sample_rate != 44100) {
av_log(inlink->dst, AV_LOG_ERROR,
"The earwax filter only works for 44.1kHz audio. Insert "
"a resample filter before this\n");
return AVERROR(EINVAL);
}
return 0;
}
//FIXME: replace with DSPContext.scalarproduct_int16
static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, int16_t *out)
{
int32_t sample;
int16_t j;
while (in < endin) {
sample = 32;
for (j = 0; j < NUMTAPS; j++)
sample += in[j] * filt[j];
*out = sample >> 6;
out++;
in++;
}
return out;
}
static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
{
AVFilterLink *outlink = inlink->dst->outputs[0];
int16_t *taps, *endin, *in, *out;
AVFilterBufferRef *outsamples =
ff_get_audio_buffer(inlink, AV_PERM_WRITE,
insamples->audio->nb_samples);
int ret;
avfilter_copy_buffer_ref_props(outsamples, insamples);
taps = ((EarwaxContext *)inlink->dst->priv)->taps;
out = (int16_t *)outsamples->data[0];
in = (int16_t *)insamples ->data[0];
// copy part of new input and process with saved input
memcpy(taps+NUMTAPS, in, NUMTAPS * sizeof(*taps));
out = scalarproduct(taps, taps + NUMTAPS, out);
// process current input
endin = in + insamples->audio->nb_samples * 2 - NUMTAPS;
out = scalarproduct(in, endin, out);
// save part of input for next round
memcpy(taps, endin, NUMTAPS * sizeof(*taps));
ret = ff_filter_samples(outlink, outsamples);
avfilter_unref_buffer(insamples);
return ret;
}
AVFilter avfilter_af_earwax = {
.name = "earwax",
.description = NULL_IF_CONFIG_SMALL("Widen the stereo image."),
.query_formats = query_formats,
.priv_size = sizeof(EarwaxContext),
.inputs = (const AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_samples = filter_samples,
.config_props = config_input,
.min_perms = AV_PERM_READ, },
{ .name = NULL}},
.outputs = (const AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO, },
{ .name = NULL}},
};