1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

avfilter: add stereowiden filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
Paul B Mahol 2015-09-12 04:01:18 +00:00
parent f2b1df735e
commit b0f9856616
6 changed files with 198 additions and 1 deletions

View File

@ -6,6 +6,7 @@ version <next>:
- extrastereo filter - extrastereo filter
- ocr filter - ocr filter
- alimiter filter - alimiter filter
- stereowiden filter
version 2.8: version 2.8:

View File

@ -2394,6 +2394,33 @@ silenceremove=1:5:0.02
@end example @end example
@end itemize @end itemize
@section stereowiden
This filter enhance the stereo effect by suppressing signal common to both
channels and by delaying the signal of left into right and vice versa,
thereby widening the stereo effect.
The filter accepts the following options:
@table @option
@item delay
Time in milliseconds of the delay of left signal into right and vice versa.
Default is 20 milliseconds.
@item feedback
Amount of gain in delayed signal into right and vice versa. Gives a delay
effect of left signal in right output and vice versa which gives widening
effect. Default is 0.3.
@item crossfeed
Cross feed of left into right with inverted phase. This helps in suppressing
the mono. If the value is 1 it will cancel all the signal common to both
channels. Default is 0.3.
@item drymix
Set level of input signal of original channel. Default is 0.8.
@end table
@section treble @section treble
Boost or cut treble (upper) frequencies of the audio using a two-pole Boost or cut treble (upper) frequencies of the audio using a two-pole

View File

@ -80,6 +80,7 @@ OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o
OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER) += af_sidechaincompress.o OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER) += af_sidechaincompress.o
OBJS-$(CONFIG_SILENCEDETECT_FILTER) += af_silencedetect.o OBJS-$(CONFIG_SILENCEDETECT_FILTER) += af_silencedetect.o
OBJS-$(CONFIG_SILENCEREMOVE_FILTER) += af_silenceremove.o OBJS-$(CONFIG_SILENCEREMOVE_FILTER) += af_silenceremove.o
OBJS-$(CONFIG_STEREOWIDEN_FILTER) += af_stereowiden.o
OBJS-$(CONFIG_TREBLE_FILTER) += af_biquads.o OBJS-$(CONFIG_TREBLE_FILTER) += af_biquads.o
OBJS-$(CONFIG_VOLUME_FILTER) += af_volume.o OBJS-$(CONFIG_VOLUME_FILTER) += af_volume.o
OBJS-$(CONFIG_VOLUMEDETECT_FILTER) += af_volumedetect.o OBJS-$(CONFIG_VOLUMEDETECT_FILTER) += af_volumedetect.o

View File

@ -0,0 +1,167 @@
/*
* Copyright (C) 2012 VLC authors and VideoLAN
* Author : Sukrit Sangwan < sukritsangwan at gmail dot com >
*
* 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
*/
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#include "avfilter.h"
#include "audio.h"
#include "formats.h"
typedef struct StereoWidenContext {
const AVClass *class;
float delay;
float feedback;
float crossfeed;
float drymix;
float *buffer;
float *write;
int length;
} StereoWidenContext;
#define OFFSET(x) offsetof(StereoWidenContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption stereowiden_options[] = {
{ "delay", "set delay time", OFFSET(delay), AV_OPT_TYPE_FLOAT, {.dbl=20}, 1, 100, A },
{ "feedback", "set feedback gain", OFFSET(feedback), AV_OPT_TYPE_FLOAT, {.dbl=.3}, 0, 0.9, A },
{ "crossfeed", "set cross feed", OFFSET(crossfeed), AV_OPT_TYPE_FLOAT, {.dbl=.3}, 0, 0.8, A },
{ "drymix", "set dry-mix", OFFSET(drymix), AV_OPT_TYPE_FLOAT, {.dbl=.8}, 0, 1.0, A },
{ NULL }
};
AVFILTER_DEFINE_CLASS(stereowiden);
static int query_formats(AVFilterContext *ctx)
{
AVFilterFormats *formats = NULL;
AVFilterChannelLayouts *layout = NULL;
ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
ff_set_common_formats(ctx, formats);
ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
ff_set_common_channel_layouts(ctx, layout);
formats = ff_all_samplerates();
if (!formats)
return AVERROR(ENOMEM);
return ff_set_common_samplerates(ctx, formats);
}
static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
StereoWidenContext *s = ctx->priv;
s->length = 2 * s->delay * inlink->sample_rate / 1000;
s->buffer = av_calloc(s->length, sizeof(s->buffer));
if (!s->buffer)
return AVERROR(ENOMEM);
s->write = s->buffer;
return 0;
}
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
AVFilterContext *ctx = inlink->dst;
AVFilterLink *outlink = ctx->outputs[0];
StereoWidenContext *s = ctx->priv;
const float *src = (const float *)in->data[0];
const float drymix = s->drymix;
const float crossfeed = s->crossfeed;
const float feedback = s->feedback;
AVFrame *out = NULL;
float *dst;
int n;
if (av_frame_is_writable(in)) {
out = in;
} else {
AVFrame *out = ff_get_audio_buffer(inlink, in->nb_samples);
if (!out) {
av_frame_free(&in);
return AVERROR(ENOMEM);
}
av_frame_copy_props(out, in);
}
dst = (float *)out->data[0];
for (n = 0; n < in->nb_samples; n++, src += 2, dst += 2) {
const float left = src[0], right = src[1];
float *read = s->write + 2;
if (read > s->buffer + s->length)
read = s->buffer;
dst[0] = drymix * left - crossfeed * right - feedback * read[1];
dst[1] = drymix * right - crossfeed * left - feedback * read[0];
s->write[0] = left;
s->write[1] = right;
if (s->write == s->buffer + s->length)
s->write = s->buffer;
else
s->write += 2;
}
if (out != in)
av_frame_free(&in);
return ff_filter_frame(outlink, out);
}
static av_cold void uninit(AVFilterContext *ctx)
{
StereoWidenContext *s = ctx->priv;
av_freep(&s->buffer);
}
static const AVFilterPad inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = filter_frame,
.config_props = config_input,
},
{ NULL }
};
static const AVFilterPad outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
},
{ NULL }
};
AVFilter ff_af_stereowiden = {
.name = "stereowiden",
.description = NULL_IF_CONFIG_SMALL("Apply stereo widening effect."),
.query_formats = query_formats,
.priv_size = sizeof(StereoWidenContext),
.priv_class = &stereowiden_class,
.uninit = uninit,
.inputs = inputs,
.outputs = outputs,
};

View File

@ -102,6 +102,7 @@ void avfilter_register_all(void)
REGISTER_FILTER(SIDECHAINCOMPRESS, sidechaincompress, af); REGISTER_FILTER(SIDECHAINCOMPRESS, sidechaincompress, af);
REGISTER_FILTER(SILENCEDETECT, silencedetect, af); REGISTER_FILTER(SILENCEDETECT, silencedetect, af);
REGISTER_FILTER(SILENCEREMOVE, silenceremove, af); REGISTER_FILTER(SILENCEREMOVE, silenceremove, af);
REGISTER_FILTER(STEREOWIDEN, stereowiden, af);
REGISTER_FILTER(TREBLE, treble, af); REGISTER_FILTER(TREBLE, treble, af);
REGISTER_FILTER(VOLUME, volume, af); REGISTER_FILTER(VOLUME, volume, af);
REGISTER_FILTER(VOLUMEDETECT, volumedetect, af); REGISTER_FILTER(VOLUMEDETECT, volumedetect, af);

View File

@ -30,7 +30,7 @@
#include "libavutil/version.h" #include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 6 #define LIBAVFILTER_VERSION_MAJOR 6
#define LIBAVFILTER_VERSION_MINOR 3 #define LIBAVFILTER_VERSION_MINOR 4
#define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \