---
 Changelog                |    1 +
 doc/filters.texi         |   33 +++++++++
 libavfilter/Makefile     |    1 +
 libavfilter/af_alength.c |  178 ++++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/allfilters.c |    1 +
 5 files changed, 214 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..2af934a
--- /dev/null
+++ b/libavfilter/af_alength.c
@@ -0,0 +1,178 @@
+/*
+ * 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;
+    int64_t final_pts;
+    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, 
{.i64=INT64_MAX}, 0, INT64_MAX, A },
+{ "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;
+    s->final_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 (s->final_pts == AV_NOPTS_VALUE) {
+        if (buf->pts != AV_NOPTS_VALUE) {
+            if (buf->pts > 0 && s->length > INT64_MAX - buf->pts)
+                s->final_pts = INT64_MAX;
+            else
+                s->final_pts = buf->pts + s->length;
+        } else {
+            s->final_pts = s->length;
+        }
+    }
+
+    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->final_pts) {
+        avfilter_unref_buffer(buf);
+        return AVERROR_EOF;
+    } else if (s->next_pts + nb_samples <= s->final_pts) {
+        s->next_pts += nb_samples;
+        s->got_output = 1;
+        return ff_filter_samples(outlink, buf);
+    } else {
+        nb_samples = s->final_pts - s->next_pts;
+        buf->audio->nb_samples = nb_samples;
+        s->next_pts += nb_samples;
+        s->got_output = 1;
+        return ff_filter_samples(outlink, buf);
+    }
+}
+
+static int alength_request_frame(AVFilterLink *outlink)
+{
+    ALengthContext *s = outlink->src->priv;
+    AVFilterLink *inlink = outlink->src->inputs[0];
+    int ret;
+
+    s->got_output = 0;
+    do {
+        ret = ff_request_frame(inlink);
+    } while (!s->got_output && ret >= 0);
+
+    if (s->final_pts == AV_NOPTS_VALUE) {
+        s->final_pts = s->length;
+    }
+
+    if (ret == AVERROR_EOF && s->pad && s->next_pts < s->final_pts) {
+        int nb_samples = FFMIN(s->frame_size, s->final_pts - s->next_pts);
+        int nb_channels = 
av_get_channel_layout_nb_channels(outlink->channel_layout);
+        AVFilterBufferRef *buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE,
+                                                     nb_samples);
+        if (!buf)
+            return AVERROR(ENOMEM);
+        av_samples_set_silence(buf->extended_data, 0, nb_samples, nb_channels,
+                               buf->format);
+        buf->pts = s->next_pts;
+        if (s->next_pts != AV_NOPTS_VALUE) {
+            s->next_pts += nb_samples;
+        }
+        return ff_filter_samples(outlink, buf);
+    }
+
+    return ret;
+}
+
+AVFilter avfilter_af_alength = {
+    .name           = "alength",
+    .description    = NULL_IF_CONFIG_SMALL("Shorten or length an audio 
stream."),
+    .priv_size      = sizeof(ALengthContext),
+    .init           = alength_init,
+
+    .inputs  = (const AVFilterPad[]) {
+        {
+            .name           = "default",
+            .type           = AVMEDIA_TYPE_AUDIO,
+            .filter_samples = alength_filter_samples,
+            .min_perms      = AV_PERM_READ|AV_PERM_WRITE
+        },
+        { .name = NULL }
+    },
+
+    .outputs = (const AVFilterPad[]) {
+        {
+            .name           = "default",
+            .type           = AVMEDIA_TYPE_AUDIO,
+            .request_frame  = alength_request_frame,
+        },
+        { .name = NULL }
+    },
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 94b3115..2602cef 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -37,6 +37,7 @@ void avfilter_register_all(void)
 
     REGISTER_FILTER (AFIFO,       afifo,       af);
     REGISTER_FILTER (AFORMAT,     aformat,     af);
+    REGISTER_FILTER (ALENGTH,     alength,     af);
     REGISTER_FILTER (AMIX,        amix,        af);
     REGISTER_FILTER (ANULL,       anull,       af);
     REGISTER_FILTER (ASPLIT,      asplit,      af);
-- 
1.7.7.3

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

Reply via email to