#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/float_dsp.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"
typedef struct MixContext {
const AVClass *class; /**< class for AVOptions */
+ AVFloatDSPContext fdsp;
int nb_inputs; /**< number of inputs */
int active_inputs; /**< number of input currently active */
int nb_channels; /**< number of channels */
int sample_rate; /**< sample rate */
+ int planar;
AVAudioFifo **fifos; /**< audio fifo for each input */
uint8_t *input_state; /**< current state of each input */
float *input_scale; /**< mixing scale factor for each input */
int i;
char buf[64];
+ s->planar = av_sample_fmt_is_planar(outlink->format);
s->sample_rate = outlink->sample_rate;
outlink->time_base = (AVRational){ 1, outlink->sample_rate };
s->next_pts = AV_NOPTS_VALUE;
av_get_channel_layout_string(buf, sizeof(buf), -1, outlink->channel_layout);
av_log(ctx, AV_LOG_VERBOSE,
- "inputs:%d fmt:%s srate:%"PRId64" cl:%s\n", s->nb_inputs,
+ "inputs:%d fmt:%s srate:%d cl:%s\n", s->nb_inputs,
av_get_sample_fmt_name(outlink->format), outlink->sample_rate, buf);
return 0;
}
-/* TODO: move optimized version from DSPContext to libavutil */
-static void vector_fmac_scalar(float *dst, const float *src, float mul, int len)
-{
- int i;
- for (i = 0; i < len; i++)
- dst[i] += src[i] * mul;
-}
-
/**
* Read samples from the input FIFOs, mix, and write to the output link.
*/
for (i = 0; i < s->nb_inputs; i++) {
if (s->input_state[i] == INPUT_ON) {
+ int planes, plane_size, p;
+
av_audio_fifo_read(s->fifos[i], (void **)in_buf->extended_data,
nb_samples);
- vector_fmac_scalar((float *)out_buf->extended_data[0],
- (float *) in_buf->extended_data[0],
- s->input_scale[i], nb_samples * s->nb_channels);
+
+ planes = s->planar ? s->nb_channels : 1;
+ plane_size = nb_samples * (s->planar ? 1 : s->nb_channels);
+ plane_size = FFALIGN(plane_size, 16);
+
+ for (p = 0; p < planes; p++) {
+ s->fdsp.vector_fmac_scalar((float *)out_buf->extended_data[p],
+ (float *) in_buf->extended_data[p],
+ s->input_scale[i], plane_size);
+ }
}
}
avfilter_unref_buffer(in_buf);
if (s->next_pts != AV_NOPTS_VALUE)
s->next_pts += nb_samples;
- ff_filter_samples(outlink, out_buf);
-
- return 0;
+ return ff_filter_samples(outlink, out_buf);
}
/**
if (s->input_state[i] == INPUT_OFF)
continue;
while (!ret && av_audio_fifo_size(s->fifos[i]) < min_samples)
- ret = avfilter_request_frame(ctx->inputs[i]);
+ ret = ff_request_frame(ctx->inputs[i]);
if (ret == AVERROR_EOF) {
if (av_audio_fifo_size(s->fifos[i]) == 0) {
s->input_state[i] = INPUT_OFF;
continue;
}
- } else if (ret)
+ } else if (ret < 0)
return ret;
}
return 0;
available_samples = get_available_samples(s);
if (!available_samples)
- return 0;
+ return AVERROR(EAGAIN);
return output_frame(outlink, available_samples);
}
if (s->frame_list->nb_frames == 0) {
- ret = avfilter_request_frame(ctx->inputs[0]);
+ ret = ff_request_frame(ctx->inputs[0]);
if (ret == AVERROR_EOF) {
s->input_state[0] = INPUT_OFF;
if (s->nb_inputs == 1)
return AVERROR_EOF;
else
return AVERROR(EAGAIN);
- } else if (ret)
+ } else if (ret < 0)
return ret;
}
av_assert0(s->frame_list->nb_frames > 0);
ret = calc_active_inputs(s);
if (ret < 0)
return ret;
+ }
+ if (s->active_inputs > 1) {
available_samples = get_available_samples(s);
if (!available_samples)
- return 0;
+ return AVERROR(EAGAIN);
available_samples = FFMIN(available_samples, wanted_samples);
} else {
available_samples = wanted_samples;
return output_frame(outlink, available_samples);
}
-static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
{
AVFilterContext *ctx = inlink->dst;
MixContext *s = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0];
- int i;
+ int i, ret = 0;
- for (i = 0; i < ctx->input_count; i++)
+ for (i = 0; i < ctx->nb_inputs; i++)
if (ctx->inputs[i] == inlink)
break;
- if (i >= ctx->input_count) {
+ if (i >= ctx->nb_inputs) {
av_log(ctx, AV_LOG_ERROR, "unknown input link\n");
- return;
+ ret = AVERROR(EINVAL);
+ goto fail;
}
if (i == 0) {
int64_t pts = av_rescale_q(buf->pts, inlink->time_base,
outlink->time_base);
- frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts);
+ ret = frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts);
+ if (ret < 0)
+ goto fail;
}
- av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data,
- buf->audio->nb_samples);
+ ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data,
+ buf->audio->nb_samples);
+fail:
avfilter_unref_buffer(buf);
+
+ return ret;
}
-static int init(AVFilterContext *ctx, const char *args, void *opaque)
+static int init(AVFilterContext *ctx, const char *args)
{
MixContext *s = ctx->priv;
int i, ret;
pad.name = av_strdup(name);
pad.filter_samples = filter_samples;
- avfilter_insert_inpad(ctx, i, &pad);
+ ff_insert_inpad(ctx, i, &pad);
}
+ avpriv_float_dsp_init(&s->fdsp, 0);
+
return 0;
}
av_freep(&s->input_state);
av_freep(&s->input_scale);
- for (i = 0; i < ctx->input_count; i++)
+ for (i = 0; i < ctx->nb_inputs; i++)
av_freep(&ctx->input_pads[i].name);
}
static int query_formats(AVFilterContext *ctx)
{
AVFilterFormats *formats = NULL;
- avfilter_add_format(&formats, AV_SAMPLE_FMT_FLT);
- avfilter_set_common_formats(ctx, formats);
+ ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
+ ff_add_format(&formats, AV_SAMPLE_FMT_FLTP);
+ ff_set_common_formats(ctx, formats);
ff_set_common_channel_layouts(ctx, ff_all_channel_layouts());
ff_set_common_samplerates(ctx, ff_all_samplerates());
return 0;