On Fri, Jan 30, 2015 at 10:17:59AM +0000, Paul B Mahol wrote: > Signed-off-by: Paul B Mahol <one...@gmail.com> > --- > doc/filters.texi | 19 ++++++ > libavfilter/Makefile | 1 + > libavfilter/af_dcshift.c | 161 > +++++++++++++++++++++++++++++++++++++++++++++++ > libavfilter/allfilters.c | 1 + > 4 files changed, 182 insertions(+) > create mode 100644 libavfilter/af_dcshift.c > > diff --git a/doc/filters.texi b/doc/filters.texi > index cba2697..27a745f 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -917,6 +917,7 @@ audio, the data is treated as if all the planes were > concatenated. > A list of Adler-32 checksums for each data plane. > @end table > > +@anchor{astats} > @section astats > > Display time domain statistical information about the audio channels. > @@ -1394,6 +1395,24 @@ > compand=.1|.1:.1|.1:-45.1/-45.1|-45/-900|0/-900:.01:45:-90:.1 > @end example > @end itemize > > +@section dcshift > +Apply a DC shift to the audio. > + > +This can be useful to remove a DC offset (caused perhaps by a hardware > problem > +in the recording chain) from the audio. The effect of a DC offset is reduced > +headroom and hence volume. The @ref{astats} filter can be used to determine > if > +a signal has a DC offset. > + > +@table @option > +@item shift > +Set the DC shift, allowed range is [-1, 1]. It indicates the amount to shift > +the audio. > + > +@item limitergain > +Optional. It should have a value much less than 1 (e.g. 0.05 or 0.02) and is > +used to prevent clipping. > +@end table > + > @section earwax > > Make audio easier to listen to on headphones. > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 7e0d456..60072f9 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -65,6 +65,7 @@ OBJS-$(CONFIG_BS2B_FILTER) += af_bs2b.o > OBJS-$(CONFIG_CHANNELMAP_FILTER) += af_channelmap.o > OBJS-$(CONFIG_CHANNELSPLIT_FILTER) += af_channelsplit.o > OBJS-$(CONFIG_COMPAND_FILTER) += af_compand.o > +OBJS-$(CONFIG_DCSHIFT_FILTER) += af_dcshift.o > OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o > OBJS-$(CONFIG_EBUR128_FILTER) += f_ebur128.o > OBJS-$(CONFIG_EQUALIZER_FILTER) += af_biquads.o > diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c > new file mode 100644 > index 0000000..25fc66a > --- /dev/null > +++ b/libavfilter/af_dcshift.c > @@ -0,0 +1,161 @@ > +/* > + * 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/opt.h" > +#include "libavutil/samplefmt.h" > +#include "avfilter.h" > +#include "audio.h" > +#include "internal.h" > + > +typedef struct DCShiftContext { > + const AVClass *class; > + double dcshift; > + double limiterthreshhold; > + double limitergain; > +} DCShiftContext; > + > +#define OFFSET(x) offsetof(DCShiftContext, x) > +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM > + > +static const AVOption dcshift_options[] = { > + { "shift", "set DC shift", OFFSET(dcshift), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, A }, > + { "limitergain", "set limiter gain", OFFSET(limitergain), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, A }, > + { NULL } > +}; > + > +AVFILTER_DEFINE_CLASS(dcshift); > + > +static av_cold int init(AVFilterContext *ctx) > +{ > + DCShiftContext *s = ctx->priv; > + > + s->limiterthreshhold = INT32_MAX * (1.0 - (fabs(s->dcshift) - > s->limitergain)); > + > + return 0; > +} > + > +static int query_formats(AVFilterContext *ctx) > +{ > + AVFilterChannelLayouts *layouts; > + AVFilterFormats *formats; > + static const enum AVSampleFormat sample_fmts[] = { > + AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE > + }; > + > + layouts = ff_all_channel_layouts(); > + if (!layouts) > + return AVERROR(ENOMEM); > + ff_set_common_channel_layouts(ctx, layouts); > + > + formats = ff_make_format_list(sample_fmts); > + if (!formats) > + return AVERROR(ENOMEM); > + ff_set_common_formats(ctx, formats); > + > + formats = ff_all_samplerates(); > + if (!formats) > + return AVERROR(ENOMEM); > + ff_set_common_samplerates(ctx, formats); > + > + return 0; > +} > + > +static int filter_frame(AVFilterLink *inlink, AVFrame *in) > +{ > + AVFilterContext *ctx = inlink->dst; > + AVFilterLink *outlink = ctx->outputs[0]; > + AVFrame *out = ff_get_audio_buffer(inlink, in->nb_samples); > + DCShiftContext *s = ctx->priv; > + int i, j; > + double dcshift = s->dcshift; > + > + if (!out) { > + av_frame_free(&in); > + return AVERROR(ENOMEM); > + } > + av_frame_copy_props(out, in); > + > + if (s->limitergain > 0) { > + for (i = 0; i < inlink->channels; i++) { > + const int32_t *src = (int32_t *)in->extended_data[i]; > + int32_t *dst = (int32_t *)out->extended_data[i]; > + > + for (j = 0; j < in->nb_samples; j++) { > + double d; > + > + d = src[j]; > + > + if (d > s->limiterthreshhold && dcshift > 0) { > + d = (d - s->limiterthreshhold) * s->limitergain / > + (INT32_MAX - s->limiterthreshhold) + > + s->limiterthreshhold + dcshift; > + } else if (d < -s->limiterthreshhold && dcshift < 0) { > + d = (d + s->limiterthreshhold) * s->limitergain / > + (INT32_MAX - s->limiterthreshhold) - > + s->limiterthreshhold + dcshift; > + } else { > + d = dcshift * INT32_MAX + d; > + } > + > + dst[j] = av_clipl_int32_c(d); > + } > + } > + } else { > + for (i = 0; i < inlink->channels; i++) { > + const int32_t *src = (int32_t *)in->extended_data[i]; > + int32_t *dst = (int32_t *)out->extended_data[i]; > + > + for (j = 0; j < in->nb_samples; j++) { > + double d = dcshift * (INT32_MAX + 1.) + src[j]; > + > + dst[j] = av_clipl_int32_c(d);
i think this should use some rounding function like llrint() ? though with 32bit precission it probably doesnt really matter much [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB No human being will ever know the Truth, for even if they happen to say it by chance, they would not even known they had done so. -- Xenophanes
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel