2 * Copyright (c) 2014 Nicholas Robbins
4 * This file is part of FFmpeg.
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.
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.
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
23 * remove judder in video stream
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
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
32 * For any repeating pattern of length n of judder this will produce
33 * an even progression of PTS's.
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.
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.
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.
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.
52 #include "libavutil/opt.h"
53 #include "libavutil/mathematics.h"
69 #define OFFSET(x) offsetof(DejudderContext, x)
70 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
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
},
78 AVFILTER_DEFINE_CLASS(dejudder
);
80 static int config_out_props(AVFilterLink
*outlink
)
82 AVFilterContext
*ctx
= outlink
->src
;
83 DejudderContext
*dj
= ctx
->priv
;
84 AVFilterLink
*inlink
= outlink
->src
->inputs
[0];
86 outlink
->time_base
= av_mul_q(inlink
->time_base
, av_make_q(1, 2 * dj
->cycle
));
87 outlink
->frame_rate
= av_mul_q(inlink
->frame_rate
, av_make_q(2 * dj
->cycle
, 1));
89 av_log(ctx
, AV_LOG_VERBOSE
, "cycle:%d\n", dj
->cycle
);
94 static av_cold
int dejudder_init(AVFilterContext
*ctx
)
96 DejudderContext
*dj
= ctx
->priv
;
98 dj
->ringbuff
= av_mallocz_array(dj
->cycle
+2, sizeof(*dj
->ringbuff
));
100 return AVERROR(ENOMEM
);
107 dj
->start_count
= dj
->cycle
+ 2;
112 static av_cold
void dejudder_uninit(AVFilterContext
*ctx
)
114 DejudderContext
*dj
= ctx
->priv
;
116 av_freep(&(dj
->ringbuff
));
119 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*frame
)
122 AVFilterContext
*ctx
= inlink
->dst
;
123 AVFilterLink
*outlink
= ctx
->outputs
[0];
124 DejudderContext
*dj
= ctx
->priv
;
125 int64_t *judbuff
= dj
->ringbuff
;
126 int64_t next_pts
= frame
->pts
;
129 if (next_pts
== AV_NOPTS_VALUE
)
130 return ff_filter_frame(outlink
, frame
);
132 if (dj
->start_count
) {
134 dj
->new_pts
= next_pts
* 2 * dj
->cycle
;
136 if (next_pts
< judbuff
[dj
->i2
]) {
137 offset
= next_pts
+ judbuff
[dj
->i3
] - judbuff
[dj
->i4
] - judbuff
[dj
->i1
];
138 for (k
= 0; k
< dj
->cycle
+ 2; k
++)
139 judbuff
[k
] += offset
;
141 dj
->new_pts
+= (dj
->cycle
- 1) * (judbuff
[dj
->i3
] - judbuff
[dj
->i1
])
142 + (dj
->cycle
+ 1) * (next_pts
- judbuff
[dj
->i4
]);
145 judbuff
[dj
->i2
] = next_pts
;
149 dj
->i4
= (dj
->i4
+ 1) % (dj
->cycle
+ 2);
151 frame
->pts
= dj
->new_pts
;
153 for (k
= 0; k
< dj
->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
);
157 return ff_filter_frame(outlink
, frame
);
160 static const AVFilterPad dejudder_inputs
[] = {
163 .type
= AVMEDIA_TYPE_VIDEO
,
164 .filter_frame
= filter_frame
,
169 static const AVFilterPad dejudder_outputs
[] = {
172 .type
= AVMEDIA_TYPE_VIDEO
,
173 .config_props
= config_out_props
,
178 AVFilter ff_vf_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
,