From: Alex Converse <alex.conve...@gmail.com> Signed-off-by: Luca Barbato <lu_z...@gentoo.org> --- Changelog | 1 + doc/filters.texi | 33 +++++++++ libavfilter/Makefile | 1 + libavfilter/af_alength.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 5 files changed, 198 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..ec15e13 --- /dev/null +++ b/libavfilter/af_alength.c @@ -0,0 +1,162 @@ +/* + * 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 }, +{ "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); + } +} + +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 (ret == AVERROR_EOF && s->pad && s->next_pts < s->length) { + int nb_samples = FFMIN(s->frame_size, s->length - 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 _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel