FFmpeg
Loading...
Searching...
No Matches
framesync.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013 Nicolas George
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 License
8 * 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
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "libavutil/avassert.h"
22#include "libavutil/mem.h"
23#include "libavutil/opt.h"
24#include "avfilter.h"
25#include "filters.h"
26#include "framesync.h"
27
28#define OFFSET(member) offsetof(FFFrameSync, member)
29#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
30
31static const char *framesync_name(void *ptr)
32{
33 return "framesync";
34}
35
36static const AVOption framesync_options[] = {
37 { "eof_action", "Action to take when encountering EOF from secondary input ",
38 OFFSET(opt_eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT },
39 EOF_ACTION_REPEAT, EOF_ACTION_PASS, .flags = FLAGS, .unit = "eof_action" },
40 { "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, .unit = "eof_action" },
41 { "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, .unit = "eof_action" },
42 { "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, .unit = "eof_action" },
43 { "shortest", "force termination when the shortest input terminates", OFFSET(opt_shortest), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
44 { "repeatlast", "extend last frame of secondary streams beyond EOF", OFFSET(opt_repeatlast), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
45 { "ts_sync_mode", "How strictly to sync streams based on secondary input timestamps",
46 OFFSET(opt_ts_sync_mode), AV_OPT_TYPE_INT, { .i64 = TS_DEFAULT },
47 TS_DEFAULT, TS_NEAREST, .flags = FLAGS, .unit = "ts_sync_mode" },
48 { "default", "Frame from secondary input with the nearest lower or equal timestamp to the primary input frame",
49 0, AV_OPT_TYPE_CONST, { .i64 = TS_DEFAULT }, .flags = FLAGS, .unit = "ts_sync_mode" },
50 { "nearest", "Frame from secondary input with the absolute nearest timestamp to the primary input frame",
51 0, AV_OPT_TYPE_CONST, { .i64 = TS_NEAREST }, .flags = FLAGS, .unit = "ts_sync_mode" },
52 { NULL }
53};
55 .version = LIBAVUTIL_VERSION_INT,
56 .class_name = "framesync",
57 .item_name = framesync_name,
58 .category = AV_CLASS_CATEGORY_FILTER,
59 .option = framesync_options,
60 .parent_log_context_offset = OFFSET(parent),
61};
62
64{
65 const AVClass *c = *iter ? NULL : &ff_framesync_class;
66 *iter = (void *)(uintptr_t)c;
67 return c;
68}
69
70enum {
74};
75
77
79{
80 if (fs->class)
81 return;
82 fs->class = &ff_framesync_class;
84}
85
86int ff_framesync_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in)
87{
88 /* For filters with several outputs, we will not be able to assume which
89 output is relevant for ff_outlink_frame_wanted() and
90 ff_outlink_set_status(). To be designed when needed. */
91 av_assert0(parent->nb_outputs == 1);
92
94 fs->parent = parent;
95 fs->nb_in = nb_in;
96
97 fs->in = av_calloc(nb_in, sizeof(*fs->in));
98 if (!fs->in) {
99 fs->nb_in = 0;
100 return AVERROR(ENOMEM);
101 }
102
103 return 0;
104}
105
107{
108 fs->eof = 1;
109 fs->frame_ready = 0;
110 ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, pts);
111}
112
114{
115 unsigned i, level = 0;
116
117 for (i = 0; i < fs->nb_in; i++)
118 if (fs->in[i].state != STATE_EOF)
119 level = FFMAX(level, fs->in[i].sync);
120 av_assert0(level <= fs->sync_level);
121 if (level < fs->sync_level)
122 av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level);
123 if (fs->opt_ts_sync_mode > TS_DEFAULT) {
124 for (i = 0; i < fs->nb_in; i++) {
125 if (fs->in[i].sync < level)
126 fs->in[i].ts_mode = fs->opt_ts_sync_mode;
127 else
128 fs->in[i].ts_mode = TS_DEFAULT;
129 }
130 }
131 if (level)
132 fs->sync_level = level;
133 else
134 framesync_eof(fs, eof_pts);
135}
136
138{
139 unsigned i;
140
141 if (!fs->opt_repeatlast || fs->opt_eof_action == EOF_ACTION_PASS) {
142 fs->opt_repeatlast = 0;
143 fs->opt_eof_action = EOF_ACTION_PASS;
144 }
145 if (fs->opt_shortest || fs->opt_eof_action == EOF_ACTION_ENDALL) {
146 fs->opt_shortest = 1;
147 fs->opt_eof_action = EOF_ACTION_ENDALL;
148 }
149 if (!fs->opt_repeatlast) {
150 for (i = 1; i < fs->nb_in; i++) {
151 fs->in[i].after = EXT_NULL;
152 fs->in[i].sync = 0;
153 }
154 }
155 if (fs->opt_shortest) {
156 for (i = 0; i < fs->nb_in; i++)
157 fs->in[i].after = EXT_STOP;
158 }
159
160 if (!fs->time_base.num) {
161 for (i = 0; i < fs->nb_in; i++) {
162 if (fs->in[i].sync) {
163 if (fs->time_base.num) {
164 fs->time_base = av_gcd_q(fs->time_base, fs->in[i].time_base,
166 } else {
167 fs->time_base = fs->in[i].time_base;
168 }
169 }
170 }
171 if (!fs->time_base.num) {
172 av_log(fs, AV_LOG_ERROR, "Impossible to set time base\n");
173 return AVERROR(EINVAL);
174 }
175 av_log(fs, AV_LOG_VERBOSE, "Selected %d/%d time base\n",
176 fs->time_base.num, fs->time_base.den);
177 }
178
179 for (i = 0; i < fs->nb_in; i++)
180 fs->in[i].pts = fs->in[i].pts_next = AV_NOPTS_VALUE;
181 fs->sync_level = UINT_MAX;
183
184 return 0;
185}
186
188{
189 unsigned i;
190 int64_t pts;
191 int ret;
192
193 while (!(fs->frame_ready || fs->eof)) {
194 ret = consume_from_fifos(fs);
195 if (ret <= 0)
196 return ret;
197
198 pts = INT64_MAX;
199 for (i = 0; i < fs->nb_in; i++)
200 if (fs->in[i].have_next && fs->in[i].pts_next < pts)
201 pts = fs->in[i].pts_next;
202 if (pts == INT64_MAX) {
204 break;
205 }
206 for (i = 0; i < fs->nb_in; i++) {
207 if (fs->in[i].pts_next == pts ||
208 (fs->in[i].ts_mode == TS_NEAREST &&
209 fs->in[i].have_next &&
210 fs->in[i].pts_next != INT64_MAX && fs->in[i].pts != AV_NOPTS_VALUE &&
211 fs->in[i].pts_next - pts < pts - fs->in[i].pts) ||
212 (fs->in[i].before == EXT_INFINITY &&
213 fs->in[i].state == STATE_BOF)) {
214 av_frame_free(&fs->in[i].frame);
215 fs->in[i].frame = fs->in[i].frame_next;
216 fs->in[i].pts = fs->in[i].pts_next;
217 fs->in[i].frame_next = NULL;
218 fs->in[i].pts_next = AV_NOPTS_VALUE;
219 fs->in[i].have_next = 0;
220 fs->in[i].state = fs->in[i].frame ? STATE_RUN : STATE_EOF;
221 if (fs->in[i].sync == fs->sync_level && fs->in[i].frame)
222 fs->frame_ready = 1;
223 if (fs->in[i].state == STATE_EOF &&
224 fs->in[i].after == EXT_STOP)
226 }
227 }
228 if (fs->frame_ready)
229 for (i = 0; i < fs->nb_in; i++)
230 if ((fs->in[i].state == STATE_BOF &&
231 fs->in[i].before == EXT_STOP))
232 fs->frame_ready = 0;
233 fs->pts = pts;
234 }
235 return 0;
236}
237
239 int64_t pts)
240{
241 /* Possible enhancement: use the link's frame rate */
242 return pts + 1;
243}
244
246{
247 int64_t pts;
248
249 av_assert0(!fs->in[in].have_next);
251 pts = av_rescale_q_rnd(frame->pts, fs->in[in].time_base, fs->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
252 frame->pts = pts;
253 fs->in[in].frame_next = frame;
254 fs->in[in].pts_next = pts;
255 fs->in[in].have_next = 1;
256}
257
258static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t eof_pts)
259{
260 av_assert0(!fs->in[in].have_next);
261 fs->in[in].sync = 0;
263 fs->in[in].frame_next = NULL;
264 fs->in[in].pts_next = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY
265 ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts);
266 fs->in[in].have_next = 1;
267}
268
269int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
270 unsigned get)
271{
272 AVFrame *frame;
273 unsigned need_copy = 0, i;
274 int64_t pts_next;
275
276 if (!fs->in[in].frame) {
277 *rframe = NULL;
278 return 0;
279 }
280 frame = fs->in[in].frame;
281 if (get) {
282 /* Find out if we need to copy the frame: is there another sync
283 stream, and do we know if its current frame will outlast this one? */
284 pts_next = fs->in[in].have_next ? fs->in[in].pts_next : INT64_MAX;
285 for (i = 0; i < fs->nb_in && !need_copy; i++)
286 if (i != in && fs->in[i].sync &&
287 (!fs->in[i].have_next || fs->in[i].pts_next < pts_next))
288 need_copy = 1;
289 if (need_copy) {
290 if (!(frame = av_frame_clone(frame)))
291 return AVERROR(ENOMEM);
292 } else {
293 fs->in[in].frame = NULL;
294 }
295 fs->frame_ready = 0;
296 }
297 *rframe = frame;
298 return 0;
299}
300
302{
303 unsigned i;
304
305 for (i = 0; i < fs->nb_in; i++) {
306 av_frame_free(&fs->in[i].frame);
307 av_frame_free(&fs->in[i].frame_next);
308 }
309
310 av_freep(&fs->in);
311}
312
314{
315 AVFilterContext *ctx = fs->parent;
316 AVFrame *frame = NULL;
317 int64_t pts;
318 unsigned i, nb_active, nb_miss;
319 int ret, status;
320
321 nb_active = nb_miss = 0;
322 for (i = 0; i < fs->nb_in; i++) {
323 if (fs->in[i].have_next || fs->in[i].state == STATE_EOF)
324 continue;
325 nb_active++;
326 ret = ff_inlink_consume_frame(ctx->inputs[i], &frame);
327 if (ret < 0)
328 return ret;
329 if (ret) {
332 } else {
333 ret = ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts);
334 if (ret > 0) {
335 framesync_inject_status(fs, i, status, pts);
336 } else if (!ret) {
337 nb_miss++;
338 }
339 }
340 }
341 if (nb_miss) {
342 if (nb_miss == nb_active && !ff_outlink_frame_wanted(ctx->outputs[0]))
343 return FFERROR_NOT_READY;
344 for (i = 0; i < fs->nb_in; i++)
345 if (!fs->in[i].have_next && fs->in[i].state != STATE_EOF)
346 ff_inlink_request_frame(ctx->inputs[i]);
347 return 0;
348 }
349 return 1;
350}
351
353{
354 AVFilterContext *ctx = fs->parent;
355 int ret;
356
358
359 ret = framesync_advance(fs);
360 if (ret < 0)
361 return ret;
362 if (fs->eof || !fs->frame_ready)
363 return 0;
364 ret = fs->on_event(fs);
365 if (ret < 0)
366 return ret;
367 fs->frame_ready = 0;
368
369 return 0;
370}
371
373{
374 int ret;
375
376 ret = ff_framesync_init(fs, parent, 2);
377 if (ret < 0)
378 return ret;
379 fs->in[0].time_base = parent->inputs[0]->time_base;
380 fs->in[1].time_base = parent->inputs[1]->time_base;
381 fs->in[0].sync = 2;
382 fs->in[0].before = EXT_STOP;
383 fs->in[0].after = EXT_INFINITY;
384 fs->in[1].sync = 1;
385 fs->in[1].before = EXT_NULL;
386 fs->in[1].after = EXT_INFINITY;
387 return 0;
388}
389
391{
392 AVFilterContext *ctx = fs->parent;
393 AVFrame *mainpic = NULL, *secondpic = NULL;
394 int ret;
395
396 if ((ret = ff_framesync_get_frame(fs, 0, &mainpic, 1)) < 0 ||
397 (ret = ff_framesync_get_frame(fs, 1, &secondpic, 0)) < 0) {
398 av_frame_free(&mainpic);
399 return ret;
400 }
401 av_assert0(mainpic);
402 mainpic->pts = av_rescale_q(fs->pts, fs->time_base, ctx->outputs[0]->time_base);
403 if (ctx->is_disabled)
404 secondpic = NULL;
405 *f0 = mainpic;
406 *f1 = secondpic;
407 return 0;
408}
409
411{
412 int ret;
413
414 ret = ff_framesync_dualinput_get(fs, f0, f1);
415 if (ret < 0)
416 return ret;
417 ret = ff_inlink_make_frame_writable(fs->parent->inputs[0], f0);
418 if (ret < 0) {
419 av_frame_free(f0);
420 *f1 = NULL;
421 return ret;
422 }
423 return 0;
424}
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition avfilter.c:1467
int ff_outlink_frame_wanted(AVFilterLink *link)
Test if a frame is wanted on an output link.
Definition avfilter.c:1690
int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe)
Make sure a frame is writable.
Definition avfilter.c:1567
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Definition avfilter.c:1520
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition avfilter.c:1623
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define fs(width, name, subs,...)
Definition cbs_vp9.c:200
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVFrame * frame
static int framesync_advance(FFFrameSync *fs)
Definition framesync.c:187
static const AVOption framesync_options[]
Definition framesync.c:36
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition framesync.c:137
static int consume_from_fifos(FFFrameSync *fs)
Definition framesync.c:313
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition framesync.c:390
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition framesync.c:352
int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, unsigned get)
Get the current frame in an input.
Definition framesync.c:269
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition framesync.c:372
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition framesync.c:301
const AVClass ff_framesync_class
Definition framesync.c:54
static void framesync_sync_level_update(FFFrameSync *fs, int64_t eof_pts)
Definition framesync.c:113
static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t eof_pts)
Definition framesync.c:258
void ff_framesync_preinit(FFFrameSync *fs)
Pre-initialize a frame sync structure.
Definition framesync.c:78
int ff_framesync_dualinput_get_writable(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Same as ff_framesync_dualinput_get(), but make sure that f0 is writable.
Definition framesync.c:410
#define OFFSET(member)
Definition framesync.c:28
static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
Definition framesync.c:245
int ff_framesync_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in)
Initialize a frame sync structure.
Definition framesync.c:86
const AVClass * ff_framesync_child_class_iterate(void **iter)
Definition framesync.c:63
static int64_t framesync_pts_extrapolate(FFFrameSync *fs, unsigned in, int64_t pts)
Definition framesync.c:238
static const char * framesync_name(void *ptr)
Definition framesync.c:31
static void framesync_eof(FFFrameSync *fs, int64_t pts)
Definition framesync.c:106
@ EOF_ACTION_REPEAT
Definition framesync.h:27
@ EXT_INFINITY
Extend the frame to infinity.
Definition framesync.h:75
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition frame.c:483
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
AVRational av_gcd_q(AVRational a, AVRational b, int max_den, AVRational def)
Return the best rational so that a and b are multiple of it.
Definition rational.c:188
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd)
Rescale a 64-bit integer by 2 rational numbers with specified rounding.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AV_ROUND_PASS_MINMAX
Flag telling rescaling functions to pass INT64_MIN/MAX through unchanged, avoiding special cases for ...
@ AV_ROUND_NEAR_INF
Round to nearest and halfway cases away from zero.
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define AV_TIME_BASE
Internal time base represented as integer.
Definition avutil.h:253
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
Definition opt.c:1754
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition filters.h:629
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
Definition filters.h:34
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
Definition filters.h:652
@ AV_CLASS_CATEGORY_FILTER
Definition log.h:36
#define FFMAX(a, b)
Definition macros.h:47
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
@ STATE_BOF
Definition packetsync.c:72
@ STATE_EOF
Definition packetsync.c:74
@ STATE_RUN
Definition packetsync.c:73
@ TS_DEFAULT
Sync to packets from secondary input with the nearest, lower or equal timestamp to the packet event o...
Definition packetsync.h:82
@ TS_NEAREST
Sync to packets from secondary input with the absolute nearest timestamp to the packet event one.
Definition packetsync.h:88
@ EOF_ACTION_PASS
Definition packetsync.h:31
@ EOF_ACTION_ENDALL
Definition packetsync.h:30
@ EXT_STOP
Completely stop all streams with this one.
Definition packetsync.h:62
@ EXT_NULL
Ignore this stream and continue processing the other ones.
Definition packetsync.h:67
static void get(const uint8_t *pixels, int stride, int16_t *block)
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
unsigned nb_outputs
number of output pads
Definition avfilter.h:286
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition frame.h:574
AVOption.
Definition opt.h:428
Frame sync structure.
Definition framesync.h:168
uint8_t level
Definition svq3.c:208
#define av_freep(p)
#define av_log(a,...)
static int64_t pts
static double c[64]