---
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
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel