On Tue, 21 Aug 2012 21:58:42 -0700, Alex Converse <alex.conve...@gmail.com> 
wrote:
> ---
>  Changelog                |    1 +
>  doc/filters.texi         |   33 ++++++++++
>  libavfilter/Makefile     |    1 +
>  libavfilter/af_alength.c |  161 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  libavfilter/allfilters.c |    1 +
>  5 files changed, 197 insertions(+), 0 deletions(-)
>  create mode 100644 libavfilter/af_alength.c
> 
> diff --git a/Changelog b/Changelog
> index 4326c68..c94b28a 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -44,6 +44,7 @@ version <next>:
>  - Canopus Lossless Codec decoder
>  - avconv -shortest option is now per-output file
>  - Ut Video encoder
> +- alength audio filter
>  
>  
>  version 0.8:
> diff --git a/doc/filters.texi b/doc/filters.texi
> index e77256e..0932516 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -133,6 +133,39 @@ For example to force the output to either unsigned 8-bit 
> or signed 16-bit stereo
>  aformat=sample_fmts\=u8\,s16:channel_layouts\=stereo
>  @end example
>  
> +@section alength
> +
> +Shorten or optionally pad input audio to a target length.
> +
> +The filter accepts the following named parameters:
> +@table @option
> +
> +@item length
> +The target length in samples
> +
> +@item pad
> +A boolean that controls whether or not to pad output with silence to reach
> +the target length.
> +
> +@item frame_size
> +The size of silent frames to be generated.
> +
> +@end table
> +
> +For example to limit output audio to at most 480000 samples
> +@example
> +alength=length=480000
> +@end example
> +
> +To force output audio to be 480000 samples
> +@example
> +alength=length=480000\,pad=1
> +@end example
> +
> +To pad or trim audio to match video length
> +@example
> +avconv -i INPUT -af alength=pad=1 -shortest OUTPUT
> +@end example
>  @section amix
>  
>  Mixes multiple audio inputs into a single output.
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 530aa57..74d57c9 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -26,6 +26,7 @@ OBJS = allfilters.o                                         
>             \
>  
>  OBJS-$(CONFIG_AFIFO_FILTER)                  += fifo.o
>  OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
> +OBJS-$(CONFIG_ALENGTH_FILTER)                += af_alength.o
>  OBJS-$(CONFIG_AMIX_FILTER)                   += af_amix.o
>  OBJS-$(CONFIG_ANULL_FILTER)                  += af_anull.o
>  OBJS-$(CONFIG_ASPLIT_FILTER)                 += split.o
> diff --git a/libavfilter/af_alength.c b/libavfilter/af_alength.c
> new file mode 100644
> index 0000000..a06bb07
> --- /dev/null
> +++ b/libavfilter/af_alength.c
> @@ -0,0 +1,161 @@
> +/*
> + * Copyright (c) 2012 Google, Inc.
> + *
> + * This file is part of Libav.
> + *
> + * Libav 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,
> + * 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
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> + */
> +
> +/**
> + * @file
> + * Filter that shortens or lengths and audio stream
> + */
> +
> +#include "libavutil/audioconvert.h"
> +#include "libavutil/common.h"
> +#include "libavutil/opt.h"
> +#include "avfilter.h"
> +#include "audio.h"
> +#include "internal.h"
> +#include "formats.h"
> +
> +typedef struct {
> +    const AVClass *class;
> +    int64_t next_pts;
> +    int64_t length;
> +    int got_output;
> +    int pad;
> +    int frame_size;
> +} ALengthContext;
> +
> +#define OFFSET(x) offsetof(ALengthContext, x)
> +#define A AV_OPT_FLAG_AUDIO_PARAM
> +
> +static const AVOption alength_options[] = {
> +{ "length", "Target length in samples", OFFSET(length), AV_OPT_TYPE_INT64, { 
> INT64_MAX }, 0, INT64_MAX, A },
                                                                                
^^^^^^^^^
As we discussed on IRC, this doesn't work currently, and after it's fixed it
should be .i64 = INT64_MAX

> +{ "pad", "Pad to length if too short", OFFSET(pad), AV_OPT_TYPE_INT, { 0 }, 
> 0, 1, A },
> +{ "frame_size", "frame_size", OFFSET(frame_size), AV_OPT_TYPE_INT, { 1024 }, 
> 0, INT_MAX, A },
> +{ NULL }
> +};
> +
> +static const AVClass alength_class = {
> +    .class_name = "alength filter",
> +    .item_name  = av_default_item_name,
> +    .option     = alength_options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +static av_cold int alength_init(AVFilterContext *ctx, const char *args)
> +{
> +    ALengthContext *s = ctx->priv;
> +    int err;
> +
> +    s->class = &alength_class;
> +    av_opt_set_defaults(s);
> +
> +    if ((err = av_set_options_string(s, args, "=", ":")) < 0)
> +        return err;
> +
> +    s->next_pts = AV_NOPTS_VALUE;
> +    av_log(ctx, AV_LOG_VERBOSE, "length:%"PRId64" pad:%d frame_size:%d\n", 
> s->length, s->pad, s->frame_size);
> +
> +    return 0;
> +}
> +
> +static int alength_filter_samples(AVFilterLink *inlink, AVFilterBufferRef 
> *buf)
> +{
> +    AVFilterContext *ctx = inlink->dst;
> +    ALengthContext *s = ctx->priv;
> +    AVFilterLink *outlink = ctx->outputs[0];
> +    int nb_samples = buf->audio->nb_samples;
> +
> +    if (buf->pts != AV_NOPTS_VALUE) {
> +        s->next_pts = buf->pts;
> +    }
> +
> +    if (s->next_pts == AV_NOPTS_VALUE) {
> +        s->got_output = 1;
> +        return ff_filter_samples(outlink, buf);
> +    } else if (s->next_pts >= s->length) {
> +        avfilter_unref_buffer(buf);
> +        return AVERROR_EOF;
> +    } else if (s->next_pts + nb_samples <= s->length) {
> +        s->next_pts += nb_samples;
> +        s->got_output = 1;
> +        return ff_filter_samples(outlink, buf);
> +    } else {
> +        nb_samples = s->length - s->next_pts;
> +        buf->audio->nb_samples = nb_samples;
> +        s->next_pts += nb_samples;
> +        s->got_output = 1;
> +        return ff_filter_samples(outlink, buf);
> +    }

This assumes the timestamps start at 0, which might not always be true. It also
won't work correctly when a timestamps at the beginning are missing.
I think
it'd be better to track the first timestamp and assume it to be 0 when it's
not present.

-- 
Anton Khirnov
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to