diff options
author | Nicolas George <george@nsup.org> | 2015-10-25 19:31:58 +0300 |
---|---|---|
committer | Nicolas George <george@nsup.org> | 2015-11-07 18:04:07 +0300 |
commit | 7037f9430b6223ec74080ecb2e58b25426f5f47d (patch) | |
tree | a20e25e9766c986085e4b11ef2aba2f6ec619077 /libavfilter/f_realtime.c | |
parent | 432e27e6e7b653c2aafc05cd5f1bb74dc758a081 (diff) |
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.
Diffstat (limited to 'libavfilter/f_realtime.c')
-rw-r--r-- | libavfilter/f_realtime.c | 132 |
1 files changed, 132 insertions, 0 deletions
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 */ |