[FFmpeg-devel] [PATCH] lavfi: add realtime filter.
Nicolas George
george at nsup.org
Sun Oct 25 17:35:32 CET 2015
Similar to the -re option in ffmpeg that only works for input files.
Can be used at any place in the filter graph.
Signed-off-by: Nicolas George <george at nsup.org>
---
Changelog | 1 +
doc/filters.texi | 16 ++++++
libavfilter/Makefile | 2 +
libavfilter/allfilters.c | 2 +
libavfilter/f_realtime.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 151 insertions(+)
create mode 100644 libavfilter/f_realtime.c
diff --git a/Changelog b/Changelog
index abaac19..1c8fe37 100644
--- a/Changelog
+++ b/Changelog
@@ -25,6 +25,7 @@ version <next>:
- wve demuxer
- zero-copy Intel QSV transcoding in ffmpeg
- shuffleframes filter
+- realtime filter
version 2.8:
diff --git a/doc/filters.texi b/doc/filters.texi
index 5a35bde..141394c 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -13052,6 +13052,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.
+ at 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:
+
+ at table @option
+ at 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.
+ at end table
+
@section select, aselect
Select frames to pass in output.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index dd4f547..9c07d98 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
@@ -196,6 +197,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 8e363a0..239fbb5 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);
@@ -217,6 +218,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 0000000..a50141c
--- /dev/null
+++ b/libavfilter/f_realtime.c
@@ -0,0 +1,130 @@
+/*
+ * 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);
+ 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 */
--
2.6.1
More information about the ffmpeg-devel
mailing list