---
 Changelog                |    1 +
 doc/filters.texi         |   34 ++++++++
 libavfilter/Makefile     |    1 +
 libavfilter/af_alength.c |  210 ++++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/allfilters.c |    1 +
 libavfilter/version.h    |    2 +-
 6 files changed, 248 insertions(+), 1 deletions(-)
 create mode 100644 libavfilter/af_alength.c

diff --git a/Changelog b/Changelog
index b4a8e60..4c97276 100644
--- a/Changelog
+++ b/Changelog
@@ -8,6 +8,7 @@ version <next>:
 - deprecated the avconv -vol option. the volume filter is to be used instead.
 - multi-channel ALAC encoding up to 7.1
 - TAK demuxer, parser, and decoder
+- add alength audio filter
 
 
 version 9_beta2:
diff --git a/doc/filters.texi b/doc/filters.texi
index 34db2f4..bb55435 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -133,6 +133,40 @@ 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 seconds
+
+@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 10 seconds
+@example
+alength=length=10
+@end example
+
+To force output audio to be 10 seconds
+@example
+alength=length=10: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 2559e8a..ac244d0 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_ASHOWINFO_FILTER)              += af_ashowinfo.o
diff --git a/libavfilter/af_alength.c b/libavfilter/af_alength.c
new file mode 100644
index 0000000..04c9ba7
--- /dev/null
+++ b/libavfilter/af_alength.c
@@ -0,0 +1,210 @@
+/*
+ * 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 lengthens an audio stream.
+ */
+
+#include "libavutil/audioconvert.h"
+#include "libavutil/common.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+#include "formats.h"
+
+typedef struct ALengthContext {
+    const AVClass *class;
+    AVRational sample_rate;
+    int64_t next_pts;
+    char *length;
+    int64_t scaled_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 seconds",   OFFSET(length),     
AV_OPT_TYPE_STRING, { .str = "-1" }, .flags = 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;
+    if (!strcmp(s->length, "-1"))
+        s->scaled_length = AV_NOPTS_VALUE;
+    else
+       if ((err = av_parse_time(&s->scaled_length, s->length, 1)))
+           return err;
+
+    s->next_pts  = AV_NOPTS_VALUE;
+    s->final_pts = AV_NOPTS_VALUE;
+    av_log(ctx, AV_LOG_VERBOSE, "length:%s pad:%d frame_size:%d\n",
+           s->length, s->pad, s->frame_size);
+
+    return 0;
+}
+
+static int alength_config_input(AVFilterLink *inlink)
+{
+    ALengthContext *s = inlink->dst->priv;
+    s->sample_rate    = (AVRational) { 1, inlink->sample_rate };
+    if (s->scaled_length == AV_NOPTS_VALUE)
+        s->scaled_length = INT64_MAX;
+    else
+        s->scaled_length = av_rescale_q(s->scaled_length,
+                                        AV_TIME_BASE_Q,
+                                        s->sample_rate);
+    return 0;
+}
+
+static int alength_config_output(AVFilterLink *outlink) {
+    ALengthContext *s = outlink->src->priv;
+    outlink->time_base = s->sample_rate;
+    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;
+    int64_t in_pts = AV_NOPTS_VALUE;
+
+    if (buf->pts != AV_NOPTS_VALUE)
+        in_pts = av_rescale_q(buf->pts, inlink->time_base, s->sample_rate);
+
+    if (s->final_pts == AV_NOPTS_VALUE) {
+        if (in_pts != AV_NOPTS_VALUE) {
+            if (in_pts > 0 && s->scaled_length > INT64_MAX - in_pts)
+                s->final_pts = INT64_MAX;
+            else
+                s->final_pts = in_pts + s->scaled_length;
+        } else {
+            s->final_pts = s->scaled_length;
+        }
+    }
+
+    if (in_pts != AV_NOPTS_VALUE)
+        s->next_pts = in_pts;
+
+    if (s->next_pts == AV_NOPTS_VALUE)
+        s->next_pts = 0;
+
+    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_frame(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_frame(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->scaled_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_frame(outlink, buf);
+    }
+
+    return ret;
+}
+
+AVFilter avfilter_af_alength = {
+    .name           = "alength",
+    .description    = NULL_IF_CONFIG_SMALL("Shorten or lengthen an audio 
stream."),
+    .priv_size      = sizeof(ALengthContext),
+    .init           = alength_init,
+
+    .inputs         = (const AVFilterPad[]) {
+        {
+            .name          = "default",
+            .config_props  = alength_config_input,
+            .type          = AVMEDIA_TYPE_AUDIO,
+            .filter_frame  = alength_filter_samples,
+            .min_perms     = AV_PERM_READ | AV_PERM_WRITE
+        },
+        { .name = NULL }
+    },
+
+    .outputs        = (const AVFilterPad[]) {
+        {
+            .name          = "default",
+            .config_props  = alength_config_output,
+            .type          = AVMEDIA_TYPE_AUDIO,
+            .request_frame = alength_request_frame,
+        },
+        { .name = NULL }
+    },
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 0d7cbc2..80e43ab 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 (ASHOWINFO,   ashowinfo,   af);
diff --git a/libavfilter/version.h b/libavfilter/version.h
index c09d44b..b62f25c 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -29,7 +29,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVFILTER_VERSION_MAJOR  3
-#define LIBAVFILTER_VERSION_MINOR  3
+#define LIBAVFILTER_VERSION_MINOR  4
 #define LIBAVFILTER_VERSION_MICRO  0
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
-- 
1.7.7.3

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

Reply via email to