Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2014 Nicholas Robbins
  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.  
  21. /**
  22.  * @file
  23.  * remove judder in video stream
  24.  *
  25.  * Algorithm:
  26.  *    - If the old packets had PTS of old_pts[i]. Replace these with new
  27.  *      value based on the running average of the last n=cycle frames. So
  28.  *
  29.  *      new_pts[i] = Sum(k=i-n+1, i, old_pts[k])/n
  30.  *                        + (old_pts[i]-old_pts[i-n])*(n-1)/2n
  31.  *
  32.  *      For any repeating pattern of length n of judder this will produce
  33.  *      an even progression of PTS's.
  34.  *
  35.  *    - In order to avoid calculating this sum ever frame, a running tally
  36.  *      is maintained in ctx->new_pts. Each frame the new term at the start
  37.  *      of the sum is added, the one and the end is removed, and the offset
  38.  *      terms (second line in formula above) are recalculated.
  39.  *
  40.  *    - To aid in this a ringbuffer of the last n-2 PTS's is maintained in
  41.  *      ctx->ringbuff. With the indices of the first two and last two entries
  42.  *      stored in i1, i2, i3, & i4.
  43.  *
  44.  *    - To ensure that the new PTS's are integers, time_base is divided
  45.  *      by 2n. This removes the division in the new_pts calculation.
  46.  *
  47.  *    - frame_rate is also multiplied by 2n to allow the frames to fall
  48.  *      where they may in what may now be a VFR output. This produces more
  49.  *      even output then setting frame_rate=1/0 in practice.
  50.  */
  51.  
  52. #include "libavutil/opt.h"
  53. #include "libavutil/mathematics.h"
  54. #include "avfilter.h"
  55. #include "internal.h"
  56. #include "video.h"
  57.  
  58. typedef struct {
  59.     const AVClass *class;
  60.     int64_t *ringbuff;
  61.     int i1, i2, i3, i4;
  62.     int64_t new_pts;
  63.     int start_count;
  64.  
  65.     /* options */
  66.     int cycle;
  67. } DejudderContext;
  68.  
  69. #define OFFSET(x) offsetof(DejudderContext, x)
  70. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
  71.  
  72. static const AVOption dejudder_options[] = {
  73.     {"cycle", "set the length of the cycle to use for dejuddering",
  74.         OFFSET(cycle), AV_OPT_TYPE_INT, {.i64 = 4}, 2, 240, .flags = FLAGS},
  75.     {NULL}
  76. };
  77.  
  78. AVFILTER_DEFINE_CLASS(dejudder);
  79.  
  80. static int config_out_props(AVFilterLink *outlink)
  81. {
  82.     AVFilterContext *ctx = outlink->src;
  83.     DejudderContext *s = ctx->priv;
  84.     AVFilterLink *inlink = outlink->src->inputs[0];
  85.  
  86.     outlink->time_base = av_mul_q(inlink->time_base, av_make_q(1, 2 * s->cycle));
  87.     outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(2 * s->cycle, 1));
  88.  
  89.     av_log(ctx, AV_LOG_VERBOSE, "cycle:%d\n", s->cycle);
  90.  
  91.     return 0;
  92. }
  93.  
  94. static av_cold int dejudder_init(AVFilterContext *ctx)
  95. {
  96.     DejudderContext *s = ctx->priv;
  97.  
  98.     s->ringbuff = av_mallocz_array(s->cycle+2, sizeof(*s->ringbuff));
  99.     if (!s->ringbuff)
  100.         return AVERROR(ENOMEM);
  101.  
  102.     s->new_pts = 0;
  103.     s->i1 = 0;
  104.     s->i2 = 1;
  105.     s->i3 = 2;
  106.     s->i4 = 3;
  107.     s->start_count = s->cycle + 2;
  108.  
  109.     return 0;
  110. }
  111.  
  112. static av_cold void dejudder_uninit(AVFilterContext *ctx)
  113. {
  114.     DejudderContext *s = ctx->priv;
  115.  
  116.     av_freep(&(s->ringbuff));
  117. }
  118.  
  119. static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
  120. {
  121.     int k;
  122.     AVFilterContext *ctx  = inlink->dst;
  123.     AVFilterLink *outlink = ctx->outputs[0];
  124.     DejudderContext *s   = ctx->priv;
  125.     int64_t *judbuff      = s->ringbuff;
  126.     int64_t next_pts      = frame->pts;
  127.     int64_t offset;
  128.  
  129.     if (next_pts == AV_NOPTS_VALUE)
  130.         return ff_filter_frame(outlink, frame);
  131.  
  132.     if (s->start_count) {
  133.         s->start_count--;
  134.         s->new_pts = next_pts * 2 * s->cycle;
  135.     } else {
  136.         if (next_pts < judbuff[s->i2]) {
  137.             offset = next_pts + judbuff[s->i3] - judbuff[s->i4] - judbuff[s->i1];
  138.             for (k = 0; k < s->cycle + 2; k++)
  139.                 judbuff[k] += offset;
  140.         }
  141.         s->new_pts += (s->cycle - 1) * (judbuff[s->i3] - judbuff[s->i1])
  142.                     + (s->cycle + 1) * (next_pts - judbuff[s->i4]);
  143.     }
  144.  
  145.     judbuff[s->i2] = next_pts;
  146.     s->i1 = s->i2;
  147.     s->i2 = s->i3;
  148.     s->i3 = s->i4;
  149.     s->i4 = (s->i4 + 1) % (s->cycle + 2);
  150.  
  151.     frame->pts = s->new_pts;
  152.  
  153.     for (k = 0; k < s->cycle + 2; k++)
  154.         av_log(ctx, AV_LOG_DEBUG, "%"PRId64"\t", judbuff[k]);
  155.     av_log(ctx, AV_LOG_DEBUG, "next=%"PRId64", new=%"PRId64"\n", next_pts, frame->pts);
  156.  
  157.     return ff_filter_frame(outlink, frame);
  158. }
  159.  
  160. static const AVFilterPad dejudder_inputs[] = {
  161.     {
  162.         .name         = "default",
  163.         .type         = AVMEDIA_TYPE_VIDEO,
  164.         .filter_frame = filter_frame,
  165.     },
  166.     { NULL }
  167. };
  168.  
  169. static const AVFilterPad dejudder_outputs[] = {
  170.     {
  171.         .name = "default",
  172.         .type = AVMEDIA_TYPE_VIDEO,
  173.         .config_props = config_out_props,
  174.     },
  175.     { NULL }
  176. };
  177.  
  178. AVFilter ff_vf_dejudder = {
  179.     .name        = "dejudder",
  180.     .description = NULL_IF_CONFIG_SMALL("Remove judder produced by pullup."),
  181.     .priv_size   = sizeof(DejudderContext),
  182.     .priv_class  = &dejudder_class,
  183.     .inputs      = dejudder_inputs,
  184.     .outputs     = dejudder_outputs,
  185.     .init        = dejudder_init,
  186.     .uninit      = dejudder_uninit,
  187. };
  188.