summaryrefslogtreecommitdiff
path: root/libavfilter/af_compand.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavfilter/af_compand.c')
-rw-r--r--libavfilter/af_compand.c160
1 files changed, 66 insertions, 94 deletions
diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c
index f21c861e06..55ad98a15d 100644
--- a/libavfilter/af_compand.c
+++ b/libavfilter/af_compand.c
@@ -5,20 +5,20 @@
* Copyright (c) 2013 Paul B Mahol
* Copyright (c) 2014 Andrew Kelley
*
- * This file is part of libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,39 +27,33 @@
* audio compand filter
*/
-#include <string.h>
-
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/common.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/mem.h"
#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
#include "audio.h"
#include "avfilter.h"
-#include "formats.h"
#include "internal.h"
typedef struct ChanParam {
- float attack;
- float decay;
- float volume;
+ double attack;
+ double decay;
+ double volume;
} ChanParam;
typedef struct CompandSegment {
- float x, y;
- float a, b;
+ double x, y;
+ double a, b;
} CompandSegment;
typedef struct CompandContext {
const AVClass *class;
- int nb_channels;
int nb_segments;
char *attacks, *decays, *points;
CompandSegment *segments;
ChanParam *channels;
- float in_min_lin;
- float out_min_lin;
+ double in_min_lin;
+ double out_min_lin;
double curve_dB;
double gain_dB;
double initial_volume;
@@ -71,12 +65,10 @@ typedef struct CompandContext {
int64_t pts;
int (*compand)(AVFilterContext *ctx, AVFrame *frame);
- /* set by filter_frame() to signal an output frame to request_frame() */
- int got_output;
} CompandContext;
#define OFFSET(x) offsetof(CompandContext, x)
-#define A AV_OPT_FLAG_AUDIO_PARAM
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption compand_options[] = {
{ "attacks", "set time over which increase of volume is determined", OFFSET(attacks), AV_OPT_TYPE_STRING, { .str = "0.3" }, 0, 0, A },
@@ -89,12 +81,7 @@ static const AVOption compand_options[] = {
{ NULL }
};
-static const AVClass compand_class = {
- .class_name = "compand filter",
- .item_name = av_default_item_name,
- .option = compand_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(compand);
static av_cold int init(AVFilterContext *ctx)
{
@@ -117,26 +104,29 @@ static int query_formats(AVFilterContext *ctx)
AVFilterChannelLayouts *layouts;
AVFilterFormats *formats;
static const enum AVSampleFormat sample_fmts[] = {
- AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_DBLP,
AV_SAMPLE_FMT_NONE
};
+ int ret;
layouts = ff_all_channel_layouts();
if (!layouts)
return AVERROR(ENOMEM);
- ff_set_common_channel_layouts(ctx, layouts);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
formats = ff_make_format_list(sample_fmts);
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_formats(ctx, formats);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
formats = ff_all_samplerates();
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_samplerates(ctx, formats);
-
- return 0;
+ return ff_set_common_samplerates(ctx, formats);
}
static void count_items(char *item_str, int *nb_items)
@@ -145,14 +135,14 @@ static void count_items(char *item_str, int *nb_items)
*nb_items = 1;
for (p = item_str; *p; p++) {
- if (*p == '|')
+ if (*p == ' ' || *p == '|')
(*nb_items)++;
}
}
-static void update_volume(ChanParam *cp, float in)
+static void update_volume(ChanParam *cp, double in)
{
- float delta = in - cp->volume;
+ double delta = in - cp->volume;
if (delta > 0.0)
cp->volume += delta * cp->attack;
@@ -160,16 +150,16 @@ static void update_volume(ChanParam *cp, float in)
cp->volume += delta * cp->decay;
}
-static float get_volume(CompandContext *s, float in_lin)
+static double get_volume(CompandContext *s, double in_lin)
{
CompandSegment *cs;
- float in_log, out_log;
+ double in_log, out_log;
int i;
if (in_lin < s->in_min_lin)
return s->out_min_lin;
- in_log = logf(in_lin);
+ in_log = log(in_lin);
for (i = 1; i < s->nb_segments; i++)
if (in_log <= s->segments[i].x)
@@ -178,14 +168,14 @@ static float get_volume(CompandContext *s, float in_lin)
in_log -= cs->x;
out_log = cs->y + in_log * (cs->a * in_log + cs->b);
- return expf(out_log);
+ return exp(out_log);
}
static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
{
CompandContext *s = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
- const int channels = s->nb_channels;
+ const int channels = inlink->channels;
const int nb_samples = frame->nb_samples;
AVFrame *out_frame;
int chan, i;
@@ -208,14 +198,14 @@ static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
}
for (chan = 0; chan < channels; chan++) {
- const float *src = (float *)frame->extended_data[chan];
- float *dst = (float *)out_frame->extended_data[chan];
+ const double *src = (double *)frame->extended_data[chan];
+ double *dst = (double *)out_frame->extended_data[chan];
ChanParam *cp = &s->channels[chan];
for (i = 0; i < nb_samples; i++) {
update_volume(cp, fabs(src[i]));
- dst[i] = av_clipf(src[i] * get_volume(s, cp->volume), -1.0f, 1.0f);
+ dst[i] = av_clipd(src[i] * get_volume(s, cp->volume), -1, 1);
}
}
@@ -231,9 +221,9 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
{
CompandContext *s = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
- const int channels = s->nb_channels;
+ const int channels = inlink->channels;
const int nb_samples = frame->nb_samples;
- int chan, i, dindex = 0, oindex, count = 0;
+ int chan, i, av_uninit(dindex), oindex, av_uninit(count);
AVFrame *out_frame = NULL;
int err;
@@ -241,17 +231,19 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
s->pts = (frame->pts == AV_NOPTS_VALUE) ? 0 : frame->pts;
}
+ av_assert1(channels > 0); /* would corrupt delay_count and delay_index */
+
for (chan = 0; chan < channels; chan++) {
AVFrame *delay_frame = s->delay_frame;
- const float *src = (float *)frame->extended_data[chan];
- float *dbuf = (float *)delay_frame->extended_data[chan];
+ const double *src = (double *)frame->extended_data[chan];
+ double *dbuf = (double *)delay_frame->extended_data[chan];
ChanParam *cp = &s->channels[chan];
- float *dst;
+ double *dst;
count = s->delay_count;
dindex = s->delay_index;
for (i = 0, oindex = 0; i < nb_samples; i++) {
- const float in = src[i];
+ const double in = src[i];
update_volume(cp, fabs(in));
if (count >= s->delay_samples) {
@@ -273,9 +265,9 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
inlink->time_base);
}
- dst = (float *)out_frame->extended_data[chan];
- dst[oindex++] = av_clipf(dbuf[dindex] *
- get_volume(s, cp->volume), -1.0f, 1.0f);
+ dst = (double *)out_frame->extended_data[chan];
+ dst[oindex++] = av_clipd(dbuf[dindex] *
+ get_volume(s, cp->volume), -1, 1);
} else {
count++;
}
@@ -292,8 +284,6 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
if (out_frame) {
err = ff_filter_frame(ctx->outputs[0], out_frame);
- if (err >= 0)
- s->got_output = 1;
return err;
}
@@ -304,7 +294,7 @@ static int compand_drain(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
CompandContext *s = ctx->priv;
- const int channels = s->nb_channels;
+ const int channels = outlink->channels;
AVFrame *frame = NULL;
int chan, i, dindex;
@@ -316,16 +306,17 @@ static int compand_drain(AVFilterLink *outlink)
s->pts += av_rescale_q(frame->nb_samples,
(AVRational){ 1, outlink->sample_rate }, outlink->time_base);
+ av_assert0(channels > 0);
for (chan = 0; chan < channels; chan++) {
AVFrame *delay_frame = s->delay_frame;
- float *dbuf = (float *)delay_frame->extended_data[chan];
- float *dst = (float *)frame->extended_data[chan];
+ double *dbuf = (double *)delay_frame->extended_data[chan];
+ double *dst = (double *)frame->extended_data[chan];
ChanParam *cp = &s->channels[chan];
dindex = s->delay_index;
for (i = 0; i < frame->nb_samples; i++) {
- dst[i] = av_clipf(dbuf[dindex] * get_volume(s, cp->volume),
- -1.0f, 1.0f);
+ dst[i] = av_clipd(dbuf[dindex] * get_volume(s, cp->volume),
+ -1, 1);
dindex = MOD(dindex + 1, s->delay_samples);
}
}
@@ -341,9 +332,8 @@ static int config_output(AVFilterLink *outlink)
CompandContext *s = ctx->priv;
const int sample_rate = outlink->sample_rate;
double radius = s->curve_dB * M_LN10 / 20.0;
- const char *p;
- const int channels =
- av_get_channel_layout_nb_channels(outlink->channel_layout);
+ char *p, *saveptr = NULL;
+ const int channels = outlink->channels;
int nb_attacks, nb_decays, nb_points;
int new_nb_items, num;
int i;
@@ -367,7 +357,6 @@ static int config_output(AVFilterLink *outlink)
uninit(ctx);
- s->nb_channels = channels;
s->channels = av_mallocz_array(channels, sizeof(*s->channels));
s->nb_segments = (nb_points + 4) * 2;
s->segments = av_mallocz_array(s->nb_segments, sizeof(*s->segments));
@@ -379,34 +368,25 @@ static int config_output(AVFilterLink *outlink)
p = s->attacks;
for (i = 0, new_nb_items = 0; i < nb_attacks; i++) {
- char *tstr = av_get_token(&p, "|");
- if (!tstr)
- return AVERROR(ENOMEM);
-
- new_nb_items += sscanf(tstr, "%f", &s->channels[i].attack) == 1;
- av_freep(&tstr);
+ char *tstr = av_strtok(p, " |", &saveptr);
+ p = NULL;
+ new_nb_items += sscanf(tstr, "%lf", &s->channels[i].attack) == 1;
if (s->channels[i].attack < 0) {
uninit(ctx);
return AVERROR(EINVAL);
}
- if (*p)
- p++;
}
nb_attacks = new_nb_items;
p = s->decays;
for (i = 0, new_nb_items = 0; i < nb_decays; i++) {
- char *tstr = av_get_token(&p, "|");
- if (!tstr)
- return AVERROR(ENOMEM);
- new_nb_items += sscanf(tstr, "%f", &s->channels[i].decay) == 1;
- av_freep(&tstr);
+ char *tstr = av_strtok(p, " |", &saveptr);
+ p = NULL;
+ new_nb_items += sscanf(tstr, "%lf", &s->channels[i].decay) == 1;
if (s->channels[i].decay < 0) {
uninit(ctx);
return AVERROR(EINVAL);
}
- if (*p)
- p++;
}
nb_decays = new_nb_items;
@@ -421,13 +401,9 @@ static int config_output(AVFilterLink *outlink)
#define S(x) s->segments[2 * ((x) + 1)]
p = s->points;
for (i = 0, new_nb_items = 0; i < nb_points; i++) {
- char *tstr = av_get_token(&p, "|");
- if (!tstr)
- return AVERROR(ENOMEM);
-
- err = sscanf(tstr, "%f/%f", &S(i).x, &S(i).y);
- av_freep(&tstr);
- if (err != 2) {
+ char *tstr = av_strtok(p, " |", &saveptr);
+ p = NULL;
+ if (sscanf(tstr, "%lf/%lf", &S(i).x, &S(i).y) != 2) {
av_log(ctx, AV_LOG_ERROR,
"Invalid and/or missing input/output value.\n");
uninit(ctx);
@@ -442,8 +418,6 @@ static int config_output(AVFilterLink *outlink)
S(i).y -= S(i).x;
av_log(ctx, AV_LOG_DEBUG, "%d: x=%f y=%f\n", i, S(i).x, S(i).y);
new_nb_items++;
- if (*p)
- p++;
}
num = new_nb_items;
@@ -464,7 +438,6 @@ static int config_output(AVFilterLink *outlink)
double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x);
int j;
- /* here we purposefully lose precision so that we can compare floats */
if (fabs(g1 - g2))
continue;
num--;
@@ -553,6 +526,7 @@ static int config_output(AVFilterLink *outlink)
if (err)
return err;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
s->compand = compand_delay;
return 0;
}
@@ -571,11 +545,9 @@ static int request_frame(AVFilterLink *outlink)
CompandContext *s = ctx->priv;
int ret = 0;
- s->got_output = 0;
- while (ret >= 0 && !s->got_output)
- ret = ff_request_frame(ctx->inputs[0]);
+ ret = ff_request_frame(ctx->inputs[0]);
- if (ret == AVERROR_EOF && s->delay_count)
+ if (ret == AVERROR_EOF && !ctx->is_disabled && s->delay_count)
ret = compand_drain(outlink);
return ret;