diff options
author | Nicolas George <george@nsup.org> | 2015-10-25 17:31:58 +0100 |
---|---|---|
committer | Nicolas George <george@nsup.org> | 2015-11-07 16:04:07 +0100 |
commit | 7037f9430b6223ec74080ecb2e58b25426f5f47d (patch) | |
tree | a20e25e9766c986085e4b11ef2aba2f6ec619077 | |
parent | 432e27e6e7b653c2aafc05cd5f1bb74dc758a081 (diff) | |
download | ffmpeg-7037f9430b6223ec74080ecb2e58b25426f5f47d.tar.gz |
lavfi: add realtime filter.
Similar to the -re option in ffmpeg that only works for input files.
Can be used at any place in the filter graph.
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | doc/filters.texi | 16 | ||||
-rw-r--r-- | libavfilter/Makefile | 2 | ||||
-rw-r--r-- | libavfilter/allfilters.c | 2 | ||||
-rw-r--r-- | libavfilter/f_realtime.c | 132 |
5 files changed, 153 insertions, 0 deletions
@@ -31,6 +31,7 @@ version <next>: - ADPCM AICA decoder - Interplay ACM demuxer and audio decoder - XMA1 & XMA2 decoder +- realtime filter version 2.8: diff --git a/doc/filters.texi b/doc/filters.texi index 15ea77a90d..a1147fff89 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -13068,6 +13068,22 @@ following one, the permission might not be received as expected in that following filter. Inserting a @ref{format} or @ref{aformat} filter before the perms/aperms filter can avoid this problem. +@section realtime, arealtime + +Slow down filtering to match real time approximatively. + +These filters will pause the filtering for a variable amount of time to +match the output rate with the input timestamps. +They are similar to the @option{re} option to @code{ffmpeg}. + +They accept the following options: + +@table @option +@item limit +Time limit for the pauses. Any pause longer than that will be considered +a timestamp discontinuity and reset the timer. Default is 2 seconds. +@end table + @section select, aselect Select frames to pass in output. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index f771dca0f9..db4f437869 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -39,6 +39,7 @@ OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o OBJS-$(CONFIG_APAD_FILTER) += af_apad.o OBJS-$(CONFIG_APERMS_FILTER) += f_perms.o OBJS-$(CONFIG_APHASER_FILTER) += af_aphaser.o generate_wave_table.o +OBJS-$(CONFIG_AREALTIME_FILTER) += f_realtime.o OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o OBJS-$(CONFIG_AREVERSE_FILTER) += f_reverse.o OBJS-$(CONFIG_ASELECT_FILTER) += f_select.o @@ -197,6 +198,7 @@ OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o dualinput.o framesync. OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o OBJS-$(CONFIG_QP_FILTER) += vf_qp.o OBJS-$(CONFIG_RANDOM_FILTER) += vf_random.o +OBJS-$(CONFIG_REALTIME_FILTER) += f_realtime.o OBJS-$(CONFIG_REMOVEGRAIN_FILTER) += vf_removegrain.o OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o OBJS-$(CONFIG_REPEATFIELDS_FILTER) += vf_repeatfields.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 05dfac9182..e35c504759 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -61,6 +61,7 @@ void avfilter_register_all(void) REGISTER_FILTER(APAD, apad, af); REGISTER_FILTER(APERMS, aperms, af); REGISTER_FILTER(APHASER, aphaser, af); + REGISTER_FILTER(AREALTIME, arealtime, af); REGISTER_FILTER(ARESAMPLE, aresample, af); REGISTER_FILTER(AREVERSE, areverse, af); REGISTER_FILTER(ASELECT, aselect, af); @@ -218,6 +219,7 @@ void avfilter_register_all(void) REGISTER_FILTER(PULLUP, pullup, vf); REGISTER_FILTER(QP, qp, vf); REGISTER_FILTER(RANDOM, random, vf); + REGISTER_FILTER(REALTIME, realtime, vf); REGISTER_FILTER(REMOVEGRAIN, removegrain, vf); REGISTER_FILTER(REMOVELOGO, removelogo, vf); REGISTER_FILTER(REPEATFIELDS, repeatfields, vf); diff --git a/libavfilter/f_realtime.c b/libavfilter/f_realtime.c new file mode 100644 index 0000000000..68ad268523 --- /dev/null +++ b/libavfilter/f_realtime.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "libavutil/time.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct RealtimeContext { + const AVClass *class; + int64_t delta; + int64_t limit; + unsigned inited; +} RealtimeContext; + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + RealtimeContext *s = ctx->priv; + + if (frame->pts != AV_NOPTS_VALUE) { + int64_t pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q); + int64_t now = av_gettime_relative(); + int64_t sleep = pts - now + s->delta; + if (!s->inited) { + s->inited = 1; + sleep = 0; + s->delta = now - pts; + } + if (sleep > s->limit || sleep < -s->limit) { + av_log(ctx, AV_LOG_WARNING, + "time discontinuity detected: %"PRIi64" us, resetting\n", + sleep); + sleep = 0; + s->delta = now - pts; + } + if (sleep > 0) { + av_log(ctx, AV_LOG_DEBUG, "sleeping %"PRIi64" us\n", sleep); + for (; sleep > 600000000; sleep -= 600000000) + av_usleep(600000000); + av_usleep(sleep); + } + } + return ff_filter_frame(inlink->dst->outputs[0], frame); +} + +#define OFFSET(x) offsetof(RealtimeContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +static const AVOption options[] = { + { "limit", "sleep time limit", OFFSET(limit), AV_OPT_TYPE_DURATION, { .i64 = 2000000 }, 0, INT64_MAX, FLAGS }, + { NULL } +}; + +#if CONFIG_REALTIME_FILTER +#define realtime_options options +AVFILTER_DEFINE_CLASS(realtime); + +static const AVFilterPad avfilter_vf_realtime_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad avfilter_vf_realtime_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_realtime = { + .name = "realtime", + .description = NULL_IF_CONFIG_SMALL("Slow down filtering to match realtime"), + .priv_size = sizeof(RealtimeContext), + .priv_class = &realtime_class, + .inputs = avfilter_vf_realtime_inputs, + .outputs = avfilter_vf_realtime_outputs, +}; +#endif /* CONFIG_REALTIME_FILTER */ + +#if CONFIG_AREALTIME_FILTER + +#define arealtime_options options +AVFILTER_DEFINE_CLASS(arealtime); + +static const AVFilterPad arealtime_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad arealtime_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_arealtime = { + .name = "arealtime", + .description = NULL_IF_CONFIG_SMALL("Slow down filtering to match realtime"), + .priv_size = sizeof(RealtimeContext), + .priv_class = &arealtime_class, + .inputs = arealtime_inputs, + .outputs = arealtime_outputs, +}; +#endif /* CONFIG_AREALTIME_FILTER */ |