vf_vfrdet.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (C) 2017 Paul B Mahol
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include "libavutil/common.h"
  21. #include "libavutil/opt.h"
  22. #include "internal.h"
  23. typedef struct VFRDETContext {
  24. const AVClass *class;
  25. int64_t prev_pts;
  26. int64_t delta;
  27. int64_t min_delta;
  28. int64_t max_delta;
  29. uint64_t vfr;
  30. uint64_t cfr;
  31. } VFRDETContext;
  32. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  33. {
  34. AVFilterContext *ctx = inlink->dst;
  35. VFRDETContext *s = ctx->priv;
  36. if (s->prev_pts != AV_NOPTS_VALUE) {
  37. int64_t delta = in->pts - s->prev_pts;
  38. if (s->delta == AV_NOPTS_VALUE) {
  39. s->delta = delta;
  40. }
  41. if (s->delta != delta) {
  42. s->vfr++;
  43. s->delta = delta;
  44. s->min_delta = FFMIN(delta, s->min_delta);
  45. s->max_delta = FFMAX(delta, s->max_delta);
  46. } else {
  47. s->cfr++;
  48. }
  49. }
  50. s->prev_pts = in->pts;
  51. return ff_filter_frame(ctx->outputs[0], in);
  52. }
  53. static av_cold int init(AVFilterContext *ctx)
  54. {
  55. VFRDETContext *s = ctx->priv;
  56. s->prev_pts = AV_NOPTS_VALUE;
  57. s->delta = AV_NOPTS_VALUE;
  58. s->min_delta = INT64_MAX;
  59. s->max_delta = INT64_MIN;
  60. return 0;
  61. }
  62. static av_cold void uninit(AVFilterContext *ctx)
  63. {
  64. VFRDETContext *s = ctx->priv;
  65. av_log(ctx, AV_LOG_INFO, "VFR:%f (%"PRIu64"/%"PRIu64")", s->vfr / (float)(s->vfr + s->cfr), s->vfr, s->cfr);
  66. if (s->vfr)
  67. av_log(ctx, AV_LOG_INFO, " min: %"PRId64" max: %"PRId64")", s->min_delta, s->max_delta);
  68. av_log(ctx, AV_LOG_INFO, "\n");
  69. }
  70. static const AVFilterPad vfrdet_inputs[] = {
  71. {
  72. .name = "default",
  73. .type = AVMEDIA_TYPE_VIDEO,
  74. .filter_frame = filter_frame,
  75. },
  76. { NULL }
  77. };
  78. static const AVFilterPad vfrdet_outputs[] = {
  79. {
  80. .name = "default",
  81. .type = AVMEDIA_TYPE_VIDEO,
  82. },
  83. { NULL }
  84. };
  85. AVFilter ff_vf_vfrdet = {
  86. .name = "vfrdet",
  87. .description = NULL_IF_CONFIG_SMALL("Variable frame rate detect filter."),
  88. .priv_size = sizeof(VFRDETContext),
  89. .init = init,
  90. .uninit = uninit,
  91. .inputs = vfrdet_inputs,
  92. .outputs = vfrdet_outputs,
  93. };