[FFmpeg-devel] [PATCH] af_mix: mix two audio streams
Clément Bœsch
ubitux at gmail.com
Wed Dec 14 08:17:25 CET 2011
On Tue, Dec 13, 2011 at 04:57:15PM +0100, Matthieu Bouron wrote:
> Hi there,
>
> Here is a first attempt to write an audio filter which merge two audio streams.
> Usage is:
> ffplay -f lavfi "amovie=test1.mp3[a];amovie=test2.mp3[b];[a][b]mix=0.7:0.3[out]"
>
> The volume of each streams can be configured and default to 0.5:0.5 is
> not specified. It only support two s16 audio streams with same sample
> rate.
> Feel free to comment.
>
> Matthieu
> From 78537e1c874d62b42b58de8da210dde28eb17859 Mon Sep 17 00:00:00 2001
> From: Matthieu Bouron <matthieu.bouron at gmail.com>
> Date: Sat, 10 Dec 2011 12:31:32 +0100
> Subject: [PATCH] af_mix: mix two audio streams.
>
> ---
> libavfilter/Makefile | 1 +
> libavfilter/af_mix.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++
> libavfilter/allfilters.c | 1 +
> 3 files changed, 225 insertions(+), 0 deletions(-)
> create mode 100644 libavfilter/af_mix.c
>
You will need to bump lavfi minor version, and ideally add a Changelog
entry and document it in doc/filters.texi.
[...]
> +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> +{
> + int i, n;
> + double vol1, vol2;
> + MixContext *mix = ctx->priv;
> +
> + if (args) {
> + n = sscanf(args, "%lf:%lf", &vol1, &vol2);
> + switch (n) {
> + case 0:
> + mix->vol[0] = 0.5;
> + mix->vol[1] = 0.5;
> + break;
> + case 1:
> + mix->vol[0] = vol1;
> + mix->vol[1] = 0.5;
> + break;
> + case 2:
> + mix->vol[0] = vol1;
> + mix->vol[1] = vol2;
> + break;
> + default:
> + av_log(ctx, AV_LOG_ERROR, "sscanf error");
> + return 1;
nit: you should remove one level of indent in the switch. Also, the error
isn't very explicit...
> + }
> + for (i = 0; i < 2; i++) {
> + mix->vol_i[i] = (int)(mix->vol[i] * 256 + 0.5);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> + int i;
> + MixContext *mix = ctx->priv;
> + AVFilterFormats *formats = NULL;
> + enum AVSampleFormat sample_fmts[] = {
> + AV_SAMPLE_FMT_S16,
> + AV_SAMPLE_FMT_NONE
> + };
> + int packing_fmts[] = { AVFILTER_PACKED, -1 };
sample_fmts and packing_fmts could be const.
> + int layout_fmts[] = {0, -1};
> +
[...]
> + if (insamples->format == AV_SAMPLE_FMT_S16) {
> + int16_t *in1 = NULL;
> + int16_t *in2 = NULL;
> + int16_t *out = NULL;
> +
> + if (!mix->ended[0])
> + in1 = (int16_t*)mix->buf[0]->data[0];
> + if (!mix->ended[1])
> + in2 = (int16_t*)mix->buf[1]->data[0];
> + out = (int16_t*)outsamples->data[0];
> +
> + for (i = 0; i < nb_samples; i++) {
> + int64_t v1 = 0;
> + int64_t v2 = 0;
> + if (!mix->ended[0])
> + v1 = (((int64_t)*in1++ * mix->vol_i[0] + 128) >> 8);
> + if (!mix->ended[1])
> + v2 = (((int64_t)*in2++ * mix->vol_i[1] + 128) >> 8);
> + *out++ = av_clip_int16((v1 + v2) / 2);
Since your volumes are by default 0.5, is the /2 really needed here?
> + }
> +
> + for (i = 0; i < 2; i++) {
> + if (!mix->ended[i]) {
> + mix->buf_pos[i] += nb_samples;
> + if (mix->buf_pos[i] == nb_samples) {
> + avfilter_unref_buffer(mix->buf[i]);
> + mix->buf[i] = 0;
> + }
> + }
> + }
> + }
> +
> + avfilter_filter_samples(outlink, outsamples);
> +}
> +
> +static int request_frame(AVFilterLink *outlink)
> +{
> + AVFilterContext *ctx = outlink->src;
> + MixContext *mix = ctx->priv;
> + int i;
> +
> + for (i = 0; i < 2; i++)
> + if (avfilter_request_frame(ctx->inputs[i]) != 0) {
> + mix->ended[i] = 1;
> + }
nit: the for without { } looks weird here, but it's at your own
discretion.
> + return 0;
> +}
> +
> +AVFilter avfilter_af_mix = {
> + .name = "mix",
> + .description = NULL_IF_CONFIG_SMALL("Mix two audio streams."),
Superfluous period
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20111214/9fdf1f7e/attachment.asc>
More information about the ffmpeg-devel
mailing list