/* * Copyright (C) 2017 Paul B Mahol * * 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/common.h" #include "libavutil/opt.h" #include "internal.h" typedef struct VFRDETContext { const AVClass *class; int64_t prev_pts; int64_t delta; int64_t min_delta; int64_t max_delta; int64_t avg_delta; uint64_t vfr; uint64_t cfr; } VFRDETContext; static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; VFRDETContext *s = ctx->priv; if (s->prev_pts != AV_NOPTS_VALUE) { int64_t delta = in->pts - s->prev_pts; if (s->delta == AV_NOPTS_VALUE) { s->delta = delta; s->min_delta = delta; s->max_delta = delta; } if (s->delta != delta) { s->vfr++; s->delta = delta; s->min_delta = FFMIN(delta, s->min_delta); s->max_delta = FFMAX(delta, s->max_delta); s->avg_delta += delta; } else { s->cfr++; } } s->prev_pts = in->pts; return ff_filter_frame(ctx->outputs[0], in); } static av_cold int init(AVFilterContext *ctx) { VFRDETContext *s = ctx->priv; s->prev_pts = AV_NOPTS_VALUE; s->delta = AV_NOPTS_VALUE; s->min_delta = INT64_MAX; s->max_delta = INT64_MIN; return 0; } static av_cold void uninit(AVFilterContext *ctx) { VFRDETContext *s = ctx->priv; av_log(ctx, AV_LOG_INFO, "VFR:%f (%"PRIu64"/%"PRIu64")", s->vfr / (float)(s->vfr + s->cfr), s->vfr, s->cfr); if (s->vfr) av_log(ctx, AV_LOG_INFO, " min: %"PRId64" max: %"PRId64" avg: %"PRId64, s->min_delta, s->max_delta, s->avg_delta / s->vfr); av_log(ctx, AV_LOG_INFO, "\n"); } static const AVFilterPad vfrdet_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .filter_frame = filter_frame, }, { NULL } }; static const AVFilterPad vfrdet_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, }, { NULL } }; AVFilter ff_vf_vfrdet = { .name = "vfrdet", .description = NULL_IF_CONFIG_SMALL("Variable frame rate detect filter."), .priv_size = sizeof(VFRDETContext), .init = init, .uninit = uninit, .inputs = vfrdet_inputs, .outputs = vfrdet_outputs, };